modified for AtomicReadFile handling.
This commit is contained in:
@@ -25,6 +25,9 @@ SRCS = ports/linux/main.c \
|
||||
device.c \
|
||||
ai.c \
|
||||
ao.c \
|
||||
bacfile.c \
|
||||
arf.c \
|
||||
awf.c \
|
||||
abort.c \
|
||||
reject.c \
|
||||
bacerror.c \
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@
|
||||
#include "bacenum.h"
|
||||
#include "config.h" // the custom stuff
|
||||
|
||||
#define MAX_ANALOG_INPUTS 32
|
||||
#define MAX_ANALOG_INPUTS 7
|
||||
|
||||
// we simply have 0-n object instances. Yours might be
|
||||
// more complex, and then you need validate that the
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@
|
||||
#include "config.h" // the custom stuff
|
||||
#include "wp.h"
|
||||
|
||||
#define MAX_ANALOG_OUTPUTS 20
|
||||
#define MAX_ANALOG_OUTPUTS 4
|
||||
|
||||
// we choose to have a NULL level in our system represented by
|
||||
// a particular value. When the priorities are not in use, they
|
||||
|
||||
+55
-15
@@ -42,6 +42,25 @@
|
||||
#include "tsm.h"
|
||||
#include "iam.h"
|
||||
|
||||
#ifdef TEST
|
||||
void tsm_free_invoke_id(uint8_t invokeID)
|
||||
{
|
||||
// dummy stub for testing
|
||||
(void)invokeID;
|
||||
}
|
||||
|
||||
void iam_handler(
|
||||
uint8_t *service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS *src)
|
||||
{
|
||||
// dummy stub for testing
|
||||
(void)service_request;
|
||||
(void)service_len;
|
||||
(void)src;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Confirmed Function Handlers
|
||||
// If they are not set, they are handled by a reject message
|
||||
static confirmed_function
|
||||
@@ -149,6 +168,35 @@ void apdu_set_confirmed_ack_handler(
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t apdu_decode_confirmed_service_request(
|
||||
uint8_t *apdu, // APDU data
|
||||
uint16_t apdu_len,
|
||||
BACNET_CONFIRMED_SERVICE_DATA *service_data,
|
||||
uint8_t *service_choice,
|
||||
uint8_t **service_request,
|
||||
uint16_t *service_request_len)
|
||||
{
|
||||
uint16_t len = 0; // counts where we are in PDU
|
||||
|
||||
service_data->segmented_message = (apdu[0] & BIT3) ? true : false;
|
||||
service_data->more_follows = (apdu[0] & BIT2) ? true : false;
|
||||
service_data->segmented_response_accepted = (apdu[0] & BIT1) ? true : false;
|
||||
service_data->max_segs = decode_max_segs(apdu[1]);
|
||||
service_data->max_resp = decode_max_apdu(apdu[1]);
|
||||
service_data->invoke_id = apdu[2];
|
||||
len = 3;
|
||||
if (service_data->segmented_message)
|
||||
{
|
||||
service_data->sequence_number = apdu[len++];
|
||||
service_data->proposed_window_number = apdu[len++];
|
||||
}
|
||||
*service_choice = apdu[len++];
|
||||
*service_request = &apdu[len++];
|
||||
*service_request_len = apdu_len - len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void apdu_handler(
|
||||
BACNET_ADDRESS *src, // source address
|
||||
bool data_expecting_reply,
|
||||
@@ -170,21 +218,13 @@ void apdu_handler(
|
||||
switch (apdu[0] & 0xF0)
|
||||
{
|
||||
case PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
|
||||
service_data.segmented_message = (apdu[0] & BIT3) ? true : false;
|
||||
service_data.more_follows = (apdu[0] & BIT2) ? true : false;
|
||||
service_data.segmented_response_accepted = (apdu[0] & BIT1) ? true : false;
|
||||
service_data.max_segs = decode_max_segs(apdu[1]);
|
||||
service_data.max_resp = decode_max_apdu(apdu[1]);
|
||||
service_data.invoke_id = apdu[2];
|
||||
len = 3;
|
||||
if (service_data.segmented_message)
|
||||
{
|
||||
service_data.sequence_number = apdu[len++];
|
||||
service_data.proposed_window_number = apdu[len++];
|
||||
}
|
||||
service_choice = apdu[len++];
|
||||
service_request = &apdu[len++];
|
||||
service_request_len = apdu_len - len;
|
||||
len = apdu_decode_confirmed_service_request(
|
||||
&apdu[0], // APDU data
|
||||
apdu_len,
|
||||
&service_data,
|
||||
&service_choice,
|
||||
&service_request,
|
||||
&service_request_len);
|
||||
if (service_choice < MAX_BACNET_CONFIRMED_SERVICE)
|
||||
{
|
||||
if (Confirmed_Function[service_choice])
|
||||
|
||||
@@ -125,6 +125,14 @@ void apdu_set_unconfirmed_handler(
|
||||
BACNET_UNCONFIRMED_SERVICE service_choice,
|
||||
unconfirmed_function pFunction);
|
||||
|
||||
uint16_t apdu_decode_confirmed_service_request(
|
||||
uint8_t *apdu, // APDU data
|
||||
uint16_t apdu_len,
|
||||
BACNET_CONFIRMED_SERVICE_DATA *service_data,
|
||||
uint8_t *service_choice,
|
||||
uint8_t **service_request,
|
||||
uint16_t *service_request_len);
|
||||
|
||||
void apdu_handler(
|
||||
BACNET_ADDRESS *src, // source address
|
||||
bool data_expecting_reply,
|
||||
|
||||
@@ -1270,7 +1270,7 @@ int decode_bacnet_time(uint8_t * apdu, int *hour, int *min, int *sec,
|
||||
int encode_bacnet_date(uint8_t * apdu, int year, int month, int day,
|
||||
int wday)
|
||||
{
|
||||
apdu[0] = year;
|
||||
apdu[0] = year - 1900;
|
||||
apdu[1] = month;
|
||||
apdu[2] = day;
|
||||
apdu[3] = wday;
|
||||
@@ -1299,7 +1299,7 @@ int encode_tagged_date(uint8_t * apdu, int year, int month, int day,
|
||||
// returns the number of apdu bytes consumed
|
||||
int decode_date(uint8_t * apdu, int *year, int *month, int *day, int *wday)
|
||||
{
|
||||
*year = apdu[0];
|
||||
*year = apdu[0] + 1900;
|
||||
*month = apdu[1];
|
||||
*day = apdu[2];
|
||||
*wday = apdu[3];
|
||||
|
||||
+14
-1
@@ -31,6 +31,7 @@
|
||||
#include "config.h" // the custom stuff
|
||||
#include "ai.h" // object list dependency
|
||||
#include "ao.h" // object list dependency
|
||||
#include "bacfile.h" // object list dependency
|
||||
#include "wp.h" // write property handling
|
||||
|
||||
static uint32_t Object_Instance_Number = 0;
|
||||
@@ -228,6 +229,7 @@ unsigned Device_Object_List_Count(void)
|
||||
|
||||
count += Analog_Input_Count();
|
||||
count += Analog_Output_Count();
|
||||
count += bacfile_count();
|
||||
|
||||
return count;
|
||||
}
|
||||
@@ -267,7 +269,18 @@ bool Device_Object_List_Identifier(unsigned array_index,
|
||||
status = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!status)
|
||||
{
|
||||
object_index -= Analog_Output_Count();
|
||||
if (object_index < bacfile_count())
|
||||
{
|
||||
*object_type = OBJECT_FILE;
|
||||
*instance = bacfile_index_to_instance(object_index);
|
||||
status = true;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,8 @@
|
||||
#include "ao.h"
|
||||
#include "rp.h"
|
||||
#include "wp.h"
|
||||
#include "arf.h"
|
||||
#include "bacfile.h"
|
||||
#include "whois.h"
|
||||
#include "iam.h"
|
||||
#include "reject.h"
|
||||
@@ -411,6 +413,39 @@ void ReadPropertyHandler(
|
||||
else
|
||||
error = true;
|
||||
break;
|
||||
case OBJECT_FILE:
|
||||
if (bacfile_valid_instance(object_instance))
|
||||
{
|
||||
len = bacfile_encode_property_apdu(
|
||||
&Temp_Buf[0],
|
||||
object_instance,
|
||||
object_property,
|
||||
array_index,
|
||||
&error_class,
|
||||
&error_code);
|
||||
if (len > 0)
|
||||
{
|
||||
// encode the APDU portion of the packet
|
||||
rp_data.object_type = object_type;
|
||||
rp_data.object_instance = object_instance;
|
||||
rp_data.object_property = object_property;
|
||||
rp_data.array_index = array_index;
|
||||
rp_data.application_data = &Temp_Buf[0];
|
||||
rp_data.application_data_len = len;
|
||||
// FIXME: probably need a length limitation sent with encode
|
||||
pdu_len += rp_ack_encode_apdu(
|
||||
&Tx_Buf[pdu_len],
|
||||
service_data->invoke_id,
|
||||
&rp_data);
|
||||
fprintf(stderr,"Sending Read Property Ack!\n");
|
||||
send = true;
|
||||
}
|
||||
else
|
||||
error = true;
|
||||
}
|
||||
else
|
||||
error = true;
|
||||
break;
|
||||
default:
|
||||
error = true;
|
||||
break;
|
||||
@@ -570,3 +605,175 @@ void WritePropertyHandler(
|
||||
return;
|
||||
}
|
||||
|
||||
void AtomicReadFileHandler(
|
||||
uint8_t *service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS *src,
|
||||
BACNET_CONFIRMED_SERVICE_DATA *service_data)
|
||||
{
|
||||
BACNET_ATOMIC_READ_FILE_DATA data;
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
BACNET_ADDRESS my_address;
|
||||
bool send = false;
|
||||
bool error = false;
|
||||
int bytes_sent = 0;
|
||||
BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT;
|
||||
BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
char buffer[MAX_APDU - 16] = ""; // for reply data, less apdu overhead
|
||||
|
||||
fprintf(stderr,"Received Atomic-Read-File Request!\n");
|
||||
len = arf_decode_service_request(
|
||||
service_request,
|
||||
service_len,
|
||||
&data);
|
||||
if (len < 0)
|
||||
fprintf(stderr,"Unable to decode Atomic-Read-File Request!\n");
|
||||
// prepare a reply
|
||||
datalink_get_my_address(&my_address);
|
||||
// encode the NPDU portion of the packet
|
||||
pdu_len = npdu_encode_apdu(
|
||||
&Tx_Buf[0],
|
||||
src,
|
||||
&my_address,
|
||||
false, // true for confirmed messages
|
||||
MESSAGE_PRIORITY_NORMAL);
|
||||
// bad decoding - send an abort
|
||||
if (len < 0)
|
||||
{
|
||||
pdu_len += abort_encode_apdu(
|
||||
&Tx_Buf[pdu_len],
|
||||
service_data->invoke_id,
|
||||
ABORT_REASON_OTHER);
|
||||
fprintf(stderr,"Sending Abort!\n");
|
||||
send = true;
|
||||
}
|
||||
else if (service_data->segmented_message)
|
||||
{
|
||||
pdu_len += abort_encode_apdu(
|
||||
&Tx_Buf[pdu_len],
|
||||
service_data->invoke_id,
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED);
|
||||
fprintf(stderr,"Sending Abort!\n");
|
||||
send = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (data.access == FILE_STREAM_ACCESS)
|
||||
{
|
||||
data.fileData = &buffer[0];
|
||||
data.fileDataLength = sizeof(buffer);
|
||||
if (data.type.stream.requestedOctetCount < data.fileDataLength)
|
||||
{
|
||||
if (bacfile_read_data(&data))
|
||||
{
|
||||
pdu_len += arf_ack_encode_apdu(
|
||||
&Tx_Buf[pdu_len],
|
||||
service_data->invoke_id,
|
||||
&data);
|
||||
send = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
send = true;
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pdu_len += abort_encode_apdu(
|
||||
&Tx_Buf[pdu_len],
|
||||
service_data->invoke_id,
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED);
|
||||
fprintf(stderr,"Sending Abort!\n");
|
||||
send = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error_class = ERROR_CLASS_SERVICES;
|
||||
error_code = ERROR_CODE_INVALID_FILE_ACCESS_METHOD;
|
||||
send = true;
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
if (error)
|
||||
{
|
||||
pdu_len += bacerror_encode_apdu(
|
||||
&Tx_Buf[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_ATOMIC_READ_FILE,
|
||||
error_class,
|
||||
error_code);
|
||||
fprintf(stderr,"Sending Error!\n");
|
||||
send = true;
|
||||
}
|
||||
if (send)
|
||||
{
|
||||
bytes_sent = datalink_send_pdu(
|
||||
src, // destination address
|
||||
&Tx_Buf[0],
|
||||
pdu_len); // number of bytes of data
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr,"Failed to send PDU (%s)!\n", strerror(errno));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// We performed an AtomicReadFile Request,
|
||||
// and here is the data from the server
|
||||
// Note: it does not have to be the same file=instance
|
||||
// that someone can read from us. It is common to
|
||||
// use the description as the file name.
|
||||
void AtomicReadFileAckHandler(
|
||||
uint8_t *service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS *src,
|
||||
BACNET_CONFIRMED_SERVICE_ACK_DATA *service_data)
|
||||
{
|
||||
int len = 0;
|
||||
BACNET_ATOMIC_READ_FILE_DATA data;
|
||||
FILE *pFile = NULL;
|
||||
char *pFilename = NULL;
|
||||
uint32_t instance = 0;
|
||||
|
||||
(void)src;
|
||||
// get the file instance from the tsm data before freeing it
|
||||
instance = bacfile_instance_from_tsm(service_data->invoke_id);
|
||||
tsm_free_invoke_id(service_data->invoke_id);
|
||||
len = arf_ack_decode_service_request(
|
||||
service_request,
|
||||
service_len,
|
||||
&data);
|
||||
fprintf(stderr,"Received Read-File Ack!\n");
|
||||
if ((len > 0) && (instance <= BACNET_MAX_INSTANCE))
|
||||
{
|
||||
// write the data received to the file specified
|
||||
if (data.access == FILE_STREAM_ACCESS)
|
||||
{
|
||||
pFilename = bacfile_name(instance);
|
||||
if (pFilename)
|
||||
{
|
||||
pFile = fopen(pFilename, "rb");
|
||||
if (pFile)
|
||||
{
|
||||
(void)fseek(pFile,
|
||||
data.type.stream.fileStartPosition,
|
||||
SEEK_SET);
|
||||
if (fwrite(data.fileData,data.fileDataLength,1,pFile) != 1)
|
||||
fprintf(stderr,"Failed to write to %s (%u)!\n",
|
||||
pFilename, instance);
|
||||
fclose(pFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (data.access == FILE_RECORD_ACCESS)
|
||||
{
|
||||
// FIXME: add handling for Record Access
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -76,4 +76,15 @@ bool Send_Read_Property_Request(
|
||||
BACNET_PROPERTY_ID object_property,
|
||||
int32_t array_index);
|
||||
|
||||
void AtomicReadFileHandler(
|
||||
uint8_t *service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS *src,
|
||||
BACNET_CONFIRMED_SERVICE_DATA *service_data);
|
||||
void AtomicReadFileAckHandler(
|
||||
uint8_t *service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS *src,
|
||||
BACNET_CONFIRMED_SERVICE_ACK_DATA *service_data);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -66,6 +66,7 @@ void iam_handler(
|
||||
int iam_send(uint8_t *buffer);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testIAm(Test * pTest);
|
||||
#endif
|
||||
|
||||
|
||||
+51
-38
@@ -175,7 +175,11 @@ int npdu_decode(
|
||||
BACNET_NPDU_DATA *npdu_data)
|
||||
{
|
||||
int len = 0; // return value - number of octets loaded in this function
|
||||
int i = 0; // counter
|
||||
int i = 0; // counter
|
||||
uint16_t src_net = 0;
|
||||
uint16_t dest_net = 0;
|
||||
uint8_t address_len = 0;
|
||||
uint8_t mac_octet = 0;
|
||||
|
||||
if (npdu && npdu_data)
|
||||
{
|
||||
@@ -211,30 +215,35 @@ int npdu_decode(
|
||||
// 1 = DNET, DLEN, and Hop Count present
|
||||
// DLEN = 0 denotes broadcast MAC DADR and DADR field is absent
|
||||
// DLEN > 0 specifies length of DADR field
|
||||
if (dest)
|
||||
if (npdu[1] & BIT5)
|
||||
{
|
||||
if (npdu[1] & BIT5)
|
||||
len += decode_unsigned16(&npdu[len], &dest_net);
|
||||
// DLEN = 0 denotes broadcast MAC DADR and DADR field is absent
|
||||
// DLEN > 0 specifies length of DADR field
|
||||
address_len = npdu[len++];
|
||||
if (dest)
|
||||
{
|
||||
len += decode_unsigned16(&npdu[len], &dest->net);
|
||||
// DLEN = 0 denotes broadcast MAC DADR and DADR field is absent
|
||||
// DLEN > 0 specifies length of DADR field
|
||||
dest->len = npdu[len++];
|
||||
if (dest->len)
|
||||
dest->net = dest_net;
|
||||
dest->len = address_len;
|
||||
}
|
||||
if (address_len)
|
||||
{
|
||||
for (i = 0; i < address_len; i++)
|
||||
{
|
||||
for (i = 0; i < dest->len; i++)
|
||||
{
|
||||
dest->adr[i] = npdu[len++];
|
||||
}
|
||||
mac_octet = npdu[len++];
|
||||
if (dest)
|
||||
dest->adr[i] = mac_octet;
|
||||
}
|
||||
}
|
||||
else
|
||||
}
|
||||
// zero out the destination address
|
||||
else if (dest)
|
||||
{
|
||||
dest->net = 0;
|
||||
dest->len = 0;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++)
|
||||
{
|
||||
dest->net = 0;
|
||||
dest->len = 0;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++)
|
||||
{
|
||||
dest->adr[i] = 0;
|
||||
}
|
||||
dest->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
// Bit 3: Source specifier where:
|
||||
@@ -242,36 +251,40 @@ int npdu_decode(
|
||||
// 1 = SNET, SLEN, and SADR present
|
||||
// SLEN = 0 Invalid
|
||||
// SLEN > 0 specifies length of SADR field
|
||||
if (src)
|
||||
if (npdu[1] & BIT3)
|
||||
{
|
||||
if (npdu[1] & BIT3)
|
||||
len += decode_unsigned16(&npdu[len], &src_net);
|
||||
// SLEN = 0 denotes broadcast MAC SADR and SADR field is absent
|
||||
// SLEN > 0 specifies length of SADR field
|
||||
address_len = npdu[len++];
|
||||
if (src)
|
||||
{
|
||||
len += decode_unsigned16(&npdu[len], &src->net);
|
||||
// SLEN = 0 denotes broadcast MAC SADR and SADR field is absent
|
||||
// SLEN > 0 specifies length of SADR field
|
||||
src->len = npdu[len++];
|
||||
if (src->len)
|
||||
src->net = src_net;
|
||||
src->len = address_len;
|
||||
}
|
||||
if (address_len)
|
||||
{
|
||||
for (i = 0; i < address_len; i++)
|
||||
{
|
||||
for (i = 0; i < src->len; i++)
|
||||
{
|
||||
src->adr[i] = npdu[len++];
|
||||
}
|
||||
mac_octet = npdu[len++];
|
||||
if (src)
|
||||
src->adr[i] = mac_octet;
|
||||
}
|
||||
}
|
||||
else
|
||||
}
|
||||
else if (src)
|
||||
{
|
||||
src->net = 0;
|
||||
src->len = 0;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++)
|
||||
{
|
||||
src->net = 0;
|
||||
src->len = 0;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++)
|
||||
{
|
||||
src->adr[i] = 0;
|
||||
}
|
||||
src->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
// The Hop Count field shall be present only if the message is
|
||||
// destined for a remote network, i.e., if DNET is present.
|
||||
// This is a one-octet field that is initialized to a value of 0xff.
|
||||
if (dest && dest->net)
|
||||
if (dest_net)
|
||||
npdu_data->hop_count = npdu[len++];
|
||||
else
|
||||
npdu_data->hop_count = 0;
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "iam.h"
|
||||
#include "tsm.h"
|
||||
#include "device.h"
|
||||
#include "bacfile.h"
|
||||
#ifdef BACDL_ETHERNET
|
||||
#include "ethernet.h"
|
||||
#endif
|
||||
@@ -236,6 +237,7 @@ static void Init_Service_Handlers(void)
|
||||
// It is required to send the proper reject message...
|
||||
apdu_set_unrecognized_service_handler_handler(
|
||||
UnrecognizedServiceHandler);
|
||||
// Set the handlers for any confirmed services that we support
|
||||
// we must implement read property - it's required!
|
||||
apdu_set_confirmed_handler(
|
||||
SERVICE_CONFIRMED_READ_PROPERTY,
|
||||
@@ -243,10 +245,16 @@ static void Init_Service_Handlers(void)
|
||||
apdu_set_confirmed_handler(
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY,
|
||||
WritePropertyHandler);
|
||||
apdu_set_confirmed_handler(
|
||||
SERVICE_CONFIRMED_ATOMIC_READ_FILE,
|
||||
AtomicReadFileHandler);
|
||||
// handle the data coming back from confirmed requests
|
||||
apdu_set_confirmed_ack_handler(
|
||||
SERVICE_CONFIRMED_READ_PROPERTY,
|
||||
ReadPropertyAckHandler);
|
||||
apdu_set_confirmed_ack_handler(
|
||||
SERVICE_CONFIRMED_ATOMIC_READ_FILE,
|
||||
AtomicReadFileAckHandler);
|
||||
}
|
||||
|
||||
static void print_address_cache(void)
|
||||
|
||||
+34
-2
@@ -137,7 +137,6 @@ uint8_t tsm_next_free_invokeID(void)
|
||||
return invokeID;
|
||||
}
|
||||
|
||||
// returns 0 if there are no free transactions
|
||||
void tsm_set_confirmed_unsegmented_transaction(
|
||||
uint8_t invokeID,
|
||||
BACNET_ADDRESS *dest,
|
||||
@@ -146,7 +145,6 @@ void tsm_set_confirmed_unsegmented_transaction(
|
||||
{
|
||||
uint16_t j = 0;
|
||||
uint8_t index;
|
||||
|
||||
|
||||
if (invokeID)
|
||||
{
|
||||
@@ -171,6 +169,40 @@ void tsm_set_confirmed_unsegmented_transaction(
|
||||
return;
|
||||
}
|
||||
|
||||
// used to retrieve the transaction payload
|
||||
// if we wanted to find out what we sent (i.e. when we get an ack)
|
||||
bool tsm_get_transaction_pdu(
|
||||
uint8_t invokeID,
|
||||
BACNET_ADDRESS *dest,
|
||||
uint8_t *pdu,
|
||||
uint16_t *pdu_len)
|
||||
{
|
||||
uint16_t j = 0;
|
||||
uint8_t index;
|
||||
bool found = false;
|
||||
|
||||
if (invokeID)
|
||||
{
|
||||
index = tsm_find_invokeID_index(invokeID);
|
||||
// how much checking is needed? state? dest match? just invokeID?
|
||||
if (index < MAX_TSM_TRANSACTIONS)
|
||||
{
|
||||
// FIXME: we may want to free the transaction so it doesn't timeout
|
||||
// retrieve the transaction
|
||||
// FIXME: bounds check the pdu_len?
|
||||
*pdu_len = TSM_List[index].pdu_len;
|
||||
for (j = 0; j < *pdu_len; j++)
|
||||
{
|
||||
pdu[j] = TSM_List[index].pdu[j];
|
||||
}
|
||||
address_copy(dest,&TSM_List[index].dest);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
// called once a millisecond
|
||||
void tsm_timer_milliseconds(uint16_t milliseconds)
|
||||
{
|
||||
|
||||
@@ -97,6 +97,12 @@ void tsm_set_confirmed_unsegmented_transaction(
|
||||
BACNET_ADDRESS *dest,
|
||||
uint8_t *pdu,
|
||||
uint16_t pdu_len);
|
||||
// returns true if transaction is found
|
||||
bool tsm_get_transaction_pdu(
|
||||
uint8_t invokeID,
|
||||
BACNET_ADDRESS *dest,
|
||||
uint8_t *pdu,
|
||||
uint16_t *pdu_len);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user