modified to support confirmed messages. Verified with ReadProperty request.

This commit is contained in:
skarg
2005-05-25 00:42:21 +00:00
parent d13c9172fa
commit 4c8f288b4b
9 changed files with 340 additions and 37 deletions
+2
View File
@@ -19,6 +19,8 @@ SRCS = ports/linux/main.c \
iam.c \
rp.c \
wp.c \
tsm.c \
address.c \
device.c \
ai.c \
ao.c \
+4 -7
View File
@@ -39,6 +39,7 @@
#include "bacdef.h"
#include "bacdcode.h"
#include "bacenum.h"
#include "tsm.h"
// Confirmed Function Handlers
// If they are not set, they are handled by a reject message
@@ -244,9 +245,7 @@ void apdu_handler(
invoke_id);
}
else
{
//FIXME: release the invoke id
}
tsm_free_invoke_id(invoke_id);
break;
default:
break;
@@ -297,9 +296,7 @@ void apdu_handler(
&service_ack_data);
}
else
{
//FIXME: release the invoke id
}
tsm_free_invoke_id(invoke_id);
break;
default:
break;
@@ -310,7 +307,7 @@ void apdu_handler(
case PDU_TYPE_REJECT:
case PDU_TYPE_ABORT:
invoke_id = apdu[1];
// FIXME: release the invoke id
tsm_free_invoke_id(invoke_id);
break;
default:
break;
+7
View File
@@ -22,4 +22,11 @@
// requests available.
#define MAX_TSM_TRANSACTIONS 16
// The address cache is used for binding to BACnet devices
// The number of entries corresponds to the number of
// devices that might respond to an I-Am on the network.
// If your device is a simple server and does not need to bind,
// then you don't need to use this.
#define MAX_ADDRESS_CACHE 255
#endif
+131
View File
@@ -42,6 +42,8 @@
#include "reject.h"
#include "abort.h"
#include "bacerror.h"
#include "address.h"
#include "tsm.h"
// Example handlers of services
@@ -70,6 +72,8 @@
// flag to send an I-Am
bool I_Am_Request = true;
// flag to send a global Who-Is
bool Who_Is_Request = true;
// buffers used for transmit and receive
static uint8_t Tx_Buf[MAX_MPDU] = {0};
@@ -150,6 +154,110 @@ void Send_IAm(void)
fprintf(stderr,"Failed to Send I-Am Request (%s)!\n", strerror(errno));
}
void Send_WhoIs(void)
{
int pdu_len = 0;
BACNET_ADDRESS dest;
int bytes_sent = 0;
// Who-Is is a global broadcast
bacdl_get_broadcast_address(&dest);
// encode the NPDU portion of the packet
pdu_len = npdu_encode_apdu(
&Tx_Buf[0],
&dest,
NULL,
false, // true for confirmed messages
MESSAGE_PRIORITY_NORMAL);
// encode the APDU portion of the packet
pdu_len += whois_encode_apdu(
&Tx_Buf[pdu_len],
-1, // send to all
-1);// send to all
bytes_sent = bacdl_send_pdu(
&dest, // destination address
&Tx_Buf[0],
pdu_len); // number of bytes of data
if (bytes_sent > 0)
fprintf(stderr,"Sent Who-Is Request!\n");
else
fprintf(stderr,"Failed to Send Who-Is Request (%s)!\n", strerror(errno));
}
// returns false if device is not bound
bool Send_Read_Property_Request(
uint32_t device_id, // destination device
BACNET_OBJECT_TYPE object_type,
uint32_t object_instance,
BACNET_PROPERTY_ID object_property,
int32_t array_index)
{
BACNET_ADDRESS dest;
BACNET_ADDRESS my_address;
unsigned max_apdu = 0;
uint8_t invoke_id = 0;
bool status = false;
int pdu_len = 0;
int bytes_sent = 0;
status = address_get_by_device(device_id, &max_apdu, &dest);
if (status)
{
bacdl_get_my_address(&my_address);
pdu_len = npdu_encode_apdu(
&Tx_Buf[0],
&dest,
&my_address,
true, // true for confirmed messages
MESSAGE_PRIORITY_NORMAL);
invoke_id = tsm_next_free_invokeID();
pdu_len += rp_encode_apdu(
&Tx_Buf[pdu_len],
invoke_id,
object_type,
object_instance,
object_property,
array_index);
if (pdu_len < max_apdu)
{
tsm_set_confirmed_unsegmented_transaction(
invoke_id,
&dest,
&Tx_Buf[0],
pdu_len);
bytes_sent = bacdl_send_pdu(
&dest, // destination address
&Tx_Buf[0],
pdu_len); // number of bytes of data
if (bytes_sent > 0)
fprintf(stderr,"Sent ReadProperty Request!\n");
else
fprintf(stderr,"Failed to Send ReadProperty Request (%s)!\n",
strerror(errno));
}
else
fprintf(stderr,"Failed to Send ReadProperty Request "
"(exceeds destination maximum APDU)!\n");
}
return status;
}
int handler_send_pdu(
BACNET_ADDRESS *dest, // destination address
uint8_t *pdu, // any data to be sent - may be null
unsigned pdu_len) // number of bytes of data
{
return bacdl_send_pdu(
dest,
pdu,
pdu_len);
}
void WhoIsHandler(
uint8_t *service_request,
uint16_t service_len,
@@ -206,6 +314,29 @@ void IAmHandler(
return;
}
void ReadPropertyAckHandler(
uint8_t *service_request,
uint16_t service_len,
BACNET_ADDRESS *src,
BACNET_CONFIRMED_SERVICE_ACK_DATA *service_data)
{
int len = 0;
BACNET_READ_PROPERTY_DATA data;
tsm_free_invoke_id(service_data->invoke_id);
len = rp_ack_decode_service_request(
service_request,
service_len,
&data);
fprintf(stderr,"Received Read-Property Ack!\n");
if (len > 0)
fprintf(stderr,"type=%u instance=%u property=%u index=%d\n",
data.object_type,
data.object_instance,
data.object_property,
data.array_index);
}
void ReadPropertyHandler(
uint8_t *service_request,
uint16_t service_len,
+22
View File
@@ -33,6 +33,13 @@
// flag to send an I-Am
extern bool I_Am_Request;
// flag to send a global Who-Is
extern bool Who_Is_Request;
int handler_send_pdu(
BACNET_ADDRESS *dest, // destination address
uint8_t *pdu, // any data to be sent - may be null
unsigned pdu_len); // number of bytes of data
void UnrecognizedServiceHandler(
uint8_t *service_request,
@@ -41,6 +48,7 @@ void UnrecognizedServiceHandler(
BACNET_CONFIRMED_SERVICE_DATA *service_data);
void Send_IAm(void);
void Send_WhoIs(void);
void WhoIsHandler(
uint8_t *service_request,
@@ -52,6 +60,12 @@ void IAmHandler(
uint16_t service_len,
BACNET_ADDRESS *src);
void ReadPropertyAckHandler(
uint8_t *service_request,
uint16_t service_len,
BACNET_ADDRESS *src,
BACNET_CONFIRMED_SERVICE_ACK_DATA *service_data);
void ReadPropertyHandler(
uint8_t *service_request,
uint16_t service_len,
@@ -64,4 +78,12 @@ void WritePropertyHandler(
BACNET_ADDRESS *src,
BACNET_CONFIRMED_SERVICE_DATA *service_data);
// returns false if device is not bound
bool Send_Read_Property_Request(
uint32_t device_id, // destination device
BACNET_OBJECT_TYPE object_type,
uint32_t object_instance,
BACNET_PROPERTY_ID object_property,
int32_t array_index);
#endif
+89 -4
View File
@@ -28,12 +28,16 @@
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include "config.h"
#include "address.h"
#include "bacdef.h"
#include "handlers.h"
#include "bacdcode.h"
#include "npdu.h"
#include "apdu.h"
#include "iam.h"
#include "tsm.h"
#include "device.h"
#ifdef BACDL_ETHERNET
#include "ethernet.h"
@@ -133,6 +137,46 @@ static void Init_Device_Parameters(void)
return;
}
static void LocalIAmHandler(
uint8_t *service_request,
uint16_t service_len,
BACNET_ADDRESS *src)
{
int len = 0;
uint32_t device_id = 0;
unsigned max_apdu = 0;
int segmentation = 0;
uint16_t vendor_id = 0;
(void)src;
(void)service_len;
len = iam_decode_service_request(
service_request,
&device_id,
&max_apdu,
&segmentation,
&vendor_id);
fprintf(stderr,"Received I-Am Request");
if (len != -1)
{
fprintf(stderr," from %u!\n",device_id);
address_add(device_id,
max_apdu,
src);
(void)Send_Read_Property_Request(
device_id, // destination device
OBJECT_DEVICE,
device_id,
PROP_OBJECT_NAME,
BACNET_ARRAY_ALL);
}
else
fprintf(stderr,"!\n");
return;
}
static void Init_Service_Handlers(void)
{
@@ -142,7 +186,7 @@ static void Init_Service_Handlers(void)
WhoIsHandler);
apdu_set_unconfirmed_handler(
SERVICE_UNCONFIRMED_I_AM,
IAmHandler);
LocalIAmHandler);
// set the handler for all the services we don't implement
// It is required to send the proper reject message...
@@ -155,6 +199,34 @@ static void Init_Service_Handlers(void)
apdu_set_confirmed_handler(
SERVICE_CONFIRMED_WRITE_PROPERTY,
WritePropertyHandler);
// handle the data coming back from confirmed requests
apdu_set_confirmed_ack_handler(
SERVICE_CONFIRMED_READ_PROPERTY,
ReadPropertyAckHandler);
}
static void print_address_cache(void)
{
unsigned i,j;
BACNET_ADDRESS address;
uint32_t device_id = 0;
unsigned max_apdu = 0;
fprintf(stderr,"Device\tMAC\tMaxAPDU\tNet\n");
for (i = 0; i < MAX_ADDRESS_CACHE; i++)
{
if (address_get_by_index(i,&device_id, &max_apdu, &address))
{
fprintf(stderr,"%u\t",device_id);
for (j = 0; j < address.mac_len; j++)
{
fprintf(stderr,"%02X",address.mac[j]);
}
fprintf(stderr,"\t");
fprintf(stderr,"%hu\t",max_apdu);
fprintf(stderr,"%hu\n",address.net);
}
}
}
static void sig_handler(int signo)
@@ -166,6 +238,8 @@ static void sig_handler(int signo)
bip_cleanup();
#endif
print_address_cache();
exit(0);
}
@@ -174,7 +248,10 @@ int main(int argc, char *argv[])
BACNET_ADDRESS src = {0}; // address where message came from
uint16_t pdu_len = 0;
unsigned timeout = 100; // milliseconds
time_t start_time;
time_t new_time = 0;
start_time = time(NULL); /* get current time */
// Linux specials
signal(SIGINT, sig_handler);
signal(SIGHUP, sig_handler);
@@ -193,12 +270,11 @@ int main(int argc, char *argv[])
return 1;
#endif
// loop forever
for (;;)
{
// input
new_time = time(NULL);
// returns 0 bytes on timeout
#ifdef BACDL_ETHERNET
pdu_len = ethernet_receive(
@@ -223,10 +299,19 @@ int main(int argc, char *argv[])
&Rx_Buf[0],
pdu_len);
}
if (new_time > start_time)
{
tsm_timer_milliseconds(new_time - start_time * 1000);
start_time = new_time;
}
if (I_Am_Request)
{
I_Am_Request = false;
Send_IAm();
} else if (Who_Is_Request)
{
Who_Is_Request = false;
Send_WhoIs();
}
// output
+12
View File
@@ -64,3 +64,15 @@ make -f ai.mak
./analog_input >> test.log
make -f ai.mak clean
make -f wp.mak clean
make -f wp.mak
./writeproperty >> test.log
make -f wp.mak clean
make -f address.mak clean
make -f address.mak
./address >> test.log
make -f address.mak clean
+62 -21
View File
@@ -44,6 +44,8 @@
#include "tsm.h"
#include "config.h"
#include "device.h"
#include "handlers.h"
#include "address.h"
// Transaction State Machine
// Really only needed for segmented messages
@@ -135,40 +137,79 @@ uint8_t tsm_next_free_invokeID(void)
}
// returns 0 if there are no free transactions
uint8_t tsm_request_confirmed_unsegmented_transaction(
void tsm_set_confirmed_unsegmented_transaction(
uint8_t invokeID,
BACNET_ADDRESS *dest,
uint8_t *pdu,
uint16_t pdu_len)
{
uint8_t invokeID = 0;
unsigned i = 0, j = 0;
uint8_t index;
// see if there is a free transaction
for (i = 0; i < MAX_TSM_TRANSACTIONS; i++)
if (invokeID)
{
if (TSM_List[i].state == TSM_STATE_IDLE)
index = tsm_find_invokeID_index(invokeID);
if (index < MAX_TSM_TRANSACTIONS)
{
// see if the current invoke id is free
invokeID = tsm_next_free_invokeID();
if (invokeID)
// assign the transaction
TSM_List[index].state = TSM_STATE_AWAIT_CONFIRMATION;
TSM_List[index].RetryCount = Device_Number_Of_APDU_Retries();
// start the timer
TSM_List[index].RequestTimer = Device_APDU_Timeout();
// copy the data
for (j = 0; j < pdu_len; j++)
{
// assign the transaction
TSM_List[i].state = TSM_STATE_AWAIT_CONFIRMATION;
TSM_List[i].RetryCount = Device_Number_Of_APDU_Retries();
// start the timer
TSM_List[i].RequestTimer = Device_APDU_Timeout();
// copy the data
for (j = 0; j < pdu_len; j++)
{
TSM_List[i].pdu[j] = pdu[j];
}
memmove(&TSM_List[i].dest,dest,sizeof(TSM_List[i].dest));
TSM_List[index].pdu[j] = pdu[j];
}
break;
TSM_List[index].pdu_len = pdu_len;
address_copy(&TSM_List[i].dest,dest);
}
}
return invokeID;
return;
}
// called once a millisecond
void tsm_timer_milliseconds(uint16_t milliseconds)
{
unsigned i = 0; // counter
int bytes_sent = 0;
for (i = 0; i < MAX_TSM_TRANSACTIONS; i++)
{
if (TSM_List[i].state == TSM_STATE_AWAIT_CONFIRMATION)
{
if (TSM_List[i].RequestTimer > milliseconds)
TSM_List[i].RequestTimer -= milliseconds;
else
TSM_List[i].RequestTimer = 0;
}
// timeout. retry?
if (TSM_List[i].RequestTimer == 0)
{
TSM_List[i].RetryCount--;
TSM_List[i].RequestTimer = Device_APDU_Timeout();
if (TSM_List[i].RetryCount)
{
bytes_sent = handler_send_pdu(
&TSM_List[i].dest, // destination address
&TSM_List[i].pdu[0],
TSM_List[i].pdu_len); // number of bytes of data
}
else
TSM_List[i].state = TSM_STATE_IDLE;
}
}
}
void tsm_free_invoke_id(uint8_t invokeID)
{
uint8_t index;
index = tsm_find_invokeID_index(invokeID);
if (index < MAX_TSM_TRANSACTIONS)
TSM_List[index].state = TSM_STATE_IDLE;
}
#ifdef TEST
+11 -5
View File
@@ -71,7 +71,8 @@ typedef struct BACnet_TSM_Data
// used to perform timeout on PDU segments
//uint8_t SegmentTimer;
// used to perform timeout on Confirmed Requests
uint8_t RequestTimer;
// in milliseconds
uint16_t RequestTimer;
// unique id
uint8_t InvokeID;
// state that the TSM is in
@@ -80,17 +81,22 @@ typedef struct BACnet_TSM_Data
BACNET_ADDRESS dest;
// copy of the PDU, should we need to send it again
uint8_t pdu[MAX_PDU];
unsigned pdu_len;
} BACNET_TSM_DATA;
bool tsm_transaction_available(void);
uint8_t tsm_transaction_idle_count(void);
uint8_t tsm_request_confirmed_unsegmented_transaction(
void tsm_timer_milliseconds(uint16_t milliseconds);
// free the invoke ID when the reply comes back
void tsm_free_invoke_id(uint8_t invokeID);
// use these in tandem
uint8_t tsm_next_free_invokeID(void);
// returns the same invoke ID that was given
void tsm_set_confirmed_unsegmented_transaction(
uint8_t invokeID,
BACNET_ADDRESS *dest,
uint8_t *pdu,
uint16_t pdu_len);
void tsm_init_list(BACNET_TSM_DATA *list);
#endif