Changed the API to pass the NPDU data down through the datalink layer in order to make the dlmstp work since it needs data-expecting-reply information. Of course, this affected all the demos, all the unit tests, and most of the demo handlers. Corrected some TSM leaks in confirmed messages. Refactored the AtomicReadFile and AtomicWriteFile demos by moving the Send_ functions to the demo/handlers directory and using the s_whois common handler. Added some common defines for the BACnet version and revision since several modules were using the info. Hopefully I didn't break too many things.
This commit is contained in:
+2
-3
@@ -272,8 +272,8 @@ uint16_t apdu_decode_confirmed_service_request(uint8_t * apdu, /* APDU data */
|
||||
return len;
|
||||
}
|
||||
|
||||
void apdu_handler(BACNET_ADDRESS * src, /* source address */
|
||||
bool data_expecting_reply, uint8_t * apdu, /* APDU data */
|
||||
void apdu_handler(BACNET_ADDRESS * src,
|
||||
uint8_t * apdu, /* APDU data */
|
||||
uint16_t apdu_len)
|
||||
{
|
||||
BACNET_CONFIRMED_SERVICE_DATA service_data = { 0 };
|
||||
@@ -289,7 +289,6 @@ void apdu_handler(BACNET_ADDRESS * src, /* source address */
|
||||
int error_class = 0;
|
||||
uint8_t reason = 0;
|
||||
|
||||
(void) data_expecting_reply;
|
||||
if (apdu) {
|
||||
/* PDU Type */
|
||||
switch (apdu[0] & 0xF0) {
|
||||
|
||||
+1
-1
@@ -149,7 +149,7 @@ extern "C" {
|
||||
uint8_t ** service_request, uint16_t * service_request_len);
|
||||
|
||||
void apdu_handler(BACNET_ADDRESS * src, /* source address */
|
||||
bool data_expecting_reply, uint8_t * apdu, /* APDU data */
|
||||
uint8_t * apdu, /* APDU data */
|
||||
uint16_t pdu_len); /* for confirmed messages */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -240,7 +240,7 @@ bool bacapp_copy(BACNET_APPLICATION_DATA_VALUE * dest_value,
|
||||
return status;
|
||||
}
|
||||
|
||||
#if PRINT_ENABLED
|
||||
#ifdef BACAPP_PRINT_ENABLED
|
||||
bool bacapp_print_value(FILE * stream,
|
||||
BACNET_APPLICATION_DATA_VALUE * value, BACNET_PROPERTY_ID property)
|
||||
{
|
||||
|
||||
@@ -73,6 +73,14 @@ extern "C" {
|
||||
BACNET_APPLICATION_DATA_VALUE * src_value);
|
||||
|
||||
#if PRINT_ENABLED
|
||||
#define BACAPP_PRINT_ENABLED
|
||||
#else
|
||||
#ifdef TEST
|
||||
#define BACAPP_PRINT_ENABLED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef BACAPP_PRINT_ENABLED
|
||||
bool bacapp_parse_application_data(BACNET_APPLICATION_TAG tag_number,
|
||||
const char *argv, BACNET_APPLICATION_DATA_VALUE * value);
|
||||
|
||||
|
||||
@@ -39,6 +39,10 @@
|
||||
#include "bacenum.h"
|
||||
#include "config.h"
|
||||
|
||||
/* This stack implements this version of BACnet */
|
||||
#define BACNET_PROTOCOL_VERSION 1
|
||||
#define BACNET_PROTOCOL_REVISION 5
|
||||
|
||||
/* largest BACnet Instance Number */
|
||||
/* Also used as a device instance number wildcard address */
|
||||
#define BACNET_MAX_INSTANCE (0x3FFFFF)
|
||||
|
||||
@@ -36,6 +36,14 @@
|
||||
|
||||
/* tiny implementations have no need to print */
|
||||
#if PRINT_ENABLED
|
||||
#define BACTEXT_PRINT_ENABLED
|
||||
#else
|
||||
#ifdef TEST
|
||||
#define BACTEXT_PRINT_ENABLED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef BACTEXT_PRINT_ENABLED
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
@@ -70,6 +78,6 @@ extern "C" {
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif
|
||||
#endif /* BACTEXT_PRINT_ENABLED */
|
||||
|
||||
#endif
|
||||
|
||||
+25
-38
@@ -136,67 +136,54 @@ uint16_t bip_get_port(void)
|
||||
return BIP_Port;
|
||||
}
|
||||
|
||||
/* function to send a packet out the BACnet/IP socket (Annex J) */
|
||||
/* returns number of bytes sent on success, negative number on failure */
|
||||
static int bip_send(struct sockaddr_in *bip_dest, uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len)
|
||||
{ /* number of bytes of data */
|
||||
uint8_t mtu[MAX_MPDU] = { 0 };
|
||||
int mtu_len = 0;
|
||||
int bytes_sent = 0;
|
||||
|
||||
/* assumes that the driver has already been initialized */
|
||||
if (BIP_Socket < 0)
|
||||
return BIP_Socket;
|
||||
|
||||
mtu[0] = BVLL_TYPE_BACNET_IP;
|
||||
if (bip_dest->sin_addr.s_addr == htonl(BIP_Broadcast_Address.s_addr))
|
||||
mtu[1] = BVLC_ORIGINAL_BROADCAST_NPDU;
|
||||
else
|
||||
mtu[1] = BVLC_ORIGINAL_UNICAST_NPDU;
|
||||
mtu_len = 2;
|
||||
mtu_len +=
|
||||
encode_unsigned16(&mtu[mtu_len],
|
||||
(uint16_t) (pdu_len + 4 /*inclusive */ ));
|
||||
memcpy(&mtu[mtu_len], pdu, pdu_len);
|
||||
mtu_len += pdu_len;
|
||||
|
||||
/* Send the packet */
|
||||
bytes_sent = sendto(BIP_Socket, (char *) mtu, mtu_len, 0,
|
||||
(struct sockaddr *) bip_dest, sizeof(struct sockaddr));
|
||||
|
||||
return bytes_sent;
|
||||
}
|
||||
|
||||
/* function to send a packet out the BACnet/IP socket (Annex J) */
|
||||
/* returns number of bytes sent on success, negative number on failure */
|
||||
int bip_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len)
|
||||
{ /* number of bytes of data */
|
||||
struct sockaddr_in bip_dest;
|
||||
uint8_t mtu[MAX_MPDU] = { 0 };
|
||||
int mtu_len = 0;
|
||||
int bytes_sent = 0;
|
||||
BACNET_ADDRESS src;
|
||||
|
||||
/* load destination IP address */
|
||||
/* assumes that the driver has already been initialized */
|
||||
if (BIP_Socket < 0)
|
||||
return BIP_Socket;
|
||||
|
||||
mtu[0] = BVLL_TYPE_BACNET_IP;
|
||||
bip_dest.sin_family = AF_INET;
|
||||
if (dest->mac_len == 6) {
|
||||
(void) decode_unsigned32(&dest->mac[0],
|
||||
&(bip_dest.sin_addr.s_addr));
|
||||
(void) decode_unsigned16(&dest->mac[4], &(bip_dest.sin_port));
|
||||
memset(&(bip_dest.sin_zero), '\0', 8);
|
||||
mtu[1] = BVLC_ORIGINAL_UNICAST_NPDU;
|
||||
}
|
||||
/* broadcast */
|
||||
else if (dest->mac_len == 0) {
|
||||
bip_dest.sin_addr.s_addr = htonl(BIP_Broadcast_Address.s_addr);
|
||||
bip_dest.sin_port = htons(BIP_Port);
|
||||
memset(&(bip_dest.sin_zero), '\0', 8);
|
||||
mtu[1] = BVLC_ORIGINAL_BROADCAST_NPDU;
|
||||
} else
|
||||
return -1;
|
||||
|
||||
/* function to send a packet out the BACnet/IP socket */
|
||||
/* returns 1 on success, 0 on failure */
|
||||
return bip_send(&bip_dest, /* destination address */
|
||||
pdu, /* any data to be sent - may be null */
|
||||
pdu_len); /* number of bytes of data */
|
||||
/* len is encoded at mtu[2], but we haven't finished packing yet */
|
||||
bip_get_my_address(&src);
|
||||
mtu_len = npdu_encode_pdu(&mtu[4], dest, &src, npdu_data);
|
||||
mtu_len += 4;
|
||||
memcpy(&mtu[mtu_len], pdu, pdu_len);
|
||||
mtu_len += pdu_len;
|
||||
encode_unsigned16(&mtu[2],mtu_len);
|
||||
|
||||
/* Send the packet */
|
||||
bytes_sent = sendto(BIP_Socket, (char *) mtu, mtu_len, 0,
|
||||
(struct sockaddr *) &bip_dest, sizeof(struct sockaddr));
|
||||
|
||||
return bytes_sent;
|
||||
}
|
||||
|
||||
/* receives a BACnet/IP packet */
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "bacdef.h"
|
||||
#include "npdu.h"
|
||||
#include "net.h"
|
||||
|
||||
/* specific defines for BACnet/IP over Ethernet */
|
||||
@@ -64,6 +65,7 @@ extern "C" {
|
||||
/* function to send a packet out the BACnet/IP socket */
|
||||
/* returns zero on success, non-zero on failure */
|
||||
int bip_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len); /* number of bytes of data */
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
/* This is used in constructing messages and to tell others our limits */
|
||||
/* 50 is the minimum; adjust to your memory and physical layer constraints */
|
||||
/* Lon=206, MS/TP=480, ARCNET=480, Ethernet=1476 */
|
||||
#define MAX_APDU 50
|
||||
/* #define MAX_APDU 480 */
|
||||
/* #define MAX_APDU 50 */
|
||||
#define MAX_APDU 480
|
||||
/* #define MAX_APDU 1476 */
|
||||
|
||||
/* for confirmed messages, this is the number of transactions */
|
||||
@@ -20,13 +20,13 @@
|
||||
/* Configure to zero if you don't want any confirmed messages */
|
||||
/* Configure from 1..255 for number of outstanding confirmed */
|
||||
/* requests available. */
|
||||
#define MAX_TSM_TRANSACTIONS 1
|
||||
#define MAX_TSM_TRANSACTIONS 255
|
||||
|
||||
/* 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 2
|
||||
#define MAX_ADDRESS_CACHE 255
|
||||
|
||||
#endif
|
||||
|
||||
+28
-30
@@ -274,6 +274,31 @@ int cov_notify_decode_service_request(uint8_t * apdu,
|
||||
return len;
|
||||
}
|
||||
|
||||
int ucov_notify_send(uint8_t * buffer, BACNET_COV_DATA * data)
|
||||
{
|
||||
int pdu_len = 0;
|
||||
BACNET_ADDRESS dest;
|
||||
int bytes_sent = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
/* unconfirmed is a broadcast */
|
||||
datalink_get_broadcast_address(&dest);
|
||||
/* encode the APDU portion of the packet */
|
||||
pdu_len = ucov_notify_encode_apdu(&buffer[0], data);
|
||||
/* encode the NPDU portion of the packet */
|
||||
npdu_encode_unconfirmed_apdu(&npdu_data, MESSAGE_PRIORITY_NORMAL);
|
||||
/* send the data */
|
||||
bytes_sent = datalink_send_pdu(&dest, &npdu_data, &buffer[0], pdu_len);
|
||||
|
||||
return bytes_sent;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
#include "bacapp.h"
|
||||
|
||||
int ccov_notify_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len, uint8_t * invoke_id, BACNET_COV_DATA * data)
|
||||
{
|
||||
@@ -325,44 +350,17 @@ int ucov_notify_decode_apdu(uint8_t * apdu,
|
||||
return len;
|
||||
}
|
||||
|
||||
int ucov_notify_send(uint8_t * buffer, BACNET_COV_DATA * data)
|
||||
{
|
||||
int pdu_len = 0;
|
||||
BACNET_ADDRESS dest;
|
||||
int bytes_sent = 0;
|
||||
|
||||
/* unconfirmed is a broadcast */
|
||||
datalink_get_broadcast_address(&dest);
|
||||
|
||||
/* encode the NPDU portion of the packet */
|
||||
pdu_len = npdu_encode_apdu(&buffer[0], &dest, NULL,
|
||||
false /* true for confirmed messages */ ,
|
||||
MESSAGE_PRIORITY_NORMAL);
|
||||
|
||||
/* encode the APDU portion of the packet */
|
||||
pdu_len += ucov_notify_encode_apdu(&buffer[pdu_len], data);
|
||||
|
||||
bytes_sent = datalink_send_pdu(&dest, /* destination address */
|
||||
&buffer[0], pdu_len); /* number of bytes of data */
|
||||
|
||||
return bytes_sent;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
#include "bacapp.h"
|
||||
|
||||
/* dummy function stubs */
|
||||
int npdu_encode_apdu(uint8_t * npdu, BACNET_ADDRESS * dest, BACNET_ADDRESS * src, bool data_expecting_reply, /* true for confirmed messages */
|
||||
void npdu_encode_unconfirmed_apdu(BACNET_NPDU_DATA * npdu,
|
||||
BACNET_MESSAGE_PRIORITY priority)
|
||||
{
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* dummy function stubs */
|
||||
int datalink_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len)
|
||||
{ /* number of bytes of data */
|
||||
|
||||
+31
-41
@@ -42,20 +42,20 @@
|
||||
|
||||
/* returns number of bytes sent on success, negative on failure */
|
||||
int datalink_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len)
|
||||
{ /* number of bytes of data */
|
||||
#ifdef BACDL_ARCNET
|
||||
return arcnet_send_pdu(dest, pdu, pdu_len);
|
||||
#endif
|
||||
#ifdef BACDL_MSTP
|
||||
return dlmstp_send_pdu(dest, pdu, pdu_len);
|
||||
#endif
|
||||
#ifdef BACDL_ETHERNET
|
||||
return ethernet_send_pdu(dest, pdu, pdu_len);
|
||||
#endif
|
||||
#ifdef BACDL_BIP
|
||||
return bip_send_pdu(dest, pdu, pdu_len);
|
||||
#if defined(BACDL_ARCNET)
|
||||
return arcnet_send_pdu(dest, npdu_data, pdu, pdu_len);
|
||||
#elif defined(BACDL_MSTP)
|
||||
return dlmstp_send_pdu(dest, npdu_data, pdu, pdu_len);
|
||||
#elif defined(BACDL_ETHERNET)
|
||||
return ethernet_send_pdu(dest, npdu_data, pdu, pdu_len);
|
||||
#elif defined(BACDL_BIP)
|
||||
return bip_send_pdu(dest, npdu_data, pdu, pdu_len);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -65,64 +65,54 @@ uint16_t datalink_receive(BACNET_ADDRESS * src, /* source address */
|
||||
uint16_t max_pdu, /* amount of space available in the PDU */
|
||||
unsigned timeout)
|
||||
{ /* number of milliseconds to wait for a packet */
|
||||
#ifdef BACDL_ARCNET
|
||||
#if defined(BACDL_ARCNET)
|
||||
return arcnet_receive(src, pdu, max_pdu, timeout);
|
||||
#endif
|
||||
#ifdef BACDL_MSTP
|
||||
#elif defined(BACDL_MSTP)
|
||||
return dlmstp_receive(src, pdu, max_pdu, timeout);
|
||||
#endif
|
||||
#ifdef BACDL_ETHERNET
|
||||
#elif defined(BACDL_ETHERNET)
|
||||
return ethernet_receive(src, pdu, max_pdu, timeout);
|
||||
#endif
|
||||
#ifdef BACDL_BIP
|
||||
#elif defined(BACDL_BIP)
|
||||
return bip_receive(src, pdu, max_pdu, timeout);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void datalink_cleanup(void)
|
||||
{
|
||||
#ifdef BACDL_ETHERNET
|
||||
ethernet_cleanup();
|
||||
#endif
|
||||
#ifdef BACDL_BIP
|
||||
bip_cleanup();
|
||||
#endif
|
||||
#ifdef BACDL_ARCNET
|
||||
#if defined(BACDL_ARCNET)
|
||||
arcnet_cleanup();
|
||||
#endif
|
||||
#ifdef BACDL_MSTP
|
||||
#elif defined(BACDL_MSTP)
|
||||
dlmstp_cleanup();
|
||||
#elif defined(BACDL_ETHERNET)
|
||||
ethernet_cleanup();
|
||||
#elif defined(BACDL_BIP)
|
||||
bip_cleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
void datalink_get_broadcast_address(BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
#ifdef BACDL_ARCNET
|
||||
#if defined(BACDL_ARCNET)
|
||||
arcnet_get_broadcast_address(dest);
|
||||
#endif
|
||||
#ifdef BACDL_MSTP
|
||||
#elif defined(BACDL_MSTP)
|
||||
dlmstp_get_broadcast_address(dest);
|
||||
#endif
|
||||
#ifdef BACDL_ETHERNET
|
||||
#elif defined(BACDL_ETHERNET)
|
||||
ethernet_get_broadcast_address(dest);
|
||||
#endif
|
||||
#ifdef BACDL_BIP
|
||||
#elif defined(BACDL_BIP)
|
||||
bip_get_broadcast_address(dest);
|
||||
#endif
|
||||
}
|
||||
|
||||
void datalink_get_my_address(BACNET_ADDRESS * my_address)
|
||||
{
|
||||
#ifdef BACDL_ARCNET
|
||||
#if defined(BACDL_ARCNET)
|
||||
arcnet_get_my_address(my_address);
|
||||
#endif
|
||||
#ifdef BACDL_MSTP
|
||||
#elif defined(BACDL_MSTP)
|
||||
dlmstp_get_my_address(my_address);
|
||||
#endif
|
||||
#ifdef BACDL_ETHERNET
|
||||
#elif defined(BACDL_ETHERNET)
|
||||
ethernet_get_my_address(my_address);
|
||||
#endif
|
||||
#ifdef BACDL_BIP
|
||||
#elif defined(BACDL_BIP)
|
||||
bip_get_my_address(my_address);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "bacdef.h"
|
||||
#include "npdu.h"
|
||||
|
||||
#ifdef BACDL_ETHERNET
|
||||
#include "ethernet.h"
|
||||
@@ -61,6 +62,7 @@ extern "C" {
|
||||
|
||||
/* returns number of bytes sent on success, negative on failure */
|
||||
int datalink_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len); /* number of bytes of data */
|
||||
|
||||
|
||||
@@ -76,6 +76,13 @@ extern "C" {
|
||||
void Send_TimeSync(BACNET_DATE * bdate, BACNET_TIME * btime);
|
||||
void Send_TimeSyncUTC(BACNET_DATE * bdate, BACNET_TIME * btime);
|
||||
|
||||
uint8_t Send_Atomic_Read_File_Stream(uint32_t device_id,
|
||||
uint32_t file_instance, int fileStartPosition,
|
||||
unsigned requestedOctetCount);
|
||||
uint8_t Send_Atomic_Write_File_Stream(uint32_t device_id,
|
||||
uint32_t file_instance,
|
||||
int fileStartPosition, BACNET_OCTET_STRING * fileData);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -48,75 +48,65 @@ void handler_atomic_read_file(uint8_t * service_request,
|
||||
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;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Received Atomic-Read-File Request!\n");
|
||||
#endif
|
||||
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(&Handler_Transmit_Buffer[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(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len = abort_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id, ABORT_REASON_OTHER);
|
||||
fprintf(stderr, "Sending Abort!\n");
|
||||
send = true;
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Bad Encoding. Sending Abort!\n");
|
||||
#endif
|
||||
} else if (service_data->segmented_message) {
|
||||
pdu_len += abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len = abort_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id,
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED);
|
||||
fprintf(stderr, "Sending Abort!\n");
|
||||
send = true;
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Segmented Message. Sending Abort!\n");
|
||||
#endif
|
||||
} else {
|
||||
if (data.access == FILE_STREAM_ACCESS) {
|
||||
if (data.type.stream.requestedOctetCount <
|
||||
octetstring_capacity(&data.fileData)) {
|
||||
if (bacfile_read_data(&data)) {
|
||||
pdu_len +=
|
||||
arf_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
send = true;
|
||||
pdu_len = arf_ack_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id, &data);
|
||||
} else {
|
||||
send = true;
|
||||
error = true;
|
||||
}
|
||||
} else {
|
||||
pdu_len +=
|
||||
abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len =
|
||||
abort_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id,
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED);
|
||||
fprintf(stderr, "Sending Abort!\n");
|
||||
send = true;
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Too Big To Send. Sending Abort!\n");
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
error_class = ERROR_CLASS_SERVICES;
|
||||
error_code = ERROR_CODE_INVALID_FILE_ACCESS_METHOD;
|
||||
send = true;
|
||||
error = true;
|
||||
pdu_len = bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_ATOMIC_READ_FILE,
|
||||
ERROR_CLASS_SERVICES, ERROR_CODE_INVALID_FILE_ACCESS_METHOD);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Record Access Requested. Sending Error!\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (error) {
|
||||
pdu_len += bacerror_encode_apdu(&Handler_Transmit_Buffer[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 */
|
||||
&Handler_Transmit_Buffer[0], pdu_len); /* number of bytes of data */
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr, "Failed to send PDU (%s)!\n", strerror(errno));
|
||||
npdu_encode_confirmed_apdu(&npdu_data, MESSAGE_PRIORITY_NORMAL);
|
||||
bytes_sent = datalink_send_pdu(src, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0) {
|
||||
fprintf(stderr, "Failed to send PDU (%s)!\n", strerror(errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -62,7 +62,9 @@ void handler_atomic_read_file_ack(uint8_t * service_request,
|
||||
instance = bacfile_instance_from_tsm(service_data->invoke_id);
|
||||
len = arf_ack_decode_service_request(service_request,
|
||||
service_len, &data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Received Read-File Ack!\n");
|
||||
#endif
|
||||
if ((len > 0) && (instance <= BACNET_MAX_INSTANCE)) {
|
||||
/* write the data received to the file specified */
|
||||
if (data.access == FILE_STREAM_ACCESS) {
|
||||
@@ -75,8 +77,12 @@ void handler_atomic_read_file_ack(uint8_t * service_request,
|
||||
if (fwrite(octetstring_value(&data.fileData),
|
||||
octetstring_length(&data.fileData), 1,
|
||||
pFile) != 1)
|
||||
{
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Failed to write to %s (%u)!\n",
|
||||
pFilename, instance);
|
||||
#endif
|
||||
}
|
||||
fclose(pFile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
#include "reject.h"
|
||||
#include "dcc.h"
|
||||
|
||||
static char *My_Password = "AnnaRoseKarg";
|
||||
static char *My_Password = "filister";
|
||||
|
||||
void handler_device_communication_control(uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
@@ -49,8 +49,8 @@ void handler_device_communication_control(uint8_t * service_request,
|
||||
BACNET_CHARACTER_STRING password;
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
BACNET_ADDRESS my_address;
|
||||
int bytes_sent = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
/* decode the service request only */
|
||||
len = dcc_decode_service_request(service_request,
|
||||
@@ -62,25 +62,17 @@ void handler_device_communication_control(uint8_t * service_request,
|
||||
"timeout=%u state=%u password=%s\n",
|
||||
(unsigned) timeDuration,
|
||||
(unsigned) state, characterstring_value(&password));
|
||||
else
|
||||
fprintf(stderr, "DeviceCommunicationControl: "
|
||||
"Unable to decode request!\n");
|
||||
#endif
|
||||
/* prepare a reply */
|
||||
datalink_get_my_address(&my_address);
|
||||
/* encode the NPDU portion of the packet */
|
||||
pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], src, &my_address, false, /* true for confirmed messages */
|
||||
MESSAGE_PRIORITY_NORMAL);
|
||||
/* bad decoding or something we didn't understand - send an abort */
|
||||
if (len == -1) {
|
||||
pdu_len += abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
if (len < 0) {
|
||||
pdu_len = abort_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id, ABORT_REASON_OTHER);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "DeviceCommunicationControl: "
|
||||
"Sending Abort - could not decode.\n");
|
||||
#endif
|
||||
} else if (service_data->segmented_message) {
|
||||
pdu_len += abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len = abort_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id,
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED);
|
||||
#if PRINT_ENABLED
|
||||
@@ -88,7 +80,7 @@ void handler_device_communication_control(uint8_t * service_request,
|
||||
"Sending Abort - segmented message.\n");
|
||||
#endif
|
||||
} else if (state >= MAX_BACNET_COMMUNICATION_ENABLE_DISABLE) {
|
||||
pdu_len += reject_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len = reject_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id, REJECT_REASON_UNDEFINED_ENUMERATION);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "DeviceCommunicationControl: "
|
||||
@@ -96,7 +88,7 @@ void handler_device_communication_control(uint8_t * service_request,
|
||||
#endif
|
||||
} else {
|
||||
if (characterstring_ansi_same(&password, My_Password)) {
|
||||
pdu_len += encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len = encode_simple_ack(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL);
|
||||
#if PRINT_ENABLED
|
||||
@@ -105,8 +97,8 @@ void handler_device_communication_control(uint8_t * service_request,
|
||||
#endif
|
||||
dcc_set_status_duration(state, timeDuration);
|
||||
} else {
|
||||
pdu_len +=
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL,
|
||||
ERROR_CLASS_SERVICES, ERROR_CODE_PASSWORD_FAILURE);
|
||||
@@ -117,8 +109,9 @@ void handler_device_communication_control(uint8_t * service_request,
|
||||
#endif
|
||||
}
|
||||
}
|
||||
bytes_sent = datalink_send_pdu(src, /* destination address */
|
||||
&Handler_Transmit_Buffer[0], pdu_len); /* number of bytes of data */
|
||||
npdu_encode_confirmed_apdu(&npdu_data, MESSAGE_PRIORITY_NORMAL);
|
||||
bytes_sent = datalink_send_pdu(src, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr, "DeviceCommunicationControl: "
|
||||
|
||||
@@ -44,12 +44,19 @@ void handler_i_am_add(uint8_t * service_request,
|
||||
(void) service_len;
|
||||
len = iam_decode_service_request(service_request,
|
||||
&device_id, &max_apdu, &segmentation, &vendor_id);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Received I-Am Request");
|
||||
#endif
|
||||
if (len != -1) {
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, " from %u!\n", device_id);
|
||||
#endif
|
||||
address_add(device_id, max_apdu, src);
|
||||
} else
|
||||
} else {
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "!\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -43,13 +43,18 @@ void handler_i_have(uint8_t * service_request,
|
||||
len = ihave_decode_service_request(service_request,
|
||||
service_len, &data);
|
||||
if (len != -1) {
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "I-Have: %s %d from %s %u!\r\n",
|
||||
bactext_object_type_name(data.object_id.type),
|
||||
data.object_id.instance,
|
||||
bactext_object_type_name(data.device_id.type),
|
||||
data.device_id.instance);
|
||||
} else
|
||||
#endif
|
||||
} else {
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "I-Have: received, but unable to decode!\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ void handler_reinitialize_device(uint8_t * service_request,
|
||||
BACNET_CHARACTER_STRING their_password;
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
BACNET_ADDRESS my_address;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
int bytes_sent = 0;
|
||||
|
||||
/* decode the service request only */
|
||||
@@ -63,21 +63,16 @@ void handler_reinitialize_device(uint8_t * service_request,
|
||||
else
|
||||
fprintf(stderr, "ReinitializeDevice: Unable to decode request!\n");
|
||||
#endif
|
||||
/* prepare a reply */
|
||||
datalink_get_my_address(&my_address);
|
||||
/* encode the NPDU portion of the packet */
|
||||
pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], src, &my_address, false, /* true for confirmed messages */
|
||||
MESSAGE_PRIORITY_NORMAL);
|
||||
/* bad decoding or something we didn't understand - send an abort */
|
||||
if (len == -1) {
|
||||
pdu_len += abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
if (len < 0) {
|
||||
pdu_len = abort_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id, ABORT_REASON_OTHER);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"ReinitializeDevice: Sending Abort - could not decode.\n");
|
||||
#endif
|
||||
} else if (service_data->segmented_message) {
|
||||
pdu_len += abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len = abort_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id,
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED);
|
||||
#if PRINT_ENABLED
|
||||
@@ -85,7 +80,7 @@ void handler_reinitialize_device(uint8_t * service_request,
|
||||
"ReinitializeDevice: Sending Abort - segmented message.\n");
|
||||
#endif
|
||||
} else if (state >= MAX_BACNET_REINITIALIZED_STATE) {
|
||||
pdu_len += reject_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len = reject_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id, REJECT_REASON_UNDEFINED_ENUMERATION);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
@@ -94,7 +89,7 @@ void handler_reinitialize_device(uint8_t * service_request,
|
||||
} else {
|
||||
characterstring_init_ansi(&My_Password, Password);
|
||||
if (characterstring_same(&their_password, &My_Password)) {
|
||||
pdu_len += encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len = encode_simple_ack(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_REINITIALIZE_DEVICE);
|
||||
#if PRINT_ENABLED
|
||||
@@ -105,8 +100,8 @@ void handler_reinitialize_device(uint8_t * service_request,
|
||||
/* Note: if you don't do something clever like actually restart,
|
||||
you probably should clear any DCC status and timeouts */
|
||||
} else {
|
||||
pdu_len +=
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_REINITIALIZE_DEVICE,
|
||||
ERROR_CLASS_SERVICES, ERROR_CODE_PASSWORD_FAILURE);
|
||||
@@ -116,8 +111,9 @@ void handler_reinitialize_device(uint8_t * service_request,
|
||||
#endif
|
||||
}
|
||||
}
|
||||
bytes_sent = datalink_send_pdu(src, /* destination address */
|
||||
&Handler_Transmit_Buffer[0], pdu_len); /* number of bytes of data */
|
||||
npdu_encode_confirmed_apdu(&npdu_data, MESSAGE_PRIORITY_NORMAL);
|
||||
bytes_sent = datalink_send_pdu(src, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr, "ReinitializeDevice: Failed to send PDU (%s)!\n",
|
||||
|
||||
@@ -58,7 +58,7 @@ void handler_read_property(uint8_t * service_request,
|
||||
BACNET_READ_PROPERTY_DATA data;
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
BACNET_ADDRESS my_address;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
bool send = false;
|
||||
bool error = false;
|
||||
int bytes_sent = 0;
|
||||
@@ -70,21 +70,16 @@ void handler_read_property(uint8_t * service_request,
|
||||
if (len <= 0)
|
||||
fprintf(stderr, "Unable to decode Read-Property Request!\n");
|
||||
#endif
|
||||
/* prepare a reply */
|
||||
datalink_get_my_address(&my_address);
|
||||
/* encode the NPDU portion of the packet */
|
||||
pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], src, &my_address, false, /* true for confirmed messages */
|
||||
MESSAGE_PRIORITY_NORMAL);
|
||||
/* bad decoding - send an abort */
|
||||
if (len == -1) {
|
||||
pdu_len += abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
if (len < 0) {
|
||||
pdu_len = abort_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id, ABORT_REASON_OTHER);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Abort!\n");
|
||||
#endif
|
||||
send = true;
|
||||
} else if (service_data->segmented_message) {
|
||||
pdu_len += abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len = abort_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id,
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED);
|
||||
#if PRINT_ENABLED
|
||||
@@ -104,9 +99,8 @@ void handler_read_property(uint8_t * service_request,
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
pdu_len +=
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
pdu_len = rp_ack_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id, &data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Read Property Ack for Device!\n");
|
||||
@@ -128,9 +122,9 @@ void handler_read_property(uint8_t * service_request,
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
pdu_len +=
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
pdu_len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id, &data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Read Property Ack for AI!\n");
|
||||
#endif
|
||||
@@ -151,9 +145,9 @@ void handler_read_property(uint8_t * service_request,
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
pdu_len +=
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
pdu_len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id, &data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Read Property Ack for BI!\n");
|
||||
#endif
|
||||
@@ -174,9 +168,8 @@ void handler_read_property(uint8_t * service_request,
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
pdu_len +=
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
pdu_len = rp_ack_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id, &data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Read Property Ack for BO!\n");
|
||||
#endif
|
||||
@@ -197,9 +190,9 @@ void handler_read_property(uint8_t * service_request,
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
pdu_len +=
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
pdu_len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id, &data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Read Property Ack for BV!\n");
|
||||
#endif
|
||||
@@ -220,9 +213,9 @@ void handler_read_property(uint8_t * service_request,
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
pdu_len +=
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
pdu_len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id, &data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Read Property Ack for AO!\n");
|
||||
#endif
|
||||
@@ -243,9 +236,9 @@ void handler_read_property(uint8_t * service_request,
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
pdu_len +=
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
pdu_len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id, &data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Read Property Ack for AV!\n");
|
||||
#endif
|
||||
@@ -266,9 +259,9 @@ void handler_read_property(uint8_t * service_request,
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
pdu_len +=
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
pdu_len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id, &data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Read Property Ack for LSP!\n");
|
||||
@@ -290,9 +283,9 @@ void handler_read_property(uint8_t * service_request,
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
pdu_len +=
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
pdu_len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id, &data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Read Property Ack for MSO!\n");
|
||||
@@ -315,9 +308,9 @@ void handler_read_property(uint8_t * service_request,
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
pdu_len +=
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
pdu_len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id, &data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Read Property Ack for File!\n");
|
||||
@@ -335,7 +328,7 @@ void handler_read_property(uint8_t * service_request,
|
||||
}
|
||||
}
|
||||
if (error) {
|
||||
pdu_len += bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len = bacerror_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_READ_PROPERTY, error_class, error_code);
|
||||
#if PRINT_ENABLED
|
||||
@@ -344,7 +337,8 @@ void handler_read_property(uint8_t * service_request,
|
||||
send = true;
|
||||
}
|
||||
if (send) {
|
||||
bytes_sent = datalink_send_pdu(src, /* destination address */
|
||||
npdu_encode_confirmed_apdu(&npdu_data, MESSAGE_PRIORITY_NORMAL);
|
||||
bytes_sent = datalink_send_pdu(src, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len); /* number of bytes of data */
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
|
||||
@@ -56,7 +56,7 @@ void handler_write_property(uint8_t * service_request,
|
||||
BACNET_WRITE_PROPERTY_DATA wp_data;
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
BACNET_ADDRESS my_address;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT;
|
||||
BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
int bytes_sent = 0;
|
||||
@@ -64,6 +64,7 @@ void handler_write_property(uint8_t * service_request,
|
||||
/* decode the service request only */
|
||||
len = wp_decode_service_request(service_request,
|
||||
service_len, &wp_data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Received Write-Property Request!\n");
|
||||
if (len > 0)
|
||||
fprintf(stderr, "type=%u instance=%u property=%u index=%d\n",
|
||||
@@ -72,192 +73,231 @@ void handler_write_property(uint8_t * service_request,
|
||||
wp_data.object_property, wp_data.array_index);
|
||||
else
|
||||
fprintf(stderr, "Unable to decode Write-Property Request!\n");
|
||||
/* prepare a reply */
|
||||
datalink_get_my_address(&my_address);
|
||||
/* encode the NPDU portion of the packet */
|
||||
pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], src, &my_address, false, /* true for confirmed messages */
|
||||
MESSAGE_PRIORITY_NORMAL);
|
||||
#endif
|
||||
/* bad decoding or something we didn't understand - send an abort */
|
||||
if (len == -1) {
|
||||
pdu_len += abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
if (len <= 0) {
|
||||
pdu_len = abort_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id, ABORT_REASON_OTHER);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Abort!\n");
|
||||
#endif
|
||||
} else if (service_data->segmented_message) {
|
||||
pdu_len += abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len = abort_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id,
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Abort!\n");
|
||||
#endif
|
||||
} else {
|
||||
switch (wp_data.object_type) {
|
||||
case OBJECT_DEVICE:
|
||||
if (Device_Write_Property(&wp_data, &error_class, &error_code)) {
|
||||
pdu_len +=
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Write Property Simple Ack for Device!\n");
|
||||
#endif
|
||||
} else {
|
||||
pdu_len +=
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Write Property Error for Device!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_INPUT:
|
||||
case OBJECT_BINARY_INPUT:
|
||||
error_class = ERROR_CLASS_PROPERTY;
|
||||
error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
pdu_len +=
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY,
|
||||
error_class, error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Write Access Error!\n");
|
||||
#endif
|
||||
break;
|
||||
case OBJECT_BINARY_OUTPUT:
|
||||
if (Binary_Output_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
pdu_len +=
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Write Property Simple Ack for BO!\n");
|
||||
#endif
|
||||
} else {
|
||||
pdu_len +=
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Write Access Error for BO!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case OBJECT_BINARY_VALUE:
|
||||
if (Binary_Value_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
pdu_len +=
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Write Property Simple Ack for BV!\n");
|
||||
#endif
|
||||
} else {
|
||||
pdu_len +=
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Write Access Error for BV!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_OUTPUT:
|
||||
if (Analog_Output_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
pdu_len +=
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Write Property Simple Ack for AO!\n");
|
||||
#endif
|
||||
} else {
|
||||
pdu_len +=
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Write Access Error for AO!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_VALUE:
|
||||
if (Analog_Value_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
pdu_len +=
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Write Property Simple Ack for AV!\n");
|
||||
#endif
|
||||
} else {
|
||||
pdu_len +=
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Write Access Error for AV!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case OBJECT_LIFE_SAFETY_POINT:
|
||||
if (Life_Safety_Point_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
pdu_len +=
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Write Property Simple Ack for LSP!\n");
|
||||
#endif
|
||||
} else {
|
||||
pdu_len +=
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Write Access Error for LSP!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case OBJECT_MULTI_STATE_OUTPUT:
|
||||
if (Multistate_Output_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
pdu_len +=
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Write Property Simple Ack for MSO!\n");
|
||||
#endif
|
||||
} else {
|
||||
pdu_len +=
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Write Access Error for MSO!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
#if BACFILE
|
||||
case OBJECT_FILE:
|
||||
if (bacfile_write_property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
pdu_len +=
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Write Property Simple Ack for File!\n");
|
||||
#endif
|
||||
} else {
|
||||
pdu_len +=
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Write Access Error for File!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
pdu_len +=
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY,
|
||||
error_class, error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Unknown Object Error!\n");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
bytes_sent = datalink_send_pdu(src, /* destination address */
|
||||
&Handler_Transmit_Buffer[0], pdu_len); /* number of bytes of data */
|
||||
npdu_encode_confirmed_apdu(&npdu_data, MESSAGE_PRIORITY_NORMAL);
|
||||
bytes_sent = datalink_send_pdu(src, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr, "Failed to send PDU (%s)!\n", strerror(errno));
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -38,26 +38,25 @@ void handler_unrecognized_service(uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * dest, BACNET_CONFIRMED_SERVICE_DATA * service_data)
|
||||
{
|
||||
BACNET_ADDRESS src;
|
||||
int pdu_len = 0;
|
||||
int bytes_sent = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
(void) service_request;
|
||||
(void) service_len;
|
||||
datalink_get_my_address(&src);
|
||||
|
||||
/* encode the NPDU portion of the packet */
|
||||
pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], dest, &src, false, /* true for confirmed messages */
|
||||
MESSAGE_PRIORITY_NORMAL);
|
||||
|
||||
/* encode the APDU portion of the packet */
|
||||
pdu_len += reject_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len = reject_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
service_data->invoke_id, REJECT_REASON_UNRECOGNIZED_SERVICE);
|
||||
|
||||
bytes_sent = datalink_send_pdu(dest, /* destination address */
|
||||
&Handler_Transmit_Buffer[0], pdu_len); /* number of bytes of data */
|
||||
/* encode the NPDU portion of the packet */
|
||||
npdu_encode_confirmed_apdu(&npdu_data, MESSAGE_PRIORITY_NORMAL);
|
||||
/* send the data */
|
||||
bytes_sent = datalink_send_pdu(dest, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent > 0)
|
||||
fprintf(stderr, "Sent Reject!\n");
|
||||
else
|
||||
fprintf(stderr, "Failed to Send Reject (%s)!\n", strerror(errno));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "address.h"
|
||||
#include "tsm.h"
|
||||
#include "npdu.h"
|
||||
#include "apdu.h"
|
||||
#include "device.h"
|
||||
#include "datalink.h"
|
||||
#include "arf.h"
|
||||
/* some demo stuff needed */
|
||||
#include "handlers.h"
|
||||
#include "txbuf.h"
|
||||
|
||||
uint8_t Send_Atomic_Read_File_Stream(uint32_t device_id,
|
||||
uint32_t file_instance,
|
||||
int fileStartPosition, unsigned requestedOctetCount)
|
||||
{
|
||||
BACNET_ADDRESS dest;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
unsigned max_apdu = 0;
|
||||
uint8_t invoke_id = 0;
|
||||
bool status = false;
|
||||
int pdu_len = 0;
|
||||
int bytes_sent = 0;
|
||||
BACNET_ATOMIC_READ_FILE_DATA data;
|
||||
|
||||
/* is the device bound? */
|
||||
status = address_get_by_device(device_id, &max_apdu, &dest);
|
||||
/* is there a tsm available? */
|
||||
if (status)
|
||||
invoke_id = tsm_next_free_invokeID();
|
||||
if (invoke_id) {
|
||||
/* load the data for the encoding */
|
||||
data.object_type = OBJECT_FILE;
|
||||
data.object_instance = file_instance;
|
||||
data.access = FILE_STREAM_ACCESS;
|
||||
data.type.stream.fileStartPosition = fileStartPosition;
|
||||
data.type.stream.requestedOctetCount = requestedOctetCount;
|
||||
pdu_len = arf_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
invoke_id, &data);
|
||||
/* will the APDU fit the target device?
|
||||
note: if there is a bottleneck router in between
|
||||
us and the destination, we won't know unless
|
||||
we have a way to check for that and update the
|
||||
max_apdu in the address binding table. */
|
||||
if ((unsigned) pdu_len < max_apdu) {
|
||||
npdu_encode_confirmed_apdu(&npdu_data, MESSAGE_PRIORITY_NORMAL);
|
||||
tsm_set_confirmed_unsegmented_transaction(invoke_id,
|
||||
&dest, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len);
|
||||
bytes_sent = datalink_send_pdu(&dest, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr,
|
||||
"Failed to Send AtomicReadFile Request (%s)!\n",
|
||||
strerror(errno));
|
||||
#endif
|
||||
} else {
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
invoke_id = 0;
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Failed to Send AtomicReadFile Request "
|
||||
"(payload exceeds destination maximum APDU)!\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return invoke_id;
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "address.h"
|
||||
#include "tsm.h"
|
||||
#include "npdu.h"
|
||||
#include "apdu.h"
|
||||
#include "device.h"
|
||||
#include "datalink.h"
|
||||
#include "awf.h"
|
||||
/* some demo stuff needed */
|
||||
#include "handlers.h"
|
||||
#include "txbuf.h"
|
||||
|
||||
uint8_t Send_Atomic_Write_File_Stream(uint32_t device_id,
|
||||
uint32_t file_instance,
|
||||
int fileStartPosition, BACNET_OCTET_STRING * fileData)
|
||||
{
|
||||
BACNET_ADDRESS dest;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
unsigned max_apdu = 0;
|
||||
uint8_t invoke_id = 0;
|
||||
bool status = false;
|
||||
int pdu_len = 0;
|
||||
int bytes_sent = 0;
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA data;
|
||||
|
||||
/* is the device bound? */
|
||||
status = address_get_by_device(device_id, &max_apdu, &dest);
|
||||
/* is there a tsm available? */
|
||||
if (status)
|
||||
invoke_id = tsm_next_free_invokeID();
|
||||
if (invoke_id) {
|
||||
/* load the data for the encoding */
|
||||
data.object_type = OBJECT_FILE;
|
||||
data.object_instance = file_instance;
|
||||
data.access = FILE_STREAM_ACCESS;
|
||||
data.type.stream.fileStartPosition = fileStartPosition;
|
||||
status = octetstring_copy(&data.fileData, fileData);
|
||||
if (status) {
|
||||
pdu_len = awf_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
invoke_id, &data);
|
||||
/* will the APDU fit the target device?
|
||||
note: if there is a bottleneck router in between
|
||||
us and the destination, we won't know unless
|
||||
we have a way to check for that and update the
|
||||
max_apdu in the address binding table. */
|
||||
if ((unsigned) pdu_len <= max_apdu) {
|
||||
npdu_encode_confirmed_apdu(&npdu_data, MESSAGE_PRIORITY_NORMAL);
|
||||
tsm_set_confirmed_unsegmented_transaction(invoke_id,
|
||||
&dest, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len);
|
||||
bytes_sent = datalink_send_pdu(&dest, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr,
|
||||
"Failed to Send AtomicWriteFile Request (%s)!\n",
|
||||
strerror(errno));
|
||||
#endif
|
||||
} else {
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
invoke_id = 0;
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Failed to Send AtomicWriteFile Request "
|
||||
"(payload [%d] exceeds destination maximum APDU [%u])!\n",
|
||||
pdu_len, max_apdu);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
invoke_id = 0;
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Failed to Send AtomicWriteFile Request "
|
||||
"(payload [%d] exceeds octet string capacity)!\n",
|
||||
pdu_len);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return invoke_id;
|
||||
}
|
||||
|
||||
@@ -45,13 +45,13 @@ uint8_t Send_Device_Communication_Control_Request(uint32_t device_id, uint16_t t
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE state, char *password)
|
||||
{ /* NULL=optional */
|
||||
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;
|
||||
BACNET_CHARACTER_STRING password_string;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
if (!dcc_communication_enabled())
|
||||
return 0;
|
||||
@@ -60,16 +60,11 @@ uint8_t Send_Device_Communication_Control_Request(uint32_t device_id, uint16_t t
|
||||
status = address_get_by_device(device_id, &max_apdu, &dest);
|
||||
/* is there a tsm available? */
|
||||
if (status)
|
||||
status = tsm_transaction_available();
|
||||
if (status) {
|
||||
datalink_get_my_address(&my_address);
|
||||
pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], &dest, &my_address, true, /* true for confirmed messages */
|
||||
MESSAGE_PRIORITY_NORMAL);
|
||||
|
||||
invoke_id = tsm_next_free_invokeID();
|
||||
if (invoke_id) {
|
||||
/* load the data for the encoding */
|
||||
characterstring_init_ansi(&password_string, password);
|
||||
pdu_len += dcc_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len = dcc_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
invoke_id,
|
||||
timeDuration, state, password ? &password_string : NULL);
|
||||
/* will it fit in the sender?
|
||||
@@ -78,18 +73,26 @@ uint8_t Send_Device_Communication_Control_Request(uint32_t device_id, uint16_t t
|
||||
we have a way to check for that and update the
|
||||
max_apdu in the address binding table. */
|
||||
if ((unsigned) pdu_len < max_apdu) {
|
||||
npdu_encode_confirmed_apdu(&npdu_data, MESSAGE_PRIORITY_NORMAL);
|
||||
tsm_set_confirmed_unsegmented_transaction(invoke_id,
|
||||
&dest, &Handler_Transmit_Buffer[0], pdu_len);
|
||||
bytes_sent = datalink_send_pdu(&dest, /* destination address */
|
||||
&Handler_Transmit_Buffer[0], pdu_len); /* number of bytes of data */
|
||||
&dest, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len);
|
||||
bytes_sent = datalink_send_pdu(&dest, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr,
|
||||
"Failed to Send DeviceCommunicationControl Request (%s)!\n",
|
||||
strerror(errno));
|
||||
} else
|
||||
#endif
|
||||
} else {
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
invoke_id = 0;
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Failed to Send DeviceCommunicationControl Request "
|
||||
"(exceeds destination maximum APDU)!\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return invoke_id;
|
||||
|
||||
@@ -51,26 +51,27 @@ void Send_I_Have(uint32_t device_id,
|
||||
BACNET_ADDRESS dest;
|
||||
int bytes_sent = 0;
|
||||
BACNET_I_HAVE_DATA data;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
/* if we are forbidden to send, don't send! */
|
||||
if (!dcc_communication_enabled())
|
||||
return;
|
||||
/* Who-Has is a global broadcast */
|
||||
datalink_get_broadcast_address(&dest);
|
||||
/* encode the NPDU portion of the packet */
|
||||
pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], &dest, NULL, false, /* true for confirmed messages */
|
||||
MESSAGE_PRIORITY_NORMAL);
|
||||
/* encode the APDU portion of the packet */
|
||||
data.device_id.type = OBJECT_DEVICE;
|
||||
data.device_id.instance = device_id;
|
||||
data.object_id.type = object_type;
|
||||
data.object_id.instance = object_instance;
|
||||
characterstring_init_ansi(&data.object_name, object_name);
|
||||
pdu_len += ihave_encode_apdu(&Handler_Transmit_Buffer[pdu_len], &data);
|
||||
pdu_len = ihave_encode_apdu(&Handler_Transmit_Buffer[0], &data);
|
||||
/* send the data */
|
||||
bytes_sent = datalink_send_pdu(&dest, /* destination address */
|
||||
npdu_encode_unconfirmed_apdu(&npdu_data, MESSAGE_PRIORITY_NORMAL);
|
||||
bytes_sent = datalink_send_pdu(&dest, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len); /* number of bytes of data */
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr, "Failed to Send I-Have Reply (%s)!\n",
|
||||
strerror(errno));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -46,13 +46,13 @@ uint8_t Send_Reinitialize_Device_Request(uint32_t device_id,
|
||||
BACNET_REINITIALIZED_STATE state, char *password)
|
||||
{
|
||||
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;
|
||||
BACNET_CHARACTER_STRING password_string;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
if (!dcc_communication_enabled())
|
||||
return 0;
|
||||
@@ -61,16 +61,11 @@ uint8_t Send_Reinitialize_Device_Request(uint32_t device_id,
|
||||
status = address_get_by_device(device_id, &max_apdu, &dest);
|
||||
/* is there a tsm available? */
|
||||
if (status)
|
||||
status = tsm_transaction_available();
|
||||
if (status) {
|
||||
datalink_get_my_address(&my_address);
|
||||
pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], &dest, &my_address, true, /* true for confirmed messages */
|
||||
MESSAGE_PRIORITY_NORMAL);
|
||||
|
||||
invoke_id = tsm_next_free_invokeID();
|
||||
if (invoke_id) {
|
||||
/* load the data for the encoding */
|
||||
characterstring_init_ansi(&password_string, password);
|
||||
pdu_len += rd_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len = rd_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
invoke_id, state, password ? &password_string : NULL);
|
||||
/* will it fit in the sender?
|
||||
note: if there is a bottleneck router in between
|
||||
@@ -78,17 +73,25 @@ uint8_t Send_Reinitialize_Device_Request(uint32_t device_id,
|
||||
we have a way to check for that and update the
|
||||
max_apdu in the address binding table. */
|
||||
if ((unsigned) pdu_len < max_apdu) {
|
||||
npdu_encode_confirmed_apdu(&npdu_data, MESSAGE_PRIORITY_NORMAL);
|
||||
tsm_set_confirmed_unsegmented_transaction(invoke_id,
|
||||
&dest, &Handler_Transmit_Buffer[0], pdu_len);
|
||||
bytes_sent = datalink_send_pdu(&dest, /* destination address */
|
||||
&Handler_Transmit_Buffer[0], pdu_len); /* number of bytes of data */
|
||||
&dest, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len);
|
||||
bytes_sent = datalink_send_pdu(&dest, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr,
|
||||
"Failed to Send ReinitializeDevice Request (%s)!\n",
|
||||
strerror(errno));
|
||||
} else
|
||||
#endif
|
||||
} else {
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
invoke_id = 0;
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Failed to Send ReinitializeDevice Request "
|
||||
"(exceeds destination maximum APDU)!\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return invoke_id;
|
||||
|
||||
@@ -49,13 +49,13 @@ uint8_t Send_Read_Property_Request(uint32_t device_id, /* destination device */
|
||||
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;
|
||||
BACNET_READ_PROPERTY_DATA data;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
if (!dcc_communication_enabled())
|
||||
return 0;
|
||||
@@ -64,19 +64,14 @@ uint8_t Send_Read_Property_Request(uint32_t device_id, /* destination device */
|
||||
status = address_get_by_device(device_id, &max_apdu, &dest);
|
||||
/* is there a tsm available? */
|
||||
if (status)
|
||||
status = tsm_transaction_available();
|
||||
if (status) {
|
||||
datalink_get_my_address(&my_address);
|
||||
pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], &dest, &my_address, true, /* true for confirmed messages */
|
||||
MESSAGE_PRIORITY_NORMAL);
|
||||
|
||||
invoke_id = tsm_next_free_invokeID();
|
||||
if (invoke_id) {
|
||||
/* load the data for the encoding */
|
||||
data.object_type = object_type;
|
||||
data.object_instance = object_instance;
|
||||
data.object_property = object_property;
|
||||
data.array_index = array_index;
|
||||
pdu_len += rp_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len = rp_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
invoke_id, &data);
|
||||
/* will it fit in the sender?
|
||||
note: if there is a bottleneck router in between
|
||||
@@ -84,17 +79,25 @@ uint8_t Send_Read_Property_Request(uint32_t device_id, /* destination device */
|
||||
we have a way to check for that and update the
|
||||
max_apdu in the address binding table. */
|
||||
if ((unsigned) pdu_len < max_apdu) {
|
||||
npdu_encode_confirmed_apdu(&npdu_data, MESSAGE_PRIORITY_NORMAL);
|
||||
tsm_set_confirmed_unsegmented_transaction(invoke_id,
|
||||
&dest, &Handler_Transmit_Buffer[0], pdu_len);
|
||||
bytes_sent = datalink_send_pdu(&dest, /* destination address */
|
||||
&Handler_Transmit_Buffer[0], pdu_len); /* number of bytes of data */
|
||||
&dest, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len);
|
||||
bytes_sent = datalink_send_pdu(&dest, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr,
|
||||
"Failed to Send ReadProperty Request (%s)!\n",
|
||||
strerror(errno));
|
||||
} else
|
||||
#endif
|
||||
} else {
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
invoke_id = 0;
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Failed to Send ReadProperty Request "
|
||||
"(exceeds destination maximum APDU)!\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return invoke_id;
|
||||
|
||||
@@ -47,25 +47,26 @@ void Send_TimeSync(BACNET_DATE * bdate, BACNET_TIME * btime)
|
||||
int pdu_len = 0;
|
||||
BACNET_ADDRESS dest;
|
||||
int bytes_sent = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
if (!dcc_communication_enabled())
|
||||
return;
|
||||
|
||||
/* we could use unicast or broadcast */
|
||||
datalink_get_broadcast_address(&dest);
|
||||
/* encode the NPDU portion of the packet */
|
||||
pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], &dest, NULL, false, /* true for confirmed messages */
|
||||
MESSAGE_PRIORITY_NORMAL);
|
||||
/* encode the APDU portion of the packet */
|
||||
pdu_len += timesync_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len = timesync_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
bdate, btime);
|
||||
npdu_encode_unconfirmed_apdu(&npdu_data, MESSAGE_PRIORITY_NORMAL);
|
||||
/* send it out the datalink */
|
||||
bytes_sent = datalink_send_pdu(&dest,
|
||||
bytes_sent = datalink_send_pdu(&dest, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr,
|
||||
"Failed to Send Time-Synchronization Request (%s)!\n",
|
||||
strerror(errno));
|
||||
#endif
|
||||
}
|
||||
|
||||
void Send_TimeSyncUTC(BACNET_DATE * bdate, BACNET_TIME * btime)
|
||||
@@ -73,23 +74,23 @@ void Send_TimeSyncUTC(BACNET_DATE * bdate, BACNET_TIME * btime)
|
||||
int pdu_len = 0;
|
||||
BACNET_ADDRESS dest;
|
||||
int bytes_sent = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
if (!dcc_communication_enabled())
|
||||
return;
|
||||
|
||||
/* we could use unicast or broadcast */
|
||||
datalink_get_broadcast_address(&dest);
|
||||
/* encode the NPDU portion of the packet */
|
||||
pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], &dest, NULL, false, /* true for confirmed messages */
|
||||
MESSAGE_PRIORITY_NORMAL);
|
||||
/* encode the APDU portion of the packet */
|
||||
pdu_len += timesync_utc_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len = timesync_utc_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
bdate, btime);
|
||||
/* send it out the datalink */
|
||||
bytes_sent = datalink_send_pdu(&dest,
|
||||
npdu_encode_unconfirmed_apdu(&npdu_data, MESSAGE_PRIORITY_NORMAL);
|
||||
bytes_sent = datalink_send_pdu(&dest, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr,
|
||||
"Failed to Send UTC-Time-Synchronization Request (%s)!\n",
|
||||
strerror(errno));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -50,28 +50,29 @@ void Send_WhoHas_Name(int32_t low_limit,
|
||||
BACNET_ADDRESS dest;
|
||||
int bytes_sent = 0;
|
||||
BACNET_WHO_HAS_DATA data;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
/* if we are forbidden to send, don't send! */
|
||||
if (!dcc_communication_enabled())
|
||||
return;
|
||||
/* Who-Has is a global broadcast */
|
||||
datalink_get_broadcast_address(&dest);
|
||||
/* encode the NPDU portion of the packet */
|
||||
pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], &dest, NULL, false, /* true for confirmed messages */
|
||||
MESSAGE_PRIORITY_NORMAL);
|
||||
/* encode the APDU portion of the packet */
|
||||
data.low_limit = low_limit;
|
||||
data.high_limit = high_limit;
|
||||
data.object_name = true;
|
||||
characterstring_init_ansi(&data.object.name, object_name);
|
||||
pdu_len += whohas_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len = whohas_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
&data);
|
||||
npdu_encode_unconfirmed_apdu(&npdu_data, MESSAGE_PRIORITY_NORMAL);
|
||||
/* send the data */
|
||||
bytes_sent = datalink_send_pdu(&dest, /* destination address */
|
||||
&Handler_Transmit_Buffer[0], pdu_len); /* number of bytes of data */
|
||||
bytes_sent = datalink_send_pdu(&dest, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr, "Failed to Send Who-Has Request (%s)!\n",
|
||||
strerror(errno));
|
||||
#endif
|
||||
}
|
||||
|
||||
/* find a specific device, or use -1 for limit if you want unlimited */
|
||||
@@ -83,27 +84,26 @@ void Send_WhoHas_Object(int32_t low_limit,
|
||||
BACNET_ADDRESS dest;
|
||||
int bytes_sent = 0;
|
||||
BACNET_WHO_HAS_DATA data;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
/* if we are forbidden to send, don't send! */
|
||||
if (!dcc_communication_enabled())
|
||||
return;
|
||||
/* Who-Has is a global broadcast */
|
||||
datalink_get_broadcast_address(&dest);
|
||||
/* encode the NPDU portion of the packet */
|
||||
pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], &dest, NULL, false, /* true for confirmed messages */
|
||||
MESSAGE_PRIORITY_NORMAL);
|
||||
/* encode the APDU portion of the packet */
|
||||
data.low_limit = low_limit;
|
||||
data.high_limit = high_limit;
|
||||
data.object_name = false;
|
||||
data.object.identifier.type = object_type;
|
||||
data.object.identifier.instance = object_instance;
|
||||
pdu_len += whohas_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
&data);
|
||||
/* send the data */
|
||||
bytes_sent = datalink_send_pdu(&dest, /* destination address */
|
||||
&Handler_Transmit_Buffer[0], pdu_len); /* number of bytes of data */
|
||||
pdu_len = whohas_encode_apdu(&Handler_Transmit_Buffer[0], &data);
|
||||
npdu_encode_unconfirmed_apdu(&npdu_data, MESSAGE_PRIORITY_NORMAL);
|
||||
bytes_sent = datalink_send_pdu(&dest, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr, "Failed to Send Who-Has Request (%s)!\n",
|
||||
strerror(errno));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -48,24 +48,22 @@ void Send_WhoIs(int32_t low_limit, int32_t high_limit)
|
||||
int pdu_len = 0;
|
||||
BACNET_ADDRESS dest;
|
||||
int bytes_sent = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
if (!dcc_communication_enabled())
|
||||
return;
|
||||
|
||||
/* Who-Is is a global broadcast */
|
||||
datalink_get_broadcast_address(&dest);
|
||||
|
||||
/* encode the NPDU portion of the packet */
|
||||
pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], &dest, NULL, false, /* true for confirmed messages */
|
||||
MESSAGE_PRIORITY_NORMAL);
|
||||
|
||||
/* encode the APDU portion of the packet */
|
||||
pdu_len += whois_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len = whois_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
low_limit, high_limit);
|
||||
|
||||
bytes_sent = datalink_send_pdu(&dest, /* destination address */
|
||||
&Handler_Transmit_Buffer[0], pdu_len); /* number of bytes of data */
|
||||
npdu_encode_unconfirmed_apdu(&npdu_data, MESSAGE_PRIORITY_NORMAL);
|
||||
bytes_sent = datalink_send_pdu(&dest, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr, "Failed to Send Who-Is Request (%s)!\n",
|
||||
strerror(errno));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -51,13 +51,13 @@ uint8_t Send_Write_Property_Request(uint32_t device_id, /* destination device */
|
||||
uint8_t priority, 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;
|
||||
BACNET_WRITE_PROPERTY_DATA data;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
if (!dcc_communication_enabled())
|
||||
return 0;
|
||||
@@ -66,13 +66,8 @@ uint8_t Send_Write_Property_Request(uint32_t device_id, /* destination device */
|
||||
status = address_get_by_device(device_id, &max_apdu, &dest);
|
||||
/* is there a tsm available? */
|
||||
if (status)
|
||||
status = tsm_transaction_available();
|
||||
if (status) {
|
||||
datalink_get_my_address(&my_address);
|
||||
pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], &dest, &my_address, true, /* true for confirmed messages */
|
||||
MESSAGE_PRIORITY_NORMAL);
|
||||
|
||||
invoke_id = tsm_next_free_invokeID();
|
||||
if (invoke_id) {
|
||||
/* load the data for the encoding */
|
||||
data.object_type = object_type;
|
||||
data.object_instance = object_instance;
|
||||
@@ -80,7 +75,7 @@ uint8_t Send_Write_Property_Request(uint32_t device_id, /* destination device */
|
||||
data.array_index = array_index;
|
||||
bacapp_copy(&data.value, object_value);
|
||||
data.priority = priority;
|
||||
pdu_len += wp_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
pdu_len = wp_encode_apdu(&Handler_Transmit_Buffer[0],
|
||||
invoke_id, &data);
|
||||
/* will it fit in the sender?
|
||||
note: if there is a bottleneck router in between
|
||||
@@ -88,17 +83,25 @@ uint8_t Send_Write_Property_Request(uint32_t device_id, /* destination device */
|
||||
we have a way to check for that and update the
|
||||
max_apdu in the address binding table. */
|
||||
if ((unsigned) pdu_len < max_apdu) {
|
||||
npdu_encode_confirmed_apdu(&npdu_data, MESSAGE_PRIORITY_NORMAL);
|
||||
tsm_set_confirmed_unsegmented_transaction(invoke_id,
|
||||
&dest, &Handler_Transmit_Buffer[0], pdu_len);
|
||||
bytes_sent = datalink_send_pdu(&dest, /* destination address */
|
||||
&Handler_Transmit_Buffer[0], pdu_len); /* number of bytes of data */
|
||||
&dest, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len);
|
||||
bytes_sent = datalink_send_pdu(&dest, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
#if PRINT_ENABLED
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr,
|
||||
"Failed to Send WriteProperty Request (%s)!\n",
|
||||
strerror(errno));
|
||||
} else
|
||||
#endif
|
||||
} else {
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
invoke_id = 0;
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Failed to Send WriteProperty Request "
|
||||
"(exceeds destination maximum APDU)!\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return invoke_id;
|
||||
|
||||
@@ -301,25 +301,21 @@ uint32_t bacfile_instance_from_tsm(uint8_t invokeID)
|
||||
uint8_t *service_request = NULL;
|
||||
uint16_t service_request_len = 0;
|
||||
BACNET_ADDRESS dest; /* where the original packet was destined */
|
||||
uint8_t pdu[MAX_PDU] = { 0 }; /* original sent packet */
|
||||
uint16_t pdu_len = 0; /* original packet length */
|
||||
uint8_t apdu[MAX_PDU] = { 0 }; /* original APDU packet */
|
||||
uint16_t apdu_len = 0; /* original APDU packet length */
|
||||
uint16_t len = 0; /* apdu header length */
|
||||
BACNET_ATOMIC_READ_FILE_DATA data = { 0 };
|
||||
uint32_t object_instance = BACNET_MAX_INSTANCE + 1; /* return value */
|
||||
bool found = false;
|
||||
int apdu_offset = 0;
|
||||
|
||||
found = tsm_get_transaction_pdu(invokeID, &dest, &pdu[0], &pdu_len);
|
||||
found = tsm_get_transaction_pdu(invokeID, &dest, &npdu_data, &apdu[0],
|
||||
&apdu_len);
|
||||
if (found) {
|
||||
apdu_offset = npdu_decode(&pdu[0], /* data to decode */
|
||||
NULL, /* destination address - get the DNET/DLEN/DADR if in there */
|
||||
NULL, /* source address - get the SNET/SLEN/SADR if in there */
|
||||
&npdu_data); /* amount of data to decode */
|
||||
if (!npdu_data.network_layer_message &&
|
||||
((pdu[apdu_offset] & 0xF0) ==
|
||||
PDU_TYPE_CONFIRMED_SERVICE_REQUEST)) {
|
||||
len = apdu_decode_confirmed_service_request(&pdu[apdu_offset], /* APDU data */
|
||||
pdu_len - apdu_offset,
|
||||
if (!npdu_data.network_layer_message && npdu_data.confirmed_message &&
|
||||
(apdu[0] == PDU_TYPE_CONFIRMED_SERVICE_REQUEST)) {
|
||||
len = apdu_decode_confirmed_service_request(&apdu[0],
|
||||
apdu_len - apdu_offset,
|
||||
&service_data,
|
||||
&service_choice, &service_request, &service_request_len);
|
||||
if (service_choice == SERVICE_CONFIRMED_ATOMIC_READ_FILE) {
|
||||
|
||||
@@ -269,12 +269,12 @@ bool Device_Set_Location(const char *name, size_t length)
|
||||
|
||||
uint8_t Device_Protocol_Version(void)
|
||||
{
|
||||
return 1;
|
||||
return BACNET_PROTOCOL_VERSION;
|
||||
}
|
||||
|
||||
uint8_t Device_Protocol_Revision(void)
|
||||
{
|
||||
return 5;
|
||||
return BACNET_PROTOCOL_REVISION;
|
||||
}
|
||||
|
||||
uint16_t Device_Max_APDU_Length_Accepted(void)
|
||||
|
||||
@@ -26,6 +26,8 @@ SRCS = readfile.c \
|
||||
$(BACNET_HANDLER)/txbuf.c \
|
||||
$(BACNET_HANDLER)/noserv.c \
|
||||
$(BACNET_HANDLER)/h_whois.c \
|
||||
$(BACNET_HANDLER)/s_whois.c \
|
||||
$(BACNET_HANDLER)/s_arfs.c \
|
||||
$(BACNET_HANDLER)/h_rp.c \
|
||||
$(BACNET_ROOT)/rp.c \
|
||||
$(BACNET_ROOT)/bacdcode.c \
|
||||
|
||||
@@ -23,6 +23,8 @@ SRCS = readfile.c \
|
||||
..\..\demo\handler\txbuf.c \
|
||||
..\..\demo\handler\noserv.c \
|
||||
..\..\demo\handler\h_whois.c \
|
||||
..\..\demo\handler\s_whois.c \
|
||||
..\..\demo\handler\s_arfs.c \
|
||||
..\..\demo\handler\h_rp.c \
|
||||
..\..\bacdcode.c \
|
||||
..\..\bacapp.c \
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
/* some demo stuff needed */
|
||||
#include "filename.h"
|
||||
#include "handlers.h"
|
||||
#include "client.h"
|
||||
#include "txbuf.h"
|
||||
|
||||
/* buffer used for receive */
|
||||
@@ -97,84 +98,6 @@ void MyRejectHandler(BACNET_ADDRESS * src,
|
||||
Error_Detected = true;
|
||||
}
|
||||
|
||||
static uint8_t Send_Atomic_Read_File_Stream(uint32_t device_id,
|
||||
uint32_t file_instance,
|
||||
int fileStartPosition, unsigned requestedOctetCount)
|
||||
{
|
||||
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;
|
||||
BACNET_ATOMIC_READ_FILE_DATA data;
|
||||
|
||||
/* is the device bound? */
|
||||
status = address_get_by_device(device_id, &max_apdu, &dest);
|
||||
/* is there a tsm available? */
|
||||
if (status)
|
||||
status = tsm_transaction_available();
|
||||
if (status) {
|
||||
datalink_get_my_address(&my_address);
|
||||
pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], &dest, &my_address, true, /* true for confirmed messages */
|
||||
MESSAGE_PRIORITY_NORMAL);
|
||||
|
||||
invoke_id = tsm_next_free_invokeID();
|
||||
/* load the data for the encoding */
|
||||
data.object_type = OBJECT_FILE;
|
||||
data.object_instance = file_instance;
|
||||
data.access = FILE_STREAM_ACCESS;
|
||||
data.type.stream.fileStartPosition = fileStartPosition;
|
||||
data.type.stream.requestedOctetCount = requestedOctetCount;
|
||||
pdu_len += arf_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
invoke_id, &data);
|
||||
/* will the APDU fit the target device?
|
||||
note: if there is a bottleneck router in between
|
||||
us and the destination, we won't know unless
|
||||
we have a way to check for that and update the
|
||||
max_apdu in the address binding table. */
|
||||
if ((unsigned) pdu_len < max_apdu) {
|
||||
tsm_set_confirmed_unsegmented_transaction(invoke_id,
|
||||
&dest, &Handler_Transmit_Buffer[0], pdu_len);
|
||||
bytes_sent = datalink_send_pdu(&dest, /* destination address */
|
||||
&Handler_Transmit_Buffer[0], pdu_len); /* number of bytes of data */
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr,
|
||||
"Failed to Send AtomicReadFile Request (%s)!\n",
|
||||
strerror(errno));
|
||||
} else
|
||||
fprintf(stderr, "Failed to Send AtomicReadFile Request "
|
||||
"(payload exceeds destination maximum APDU)!\n");
|
||||
}
|
||||
|
||||
return invoke_id;
|
||||
}
|
||||
|
||||
static void Send_WhoIs(uint32_t device_id)
|
||||
{
|
||||
int pdu_len = 0;
|
||||
BACNET_ADDRESS dest;
|
||||
int bytes_sent = 0;
|
||||
|
||||
/* Who-Is is a global broadcast */
|
||||
datalink_get_broadcast_address(&dest);
|
||||
|
||||
/* encode the NPDU portion of the packet */
|
||||
pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], &dest, NULL, false, /* true for confirmed messages */
|
||||
MESSAGE_PRIORITY_NORMAL);
|
||||
|
||||
/* encode the APDU portion of the packet */
|
||||
pdu_len += whois_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
device_id, device_id);
|
||||
|
||||
bytes_sent = datalink_send_pdu(&dest, /* destination address */
|
||||
&Handler_Transmit_Buffer[0], pdu_len); /* number of bytes of data */
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr, "Failed to Send Who-Is Request (%s)!\n",
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
static void AtomicReadFileAckHandler(uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_ACK_DATA * service_data)
|
||||
@@ -316,7 +239,7 @@ int main(int argc, char *argv[])
|
||||
timeout_seconds = (Device_APDU_Timeout() / 1000) *
|
||||
Device_Number_Of_APDU_Retries();
|
||||
/* try to bind with the device */
|
||||
Send_WhoIs(Target_Device_Object_Instance);
|
||||
Send_WhoIs(Target_Device_Object_Instance,Target_Device_Object_Instance);
|
||||
/* loop forever */
|
||||
for (;;) {
|
||||
/* increment timer - exit if timed out */
|
||||
|
||||
@@ -49,8 +49,10 @@
|
||||
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
||||
|
||||
/* global variables used in this file */
|
||||
#if 0
|
||||
static int32_t Target_Object_Instance_Min = 0;
|
||||
static int32_t Target_Object_Instance_Max = BACNET_MAX_INSTANCE;
|
||||
#endif
|
||||
|
||||
static bool Error_Detected = false;
|
||||
|
||||
@@ -133,7 +135,7 @@ int main(int argc, char *argv[])
|
||||
BACNET_ADDRESS my_address, broadcast_address;
|
||||
#endif
|
||||
|
||||
/* FIXME: we could send directed time sync, and how to we send UTC? */
|
||||
/* FIXME: we could send directed time sync, and how do we send UTC? */
|
||||
#if 0
|
||||
if (argc < 2) {
|
||||
printf("Usage: %s date time [device-instance]\r\n"
|
||||
|
||||
@@ -27,6 +27,8 @@ SRCS = writefile.c \
|
||||
$(BACNET_HANDLER)/noserv.c \
|
||||
$(BACNET_HANDLER)/h_whois.c \
|
||||
$(BACNET_HANDLER)/h_rp.c \
|
||||
$(BACNET_HANDLER)/s_whois.c \
|
||||
$(BACNET_HANDLER)/s_awfs.c \
|
||||
$(BACNET_ROOT)/rp.c \
|
||||
$(BACNET_ROOT)/bacdcode.c \
|
||||
$(BACNET_ROOT)/bacapp.c \
|
||||
|
||||
@@ -24,6 +24,8 @@ SRCS = writefile.c \
|
||||
..\..\demo\handler\noserv.c \
|
||||
..\..\demo\handler\h_whois.c \
|
||||
..\..\demo\handler\h_rp.c \
|
||||
..\..\demo\handler\s_whois.c \
|
||||
..\..\demo\handler\s_awr.c \
|
||||
..\..\bacdcode.c \
|
||||
..\..\bacapp.c \
|
||||
..\..\bacstr.c \
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
/* some demo stuff needed */
|
||||
#include "filename.h"
|
||||
#include "handlers.h"
|
||||
#include "client.h"
|
||||
#include "txbuf.h"
|
||||
|
||||
/* buffer used for receive */
|
||||
@@ -97,90 +98,6 @@ void MyRejectHandler(BACNET_ADDRESS * src,
|
||||
Error_Detected = true;
|
||||
}
|
||||
|
||||
static uint8_t Send_Atomic_Write_File_Stream(uint32_t device_id,
|
||||
uint32_t file_instance,
|
||||
int fileStartPosition, BACNET_OCTET_STRING * fileData)
|
||||
{
|
||||
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;
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA data;
|
||||
|
||||
/* is the device bound? */
|
||||
status = address_get_by_device(device_id, &max_apdu, &dest);
|
||||
/* is there a tsm available? */
|
||||
if (status)
|
||||
status = tsm_transaction_available();
|
||||
if (status) {
|
||||
datalink_get_my_address(&my_address);
|
||||
pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], &dest, &my_address, true, /* true for confirmed messages */
|
||||
MESSAGE_PRIORITY_NORMAL);
|
||||
|
||||
invoke_id = tsm_next_free_invokeID();
|
||||
/* load the data for the encoding */
|
||||
data.object_type = OBJECT_FILE;
|
||||
data.object_instance = file_instance;
|
||||
data.access = FILE_STREAM_ACCESS;
|
||||
data.type.stream.fileStartPosition = fileStartPosition;
|
||||
status = octetstring_copy(&data.fileData, fileData);
|
||||
if (status) {
|
||||
pdu_len += awf_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
invoke_id, &data);
|
||||
/* will the APDU fit the target device?
|
||||
note: if there is a bottleneck router in between
|
||||
us and the destination, we won't know unless
|
||||
we have a way to check for that and update the
|
||||
max_apdu in the address binding table. */
|
||||
if ((unsigned) pdu_len <= max_apdu) {
|
||||
tsm_set_confirmed_unsegmented_transaction(invoke_id,
|
||||
&dest, &Handler_Transmit_Buffer[0], pdu_len);
|
||||
bytes_sent = datalink_send_pdu(&dest, /* destination address */
|
||||
&Handler_Transmit_Buffer[0], pdu_len); /* number of bytes of data */
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr,
|
||||
"Failed to Send AtomicWriteFile Request (%s)!\n",
|
||||
strerror(errno));
|
||||
} else
|
||||
fprintf(stderr, "Failed to Send AtomicWriteFile Request "
|
||||
"(payload [%d] exceeds destination maximum APDU [%u])!\n",
|
||||
pdu_len, max_apdu);
|
||||
} else
|
||||
fprintf(stderr, "Failed to Send AtomicWriteFile Request "
|
||||
"(payload [%d] exceeds octet string capacity)!\n",
|
||||
pdu_len);
|
||||
}
|
||||
|
||||
return invoke_id;
|
||||
}
|
||||
|
||||
static void Send_WhoIs(uint32_t device_id)
|
||||
{
|
||||
int pdu_len = 0;
|
||||
BACNET_ADDRESS dest;
|
||||
int bytes_sent = 0;
|
||||
|
||||
/* Who-Is is a global broadcast */
|
||||
datalink_get_broadcast_address(&dest);
|
||||
|
||||
/* encode the NPDU portion of the packet */
|
||||
pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], &dest, NULL, false, /* true for confirmed messages */
|
||||
MESSAGE_PRIORITY_NORMAL);
|
||||
|
||||
/* encode the APDU portion of the packet */
|
||||
pdu_len += whois_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
device_id, device_id);
|
||||
|
||||
bytes_sent = datalink_send_pdu(&dest, /* destination address */
|
||||
&Handler_Transmit_Buffer[0], pdu_len); /* number of bytes of data */
|
||||
if (bytes_sent <= 0)
|
||||
fprintf(stderr, "Failed to Send Who-Is Request (%s)!\n",
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
static void LocalIAmHandler(uint8_t * service_request,
|
||||
uint16_t service_len, BACNET_ADDRESS * src)
|
||||
{
|
||||
@@ -278,7 +195,7 @@ int main(int argc, char *argv[])
|
||||
timeout_seconds = (Device_APDU_Timeout() / 1000) *
|
||||
Device_Number_Of_APDU_Retries();
|
||||
/* try to bind with the device */
|
||||
Send_WhoIs(Target_Device_Object_Instance);
|
||||
Send_WhoIs(Target_Device_Object_Instance,Target_Device_Object_Instance);
|
||||
/* loop forever */
|
||||
for (;;) {
|
||||
/* increment timer - exit if timed out */
|
||||
|
||||
+8
-8
@@ -139,21 +139,20 @@ int iam_send(uint8_t * buffer)
|
||||
int pdu_len = 0;
|
||||
BACNET_ADDRESS dest;
|
||||
int bytes_sent = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
/* I-Am is a global broadcast */
|
||||
datalink_get_broadcast_address(&dest);
|
||||
|
||||
/* encode the NPDU portion of the packet */
|
||||
pdu_len = npdu_encode_apdu(&buffer[0], &dest, NULL, false, /* true for confirmed messages */
|
||||
MESSAGE_PRIORITY_NORMAL);
|
||||
|
||||
/* encode the APDU portion of the packet */
|
||||
pdu_len += iam_encode_apdu(&buffer[pdu_len],
|
||||
pdu_len = iam_encode_apdu(&buffer[0],
|
||||
Device_Object_Instance_Number(),
|
||||
MAX_APDU, SEGMENTATION_NONE, Device_Vendor_Identifier());
|
||||
|
||||
bytes_sent = datalink_send_pdu(&dest, /* destination address */
|
||||
&buffer[0], pdu_len); /* number of bytes of data */
|
||||
/* encode the NPDU portion of the packet */
|
||||
npdu_encode_unconfirmed_apdu(&npdu_data, MESSAGE_PRIORITY_NORMAL);
|
||||
/* send data */
|
||||
bytes_sent = datalink_send_pdu(&dest, &npdu_data,
|
||||
&buffer[0], pdu_len);
|
||||
|
||||
return bytes_sent;
|
||||
}
|
||||
@@ -219,6 +218,7 @@ void datalink_get_broadcast_address(BACNET_ADDRESS * dest)
|
||||
}
|
||||
|
||||
int datalink_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len)
|
||||
{ /* number of bytes of data */
|
||||
|
||||
+68
-35
@@ -40,17 +40,37 @@
|
||||
#include "npdu.h"
|
||||
#include "apdu.h"
|
||||
|
||||
int npdu_encode_raw(uint8_t * npdu,
|
||||
void npdu_copy_data(BACNET_NPDU_DATA * dest, BACNET_NPDU_DATA * src)
|
||||
{
|
||||
if (dest && src) {
|
||||
dest->protocol_version = src->protocol_version;
|
||||
dest->confirmed_message = src->confirmed_message;
|
||||
dest->network_layer_message = src->network_layer_message;
|
||||
dest->priority = src->priority;
|
||||
dest->network_message_type = src->network_message_type;
|
||||
dest->vendor_id = src->vendor_id;
|
||||
dest->hop_count = src->hop_count;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int npdu_encode_pdu(uint8_t * npdu,
|
||||
BACNET_ADDRESS * dest,
|
||||
BACNET_ADDRESS * src, BACNET_NPDU_DATA * npdu_data)
|
||||
BACNET_ADDRESS * src,
|
||||
BACNET_NPDU_DATA * npdu_data)
|
||||
{
|
||||
int len = 0; /* return value - number of octets loaded in this function */
|
||||
int i = 0; /* counter */
|
||||
|
||||
|
||||
if (npdu && npdu_data) {
|
||||
/* Protocol Version */
|
||||
npdu[0] = 1;
|
||||
/* control octet */
|
||||
/* only include src address for data expecting reply, or replies */
|
||||
if (!(npdu_data->confirmed_message))
|
||||
src = NULL;
|
||||
/* protocol version */
|
||||
npdu[0] = npdu_data->protocol_version;
|
||||
/* initialize the control octet */
|
||||
npdu[1] = 0;
|
||||
/* Bit 7: 1 indicates that the NSDU conveys a network layer message. */
|
||||
/* Message Type field is present. */
|
||||
@@ -74,15 +94,15 @@ int npdu_encode_raw(uint8_t * npdu,
|
||||
/* SLEN > 0 specifies length of SADR field */
|
||||
if (src && src->net)
|
||||
npdu[1] |= BIT3;
|
||||
/* Bit 2: The value of this bit corresponds to the data_expecting_reply */
|
||||
/* parameter in the N-UNITDATA primitives. */
|
||||
/* Bit 2: The value of this bit corresponds to the */
|
||||
/* data_expecting_reply parameter in the N-UNITDATA primitives. */
|
||||
/* 1 indicates that a BACnet-Confirmed-Request-PDU, */
|
||||
/* a segment of a BACnet-ComplexACK-PDU, */
|
||||
/* or a network layer message expecting a reply is present. */
|
||||
/* 0 indicates that other than a BACnet-Confirmed-Request-PDU, */
|
||||
/* a segment of a BACnet-ComplexACK-PDU, */
|
||||
/* or a network layer message expecting a reply is present. */
|
||||
if (npdu_data->data_expecting_reply)
|
||||
if (npdu_data->confirmed_message)
|
||||
npdu[1] |= BIT2;
|
||||
/* Bits 1,0: Network priority where: */
|
||||
/* B'11' = Life Safety message */
|
||||
@@ -133,20 +153,36 @@ int npdu_encode_raw(uint8_t * npdu,
|
||||
return len;
|
||||
}
|
||||
|
||||
/* encode the NPDU portion of the packet for an APDU */
|
||||
/* Configure the NPDU portion of the packet for an APDU */
|
||||
/* This function does not handle the network messages, just APDUs. */
|
||||
int npdu_encode_apdu(uint8_t * npdu, BACNET_ADDRESS * dest, BACNET_ADDRESS * src, bool data_expecting_reply, /* true for confirmed messages */
|
||||
void npdu_encode_confirmed_apdu(BACNET_NPDU_DATA * npdu_data,
|
||||
BACNET_MESSAGE_PRIORITY priority)
|
||||
{
|
||||
BACNET_NPDU_DATA npdu_data = { 0 };
|
||||
if (npdu_data)
|
||||
{
|
||||
npdu_data->confirmed_message = true;
|
||||
npdu_data->protocol_version = BACNET_PROTOCOL_VERSION;
|
||||
npdu_data->network_layer_message = false; /* false if APDU */
|
||||
npdu_data->network_message_type = 0; /* optional */
|
||||
npdu_data->vendor_id = 0; /* optional, if net message type is > 0x80 */
|
||||
npdu_data->priority = priority;
|
||||
npdu_data->hop_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
npdu_data.data_expecting_reply = data_expecting_reply;
|
||||
npdu_data.network_layer_message = false; /* false if APDU */
|
||||
npdu_data.network_message_type = 0; /* optional */
|
||||
npdu_data.vendor_id = 0; /* optional, if net message type is > 0x80 */
|
||||
npdu_data.priority = priority;
|
||||
/* call the real function... */
|
||||
return npdu_encode_raw(npdu, dest, src, &npdu_data);
|
||||
void npdu_encode_unconfirmed_apdu(BACNET_NPDU_DATA * npdu_data,
|
||||
BACNET_MESSAGE_PRIORITY priority)
|
||||
{
|
||||
if (npdu_data)
|
||||
{
|
||||
npdu_data->confirmed_message = false;
|
||||
npdu_data->protocol_version = BACNET_PROTOCOL_VERSION;
|
||||
npdu_data->network_layer_message = false; /* false if APDU */
|
||||
npdu_data->network_message_type = 0; /* optional */
|
||||
npdu_data->vendor_id = 0; /* optional, if net message type is > 0x80 */
|
||||
npdu_data->priority = priority;
|
||||
npdu_data->hop_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int npdu_decode(uint8_t * npdu,
|
||||
@@ -171,7 +207,7 @@ int npdu_decode(uint8_t * npdu,
|
||||
npdu_data->network_layer_message = (npdu[1] & BIT7) ? true : false;
|
||||
/*Bit 6: Reserved. Shall be zero. */
|
||||
/* Bit 4: Reserved. Shall be zero. */
|
||||
/* Bit 2: The value of this bit corresponds to the data_expecting_reply */
|
||||
/* Bit 2: The value of this bit corresponds to data expecting reply */
|
||||
/* parameter in the N-UNITDATA primitives. */
|
||||
/* 1 indicates that a BACnet-Confirmed-Request-PDU, */
|
||||
/* a segment of a BACnet-ComplexACK-PDU, */
|
||||
@@ -179,7 +215,7 @@ int npdu_decode(uint8_t * npdu,
|
||||
/* 0 indicates that other than a BACnet-Confirmed-Request-PDU, */
|
||||
/* a segment of a BACnet-ComplexACK-PDU, */
|
||||
/* or a network layer message expecting a reply is present. */
|
||||
npdu_data->data_expecting_reply = (npdu[1] & BIT2) ? true : false;
|
||||
npdu_data->confirmed_message = (npdu[1] & BIT2) ? true : false;
|
||||
/* Bits 1,0: Network priority where: */
|
||||
/* B'11' = Life Safety message */
|
||||
/* B'10' = Critical Equipment message */
|
||||
@@ -277,16 +313,13 @@ void npdu_handler(BACNET_ADDRESS * src, /* source address */
|
||||
BACNET_ADDRESS dest = { 0 };
|
||||
BACNET_NPDU_DATA npdu_data = { 0 };
|
||||
|
||||
apdu_offset = npdu_decode(&pdu[0], /* data to decode */
|
||||
&dest, /* destination address - get the DNET/DLEN/DADR if in there */
|
||||
src, /* source address - get the SNET/SLEN/SADR if in there */
|
||||
&npdu_data); /* amount of data to decode */
|
||||
apdu_offset = npdu_decode(&pdu[0], &dest, src, &npdu_data);
|
||||
if (npdu_data.network_layer_message) {
|
||||
/*FIXME: network layer message received! Handle it! */
|
||||
} else {
|
||||
apdu_handler(src,
|
||||
npdu_data.data_expecting_reply,
|
||||
&pdu[apdu_offset], pdu_len - apdu_offset);
|
||||
/* only handle the version that we know how to handle */
|
||||
if (npdu_data.protocol_version == BACNET_PROTOCOL_VERSION)
|
||||
apdu_handler(src, &pdu[apdu_offset], pdu_len - apdu_offset);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -306,7 +339,7 @@ void testNPDU2(Test * pTest)
|
||||
BACNET_ADDRESS npdu_dest = { 0 };
|
||||
BACNET_ADDRESS npdu_src = { 0 };
|
||||
int len = 0;
|
||||
bool data_expecting_reply = false; /* true for confirmed messages */
|
||||
bool confirmed_message = true; /* true for confirmed messages */
|
||||
BACNET_MESSAGE_PRIORITY priority = MESSAGE_PRIORITY_NORMAL;
|
||||
BACNET_NPDU_DATA npdu_data = { 0 };
|
||||
int i = 0; /* counter */
|
||||
@@ -336,13 +369,13 @@ void testNPDU2(Test * pTest)
|
||||
for (i = 0; i < src.len; i++) {
|
||||
src.adr[i] = 0x40;
|
||||
}
|
||||
len = npdu_encode_apdu(&pdu[0],
|
||||
&dest, &src, data_expecting_reply, priority);
|
||||
npdu_encode_confirmed_apdu(&npdu_data, priority);
|
||||
len = npdu_encode_pdu(&pdu[0], &dest, &src, &npdu_data);
|
||||
ct_test(pTest, len != 0);
|
||||
/* can we get the info back? */
|
||||
npdu_len = npdu_decode(&pdu[0], &npdu_dest, &npdu_src, &npdu_data);
|
||||
ct_test(pTest, npdu_len != 0);
|
||||
ct_test(pTest, npdu_data.data_expecting_reply == data_expecting_reply);
|
||||
ct_test(pTest, npdu_data.confirmed_message == confirmed_message);
|
||||
ct_test(pTest,
|
||||
npdu_data.network_layer_message == network_layer_message);
|
||||
ct_test(pTest, npdu_data.network_message_type == network_message_type);
|
||||
@@ -370,7 +403,7 @@ void testNPDU1(Test * pTest)
|
||||
BACNET_ADDRESS npdu_dest = { 0 };
|
||||
BACNET_ADDRESS npdu_src = { 0 };
|
||||
int len = 0;
|
||||
bool data_expecting_reply = false; /* true for confirmed messages */
|
||||
bool confirmed_message = false; /* true for confirmed messages */
|
||||
BACNET_MESSAGE_PRIORITY priority = MESSAGE_PRIORITY_NORMAL;
|
||||
BACNET_NPDU_DATA npdu_data = { 0 };
|
||||
int i = 0; /* counter */
|
||||
@@ -400,13 +433,13 @@ void testNPDU1(Test * pTest)
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
src.adr[i] = 0;
|
||||
}
|
||||
len = npdu_encode_apdu(&pdu[0],
|
||||
&dest, &src, data_expecting_reply, priority);
|
||||
npdu_encode_unconfirmed_apdu(&npdu_data, priority);
|
||||
len = npdu_encode_pdu(&pdu[0], &dest, &src, &npdu_data);
|
||||
ct_test(pTest, len != 0);
|
||||
/* can we get the info back? */
|
||||
npdu_len = npdu_decode(&pdu[0], &npdu_dest, &npdu_src, &npdu_data);
|
||||
ct_test(pTest, npdu_len != 0);
|
||||
ct_test(pTest, npdu_data.data_expecting_reply == data_expecting_reply);
|
||||
ct_test(pTest, npdu_data.confirmed_message == confirmed_message);
|
||||
ct_test(pTest,
|
||||
npdu_data.network_layer_message == network_layer_message);
|
||||
ct_test(pTest, npdu_data.network_message_type == network_message_type);
|
||||
|
||||
+9
-4
@@ -43,7 +43,7 @@
|
||||
typedef struct bacnet_npdu_data_t {
|
||||
uint8_t protocol_version;
|
||||
/* parts of the control octet: */
|
||||
bool data_expecting_reply; /* true for confirmed messages */
|
||||
bool confirmed_message; /* true for confirmed messages */
|
||||
bool network_layer_message; /* false if APDU */
|
||||
BACNET_MESSAGE_PRIORITY priority;
|
||||
/* optional network message info */
|
||||
@@ -57,12 +57,17 @@ extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
uint8_t npdu_encode_max_seg_max_apdu(int max_segs, int max_apdu);
|
||||
int npdu_encode_raw(uint8_t * npdu,
|
||||
|
||||
int npdu_encode_pdu(uint8_t * npdu,
|
||||
BACNET_ADDRESS * dest,
|
||||
BACNET_ADDRESS * src, BACNET_NPDU_DATA * npdu_data);
|
||||
/* encode the NPDU portion of the packet for an APDU */
|
||||
int npdu_encode_apdu(uint8_t * npdu, BACNET_ADDRESS * dest, BACNET_ADDRESS * src, bool data_expecting_reply, /* true for confirmed messages */
|
||||
|
||||
void npdu_encode_confirmed_apdu(BACNET_NPDU_DATA * npdu,
|
||||
BACNET_MESSAGE_PRIORITY priority);
|
||||
void npdu_encode_unconfirmed_apdu(BACNET_NPDU_DATA * npdu,
|
||||
BACNET_MESSAGE_PRIORITY priority);
|
||||
|
||||
void npdu_copy_data(BACNET_NPDU_DATA * dest, BACNET_NPDU_DATA * src);
|
||||
|
||||
int npdu_decode(uint8_t * npdu,
|
||||
BACNET_ADDRESS * dest,
|
||||
|
||||
+35
-26
@@ -132,22 +132,26 @@ uint8_t tsm_next_free_invokeID(void)
|
||||
uint8_t invokeID = 0;
|
||||
bool found = false;
|
||||
|
||||
while (!found) {
|
||||
index = tsm_find_invokeID_index(current_invokeID);
|
||||
/* not found - that is good! */
|
||||
if (index == MAX_TSM_TRANSACTIONS) {
|
||||
found = true;
|
||||
/* set this id into the table */
|
||||
index = tsm_find_first_free_index();
|
||||
if (index != MAX_TSM_TRANSACTIONS) {
|
||||
TSM_List[index].InvokeID = invokeID = current_invokeID;
|
||||
TSM_List[index].state = TSM_STATE_IDLE;
|
||||
TSM_List[index].RequestTimer = Device_APDU_Timeout();
|
||||
/* update for the next call or check */
|
||||
current_invokeID++;
|
||||
/* skip zero - we treat that internally as invalid or no free */
|
||||
if (current_invokeID == 0)
|
||||
current_invokeID = 1;
|
||||
/* is there even space available? */
|
||||
if (tsm_transaction_available())
|
||||
{
|
||||
while (!found) {
|
||||
index = tsm_find_invokeID_index(current_invokeID);
|
||||
/* not found - that is good! */
|
||||
if (index == MAX_TSM_TRANSACTIONS) {
|
||||
found = true;
|
||||
/* set this id into the table */
|
||||
index = tsm_find_first_free_index();
|
||||
if (index != MAX_TSM_TRANSACTIONS) {
|
||||
TSM_List[index].InvokeID = invokeID = current_invokeID;
|
||||
TSM_List[index].state = TSM_STATE_IDLE;
|
||||
TSM_List[index].RequestTimer = Device_APDU_Timeout();
|
||||
/* update for the next call or check */
|
||||
current_invokeID++;
|
||||
/* skip zero - we treat that internally as invalid or no free */
|
||||
if (current_invokeID == 0)
|
||||
current_invokeID = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -156,7 +160,8 @@ uint8_t tsm_next_free_invokeID(void)
|
||||
}
|
||||
|
||||
void tsm_set_confirmed_unsegmented_transaction(uint8_t invokeID,
|
||||
BACNET_ADDRESS * dest, uint8_t * pdu, uint16_t pdu_len)
|
||||
BACNET_ADDRESS * dest, BACNET_NPDU_DATA * ndpu_data,
|
||||
uint8_t * apdu, uint16_t apdu_len)
|
||||
{
|
||||
uint16_t j = 0;
|
||||
uint8_t index;
|
||||
@@ -170,10 +175,11 @@ void tsm_set_confirmed_unsegmented_transaction(uint8_t invokeID,
|
||||
/* start the timer */
|
||||
TSM_List[index].RequestTimer = Device_APDU_Timeout();
|
||||
/* copy the data */
|
||||
for (j = 0; j < pdu_len; j++) {
|
||||
TSM_List[index].pdu[j] = pdu[j];
|
||||
for (j = 0; j < apdu_len; j++) {
|
||||
TSM_List[index].apdu[j] = apdu[j];
|
||||
}
|
||||
TSM_List[index].pdu_len = pdu_len;
|
||||
TSM_List[index].apdu_len = apdu_len;
|
||||
npdu_copy_data(&TSM_List[index].npdu_data, ndpu_data);
|
||||
address_copy(&TSM_List[index].dest, dest);
|
||||
}
|
||||
}
|
||||
@@ -184,7 +190,8 @@ void tsm_set_confirmed_unsegmented_transaction(uint8_t invokeID,
|
||||
/* 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)
|
||||
BACNET_ADDRESS * dest, BACNET_NPDU_DATA * ndpu_data,
|
||||
uint8_t * apdu, uint16_t * apdu_len)
|
||||
{
|
||||
uint16_t j = 0;
|
||||
uint8_t index;
|
||||
@@ -197,10 +204,11 @@ bool tsm_get_transaction_pdu(uint8_t invokeID,
|
||||
/* 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];
|
||||
*apdu_len = TSM_List[index].apdu_len;
|
||||
for (j = 0; j < *apdu_len; j++) {
|
||||
apdu[j] = TSM_List[index].apdu[j];
|
||||
}
|
||||
npdu_copy_data(ndpu_data,&TSM_List[index].npdu_data);
|
||||
address_copy(dest, &TSM_List[index].dest);
|
||||
found = true;
|
||||
}
|
||||
@@ -226,8 +234,9 @@ void tsm_timer_milliseconds(uint16_t milliseconds)
|
||||
TSM_List[i].RetryCount--;
|
||||
TSM_List[i].RequestTimer = Device_APDU_Timeout();
|
||||
if (TSM_List[i].RetryCount) {
|
||||
bytes_sent = datalink_send_pdu(&TSM_List[i].dest, /* destination address */
|
||||
&TSM_List[i].pdu[0], TSM_List[i].pdu_len); /* number of bytes of data */
|
||||
bytes_sent = datalink_send_pdu(&TSM_List[i].dest,
|
||||
&TSM_List[i].npdu_data,
|
||||
&TSM_List[i].apdu[0], TSM_List[i].apdu_len);
|
||||
} else {
|
||||
TSM_List[i].InvokeID = 0;
|
||||
TSM_List[i].state = TSM_STATE_IDLE;
|
||||
|
||||
+10
-5
@@ -38,6 +38,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "bacdef.h"
|
||||
#include "npdu.h"
|
||||
|
||||
/* note: TSM functionality is optional - only needed if we are
|
||||
doing client requests */
|
||||
@@ -80,9 +81,11 @@ typedef struct BACnet_TSM_Data {
|
||||
BACNET_TSM_STATE state;
|
||||
/* the address we sent it to */
|
||||
BACNET_ADDRESS dest;
|
||||
/* copy of the PDU, should we need to send it again */
|
||||
uint8_t pdu[MAX_PDU];
|
||||
unsigned pdu_len;
|
||||
/* the network layer info */
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
/* copy of the APDU, should we need to send it again */
|
||||
uint8_t apdu[MAX_PDU];
|
||||
unsigned apdu_len;
|
||||
} BACNET_TSM_DATA;
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -98,10 +101,12 @@ extern "C" {
|
||||
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);
|
||||
BACNET_ADDRESS * dest, BACNET_NPDU_DATA * ndpu_data,
|
||||
uint8_t * apdu, uint16_t apdu_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);
|
||||
BACNET_ADDRESS * dest, BACNET_NPDU_DATA * ndpu_data,
|
||||
uint8_t * apdu, uint16_t * apdu_len);
|
||||
|
||||
bool tsm_invoke_id_free(uint8_t invokeID);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user