modified to support confirmed messages. Verified with ReadProperty request.
This commit is contained in:
@@ -19,6 +19,8 @@ SRCS = ports/linux/main.c \
|
|||||||
iam.c \
|
iam.c \
|
||||||
rp.c \
|
rp.c \
|
||||||
wp.c \
|
wp.c \
|
||||||
|
tsm.c \
|
||||||
|
address.c \
|
||||||
device.c \
|
device.c \
|
||||||
ai.c \
|
ai.c \
|
||||||
ao.c \
|
ao.c \
|
||||||
|
|||||||
+4
-7
@@ -39,6 +39,7 @@
|
|||||||
#include "bacdef.h"
|
#include "bacdef.h"
|
||||||
#include "bacdcode.h"
|
#include "bacdcode.h"
|
||||||
#include "bacenum.h"
|
#include "bacenum.h"
|
||||||
|
#include "tsm.h"
|
||||||
|
|
||||||
// Confirmed Function Handlers
|
// Confirmed Function Handlers
|
||||||
// If they are not set, they are handled by a reject message
|
// If they are not set, they are handled by a reject message
|
||||||
@@ -244,9 +245,7 @@ void apdu_handler(
|
|||||||
invoke_id);
|
invoke_id);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
tsm_free_invoke_id(invoke_id);
|
||||||
//FIXME: release the invoke id
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -297,9 +296,7 @@ void apdu_handler(
|
|||||||
&service_ack_data);
|
&service_ack_data);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
tsm_free_invoke_id(invoke_id);
|
||||||
//FIXME: release the invoke id
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -310,7 +307,7 @@ void apdu_handler(
|
|||||||
case PDU_TYPE_REJECT:
|
case PDU_TYPE_REJECT:
|
||||||
case PDU_TYPE_ABORT:
|
case PDU_TYPE_ABORT:
|
||||||
invoke_id = apdu[1];
|
invoke_id = apdu[1];
|
||||||
// FIXME: release the invoke id
|
tsm_free_invoke_id(invoke_id);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -22,4 +22,11 @@
|
|||||||
// requests available.
|
// requests available.
|
||||||
#define MAX_TSM_TRANSACTIONS 16
|
#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
|
#endif
|
||||||
|
|||||||
@@ -42,6 +42,8 @@
|
|||||||
#include "reject.h"
|
#include "reject.h"
|
||||||
#include "abort.h"
|
#include "abort.h"
|
||||||
#include "bacerror.h"
|
#include "bacerror.h"
|
||||||
|
#include "address.h"
|
||||||
|
#include "tsm.h"
|
||||||
|
|
||||||
// Example handlers of services
|
// Example handlers of services
|
||||||
|
|
||||||
@@ -70,6 +72,8 @@
|
|||||||
|
|
||||||
// flag to send an I-Am
|
// flag to send an I-Am
|
||||||
bool I_Am_Request = true;
|
bool I_Am_Request = true;
|
||||||
|
// flag to send a global Who-Is
|
||||||
|
bool Who_Is_Request = true;
|
||||||
|
|
||||||
// buffers used for transmit and receive
|
// buffers used for transmit and receive
|
||||||
static uint8_t Tx_Buf[MAX_MPDU] = {0};
|
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));
|
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(
|
void WhoIsHandler(
|
||||||
uint8_t *service_request,
|
uint8_t *service_request,
|
||||||
uint16_t service_len,
|
uint16_t service_len,
|
||||||
@@ -206,6 +314,29 @@ void IAmHandler(
|
|||||||
return;
|
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(
|
void ReadPropertyHandler(
|
||||||
uint8_t *service_request,
|
uint8_t *service_request,
|
||||||
uint16_t service_len,
|
uint16_t service_len,
|
||||||
|
|||||||
@@ -33,6 +33,13 @@
|
|||||||
|
|
||||||
// flag to send an I-Am
|
// flag to send an I-Am
|
||||||
extern bool I_Am_Request;
|
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(
|
void UnrecognizedServiceHandler(
|
||||||
uint8_t *service_request,
|
uint8_t *service_request,
|
||||||
@@ -41,6 +48,7 @@ void UnrecognizedServiceHandler(
|
|||||||
BACNET_CONFIRMED_SERVICE_DATA *service_data);
|
BACNET_CONFIRMED_SERVICE_DATA *service_data);
|
||||||
|
|
||||||
void Send_IAm(void);
|
void Send_IAm(void);
|
||||||
|
void Send_WhoIs(void);
|
||||||
|
|
||||||
void WhoIsHandler(
|
void WhoIsHandler(
|
||||||
uint8_t *service_request,
|
uint8_t *service_request,
|
||||||
@@ -52,6 +60,12 @@ void IAmHandler(
|
|||||||
uint16_t service_len,
|
uint16_t service_len,
|
||||||
BACNET_ADDRESS *src);
|
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(
|
void ReadPropertyHandler(
|
||||||
uint8_t *service_request,
|
uint8_t *service_request,
|
||||||
uint16_t service_len,
|
uint16_t service_len,
|
||||||
@@ -64,4 +78,12 @@ void WritePropertyHandler(
|
|||||||
BACNET_ADDRESS *src,
|
BACNET_ADDRESS *src,
|
||||||
BACNET_CONFIRMED_SERVICE_DATA *service_data);
|
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
|
#endif
|
||||||
|
|||||||
@@ -28,12 +28,16 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <time.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "address.h"
|
||||||
#include "bacdef.h"
|
#include "bacdef.h"
|
||||||
#include "handlers.h"
|
#include "handlers.h"
|
||||||
#include "bacdcode.h"
|
#include "bacdcode.h"
|
||||||
#include "npdu.h"
|
#include "npdu.h"
|
||||||
#include "apdu.h"
|
#include "apdu.h"
|
||||||
|
#include "iam.h"
|
||||||
|
#include "tsm.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
#ifdef BACDL_ETHERNET
|
#ifdef BACDL_ETHERNET
|
||||||
#include "ethernet.h"
|
#include "ethernet.h"
|
||||||
@@ -134,6 +138,46 @@ static void Init_Device_Parameters(void)
|
|||||||
return;
|
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)
|
static void Init_Service_Handlers(void)
|
||||||
{
|
{
|
||||||
// we need to handle who-is to support dynamic device binding
|
// we need to handle who-is to support dynamic device binding
|
||||||
@@ -142,7 +186,7 @@ static void Init_Service_Handlers(void)
|
|||||||
WhoIsHandler);
|
WhoIsHandler);
|
||||||
apdu_set_unconfirmed_handler(
|
apdu_set_unconfirmed_handler(
|
||||||
SERVICE_UNCONFIRMED_I_AM,
|
SERVICE_UNCONFIRMED_I_AM,
|
||||||
IAmHandler);
|
LocalIAmHandler);
|
||||||
|
|
||||||
// set the handler for all the services we don't implement
|
// set the handler for all the services we don't implement
|
||||||
// It is required to send the proper reject message...
|
// It is required to send the proper reject message...
|
||||||
@@ -155,6 +199,34 @@ static void Init_Service_Handlers(void)
|
|||||||
apdu_set_confirmed_handler(
|
apdu_set_confirmed_handler(
|
||||||
SERVICE_CONFIRMED_WRITE_PROPERTY,
|
SERVICE_CONFIRMED_WRITE_PROPERTY,
|
||||||
WritePropertyHandler);
|
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)
|
static void sig_handler(int signo)
|
||||||
@@ -166,6 +238,8 @@ static void sig_handler(int signo)
|
|||||||
bip_cleanup();
|
bip_cleanup();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
print_address_cache();
|
||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,7 +248,10 @@ int main(int argc, char *argv[])
|
|||||||
BACNET_ADDRESS src = {0}; // address where message came from
|
BACNET_ADDRESS src = {0}; // address where message came from
|
||||||
uint16_t pdu_len = 0;
|
uint16_t pdu_len = 0;
|
||||||
unsigned timeout = 100; // milliseconds
|
unsigned timeout = 100; // milliseconds
|
||||||
|
time_t start_time;
|
||||||
|
time_t new_time = 0;
|
||||||
|
|
||||||
|
start_time = time(NULL); /* get current time */
|
||||||
// Linux specials
|
// Linux specials
|
||||||
signal(SIGINT, sig_handler);
|
signal(SIGINT, sig_handler);
|
||||||
signal(SIGHUP, sig_handler);
|
signal(SIGHUP, sig_handler);
|
||||||
@@ -193,12 +270,11 @@ int main(int argc, char *argv[])
|
|||||||
return 1;
|
return 1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// loop forever
|
// loop forever
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
// input
|
// input
|
||||||
|
new_time = time(NULL);
|
||||||
// returns 0 bytes on timeout
|
// returns 0 bytes on timeout
|
||||||
#ifdef BACDL_ETHERNET
|
#ifdef BACDL_ETHERNET
|
||||||
pdu_len = ethernet_receive(
|
pdu_len = ethernet_receive(
|
||||||
@@ -223,10 +299,19 @@ int main(int argc, char *argv[])
|
|||||||
&Rx_Buf[0],
|
&Rx_Buf[0],
|
||||||
pdu_len);
|
pdu_len);
|
||||||
}
|
}
|
||||||
|
if (new_time > start_time)
|
||||||
|
{
|
||||||
|
tsm_timer_milliseconds(new_time - start_time * 1000);
|
||||||
|
start_time = new_time;
|
||||||
|
}
|
||||||
if (I_Am_Request)
|
if (I_Am_Request)
|
||||||
{
|
{
|
||||||
I_Am_Request = false;
|
I_Am_Request = false;
|
||||||
Send_IAm();
|
Send_IAm();
|
||||||
|
} else if (Who_Is_Request)
|
||||||
|
{
|
||||||
|
Who_Is_Request = false;
|
||||||
|
Send_WhoIs();
|
||||||
}
|
}
|
||||||
// output
|
// output
|
||||||
|
|
||||||
|
|||||||
@@ -64,3 +64,15 @@ make -f ai.mak
|
|||||||
./analog_input >> test.log
|
./analog_input >> test.log
|
||||||
make -f ai.mak clean
|
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
@@ -44,6 +44,8 @@
|
|||||||
#include "tsm.h"
|
#include "tsm.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
|
#include "handlers.h"
|
||||||
|
#include "address.h"
|
||||||
|
|
||||||
// Transaction State Machine
|
// Transaction State Machine
|
||||||
// Really only needed for segmented messages
|
// 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
|
// 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,
|
BACNET_ADDRESS *dest,
|
||||||
uint8_t *pdu,
|
uint8_t *pdu,
|
||||||
uint16_t pdu_len)
|
uint16_t pdu_len)
|
||||||
{
|
{
|
||||||
uint8_t invokeID = 0;
|
|
||||||
unsigned i = 0, j = 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
|
// assign the transaction
|
||||||
invokeID = tsm_next_free_invokeID();
|
TSM_List[index].state = TSM_STATE_AWAIT_CONFIRMATION;
|
||||||
if (invokeID)
|
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[index].pdu[j] = pdu[j];
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
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
|
#ifdef TEST
|
||||||
|
|||||||
+11
-5
@@ -71,7 +71,8 @@ typedef struct BACnet_TSM_Data
|
|||||||
// used to perform timeout on PDU segments
|
// used to perform timeout on PDU segments
|
||||||
//uint8_t SegmentTimer;
|
//uint8_t SegmentTimer;
|
||||||
// used to perform timeout on Confirmed Requests
|
// used to perform timeout on Confirmed Requests
|
||||||
uint8_t RequestTimer;
|
// in milliseconds
|
||||||
|
uint16_t RequestTimer;
|
||||||
// unique id
|
// unique id
|
||||||
uint8_t InvokeID;
|
uint8_t InvokeID;
|
||||||
// state that the TSM is in
|
// state that the TSM is in
|
||||||
@@ -80,17 +81,22 @@ typedef struct BACnet_TSM_Data
|
|||||||
BACNET_ADDRESS dest;
|
BACNET_ADDRESS dest;
|
||||||
// copy of the PDU, should we need to send it again
|
// copy of the PDU, should we need to send it again
|
||||||
uint8_t pdu[MAX_PDU];
|
uint8_t pdu[MAX_PDU];
|
||||||
|
unsigned pdu_len;
|
||||||
} BACNET_TSM_DATA;
|
} BACNET_TSM_DATA;
|
||||||
|
|
||||||
bool tsm_transaction_available(void);
|
bool tsm_transaction_available(void);
|
||||||
uint8_t tsm_transaction_idle_count(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,
|
BACNET_ADDRESS *dest,
|
||||||
uint8_t *pdu,
|
uint8_t *pdu,
|
||||||
uint16_t pdu_len);
|
uint16_t pdu_len);
|
||||||
void tsm_init_list(BACNET_TSM_DATA *list);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user