ran the indent program on the source files to make them consistent.
This commit is contained in:
+80
-124
@@ -37,71 +37,56 @@
|
||||
#include "bacdef.h"
|
||||
|
||||
// encode service
|
||||
int abort_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint8_t invoke_id,
|
||||
uint8_t abort_reason)
|
||||
int abort_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, uint8_t abort_reason)
|
||||
{
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
|
||||
if (apdu)
|
||||
{
|
||||
apdu[0] = PDU_TYPE_ABORT;
|
||||
apdu[1] = invoke_id;
|
||||
apdu[2] = abort_reason;
|
||||
apdu_len = 3;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
if (apdu) {
|
||||
apdu[0] = PDU_TYPE_ABORT;
|
||||
apdu[1] = invoke_id;
|
||||
apdu[2] = abort_reason;
|
||||
apdu_len = 3;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
// decode the service request only
|
||||
int abort_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
uint8_t *abort_reason)
|
||||
int abort_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, uint8_t * invoke_id, uint8_t * abort_reason)
|
||||
{
|
||||
int len = 0;
|
||||
int len = 0;
|
||||
|
||||
if (apdu_len)
|
||||
{
|
||||
if (invoke_id)
|
||||
*invoke_id = apdu[0];
|
||||
if (abort_reason)
|
||||
*abort_reason = apdu[1];
|
||||
}
|
||||
|
||||
return len;
|
||||
if (apdu_len) {
|
||||
if (invoke_id)
|
||||
*invoke_id = apdu[0];
|
||||
if (abort_reason)
|
||||
*abort_reason = apdu[1];
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
// decode the whole APDU - mainly used for unit testing
|
||||
int abort_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
uint8_t *abort_reason)
|
||||
int abort_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len, uint8_t * invoke_id, uint8_t * abort_reason)
|
||||
{
|
||||
int len = 0;
|
||||
int len = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu_len)
|
||||
{
|
||||
if (apdu[0] != PDU_TYPE_ABORT)
|
||||
return -1;
|
||||
if (apdu_len > 1)
|
||||
{
|
||||
len = abort_decode_service_request(
|
||||
&apdu[1],
|
||||
apdu_len - 1,
|
||||
invoke_id,
|
||||
abort_reason);
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu_len) {
|
||||
if (apdu[0] != PDU_TYPE_ABORT)
|
||||
return -1;
|
||||
if (apdu_len > 1) {
|
||||
len = abort_decode_service_request(&apdu[1],
|
||||
apdu_len - 1, invoke_id, abort_reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
@@ -111,83 +96,54 @@ int abort_decode_apdu(
|
||||
|
||||
void testAbort(Test * pTest)
|
||||
{
|
||||
uint8_t apdu[480] = {0};
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 0;
|
||||
uint8_t abort_reason = 0;
|
||||
uint8_t test_invoke_id = 0;
|
||||
uint8_t test_abort_reason = 0;
|
||||
|
||||
len = abort_encode_apdu(
|
||||
&apdu[0],
|
||||
invoke_id,
|
||||
abort_reason);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 0;
|
||||
uint8_t abort_reason = 0;
|
||||
uint8_t test_invoke_id = 0;
|
||||
uint8_t test_abort_reason = 0;
|
||||
|
||||
len = abort_decode_apdu(
|
||||
&apdu[0],
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_abort_reason);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
ct_test(pTest, test_abort_reason == abort_reason);
|
||||
len = abort_encode_apdu(&apdu[0], invoke_id, abort_reason);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
|
||||
// change type to get negative response
|
||||
apdu[0] = PDU_TYPE_REJECT;
|
||||
len = abort_decode_apdu(
|
||||
&apdu[0],
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_abort_reason);
|
||||
ct_test(pTest, len == -1);
|
||||
len = abort_decode_apdu(&apdu[0],
|
||||
apdu_len, &test_invoke_id, &test_abort_reason);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
ct_test(pTest, test_abort_reason == abort_reason);
|
||||
|
||||
// test NULL APDU
|
||||
len = abort_decode_apdu(
|
||||
NULL,
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_abort_reason);
|
||||
ct_test(pTest, len == -1);
|
||||
// change type to get negative response
|
||||
apdu[0] = PDU_TYPE_REJECT;
|
||||
len = abort_decode_apdu(&apdu[0],
|
||||
apdu_len, &test_invoke_id, &test_abort_reason);
|
||||
ct_test(pTest, len == -1);
|
||||
|
||||
// force a zero length
|
||||
len = abort_decode_apdu(
|
||||
&apdu[0],
|
||||
0,
|
||||
&test_invoke_id,
|
||||
&test_abort_reason);
|
||||
ct_test(pTest, len == 0);
|
||||
|
||||
|
||||
// check them all...
|
||||
for (
|
||||
invoke_id = 0;
|
||||
invoke_id < 255;
|
||||
invoke_id++)
|
||||
{
|
||||
for (
|
||||
abort_reason = 0;
|
||||
abort_reason < 255;
|
||||
abort_reason++)
|
||||
{
|
||||
len = abort_encode_apdu(
|
||||
&apdu[0],
|
||||
invoke_id,
|
||||
abort_reason);
|
||||
apdu_len = len;
|
||||
ct_test(pTest, len != 0);
|
||||
len = abort_decode_apdu(
|
||||
&apdu[0],
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_abort_reason);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
ct_test(pTest, test_abort_reason == abort_reason);
|
||||
// test NULL APDU
|
||||
len = abort_decode_apdu(NULL,
|
||||
apdu_len, &test_invoke_id, &test_abort_reason);
|
||||
ct_test(pTest, len == -1);
|
||||
|
||||
// force a zero length
|
||||
len = abort_decode_apdu(&apdu[0],
|
||||
0, &test_invoke_id, &test_abort_reason);
|
||||
ct_test(pTest, len == 0);
|
||||
|
||||
|
||||
// check them all...
|
||||
for (invoke_id = 0; invoke_id < 255; invoke_id++) {
|
||||
for (abort_reason = 0; abort_reason < 255; abort_reason++) {
|
||||
len = abort_encode_apdu(&apdu[0], invoke_id, abort_reason);
|
||||
apdu_len = len;
|
||||
ct_test(pTest, len != 0);
|
||||
len = abort_decode_apdu(&apdu[0],
|
||||
apdu_len, &test_invoke_id, &test_abort_reason);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
ct_test(pTest, test_abort_reason == abort_reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST_ABORT
|
||||
|
||||
+10
-20
@@ -39,33 +39,23 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int abort_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint8_t invoke_id,
|
||||
uint8_t abort_reason);
|
||||
int abort_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, uint8_t abort_reason);
|
||||
|
||||
int abort_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
uint8_t *abort_reason);
|
||||
|
||||
int abort_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
uint8_t *abort_reason);
|
||||
int abort_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, uint8_t * invoke_id, uint8_t * abort_reason);
|
||||
|
||||
int abort_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len, uint8_t * invoke_id, uint8_t * abort_reason);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testAbort(Test * pTest);
|
||||
void testAbort(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
|
||||
+223
-279
@@ -44,287 +44,241 @@
|
||||
// occurs in BACnet. A device id is bound to a MAC address.
|
||||
// The normal method is using Who-Is, and using the data from I-Am
|
||||
|
||||
static struct Address_Cache_Entry
|
||||
{
|
||||
bool valid;
|
||||
bool bind_request;
|
||||
uint32_t device_id;
|
||||
unsigned max_apdu;
|
||||
BACNET_ADDRESS address;
|
||||
static struct Address_Cache_Entry {
|
||||
bool valid;
|
||||
bool bind_request;
|
||||
uint32_t device_id;
|
||||
unsigned max_apdu;
|
||||
BACNET_ADDRESS address;
|
||||
} Address_Cache[MAX_ADDRESS_CACHE];
|
||||
|
||||
void address_copy(
|
||||
BACNET_ADDRESS *dest,
|
||||
BACNET_ADDRESS *src)
|
||||
void address_copy(BACNET_ADDRESS * dest, BACNET_ADDRESS * src)
|
||||
{
|
||||
unsigned i = 0; // counter
|
||||
|
||||
if (dest && src)
|
||||
{
|
||||
for (i = 0; i < MAX_MAC_LEN; i++)
|
||||
{
|
||||
dest->mac[i] = src->mac[i];
|
||||
}
|
||||
dest->mac_len = src->mac_len;
|
||||
dest->net = src->net;
|
||||
dest->len = src->len;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++)
|
||||
{
|
||||
dest->adr[i] = src->adr[i];
|
||||
}
|
||||
}
|
||||
unsigned i = 0; // counter
|
||||
|
||||
return;
|
||||
if (dest && src) {
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
dest->mac[i] = src->mac[i];
|
||||
}
|
||||
dest->mac_len = src->mac_len;
|
||||
dest->net = src->net;
|
||||
dest->len = src->len;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
dest->adr[i] = src->adr[i];
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void address_remove_device(
|
||||
uint32_t device_id)
|
||||
void address_remove_device(uint32_t device_id)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++)
|
||||
{
|
||||
if ((Address_Cache[i].valid ||
|
||||
Address_Cache[i].bind_request) &&
|
||||
(Address_Cache[i].device_id == device_id))
|
||||
{
|
||||
Address_Cache[i].valid = false;
|
||||
break;
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
|
||||
if ((Address_Cache[i].valid ||
|
||||
Address_Cache[i].bind_request) &&
|
||||
(Address_Cache[i].device_id == device_id)) {
|
||||
Address_Cache[i].valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
void address_init(void)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++)
|
||||
{
|
||||
Address_Cache[i].valid = false;
|
||||
Address_Cache[i].bind_request = false;
|
||||
}
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
|
||||
Address_Cache[i].valid = false;
|
||||
Address_Cache[i].bind_request = false;
|
||||
}
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
bool address_get_by_device(
|
||||
uint32_t device_id,
|
||||
unsigned *max_apdu,
|
||||
BACNET_ADDRESS *src)
|
||||
bool address_get_by_device(uint32_t device_id,
|
||||
unsigned *max_apdu, BACNET_ADDRESS * src)
|
||||
{
|
||||
unsigned i;
|
||||
bool found = false; // return value
|
||||
unsigned i;
|
||||
bool found = false; // return value
|
||||
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++)
|
||||
{
|
||||
if (Address_Cache[i].valid &&
|
||||
(Address_Cache[i].device_id == device_id))
|
||||
{
|
||||
address_copy(src, &Address_Cache[i].address);
|
||||
*max_apdu = Address_Cache[i].max_apdu;
|
||||
found = true;
|
||||
break;
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
|
||||
if (Address_Cache[i].valid &&
|
||||
(Address_Cache[i].device_id == device_id)) {
|
||||
address_copy(src, &Address_Cache[i].address);
|
||||
*max_apdu = Address_Cache[i].max_apdu;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
return found;
|
||||
}
|
||||
|
||||
void address_add(
|
||||
uint32_t device_id,
|
||||
unsigned max_apdu,
|
||||
BACNET_ADDRESS *src)
|
||||
void address_add(uint32_t device_id,
|
||||
unsigned max_apdu, BACNET_ADDRESS * src)
|
||||
{
|
||||
unsigned i;
|
||||
bool found = false; // return value
|
||||
unsigned i;
|
||||
bool found = false; // return value
|
||||
|
||||
// existing device - update address
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++)
|
||||
{
|
||||
if (Address_Cache[i].valid &&
|
||||
(Address_Cache[i].device_id == device_id))
|
||||
{
|
||||
address_copy(&Address_Cache[i].address,src);
|
||||
Address_Cache[i].max_apdu = max_apdu;
|
||||
found = true;
|
||||
break;
|
||||
// existing device - update address
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
|
||||
if (Address_Cache[i].valid &&
|
||||
(Address_Cache[i].device_id == device_id)) {
|
||||
address_copy(&Address_Cache[i].address, src);
|
||||
Address_Cache[i].max_apdu = max_apdu;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// new device
|
||||
if (!found)
|
||||
{
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++)
|
||||
{
|
||||
if (!Address_Cache[i].valid)
|
||||
{
|
||||
Address_Cache[i].valid = true;
|
||||
Address_Cache[i].device_id = device_id;
|
||||
Address_Cache[i].max_apdu = max_apdu;
|
||||
address_copy(&Address_Cache[i].address,src);
|
||||
break;
|
||||
}
|
||||
// new device
|
||||
if (!found) {
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
|
||||
if (!Address_Cache[i].valid) {
|
||||
Address_Cache[i].valid = true;
|
||||
Address_Cache[i].device_id = device_id;
|
||||
Address_Cache[i].max_apdu = max_apdu;
|
||||
address_copy(&Address_Cache[i].address, src);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
// returns true if device is already bound
|
||||
// also returns the address and max apdu if already bound
|
||||
bool address_bind_request(
|
||||
uint32_t device_id,
|
||||
unsigned *max_apdu,
|
||||
BACNET_ADDRESS *src)
|
||||
bool address_bind_request(uint32_t device_id,
|
||||
unsigned *max_apdu, BACNET_ADDRESS * src)
|
||||
{
|
||||
unsigned i;
|
||||
bool found = false; // return value
|
||||
unsigned i;
|
||||
bool found = false; // return value
|
||||
|
||||
// existing device - update address
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++)
|
||||
{
|
||||
if (Address_Cache[i].valid &&
|
||||
(Address_Cache[i].device_id == device_id))
|
||||
{
|
||||
found = true;
|
||||
address_copy(src, &Address_Cache[i].address);
|
||||
*max_apdu = Address_Cache[i].max_apdu;
|
||||
break;
|
||||
// existing device - update address
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
|
||||
if (Address_Cache[i].valid &&
|
||||
(Address_Cache[i].device_id == device_id)) {
|
||||
found = true;
|
||||
address_copy(src, &Address_Cache[i].address);
|
||||
*max_apdu = Address_Cache[i].max_apdu;
|
||||
break;
|
||||
}
|
||||
// already have a bind request active for this puppy
|
||||
else if (Address_Cache[i].bind_request &&
|
||||
(Address_Cache[i].device_id == device_id)) {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
// already have a bind request active for this puppy
|
||||
else if (Address_Cache[i].bind_request &&
|
||||
(Address_Cache[i].device_id == device_id))
|
||||
{
|
||||
return found;
|
||||
|
||||
if (!found) {
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
|
||||
if (!(Address_Cache[i].bind_request || Address_Cache[i].valid)) {
|
||||
Address_Cache[i].bind_request = true;
|
||||
Address_Cache[i].device_id = device_id;
|
||||
// now would be a good time to do a Who-Is request
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++)
|
||||
{
|
||||
if (!(Address_Cache[i].bind_request || Address_Cache[i].valid))
|
||||
{
|
||||
Address_Cache[i].bind_request = true;
|
||||
Address_Cache[i].device_id = device_id;
|
||||
// now would be a good time to do a Who-Is request
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
void address_add_binding(
|
||||
uint32_t device_id,
|
||||
unsigned max_apdu,
|
||||
BACNET_ADDRESS *src)
|
||||
void address_add_binding(uint32_t device_id,
|
||||
unsigned max_apdu, BACNET_ADDRESS * src)
|
||||
{
|
||||
unsigned i;
|
||||
bool found = false; // return value
|
||||
unsigned i;
|
||||
bool found = false; // return value
|
||||
|
||||
// existing device - update address
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++)
|
||||
{
|
||||
if (Address_Cache[i].valid &&
|
||||
(Address_Cache[i].device_id == device_id))
|
||||
{
|
||||
address_copy(&Address_Cache[i].address,src);
|
||||
Address_Cache[i].max_apdu = max_apdu;
|
||||
found = true;
|
||||
break;
|
||||
// existing device - update address
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
|
||||
if (Address_Cache[i].valid &&
|
||||
(Address_Cache[i].device_id == device_id)) {
|
||||
address_copy(&Address_Cache[i].address, src);
|
||||
Address_Cache[i].max_apdu = max_apdu;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// add new device - but only if bind requested
|
||||
if (!found)
|
||||
{
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++)
|
||||
{
|
||||
if (!Address_Cache[i].valid && Address_Cache[i].bind_request)
|
||||
{
|
||||
Address_Cache[i].valid = true;
|
||||
Address_Cache[i].bind_request = false;
|
||||
Address_Cache[i].device_id = device_id;
|
||||
Address_Cache[i].max_apdu = max_apdu;
|
||||
address_copy(&Address_Cache[i].address,src);
|
||||
break;
|
||||
}
|
||||
// add new device - but only if bind requested
|
||||
if (!found) {
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
|
||||
if (!Address_Cache[i].valid && Address_Cache[i].bind_request) {
|
||||
Address_Cache[i].valid = true;
|
||||
Address_Cache[i].bind_request = false;
|
||||
Address_Cache[i].device_id = device_id;
|
||||
Address_Cache[i].max_apdu = max_apdu;
|
||||
address_copy(&Address_Cache[i].address, src);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
bool address_get_by_index(
|
||||
unsigned index,
|
||||
uint32_t *device_id,
|
||||
unsigned *max_apdu,
|
||||
BACNET_ADDRESS *src)
|
||||
bool address_get_by_index(unsigned index,
|
||||
uint32_t * device_id, unsigned *max_apdu, BACNET_ADDRESS * src)
|
||||
{
|
||||
bool found = false; // return value
|
||||
bool found = false; // return value
|
||||
|
||||
if (index < MAX_ADDRESS_CACHE)
|
||||
{
|
||||
if (Address_Cache[index].valid)
|
||||
{
|
||||
address_copy(src, &Address_Cache[index].address);
|
||||
*device_id = Address_Cache[index].device_id;
|
||||
*max_apdu = Address_Cache[index].max_apdu;
|
||||
found = true;
|
||||
if (index < MAX_ADDRESS_CACHE) {
|
||||
if (Address_Cache[index].valid) {
|
||||
address_copy(src, &Address_Cache[index].address);
|
||||
*device_id = Address_Cache[index].device_id;
|
||||
*max_apdu = Address_Cache[index].max_apdu;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
return found;
|
||||
}
|
||||
|
||||
unsigned address_count(void)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned count = 0; // return value
|
||||
unsigned i;
|
||||
unsigned count = 0; // return value
|
||||
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++)
|
||||
{
|
||||
if (Address_Cache[i].valid)
|
||||
count++;
|
||||
}
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
|
||||
if (Address_Cache[i].valid)
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
return count;
|
||||
}
|
||||
|
||||
bool address_match(
|
||||
BACNET_ADDRESS *dest,
|
||||
BACNET_ADDRESS *src)
|
||||
bool address_match(BACNET_ADDRESS * dest, BACNET_ADDRESS * src)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned max_len;
|
||||
bool match = true; // return value
|
||||
unsigned i;
|
||||
unsigned max_len;
|
||||
bool match = true; // return value
|
||||
|
||||
if (dest->mac_len != src->mac_len)
|
||||
match = false;
|
||||
max_len = dest->mac_len;
|
||||
if (max_len > MAX_MAC_LEN)
|
||||
max_len = MAX_MAC_LEN;
|
||||
for (i = 0; i < max_len; i++)
|
||||
{
|
||||
if (dest->mac[i] != src->mac[i])
|
||||
match = false;
|
||||
}
|
||||
if (dest->net != src->net)
|
||||
match = false;
|
||||
if (dest->len != src->len)
|
||||
match = false;
|
||||
max_len = dest->len;
|
||||
if (max_len > MAX_MAC_LEN)
|
||||
max_len = MAX_MAC_LEN;
|
||||
for (i = 0; i < max_len; i++)
|
||||
{
|
||||
if (dest->adr[i] != src->adr[i])
|
||||
match = false;
|
||||
}
|
||||
|
||||
return match;
|
||||
if (dest->mac_len != src->mac_len)
|
||||
match = false;
|
||||
max_len = dest->mac_len;
|
||||
if (max_len > MAX_MAC_LEN)
|
||||
max_len = MAX_MAC_LEN;
|
||||
for (i = 0; i < max_len; i++) {
|
||||
if (dest->mac[i] != src->mac[i])
|
||||
match = false;
|
||||
}
|
||||
if (dest->net != src->net)
|
||||
match = false;
|
||||
if (dest->len != src->len)
|
||||
match = false;
|
||||
max_len = dest->len;
|
||||
if (max_len > MAX_MAC_LEN)
|
||||
max_len = MAX_MAC_LEN;
|
||||
for (i = 0; i < max_len; i++) {
|
||||
if (dest->adr[i] != src->adr[i])
|
||||
match = false;
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
@@ -332,72 +286,62 @@ bool address_match(
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
static void set_address(
|
||||
unsigned index,
|
||||
BACNET_ADDRESS *dest)
|
||||
static void set_address(unsigned index, BACNET_ADDRESS * dest)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < MAX_MAC_LEN; i++)
|
||||
{
|
||||
dest->mac[i] = index;
|
||||
}
|
||||
dest->mac_len = MAX_MAC_LEN;
|
||||
dest->net = 7;
|
||||
dest->len = MAX_MAC_LEN;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++)
|
||||
{
|
||||
dest->adr[i] = index;
|
||||
}
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
dest->mac[i] = index;
|
||||
}
|
||||
dest->mac_len = MAX_MAC_LEN;
|
||||
dest->net = 7;
|
||||
dest->len = MAX_MAC_LEN;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
dest->adr[i] = index;
|
||||
}
|
||||
}
|
||||
|
||||
void testAddress(Test * pTest)
|
||||
{
|
||||
unsigned i, count;
|
||||
BACNET_ADDRESS src;
|
||||
uint32_t device_id = 0;
|
||||
unsigned max_apdu = 480;
|
||||
BACNET_ADDRESS test_address;
|
||||
uint32_t test_device_id = 0;
|
||||
unsigned test_max_apdu = 0;
|
||||
unsigned i, count;
|
||||
BACNET_ADDRESS src;
|
||||
uint32_t device_id = 0;
|
||||
unsigned max_apdu = 480;
|
||||
BACNET_ADDRESS test_address;
|
||||
uint32_t test_device_id = 0;
|
||||
unsigned test_max_apdu = 0;
|
||||
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++)
|
||||
{
|
||||
set_address(i,&src);
|
||||
device_id = i * 255;
|
||||
address_add(
|
||||
device_id,
|
||||
max_apdu,
|
||||
&src);
|
||||
count = address_count();
|
||||
ct_test(pTest, count == (i + 1));
|
||||
}
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
|
||||
set_address(i, &src);
|
||||
device_id = i * 255;
|
||||
address_add(device_id, max_apdu, &src);
|
||||
count = address_count();
|
||||
ct_test(pTest, count == (i + 1));
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++)
|
||||
{
|
||||
device_id = i * 255;
|
||||
ct_test(pTest, address_get_by_device(device_id, &test_max_apdu,
|
||||
&test_address));
|
||||
set_address(i,&src);
|
||||
ct_test(pTest, test_max_apdu == max_apdu);
|
||||
ct_test(pTest, address_match(&test_address,&src));
|
||||
ct_test(pTest, address_get_by_index(i, &test_device_id,
|
||||
&test_max_apdu,&test_address));
|
||||
ct_test(pTest, test_device_id == device_id);
|
||||
ct_test(pTest, test_max_apdu == max_apdu);
|
||||
ct_test(pTest, address_match(&test_address,&src));
|
||||
ct_test(pTest, address_count() == MAX_ADDRESS_CACHE);
|
||||
}
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
|
||||
device_id = i * 255;
|
||||
ct_test(pTest, address_get_by_device(device_id, &test_max_apdu,
|
||||
&test_address));
|
||||
set_address(i, &src);
|
||||
ct_test(pTest, test_max_apdu == max_apdu);
|
||||
ct_test(pTest, address_match(&test_address, &src));
|
||||
ct_test(pTest, address_get_by_index(i, &test_device_id,
|
||||
&test_max_apdu, &test_address));
|
||||
ct_test(pTest, test_device_id == device_id);
|
||||
ct_test(pTest, test_max_apdu == max_apdu);
|
||||
ct_test(pTest, address_match(&test_address, &src));
|
||||
ct_test(pTest, address_count() == MAX_ADDRESS_CACHE);
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++)
|
||||
{
|
||||
device_id = i * 255;
|
||||
address_remove_device(device_id);
|
||||
ct_test(pTest, !address_get_by_device(device_id, &test_max_apdu,
|
||||
&test_address));
|
||||
count = address_count();
|
||||
ct_test(pTest, count == (MAX_ADDRESS_CACHE-i-1));
|
||||
}
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
|
||||
device_id = i * 255;
|
||||
address_remove_device(device_id);
|
||||
ct_test(pTest, !address_get_by_device(device_id, &test_max_apdu,
|
||||
&test_address));
|
||||
count = address_count();
|
||||
ct_test(pTest, count == (MAX_ADDRESS_CACHE - i - 1));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST_ADDRESS
|
||||
|
||||
+19
-36
@@ -41,51 +41,34 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void address_init(void);
|
||||
void address_init(void);
|
||||
|
||||
void address_copy(
|
||||
BACNET_ADDRESS *dest,
|
||||
BACNET_ADDRESS *src);
|
||||
void address_copy(BACNET_ADDRESS * dest, BACNET_ADDRESS * src);
|
||||
|
||||
void address_add(
|
||||
uint32_t device_id,
|
||||
unsigned max_apdu,
|
||||
BACNET_ADDRESS *src);
|
||||
void address_add(uint32_t device_id,
|
||||
unsigned max_apdu, BACNET_ADDRESS * src);
|
||||
|
||||
void address_remove_device(
|
||||
uint32_t device_id);
|
||||
void address_remove_device(uint32_t device_id);
|
||||
|
||||
bool address_get_by_device(
|
||||
uint32_t device_id,
|
||||
unsigned *max_apdu,
|
||||
BACNET_ADDRESS *src);
|
||||
bool address_get_by_device(uint32_t device_id,
|
||||
unsigned *max_apdu, BACNET_ADDRESS * src);
|
||||
|
||||
bool address_get_by_index(
|
||||
unsigned index,
|
||||
uint32_t *device_id,
|
||||
unsigned *max_apdu,
|
||||
BACNET_ADDRESS *src);
|
||||
bool address_get_by_index(unsigned index,
|
||||
uint32_t * device_id, unsigned *max_apdu, BACNET_ADDRESS * src);
|
||||
|
||||
unsigned address_count(void);
|
||||
unsigned address_count(void);
|
||||
|
||||
bool address_match(
|
||||
BACNET_ADDRESS *dest,
|
||||
BACNET_ADDRESS *src);
|
||||
|
||||
bool address_bind_request(
|
||||
uint32_t device_id,
|
||||
unsigned *max_apdu,
|
||||
BACNET_ADDRESS *src);
|
||||
|
||||
void address_add_binding(
|
||||
uint32_t device_id,
|
||||
unsigned max_apdu,
|
||||
BACNET_ADDRESS *src);
|
||||
bool address_match(BACNET_ADDRESS * dest, BACNET_ADDRESS * src);
|
||||
|
||||
bool address_bind_request(uint32_t device_id,
|
||||
unsigned *max_apdu, BACNET_ADDRESS * src);
|
||||
|
||||
void address_add_binding(uint32_t device_id,
|
||||
unsigned max_apdu, BACNET_ADDRESS * src);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
+330
-378
@@ -44,482 +44,434 @@
|
||||
#include "iam.h"
|
||||
|
||||
/* a simple table for crossing the services supported */
|
||||
static BACNET_SERVICES_SUPPORTED confirmed_service_supported[MAX_BACNET_CONFIRMED_SERVICE] =
|
||||
{
|
||||
SERVICE_SUPPORTED_ACKNOWLEDGE_ALARM,
|
||||
SERVICE_SUPPORTED_CONFIRMED_COV_NOTIFICATION,
|
||||
SERVICE_SUPPORTED_CONFIRMED_EVENT_NOTIFICATION,
|
||||
SERVICE_SUPPORTED_GET_ALARM_SUMMARY,
|
||||
SERVICE_SUPPORTED_GET_ENROLLMENT_SUMMARY,
|
||||
SERVICE_SUPPORTED_SUBSCRIBE_COV,
|
||||
SERVICE_SUPPORTED_ATOMIC_READ_FILE,
|
||||
SERVICE_SUPPORTED_ATOMIC_WRITE_FILE,
|
||||
SERVICE_SUPPORTED_ADD_LIST_ELEMENT,
|
||||
SERVICE_SUPPORTED_REMOVE_LIST_ELEMENT,
|
||||
SERVICE_SUPPORTED_CREATE_OBJECT,
|
||||
SERVICE_SUPPORTED_DELETE_OBJECT,
|
||||
SERVICE_SUPPORTED_READ_PROPERTY,
|
||||
SERVICE_SUPPORTED_READ_PROPERTY_CONDITIONAL,
|
||||
SERVICE_SUPPORTED_READ_PROPERTY_MULTIPLE,
|
||||
SERVICE_SUPPORTED_WRITE_PROPERTY,
|
||||
SERVICE_SUPPORTED_WRITE_PROPERTY_MULTIPLE,
|
||||
SERVICE_SUPPORTED_DEVICE_COMMUNICATION_CONTROL,
|
||||
SERVICE_SUPPORTED_PRIVATE_TRANSFER,
|
||||
SERVICE_SUPPORTED_TEXT_MESSAGE,
|
||||
SERVICE_SUPPORTED_REINITIALIZE_DEVICE,
|
||||
SERVICE_SUPPORTED_VT_OPEN,
|
||||
SERVICE_SUPPORTED_VT_CLOSE,
|
||||
SERVICE_SUPPORTED_VT_DATA,
|
||||
SERVICE_SUPPORTED_AUTHENTICATE,
|
||||
SERVICE_SUPPORTED_REQUEST_KEY,
|
||||
SERVICE_SUPPORTED_READ_RANGE,
|
||||
SERVICE_SUPPORTED_LIFE_SAFETY_OPERATION,
|
||||
SERVICE_SUPPORTED_SUBSCRIBE_COV_PROPERTY,
|
||||
SERVICE_SUPPORTED_GET_EVENT_INFORMATION
|
||||
static BACNET_SERVICES_SUPPORTED
|
||||
confirmed_service_supported[MAX_BACNET_CONFIRMED_SERVICE] = {
|
||||
SERVICE_SUPPORTED_ACKNOWLEDGE_ALARM,
|
||||
SERVICE_SUPPORTED_CONFIRMED_COV_NOTIFICATION,
|
||||
SERVICE_SUPPORTED_CONFIRMED_EVENT_NOTIFICATION,
|
||||
SERVICE_SUPPORTED_GET_ALARM_SUMMARY,
|
||||
SERVICE_SUPPORTED_GET_ENROLLMENT_SUMMARY,
|
||||
SERVICE_SUPPORTED_SUBSCRIBE_COV,
|
||||
SERVICE_SUPPORTED_ATOMIC_READ_FILE,
|
||||
SERVICE_SUPPORTED_ATOMIC_WRITE_FILE,
|
||||
SERVICE_SUPPORTED_ADD_LIST_ELEMENT,
|
||||
SERVICE_SUPPORTED_REMOVE_LIST_ELEMENT,
|
||||
SERVICE_SUPPORTED_CREATE_OBJECT,
|
||||
SERVICE_SUPPORTED_DELETE_OBJECT,
|
||||
SERVICE_SUPPORTED_READ_PROPERTY,
|
||||
SERVICE_SUPPORTED_READ_PROPERTY_CONDITIONAL,
|
||||
SERVICE_SUPPORTED_READ_PROPERTY_MULTIPLE,
|
||||
SERVICE_SUPPORTED_WRITE_PROPERTY,
|
||||
SERVICE_SUPPORTED_WRITE_PROPERTY_MULTIPLE,
|
||||
SERVICE_SUPPORTED_DEVICE_COMMUNICATION_CONTROL,
|
||||
SERVICE_SUPPORTED_PRIVATE_TRANSFER,
|
||||
SERVICE_SUPPORTED_TEXT_MESSAGE,
|
||||
SERVICE_SUPPORTED_REINITIALIZE_DEVICE,
|
||||
SERVICE_SUPPORTED_VT_OPEN,
|
||||
SERVICE_SUPPORTED_VT_CLOSE,
|
||||
SERVICE_SUPPORTED_VT_DATA,
|
||||
SERVICE_SUPPORTED_AUTHENTICATE,
|
||||
SERVICE_SUPPORTED_REQUEST_KEY,
|
||||
SERVICE_SUPPORTED_READ_RANGE,
|
||||
SERVICE_SUPPORTED_LIFE_SAFETY_OPERATION,
|
||||
SERVICE_SUPPORTED_SUBSCRIBE_COV_PROPERTY,
|
||||
SERVICE_SUPPORTED_GET_EVENT_INFORMATION
|
||||
};
|
||||
|
||||
/* a simple table for crossing the services supported */
|
||||
static BACNET_SERVICES_SUPPORTED unconfirmed_service_supported[MAX_BACNET_UNCONFIRMED_SERVICE] =
|
||||
{
|
||||
SERVICE_SUPPORTED_I_AM,
|
||||
SERVICE_SUPPORTED_I_HAVE,
|
||||
SERVICE_SUPPORTED_UNCONFIRMED_COV_NOTIFICATION,
|
||||
SERVICE_SUPPORTED_UNCONFIRMED_EVENT_NOTIFICATION,
|
||||
SERVICE_SUPPORTED_UNCONFIRMED_PRIVATE_TRANSFER,
|
||||
SERVICE_SUPPORTED_UNCONFIRMED_TEXT_MESSAGE,
|
||||
SERVICE_SUPPORTED_TIME_SYNCHRONIZATION,
|
||||
SERVICE_SUPPORTED_WHO_HAS,
|
||||
SERVICE_SUPPORTED_WHO_IS,
|
||||
SERVICE_SUPPORTED_UTC_TIME_SYNCHRONIZATION
|
||||
static BACNET_SERVICES_SUPPORTED
|
||||
unconfirmed_service_supported[MAX_BACNET_UNCONFIRMED_SERVICE] = {
|
||||
SERVICE_SUPPORTED_I_AM,
|
||||
SERVICE_SUPPORTED_I_HAVE,
|
||||
SERVICE_SUPPORTED_UNCONFIRMED_COV_NOTIFICATION,
|
||||
SERVICE_SUPPORTED_UNCONFIRMED_EVENT_NOTIFICATION,
|
||||
SERVICE_SUPPORTED_UNCONFIRMED_PRIVATE_TRANSFER,
|
||||
SERVICE_SUPPORTED_UNCONFIRMED_TEXT_MESSAGE,
|
||||
SERVICE_SUPPORTED_TIME_SYNCHRONIZATION,
|
||||
SERVICE_SUPPORTED_WHO_HAS,
|
||||
SERVICE_SUPPORTED_WHO_IS,
|
||||
SERVICE_SUPPORTED_UTC_TIME_SYNCHRONIZATION
|
||||
};
|
||||
|
||||
// Confirmed Function Handlers
|
||||
// If they are not set, they are handled by a reject message
|
||||
static confirmed_function
|
||||
Confirmed_Function[MAX_BACNET_CONFIRMED_SERVICE];
|
||||
static confirmed_function Confirmed_Function[MAX_BACNET_CONFIRMED_SERVICE];
|
||||
|
||||
void apdu_set_confirmed_handler(
|
||||
BACNET_CONFIRMED_SERVICE service_choice,
|
||||
confirmed_function pFunction)
|
||||
void apdu_set_confirmed_handler(BACNET_CONFIRMED_SERVICE service_choice,
|
||||
confirmed_function pFunction)
|
||||
{
|
||||
if (service_choice < MAX_BACNET_CONFIRMED_SERVICE)
|
||||
Confirmed_Function[service_choice] = pFunction;
|
||||
if (service_choice < MAX_BACNET_CONFIRMED_SERVICE)
|
||||
Confirmed_Function[service_choice] = pFunction;
|
||||
}
|
||||
|
||||
/* returns true if the handler is set */
|
||||
bool apdu_confirmed_handler(
|
||||
BACNET_CONFIRMED_SERVICE service_choice)
|
||||
bool apdu_confirmed_handler(BACNET_CONFIRMED_SERVICE service_choice)
|
||||
{
|
||||
bool status = false;
|
||||
if ((service_choice < MAX_BACNET_CONFIRMED_SERVICE) &&
|
||||
(Confirmed_Function[service_choice] != NULL))
|
||||
status = true;
|
||||
bool status = false;
|
||||
if ((service_choice < MAX_BACNET_CONFIRMED_SERVICE) &&
|
||||
(Confirmed_Function[service_choice] != NULL))
|
||||
status = true;
|
||||
|
||||
return status;
|
||||
return status;
|
||||
}
|
||||
|
||||
bool apdu_service_supported(BACNET_SERVICES_SUPPORTED service_supported)
|
||||
{
|
||||
int i = 0;
|
||||
bool status = false;
|
||||
bool found = false;
|
||||
int i = 0;
|
||||
bool status = false;
|
||||
bool found = false;
|
||||
|
||||
if (service_supported < MAX_BACNET_SERVICES_SUPPORTED)
|
||||
{
|
||||
/* is it a confirmed service? */
|
||||
for (i = 0; i < MAX_BACNET_CONFIRMED_SERVICE; i++)
|
||||
{
|
||||
if (confirmed_service_supported[i] == service_supported)
|
||||
{
|
||||
if (apdu_confirmed_handler(i))
|
||||
status = true;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
/* is it an unconfirmed service? */
|
||||
for (i = 0; i < MAX_BACNET_UNCONFIRMED_SERVICE; i++)
|
||||
{
|
||||
if (unconfirmed_service_supported[i] == service_supported)
|
||||
{
|
||||
if (apdu_unconfirmed_handler(i))
|
||||
status = true;
|
||||
break;
|
||||
if (service_supported < MAX_BACNET_SERVICES_SUPPORTED) {
|
||||
/* is it a confirmed service? */
|
||||
for (i = 0; i < MAX_BACNET_CONFIRMED_SERVICE; i++) {
|
||||
if (confirmed_service_supported[i] == service_supported) {
|
||||
if (apdu_confirmed_handler(i))
|
||||
status = true;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
/* is it an unconfirmed service? */
|
||||
for (i = 0; i < MAX_BACNET_UNCONFIRMED_SERVICE; i++) {
|
||||
if (unconfirmed_service_supported[i] == service_supported) {
|
||||
if (apdu_unconfirmed_handler(i))
|
||||
status = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return status;
|
||||
return status;
|
||||
}
|
||||
|
||||
// Allow the APDU handler to automatically reject
|
||||
static confirmed_function Unrecognized_Service_Handler;
|
||||
|
||||
void apdu_set_unrecognized_service_handler_handler(
|
||||
confirmed_function pFunction)
|
||||
void apdu_set_unrecognized_service_handler_handler(confirmed_function
|
||||
pFunction)
|
||||
{
|
||||
Unrecognized_Service_Handler = pFunction;
|
||||
}
|
||||
|
||||
// Unconfirmed Function Handlers
|
||||
// If they are not set, they are not handled
|
||||
static unconfirmed_function
|
||||
Unconfirmed_Function[MAX_BACNET_UNCONFIRMED_SERVICE] =
|
||||
{
|
||||
static unconfirmed_function
|
||||
Unconfirmed_Function[MAX_BACNET_UNCONFIRMED_SERVICE] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
void apdu_set_unconfirmed_handler(
|
||||
BACNET_UNCONFIRMED_SERVICE service_choice,
|
||||
unconfirmed_function pFunction)
|
||||
void apdu_set_unconfirmed_handler(BACNET_UNCONFIRMED_SERVICE
|
||||
service_choice, unconfirmed_function pFunction)
|
||||
{
|
||||
if (service_choice < MAX_BACNET_UNCONFIRMED_SERVICE)
|
||||
Unconfirmed_Function[service_choice] = pFunction;
|
||||
if (service_choice < MAX_BACNET_UNCONFIRMED_SERVICE)
|
||||
Unconfirmed_Function[service_choice] = pFunction;
|
||||
}
|
||||
|
||||
bool apdu_unconfirmed_handler(
|
||||
BACNET_UNCONFIRMED_SERVICE service_choice)
|
||||
bool apdu_unconfirmed_handler(BACNET_UNCONFIRMED_SERVICE service_choice)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
if ((service_choice < MAX_BACNET_UNCONFIRMED_SERVICE) &&
|
||||
(Unconfirmed_Function[service_choice] != NULL))
|
||||
status = true;
|
||||
bool status = false;
|
||||
|
||||
return status;
|
||||
if ((service_choice < MAX_BACNET_UNCONFIRMED_SERVICE) &&
|
||||
(Unconfirmed_Function[service_choice] != NULL))
|
||||
status = true;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Confirmed ACK Function Handlers
|
||||
static void *Confirmed_ACK_Function[MAX_BACNET_CONFIRMED_SERVICE];
|
||||
|
||||
void apdu_set_confirmed_simple_ack_handler(
|
||||
BACNET_CONFIRMED_SERVICE service_choice,
|
||||
confirmed_simple_ack_function pFunction)
|
||||
void apdu_set_confirmed_simple_ack_handler(BACNET_CONFIRMED_SERVICE
|
||||
service_choice, confirmed_simple_ack_function pFunction)
|
||||
{
|
||||
switch (service_choice)
|
||||
{
|
||||
switch (service_choice) {
|
||||
case SERVICE_CONFIRMED_ACKNOWLEDGE_ALARM:
|
||||
case SERVICE_CONFIRMED_COV_NOTIFICATION:
|
||||
case SERVICE_CONFIRMED_EVENT_NOTIFICATION:
|
||||
case SERVICE_CONFIRMED_SUBSCRIBE_COV:
|
||||
case SERVICE_CONFIRMED_SUBSCRIBE_COV_PROPERTY:
|
||||
case SERVICE_CONFIRMED_LIFE_SAFETY_OPERATION:
|
||||
// Object Access Services
|
||||
// Object Access Services
|
||||
case SERVICE_CONFIRMED_ADD_LIST_ELEMENT:
|
||||
case SERVICE_CONFIRMED_REMOVE_LIST_ELEMENT:
|
||||
case SERVICE_CONFIRMED_DELETE_OBJECT:
|
||||
case SERVICE_CONFIRMED_WRITE_PROPERTY:
|
||||
case SERVICE_CONFIRMED_WRITE_PROPERTY_MULTIPLE:
|
||||
// Remote Device Management Services
|
||||
// Remote Device Management Services
|
||||
case SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL:
|
||||
case SERVICE_CONFIRMED_TEXT_MESSAGE:
|
||||
case SERVICE_CONFIRMED_REINITIALIZE_DEVICE:
|
||||
// Virtual Terminal Services
|
||||
// Virtual Terminal Services
|
||||
case SERVICE_CONFIRMED_VT_CLOSE:
|
||||
// Security Services
|
||||
// Security Services
|
||||
case SERVICE_CONFIRMED_REQUEST_KEY:
|
||||
Confirmed_ACK_Function[service_choice] = (void *)pFunction;
|
||||
break;
|
||||
Confirmed_ACK_Function[service_choice] = (void *) pFunction;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void apdu_set_confirmed_ack_handler(
|
||||
BACNET_CONFIRMED_SERVICE service_choice,
|
||||
confirmed_ack_function pFunction)
|
||||
void apdu_set_confirmed_ack_handler(BACNET_CONFIRMED_SERVICE
|
||||
service_choice, confirmed_ack_function pFunction)
|
||||
{
|
||||
switch (service_choice)
|
||||
{
|
||||
switch (service_choice) {
|
||||
case SERVICE_CONFIRMED_GET_ALARM_SUMMARY:
|
||||
case SERVICE_CONFIRMED_GET_ENROLLMENT_SUMMARY:
|
||||
case SERVICE_CONFIRMED_GET_EVENT_INFORMATION:
|
||||
// File Access Services
|
||||
// File Access Services
|
||||
case SERVICE_CONFIRMED_ATOMIC_READ_FILE:
|
||||
case SERVICE_CONFIRMED_ATOMIC_WRITE_FILE:
|
||||
// Object Access Services
|
||||
// Object Access Services
|
||||
case SERVICE_CONFIRMED_CREATE_OBJECT:
|
||||
case SERVICE_CONFIRMED_READ_PROPERTY:
|
||||
case SERVICE_CONFIRMED_READ_PROPERTY_CONDITIONAL:
|
||||
case SERVICE_CONFIRMED_READ_PROPERTY_MULTIPLE:
|
||||
case SERVICE_CONFIRMED_READ_RANGE:
|
||||
// Remote Device Management Services
|
||||
// Remote Device Management Services
|
||||
case SERVICE_CONFIRMED_PRIVATE_TRANSFER:
|
||||
// Virtual Terminal Services
|
||||
// Virtual Terminal Services
|
||||
case SERVICE_CONFIRMED_VT_OPEN:
|
||||
case SERVICE_CONFIRMED_VT_DATA:
|
||||
// Security Services
|
||||
// Security Services
|
||||
case SERVICE_CONFIRMED_AUTHENTICATE:
|
||||
Confirmed_ACK_Function[service_choice] = (void *)pFunction;
|
||||
break;
|
||||
Confirmed_ACK_Function[service_choice] = (void *) pFunction;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static error_function
|
||||
Error_Function[MAX_BACNET_CONFIRMED_SERVICE];
|
||||
static error_function Error_Function[MAX_BACNET_CONFIRMED_SERVICE];
|
||||
|
||||
void apdu_set_error_handler(
|
||||
BACNET_CONFIRMED_SERVICE service_choice,
|
||||
error_function pFunction)
|
||||
void apdu_set_error_handler(BACNET_CONFIRMED_SERVICE service_choice,
|
||||
error_function pFunction)
|
||||
{
|
||||
if (service_choice < MAX_BACNET_CONFIRMED_SERVICE)
|
||||
Error_Function[service_choice] = pFunction;
|
||||
if (service_choice < MAX_BACNET_CONFIRMED_SERVICE)
|
||||
Error_Function[service_choice] = pFunction;
|
||||
}
|
||||
|
||||
static abort_function Abort_Function;
|
||||
|
||||
void apdu_set_abort_handler(
|
||||
abort_function pFunction)
|
||||
void apdu_set_abort_handler(abort_function pFunction)
|
||||
{
|
||||
Abort_Function = pFunction;
|
||||
Abort_Function = pFunction;
|
||||
}
|
||||
|
||||
static reject_function Reject_Function;
|
||||
|
||||
void apdu_set_reject_handler(
|
||||
reject_function pFunction)
|
||||
void apdu_set_reject_handler(reject_function pFunction)
|
||||
{
|
||||
Reject_Function = pFunction;
|
||||
Reject_Function = pFunction;
|
||||
}
|
||||
|
||||
uint16_t apdu_decode_confirmed_service_request(
|
||||
uint8_t *apdu, // APDU data
|
||||
uint16_t apdu_len,
|
||||
BACNET_CONFIRMED_SERVICE_DATA *service_data,
|
||||
uint8_t *service_choice,
|
||||
uint8_t **service_request,
|
||||
uint16_t *service_request_len)
|
||||
uint16_t apdu_decode_confirmed_service_request(uint8_t * apdu, // APDU data
|
||||
uint16_t apdu_len,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data,
|
||||
uint8_t * service_choice,
|
||||
uint8_t ** service_request, uint16_t * service_request_len)
|
||||
{
|
||||
uint16_t len = 0; // counts where we are in PDU
|
||||
|
||||
service_data->segmented_message = (apdu[0] & BIT3) ? true : false;
|
||||
service_data->more_follows = (apdu[0] & BIT2) ? true : false;
|
||||
service_data->segmented_response_accepted = (apdu[0] & BIT1) ? true : false;
|
||||
service_data->max_segs = decode_max_segs(apdu[1]);
|
||||
service_data->max_resp = decode_max_apdu(apdu[1]);
|
||||
service_data->invoke_id = apdu[2];
|
||||
len = 3;
|
||||
if (service_data->segmented_message)
|
||||
{
|
||||
service_data->sequence_number = apdu[len++];
|
||||
service_data->proposed_window_number = apdu[len++];
|
||||
}
|
||||
*service_choice = apdu[len++];
|
||||
*service_request = &apdu[len];
|
||||
*service_request_len = apdu_len - len;
|
||||
uint16_t len = 0; // counts where we are in PDU
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void apdu_handler(
|
||||
BACNET_ADDRESS *src, // source address
|
||||
bool data_expecting_reply,
|
||||
uint8_t *apdu, // APDU data
|
||||
uint16_t apdu_len)
|
||||
{
|
||||
BACNET_CONFIRMED_SERVICE_DATA service_data = {0};
|
||||
BACNET_CONFIRMED_SERVICE_ACK_DATA service_ack_data = {0};
|
||||
uint8_t invoke_id = 0;
|
||||
uint8_t service_choice = 0;
|
||||
uint8_t *service_request = NULL;
|
||||
uint16_t service_request_len = 0;
|
||||
uint16_t len = 0; // counts where we are in PDU
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value = 0;
|
||||
int error_code = 0;
|
||||
int error_class = 0;
|
||||
uint8_t reason = 0;
|
||||
|
||||
(void)data_expecting_reply;
|
||||
if (apdu)
|
||||
{
|
||||
// PDU Type
|
||||
switch (apdu[0] & 0xF0)
|
||||
{
|
||||
case PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
|
||||
len = apdu_decode_confirmed_service_request(
|
||||
&apdu[0], // APDU data
|
||||
apdu_len,
|
||||
&service_data,
|
||||
&service_choice,
|
||||
&service_request,
|
||||
&service_request_len);
|
||||
/* When network communications are completely disabled,
|
||||
only DeviceCommunicationControl and ReinitializeDevice APDUs
|
||||
shall be processed and no messages shall be initiated.*/
|
||||
if (dcc_communication_disabled() &&
|
||||
((service_choice != SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL) &&
|
||||
(service_choice != SERVICE_CONFIRMED_REINITIALIZE_DEVICE)))
|
||||
break;
|
||||
if ((service_choice < MAX_BACNET_CONFIRMED_SERVICE) &&
|
||||
(Confirmed_Function[service_choice]))
|
||||
Confirmed_Function[service_choice](
|
||||
service_request,
|
||||
service_request_len,
|
||||
src,
|
||||
&service_data);
|
||||
else if (Unrecognized_Service_Handler)
|
||||
Unrecognized_Service_Handler(
|
||||
service_request,
|
||||
service_request_len,
|
||||
src,
|
||||
&service_data);
|
||||
break;
|
||||
case PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST:
|
||||
if (dcc_communication_disabled())
|
||||
break;
|
||||
service_choice = apdu[1];
|
||||
service_request = &apdu[2];
|
||||
service_request_len = apdu_len - 2;
|
||||
if (service_choice < MAX_BACNET_UNCONFIRMED_SERVICE)
|
||||
{
|
||||
if (Unconfirmed_Function[service_choice])
|
||||
Unconfirmed_Function[service_choice](
|
||||
service_request,
|
||||
service_request_len,
|
||||
src);
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_SIMPLE_ACK:
|
||||
invoke_id = apdu[1];
|
||||
service_choice = apdu[2];
|
||||
switch (service_choice)
|
||||
{
|
||||
case SERVICE_CONFIRMED_ACKNOWLEDGE_ALARM:
|
||||
case SERVICE_CONFIRMED_COV_NOTIFICATION:
|
||||
case SERVICE_CONFIRMED_EVENT_NOTIFICATION:
|
||||
case SERVICE_CONFIRMED_SUBSCRIBE_COV:
|
||||
case SERVICE_CONFIRMED_SUBSCRIBE_COV_PROPERTY:
|
||||
case SERVICE_CONFIRMED_LIFE_SAFETY_OPERATION:
|
||||
// Object Access Services
|
||||
case SERVICE_CONFIRMED_ADD_LIST_ELEMENT:
|
||||
case SERVICE_CONFIRMED_REMOVE_LIST_ELEMENT:
|
||||
case SERVICE_CONFIRMED_DELETE_OBJECT:
|
||||
case SERVICE_CONFIRMED_WRITE_PROPERTY:
|
||||
case SERVICE_CONFIRMED_WRITE_PROPERTY_MULTIPLE:
|
||||
// Remote Device Management Services
|
||||
case SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL:
|
||||
case SERVICE_CONFIRMED_REINITIALIZE_DEVICE:
|
||||
case SERVICE_CONFIRMED_TEXT_MESSAGE:
|
||||
// Virtual Terminal Services
|
||||
case SERVICE_CONFIRMED_VT_CLOSE:
|
||||
// Security Services
|
||||
case SERVICE_CONFIRMED_REQUEST_KEY:
|
||||
if (Confirmed_ACK_Function[service_choice])
|
||||
{
|
||||
((confirmed_simple_ack_function)
|
||||
Confirmed_ACK_Function[service_choice])(
|
||||
src,
|
||||
invoke_id);
|
||||
}
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_COMPLEX_ACK:
|
||||
service_ack_data.segmented_message = (apdu[0] & BIT3) ? true : false;
|
||||
service_ack_data.more_follows = (apdu[0] & BIT2) ? true : false;
|
||||
invoke_id = service_ack_data.invoke_id = apdu[1];
|
||||
len = 2;
|
||||
if (service_ack_data.segmented_message)
|
||||
{
|
||||
service_ack_data.sequence_number = apdu[len++];
|
||||
service_ack_data.proposed_window_number = apdu[len++];
|
||||
}
|
||||
service_choice = apdu[len++];
|
||||
service_request = &apdu[len];
|
||||
service_request_len = apdu_len - len;
|
||||
switch (service_choice)
|
||||
{
|
||||
case SERVICE_CONFIRMED_GET_ALARM_SUMMARY:
|
||||
case SERVICE_CONFIRMED_GET_ENROLLMENT_SUMMARY:
|
||||
case SERVICE_CONFIRMED_GET_EVENT_INFORMATION:
|
||||
// File Access Services
|
||||
case SERVICE_CONFIRMED_ATOMIC_READ_FILE:
|
||||
case SERVICE_CONFIRMED_ATOMIC_WRITE_FILE:
|
||||
// Object Access Services
|
||||
case SERVICE_CONFIRMED_CREATE_OBJECT:
|
||||
case SERVICE_CONFIRMED_READ_PROPERTY:
|
||||
case SERVICE_CONFIRMED_READ_PROPERTY_CONDITIONAL:
|
||||
case SERVICE_CONFIRMED_READ_PROPERTY_MULTIPLE:
|
||||
case SERVICE_CONFIRMED_READ_RANGE:
|
||||
case SERVICE_CONFIRMED_PRIVATE_TRANSFER:
|
||||
// Virtual Terminal Services
|
||||
case SERVICE_CONFIRMED_VT_OPEN:
|
||||
case SERVICE_CONFIRMED_VT_DATA:
|
||||
// Security Services
|
||||
case SERVICE_CONFIRMED_AUTHENTICATE:
|
||||
if (Confirmed_ACK_Function[service_choice])
|
||||
{
|
||||
((confirmed_ack_function)
|
||||
Confirmed_ACK_Function[service_choice])(
|
||||
service_request,
|
||||
service_request_len,
|
||||
src,
|
||||
&service_ack_data);
|
||||
}
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_SEGMENT_ACK:
|
||||
/* FIXME: what about a denial of service attack here?
|
||||
we could check src to see if that matched the tsm */
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
break;
|
||||
case PDU_TYPE_ERROR:
|
||||
invoke_id = apdu[1];
|
||||
service_choice = apdu[2];
|
||||
len = 3;
|
||||
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value);
|
||||
/* FIXME: we could validate that the tag is enumerated... */
|
||||
len += decode_enumerated(&apdu[len],len_value, &error_class);
|
||||
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value);
|
||||
/* FIXME: we could validate that the tag is enumerated... */
|
||||
len += decode_enumerated(&apdu[len],len_value, &error_code);
|
||||
if (service_choice < MAX_BACNET_CONFIRMED_SERVICE)
|
||||
{
|
||||
if (Error_Function[service_choice])
|
||||
Error_Function[service_choice](
|
||||
src,
|
||||
invoke_id,
|
||||
error_class,
|
||||
error_code);
|
||||
}
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
break;
|
||||
case PDU_TYPE_REJECT:
|
||||
invoke_id = apdu[1];
|
||||
reason = apdu[2];
|
||||
if (Reject_Function)
|
||||
Reject_Function(
|
||||
src,
|
||||
invoke_id,
|
||||
reason);
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
break;
|
||||
case PDU_TYPE_ABORT:
|
||||
invoke_id = apdu[1];
|
||||
reason = apdu[2];
|
||||
if (Abort_Function)
|
||||
Abort_Function(
|
||||
src,
|
||||
invoke_id,
|
||||
reason);
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
service_data->segmented_message = (apdu[0] & BIT3) ? true : false;
|
||||
service_data->more_follows = (apdu[0] & BIT2) ? true : false;
|
||||
service_data->segmented_response_accepted =
|
||||
(apdu[0] & BIT1) ? true : false;
|
||||
service_data->max_segs = decode_max_segs(apdu[1]);
|
||||
service_data->max_resp = decode_max_apdu(apdu[1]);
|
||||
service_data->invoke_id = apdu[2];
|
||||
len = 3;
|
||||
if (service_data->segmented_message) {
|
||||
service_data->sequence_number = apdu[len++];
|
||||
service_data->proposed_window_number = apdu[len++];
|
||||
}
|
||||
}
|
||||
return;
|
||||
*service_choice = apdu[len++];
|
||||
*service_request = &apdu[len];
|
||||
*service_request_len = apdu_len - len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void apdu_handler(BACNET_ADDRESS * src, // source address
|
||||
bool data_expecting_reply, uint8_t * apdu, // APDU data
|
||||
uint16_t apdu_len)
|
||||
{
|
||||
BACNET_CONFIRMED_SERVICE_DATA service_data = { 0 };
|
||||
BACNET_CONFIRMED_SERVICE_ACK_DATA service_ack_data = { 0 };
|
||||
uint8_t invoke_id = 0;
|
||||
uint8_t service_choice = 0;
|
||||
uint8_t *service_request = NULL;
|
||||
uint16_t service_request_len = 0;
|
||||
uint16_t len = 0; // counts where we are in PDU
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value = 0;
|
||||
int error_code = 0;
|
||||
int error_class = 0;
|
||||
uint8_t reason = 0;
|
||||
|
||||
(void) data_expecting_reply;
|
||||
if (apdu) {
|
||||
// PDU Type
|
||||
switch (apdu[0] & 0xF0) {
|
||||
case PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
|
||||
len = apdu_decode_confirmed_service_request(&apdu[0], // APDU data
|
||||
apdu_len,
|
||||
&service_data,
|
||||
&service_choice, &service_request, &service_request_len);
|
||||
/* When network communications are completely disabled,
|
||||
only DeviceCommunicationControl and ReinitializeDevice APDUs
|
||||
shall be processed and no messages shall be initiated. */
|
||||
if (dcc_communication_disabled() &&
|
||||
((service_choice !=
|
||||
SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL)
|
||||
&& (service_choice !=
|
||||
SERVICE_CONFIRMED_REINITIALIZE_DEVICE)))
|
||||
break;
|
||||
if ((service_choice < MAX_BACNET_CONFIRMED_SERVICE) &&
|
||||
(Confirmed_Function[service_choice]))
|
||||
Confirmed_Function[service_choice] (service_request,
|
||||
service_request_len, src, &service_data);
|
||||
else if (Unrecognized_Service_Handler)
|
||||
Unrecognized_Service_Handler(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
break;
|
||||
case PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST:
|
||||
if (dcc_communication_disabled())
|
||||
break;
|
||||
service_choice = apdu[1];
|
||||
service_request = &apdu[2];
|
||||
service_request_len = apdu_len - 2;
|
||||
if (service_choice < MAX_BACNET_UNCONFIRMED_SERVICE) {
|
||||
if (Unconfirmed_Function[service_choice])
|
||||
Unconfirmed_Function[service_choice] (service_request,
|
||||
service_request_len, src);
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_SIMPLE_ACK:
|
||||
invoke_id = apdu[1];
|
||||
service_choice = apdu[2];
|
||||
switch (service_choice) {
|
||||
case SERVICE_CONFIRMED_ACKNOWLEDGE_ALARM:
|
||||
case SERVICE_CONFIRMED_COV_NOTIFICATION:
|
||||
case SERVICE_CONFIRMED_EVENT_NOTIFICATION:
|
||||
case SERVICE_CONFIRMED_SUBSCRIBE_COV:
|
||||
case SERVICE_CONFIRMED_SUBSCRIBE_COV_PROPERTY:
|
||||
case SERVICE_CONFIRMED_LIFE_SAFETY_OPERATION:
|
||||
// Object Access Services
|
||||
case SERVICE_CONFIRMED_ADD_LIST_ELEMENT:
|
||||
case SERVICE_CONFIRMED_REMOVE_LIST_ELEMENT:
|
||||
case SERVICE_CONFIRMED_DELETE_OBJECT:
|
||||
case SERVICE_CONFIRMED_WRITE_PROPERTY:
|
||||
case SERVICE_CONFIRMED_WRITE_PROPERTY_MULTIPLE:
|
||||
// Remote Device Management Services
|
||||
case SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL:
|
||||
case SERVICE_CONFIRMED_REINITIALIZE_DEVICE:
|
||||
case SERVICE_CONFIRMED_TEXT_MESSAGE:
|
||||
// Virtual Terminal Services
|
||||
case SERVICE_CONFIRMED_VT_CLOSE:
|
||||
// Security Services
|
||||
case SERVICE_CONFIRMED_REQUEST_KEY:
|
||||
if (Confirmed_ACK_Function[service_choice]) {
|
||||
((confirmed_simple_ack_function)
|
||||
Confirmed_ACK_Function[service_choice]) (src,
|
||||
invoke_id);
|
||||
}
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_COMPLEX_ACK:
|
||||
service_ack_data.segmented_message =
|
||||
(apdu[0] & BIT3) ? true : false;
|
||||
service_ack_data.more_follows =
|
||||
(apdu[0] & BIT2) ? true : false;
|
||||
invoke_id = service_ack_data.invoke_id = apdu[1];
|
||||
len = 2;
|
||||
if (service_ack_data.segmented_message) {
|
||||
service_ack_data.sequence_number = apdu[len++];
|
||||
service_ack_data.proposed_window_number = apdu[len++];
|
||||
}
|
||||
service_choice = apdu[len++];
|
||||
service_request = &apdu[len];
|
||||
service_request_len = apdu_len - len;
|
||||
switch (service_choice) {
|
||||
case SERVICE_CONFIRMED_GET_ALARM_SUMMARY:
|
||||
case SERVICE_CONFIRMED_GET_ENROLLMENT_SUMMARY:
|
||||
case SERVICE_CONFIRMED_GET_EVENT_INFORMATION:
|
||||
// File Access Services
|
||||
case SERVICE_CONFIRMED_ATOMIC_READ_FILE:
|
||||
case SERVICE_CONFIRMED_ATOMIC_WRITE_FILE:
|
||||
// Object Access Services
|
||||
case SERVICE_CONFIRMED_CREATE_OBJECT:
|
||||
case SERVICE_CONFIRMED_READ_PROPERTY:
|
||||
case SERVICE_CONFIRMED_READ_PROPERTY_CONDITIONAL:
|
||||
case SERVICE_CONFIRMED_READ_PROPERTY_MULTIPLE:
|
||||
case SERVICE_CONFIRMED_READ_RANGE:
|
||||
case SERVICE_CONFIRMED_PRIVATE_TRANSFER:
|
||||
// Virtual Terminal Services
|
||||
case SERVICE_CONFIRMED_VT_OPEN:
|
||||
case SERVICE_CONFIRMED_VT_DATA:
|
||||
// Security Services
|
||||
case SERVICE_CONFIRMED_AUTHENTICATE:
|
||||
if (Confirmed_ACK_Function[service_choice]) {
|
||||
((confirmed_ack_function)
|
||||
Confirmed_ACK_Function[service_choice])
|
||||
(service_request, service_request_len, src,
|
||||
&service_ack_data);
|
||||
}
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_SEGMENT_ACK:
|
||||
/* FIXME: what about a denial of service attack here?
|
||||
we could check src to see if that matched the tsm */
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
break;
|
||||
case PDU_TYPE_ERROR:
|
||||
invoke_id = apdu[1];
|
||||
service_choice = apdu[2];
|
||||
len = 3;
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
/* FIXME: we could validate that the tag is enumerated... */
|
||||
len += decode_enumerated(&apdu[len], len_value, &error_class);
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
/* FIXME: we could validate that the tag is enumerated... */
|
||||
len += decode_enumerated(&apdu[len], len_value, &error_code);
|
||||
if (service_choice < MAX_BACNET_CONFIRMED_SERVICE) {
|
||||
if (Error_Function[service_choice])
|
||||
Error_Function[service_choice] (src,
|
||||
invoke_id, error_class, error_code);
|
||||
}
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
break;
|
||||
case PDU_TYPE_REJECT:
|
||||
invoke_id = apdu[1];
|
||||
reason = apdu[2];
|
||||
if (Reject_Function)
|
||||
Reject_Function(src, invoke_id, reason);
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
break;
|
||||
case PDU_TYPE_ABORT:
|
||||
invoke_id = apdu[1];
|
||||
reason = apdu[2];
|
||||
if (Abort_Function)
|
||||
Abort_Function(src, invoke_id, reason);
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
+65
-90
@@ -41,28 +41,26 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct _confirmed_service_data
|
||||
{
|
||||
bool segmented_message;
|
||||
bool more_follows;
|
||||
bool segmented_response_accepted;
|
||||
int max_segs;
|
||||
int max_resp;
|
||||
uint8_t invoke_id;
|
||||
uint8_t sequence_number;
|
||||
uint8_t proposed_window_number;
|
||||
} BACNET_CONFIRMED_SERVICE_DATA;
|
||||
typedef struct _confirmed_service_data {
|
||||
bool segmented_message;
|
||||
bool more_follows;
|
||||
bool segmented_response_accepted;
|
||||
int max_segs;
|
||||
int max_resp;
|
||||
uint8_t invoke_id;
|
||||
uint8_t sequence_number;
|
||||
uint8_t proposed_window_number;
|
||||
} BACNET_CONFIRMED_SERVICE_DATA;
|
||||
|
||||
typedef struct _confirmed_service_ack_data
|
||||
{
|
||||
bool segmented_message;
|
||||
bool more_follows;
|
||||
uint8_t invoke_id;
|
||||
uint8_t sequence_number;
|
||||
uint8_t proposed_window_number;
|
||||
} BACNET_CONFIRMED_SERVICE_ACK_DATA;
|
||||
typedef struct _confirmed_service_ack_data {
|
||||
bool segmented_message;
|
||||
bool more_follows;
|
||||
uint8_t invoke_id;
|
||||
uint8_t sequence_number;
|
||||
uint8_t proposed_window_number;
|
||||
} BACNET_CONFIRMED_SERVICE_ACK_DATA;
|
||||
|
||||
// generic unconfirmed function handler
|
||||
// Suitable to handle the following services:
|
||||
@@ -70,10 +68,8 @@ typedef struct _confirmed_service_ack_data
|
||||
// Unconfirmed_Event_Notification, Unconfirmed_Private_Transfer,
|
||||
// Unconfirmed_Text_Message, Time_Synchronization, Who_Has,
|
||||
// UTC_Time_Synchronization
|
||||
typedef void (*unconfirmed_function)(
|
||||
uint8_t *service_request,
|
||||
uint16_t len,
|
||||
BACNET_ADDRESS *src);
|
||||
typedef void (*unconfirmed_function) (uint8_t * service_request,
|
||||
uint16_t len, BACNET_ADDRESS * src);
|
||||
|
||||
// generic confirmed function handler
|
||||
// Suitable to handle the following services:
|
||||
@@ -91,100 +87,79 @@ typedef void (*unconfirmed_function)(
|
||||
// Confirmed_Text_Message, Reinitialize_Device,
|
||||
// VT_Open, VT_Close, VT_Data_Handler,
|
||||
// Authenticate, Request_Key
|
||||
typedef void (*confirmed_function)(
|
||||
uint8_t *service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS *src,
|
||||
BACNET_CONFIRMED_SERVICE_DATA *service_data);
|
||||
typedef void (*confirmed_function) (uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data);
|
||||
|
||||
// generic confirmed simple ack function handler
|
||||
typedef void (*confirmed_simple_ack_function)(
|
||||
BACNET_ADDRESS *src,
|
||||
uint8_t invoke_id);
|
||||
typedef void (*confirmed_simple_ack_function) (BACNET_ADDRESS * src,
|
||||
uint8_t invoke_id);
|
||||
|
||||
// generic confirmed ack function handler
|
||||
typedef void (*confirmed_ack_function)(
|
||||
uint8_t *service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS *src,
|
||||
BACNET_CONFIRMED_SERVICE_ACK_DATA *service_data);
|
||||
typedef void (*confirmed_ack_function) (uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src,
|
||||
BACNET_CONFIRMED_SERVICE_ACK_DATA * service_data);
|
||||
|
||||
// generic error reply function
|
||||
typedef void (*error_function)(
|
||||
BACNET_ADDRESS *src,
|
||||
uint8_t invoke_id,
|
||||
BACNET_ERROR_CLASS error_class,
|
||||
BACNET_ERROR_CODE error_code);
|
||||
typedef void (*error_function) (BACNET_ADDRESS * src,
|
||||
uint8_t invoke_id,
|
||||
BACNET_ERROR_CLASS error_class, BACNET_ERROR_CODE error_code);
|
||||
|
||||
// generic abort reply function
|
||||
typedef void (*abort_function)(
|
||||
BACNET_ADDRESS *src,
|
||||
uint8_t invoke_id,
|
||||
uint8_t abort_reason);
|
||||
typedef void (*abort_function) (BACNET_ADDRESS * src,
|
||||
uint8_t invoke_id, uint8_t abort_reason);
|
||||
|
||||
// generic reject reply function
|
||||
typedef void (*reject_function)(
|
||||
BACNET_ADDRESS *src,
|
||||
uint8_t invoke_id,
|
||||
uint8_t reject_reason);
|
||||
typedef void (*reject_function) (BACNET_ADDRESS * src,
|
||||
uint8_t invoke_id, uint8_t reject_reason);
|
||||
|
||||
void apdu_set_confirmed_ack_handler(
|
||||
BACNET_CONFIRMED_SERVICE service_choice,
|
||||
confirmed_ack_function pFunction);
|
||||
void apdu_set_confirmed_ack_handler(BACNET_CONFIRMED_SERVICE
|
||||
service_choice, confirmed_ack_function pFunction);
|
||||
|
||||
void apdu_set_confirmed_simple_ack_handler(
|
||||
BACNET_CONFIRMED_SERVICE service_choice,
|
||||
confirmed_simple_ack_function pFunction);
|
||||
void apdu_set_confirmed_simple_ack_handler(BACNET_CONFIRMED_SERVICE
|
||||
service_choice, confirmed_simple_ack_function pFunction);
|
||||
|
||||
// configure reject for confirmed services that are not supported
|
||||
void apdu_set_unrecognized_service_handler_handler(
|
||||
confirmed_function pFunction);
|
||||
void apdu_set_unrecognized_service_handler_handler(confirmed_function
|
||||
pFunction);
|
||||
|
||||
void apdu_set_confirmed_handler(
|
||||
BACNET_CONFIRMED_SERVICE service_choice,
|
||||
confirmed_function pFunction);
|
||||
void apdu_set_confirmed_handler(BACNET_CONFIRMED_SERVICE
|
||||
service_choice, confirmed_function pFunction);
|
||||
|
||||
/* returns true if the handler is set */
|
||||
bool apdu_confirmed_handler(
|
||||
BACNET_CONFIRMED_SERVICE service_choice);
|
||||
bool apdu_confirmed_handler(BACNET_CONFIRMED_SERVICE service_choice);
|
||||
|
||||
void apdu_set_unconfirmed_handler(
|
||||
BACNET_UNCONFIRMED_SERVICE service_choice,
|
||||
unconfirmed_function pFunction);
|
||||
void apdu_set_unconfirmed_handler(BACNET_UNCONFIRMED_SERVICE
|
||||
service_choice, unconfirmed_function pFunction);
|
||||
|
||||
/* returns true if the handler is set */
|
||||
bool apdu_unconfirmed_handler(
|
||||
BACNET_UNCONFIRMED_SERVICE service_choice);
|
||||
bool apdu_unconfirmed_handler(BACNET_UNCONFIRMED_SERVICE
|
||||
service_choice);
|
||||
|
||||
/* returns true if the service is supported by a handler */
|
||||
bool apdu_service_supported(BACNET_SERVICES_SUPPORTED service_supported);
|
||||
bool apdu_service_supported(BACNET_SERVICES_SUPPORTED
|
||||
service_supported);
|
||||
|
||||
void apdu_set_error_handler(
|
||||
BACNET_CONFIRMED_SERVICE service_choice,
|
||||
error_function pFunction);
|
||||
void apdu_set_error_handler(BACNET_CONFIRMED_SERVICE service_choice,
|
||||
error_function pFunction);
|
||||
|
||||
void apdu_set_abort_handler(
|
||||
abort_function pFunction);
|
||||
void apdu_set_abort_handler(abort_function pFunction);
|
||||
|
||||
void apdu_set_reject_handler(
|
||||
reject_function pFunction);
|
||||
void apdu_set_reject_handler(reject_function pFunction);
|
||||
|
||||
uint16_t apdu_decode_confirmed_service_request(
|
||||
uint8_t *apdu, // APDU data
|
||||
uint16_t apdu_len,
|
||||
BACNET_CONFIRMED_SERVICE_DATA *service_data,
|
||||
uint8_t *service_choice,
|
||||
uint8_t **service_request,
|
||||
uint16_t *service_request_len);
|
||||
uint16_t apdu_decode_confirmed_service_request(uint8_t * apdu, // APDU data
|
||||
uint16_t apdu_len,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data,
|
||||
uint8_t * service_choice,
|
||||
uint8_t ** service_request, uint16_t * service_request_len);
|
||||
|
||||
void apdu_handler(
|
||||
BACNET_ADDRESS *src, // source address
|
||||
bool data_expecting_reply,
|
||||
uint8_t *apdu, // APDU data
|
||||
uint16_t pdu_len); // for confirmed messages
|
||||
void apdu_handler(BACNET_ADDRESS * src, // source address
|
||||
bool data_expecting_reply, uint8_t * apdu, // APDU data
|
||||
uint16_t pdu_len); // for confirmed messages
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
+18
-23
@@ -45,41 +45,36 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
bool arcnet_valid(void);
|
||||
void arcnet_cleanup(void);
|
||||
bool arcnet_init(char *interface_name);
|
||||
bool arcnet_valid(void);
|
||||
void arcnet_cleanup(void);
|
||||
bool arcnet_init(char *interface_name);
|
||||
|
||||
/* function to send a packet out the 802.2 socket */
|
||||
/* returns 0 on success, non-zero on failure */
|
||||
int arcnet_send(
|
||||
BACNET_ADDRESS *dest, // destination address
|
||||
BACNET_ADDRESS *src, // source address
|
||||
uint8_t *pdu, // any data to be sent - may be null
|
||||
unsigned pdu_len); // number of bytes of data
|
||||
int arcnet_send(BACNET_ADDRESS * dest, // destination address
|
||||
BACNET_ADDRESS * src, // source address
|
||||
uint8_t * pdu, // any data to be sent - may be null
|
||||
unsigned pdu_len); // number of bytes of data
|
||||
|
||||
/* function to send a packet out the 802.2 socket */
|
||||
/* returns zero on success, non-zero on failure */
|
||||
int arcnet_send_pdu(
|
||||
BACNET_ADDRESS *dest, // destination address
|
||||
uint8_t *pdu, // any data to be sent - may be null
|
||||
unsigned pdu_len); // number of bytes of data
|
||||
int arcnet_send_pdu(BACNET_ADDRESS * dest, // destination address
|
||||
uint8_t * pdu, // any data to be sent - may be null
|
||||
unsigned pdu_len); // number of bytes of data
|
||||
|
||||
// receives an framed packet
|
||||
// returns the number of octets in the PDU, or zero on failure
|
||||
uint16_t arcnet_receive(
|
||||
BACNET_ADDRESS *src, // source address
|
||||
uint8_t *pdu, // PDU data
|
||||
uint16_t max_pdu, // amount of space available in the PDU
|
||||
unsigned timeout); // milliseconds to wait for a packet
|
||||
uint16_t arcnet_receive(BACNET_ADDRESS * src, // source address
|
||||
uint8_t * pdu, // PDU data
|
||||
uint16_t max_pdu, // amount of space available in the PDU
|
||||
unsigned timeout); // milliseconds to wait for a packet
|
||||
|
||||
void arcnet_get_my_address(BACNET_ADDRESS *my_address);
|
||||
void arcnet_get_broadcast_address(
|
||||
BACNET_ADDRESS *dest); // destination address
|
||||
void arcnet_get_my_address(BACNET_ADDRESS * my_address);
|
||||
void arcnet_get_broadcast_address(BACNET_ADDRESS * dest); // destination address
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
+341
-398
@@ -41,324 +41,289 @@
|
||||
// Atomic Read File
|
||||
|
||||
// encode service
|
||||
int arf_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint8_t invoke_id,
|
||||
BACNET_ATOMIC_READ_FILE_DATA *data)
|
||||
int arf_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, BACNET_ATOMIC_READ_FILE_DATA * data)
|
||||
{
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
|
||||
if (apdu)
|
||||
{
|
||||
apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
|
||||
apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted());
|
||||
apdu[2] = invoke_id;
|
||||
apdu[3] = SERVICE_CONFIRMED_ATOMIC_READ_FILE; // service choice
|
||||
apdu_len = 4;
|
||||
apdu_len += encode_tagged_object_id(&apdu[apdu_len],
|
||||
data->object_type, data->object_instance);
|
||||
switch (data->access)
|
||||
{
|
||||
case FILE_STREAM_ACCESS:
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 0);
|
||||
apdu_len += encode_tagged_signed(&apdu[apdu_len],
|
||||
data->type.stream.fileStartPosition);
|
||||
apdu_len += encode_tagged_unsigned(&apdu[apdu_len],
|
||||
data->type.stream.requestedOctetCount);
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 0);
|
||||
break;
|
||||
case FILE_RECORD_ACCESS:
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 1);
|
||||
apdu_len += encode_tagged_signed(&apdu[apdu_len],
|
||||
data->type.record.fileStartRecord);
|
||||
apdu_len += encode_tagged_unsigned(&apdu[apdu_len],
|
||||
data->type.record.RecordCount);
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (apdu) {
|
||||
apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
|
||||
apdu[1] =
|
||||
encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted());
|
||||
apdu[2] = invoke_id;
|
||||
apdu[3] = SERVICE_CONFIRMED_ATOMIC_READ_FILE; // service choice
|
||||
apdu_len = 4;
|
||||
apdu_len += encode_tagged_object_id(&apdu[apdu_len],
|
||||
data->object_type, data->object_instance);
|
||||
switch (data->access) {
|
||||
case FILE_STREAM_ACCESS:
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 0);
|
||||
apdu_len += encode_tagged_signed(&apdu[apdu_len],
|
||||
data->type.stream.fileStartPosition);
|
||||
apdu_len += encode_tagged_unsigned(&apdu[apdu_len],
|
||||
data->type.stream.requestedOctetCount);
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 0);
|
||||
break;
|
||||
case FILE_RECORD_ACCESS:
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 1);
|
||||
apdu_len += encode_tagged_signed(&apdu[apdu_len],
|
||||
data->type.record.fileStartRecord);
|
||||
apdu_len += encode_tagged_unsigned(&apdu[apdu_len],
|
||||
data->type.record.RecordCount);
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
// decode the service request only
|
||||
int arf_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_ATOMIC_READ_FILE_DATA *data)
|
||||
int arf_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_ATOMIC_READ_FILE_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
int tag_len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value_type = 0;
|
||||
int type = 0; // for decoding
|
||||
int len = 0;
|
||||
int tag_len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value_type = 0;
|
||||
int type = 0; // for decoding
|
||||
|
||||
// check for value pointers
|
||||
if (apdu_len && data)
|
||||
{
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value_type);
|
||||
if (tag_number != BACNET_APPLICATION_TAG_OBJECT_ID)
|
||||
return -1;
|
||||
len += decode_object_id(&apdu[len], &type, &data->object_instance);
|
||||
data->object_type = type;
|
||||
if (decode_is_opening_tag_number(&apdu[len], 0))
|
||||
{
|
||||
data->access = FILE_STREAM_ACCESS;
|
||||
// a tag number is not extended so only one octet
|
||||
len++;
|
||||
// fileStartPosition
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_SIGNED_INT)
|
||||
return -1;
|
||||
len += decode_signed(&apdu[len],
|
||||
len_value_type,
|
||||
&data->type.stream.fileStartPosition);
|
||||
// requestedOctetCount
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT)
|
||||
return -1;
|
||||
len += decode_unsigned(&apdu[len],
|
||||
len_value_type,
|
||||
&data->type.stream.requestedOctetCount);
|
||||
if (!decode_is_closing_tag_number(&apdu[len], 0))
|
||||
return -1;
|
||||
// a tag number is not extended so only one octet
|
||||
len++;
|
||||
// check for value pointers
|
||||
if (apdu_len && data) {
|
||||
len =
|
||||
decode_tag_number_and_value(&apdu[0], &tag_number,
|
||||
&len_value_type);
|
||||
if (tag_number != BACNET_APPLICATION_TAG_OBJECT_ID)
|
||||
return -1;
|
||||
len += decode_object_id(&apdu[len], &type, &data->object_instance);
|
||||
data->object_type = type;
|
||||
if (decode_is_opening_tag_number(&apdu[len], 0)) {
|
||||
data->access = FILE_STREAM_ACCESS;
|
||||
// a tag number is not extended so only one octet
|
||||
len++;
|
||||
// fileStartPosition
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_SIGNED_INT)
|
||||
return -1;
|
||||
len += decode_signed(&apdu[len],
|
||||
len_value_type, &data->type.stream.fileStartPosition);
|
||||
// requestedOctetCount
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT)
|
||||
return -1;
|
||||
len += decode_unsigned(&apdu[len],
|
||||
len_value_type, &data->type.stream.requestedOctetCount);
|
||||
if (!decode_is_closing_tag_number(&apdu[len], 0))
|
||||
return -1;
|
||||
// a tag number is not extended so only one octet
|
||||
len++;
|
||||
} else if (decode_is_opening_tag_number(&apdu[len], 1)) {
|
||||
data->access = FILE_RECORD_ACCESS;
|
||||
// a tag number is not extended so only one octet
|
||||
len++;
|
||||
// fileStartRecord
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_SIGNED_INT)
|
||||
return -1;
|
||||
len += decode_signed(&apdu[len],
|
||||
len_value_type, &data->type.record.fileStartRecord);
|
||||
// RecordCount
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT)
|
||||
return -1;
|
||||
len += decode_unsigned(&apdu[len],
|
||||
len_value_type, &data->type.record.RecordCount);
|
||||
if (!decode_is_closing_tag_number(&apdu[len], 1))
|
||||
return -1;
|
||||
// a tag number is not extended so only one octet
|
||||
len++;
|
||||
} else
|
||||
return -1;
|
||||
}
|
||||
else if (decode_is_opening_tag_number(&apdu[len], 1))
|
||||
{
|
||||
data->access = FILE_RECORD_ACCESS;
|
||||
// a tag number is not extended so only one octet
|
||||
len++;
|
||||
// fileStartRecord
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_SIGNED_INT)
|
||||
return -1;
|
||||
len += decode_signed(&apdu[len],
|
||||
len_value_type,
|
||||
&data->type.record.fileStartRecord);
|
||||
// RecordCount
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT)
|
||||
return -1;
|
||||
len += decode_unsigned(&apdu[len],
|
||||
len_value_type,
|
||||
&data->type.record.RecordCount);
|
||||
if (!decode_is_closing_tag_number(&apdu[len], 1))
|
||||
return -1;
|
||||
// a tag number is not extended so only one octet
|
||||
len++;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
return len;
|
||||
return len;
|
||||
}
|
||||
|
||||
int arf_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
BACNET_ATOMIC_READ_FILE_DATA *data)
|
||||
int arf_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id, BACNET_ATOMIC_READ_FILE_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
unsigned offset = 0;
|
||||
int len = 0;
|
||||
unsigned offset = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
|
||||
return -1;
|
||||
// apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted());
|
||||
*invoke_id = apdu[2]; /* invoke id - filled in by net layer */
|
||||
if (apdu[3] != SERVICE_CONFIRMED_ATOMIC_READ_FILE)
|
||||
return -1;
|
||||
offset = 4;
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
|
||||
return -1;
|
||||
// apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted());
|
||||
*invoke_id = apdu[2]; /* invoke id - filled in by net layer */
|
||||
if (apdu[3] != SERVICE_CONFIRMED_ATOMIC_READ_FILE)
|
||||
return -1;
|
||||
offset = 4;
|
||||
|
||||
if (apdu_len > offset)
|
||||
{
|
||||
len = arf_decode_service_request(
|
||||
&apdu[offset],
|
||||
apdu_len - offset,
|
||||
data);
|
||||
}
|
||||
|
||||
return len;
|
||||
if (apdu_len > offset) {
|
||||
len = arf_decode_service_request(&apdu[offset],
|
||||
apdu_len - offset, data);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
// encode service
|
||||
int arf_ack_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint8_t invoke_id,
|
||||
BACNET_ATOMIC_READ_FILE_DATA *data)
|
||||
int arf_ack_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, BACNET_ATOMIC_READ_FILE_DATA * data)
|
||||
{
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
|
||||
if (apdu)
|
||||
{
|
||||
apdu[0] = PDU_TYPE_COMPLEX_ACK;
|
||||
apdu[1] = invoke_id;
|
||||
apdu[2] = SERVICE_CONFIRMED_ATOMIC_READ_FILE; // service choice
|
||||
apdu_len = 3;
|
||||
// endOfFile
|
||||
apdu_len += encode_tagged_boolean(&apdu[apdu_len], data->endOfFile);
|
||||
switch (data->access)
|
||||
{
|
||||
case FILE_STREAM_ACCESS:
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 0);
|
||||
apdu_len += encode_tagged_signed(&apdu[apdu_len],
|
||||
data->type.stream.fileStartPosition);
|
||||
apdu_len += encode_tagged_octet_string(&apdu[apdu_len],
|
||||
&data->fileData);
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 0);
|
||||
break;
|
||||
case FILE_RECORD_ACCESS:
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 1);
|
||||
apdu_len += encode_tagged_signed(&apdu[apdu_len],
|
||||
data->type.record.fileStartRecord);
|
||||
apdu_len += encode_tagged_unsigned(&apdu[apdu_len],
|
||||
data->type.record.RecordCount);
|
||||
apdu_len += encode_tagged_octet_string(&apdu[apdu_len],
|
||||
&data->fileData);
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (apdu) {
|
||||
apdu[0] = PDU_TYPE_COMPLEX_ACK;
|
||||
apdu[1] = invoke_id;
|
||||
apdu[2] = SERVICE_CONFIRMED_ATOMIC_READ_FILE; // service choice
|
||||
apdu_len = 3;
|
||||
// endOfFile
|
||||
apdu_len +=
|
||||
encode_tagged_boolean(&apdu[apdu_len], data->endOfFile);
|
||||
switch (data->access) {
|
||||
case FILE_STREAM_ACCESS:
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 0);
|
||||
apdu_len += encode_tagged_signed(&apdu[apdu_len],
|
||||
data->type.stream.fileStartPosition);
|
||||
apdu_len += encode_tagged_octet_string(&apdu[apdu_len],
|
||||
&data->fileData);
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 0);
|
||||
break;
|
||||
case FILE_RECORD_ACCESS:
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 1);
|
||||
apdu_len += encode_tagged_signed(&apdu[apdu_len],
|
||||
data->type.record.fileStartRecord);
|
||||
apdu_len += encode_tagged_unsigned(&apdu[apdu_len],
|
||||
data->type.record.RecordCount);
|
||||
apdu_len += encode_tagged_octet_string(&apdu[apdu_len],
|
||||
&data->fileData);
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
// decode the service request only
|
||||
int arf_ack_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_ATOMIC_READ_FILE_DATA *data)
|
||||
int arf_ack_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_ATOMIC_READ_FILE_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
int tag_len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value_type = 0;
|
||||
int len = 0;
|
||||
int tag_len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value_type = 0;
|
||||
|
||||
// check for value pointers
|
||||
if (apdu_len && data)
|
||||
{
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value_type);
|
||||
if (tag_number != BACNET_APPLICATION_TAG_BOOLEAN)
|
||||
return -1;
|
||||
data->endOfFile = decode_boolean(len_value_type);
|
||||
if (decode_is_opening_tag_number(&apdu[len], 0))
|
||||
{
|
||||
data->access = FILE_STREAM_ACCESS;
|
||||
// a tag number is not extended so only one octet
|
||||
len++;
|
||||
// fileStartPosition
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_SIGNED_INT)
|
||||
return -1;
|
||||
len += decode_signed(&apdu[len],
|
||||
len_value_type,
|
||||
&data->type.stream.fileStartPosition);
|
||||
// fileData
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_OCTET_STRING)
|
||||
return -1;
|
||||
len += decode_octet_string(&apdu[len],
|
||||
len_value_type,
|
||||
&data->fileData);
|
||||
if (!decode_is_closing_tag_number(&apdu[len], 0))
|
||||
return -1;
|
||||
// a tag number is not extended so only one octet
|
||||
len++;
|
||||
// check for value pointers
|
||||
if (apdu_len && data) {
|
||||
len =
|
||||
decode_tag_number_and_value(&apdu[0], &tag_number,
|
||||
&len_value_type);
|
||||
if (tag_number != BACNET_APPLICATION_TAG_BOOLEAN)
|
||||
return -1;
|
||||
data->endOfFile = decode_boolean(len_value_type);
|
||||
if (decode_is_opening_tag_number(&apdu[len], 0)) {
|
||||
data->access = FILE_STREAM_ACCESS;
|
||||
// a tag number is not extended so only one octet
|
||||
len++;
|
||||
// fileStartPosition
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_SIGNED_INT)
|
||||
return -1;
|
||||
len += decode_signed(&apdu[len],
|
||||
len_value_type, &data->type.stream.fileStartPosition);
|
||||
// fileData
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_OCTET_STRING)
|
||||
return -1;
|
||||
len += decode_octet_string(&apdu[len],
|
||||
len_value_type, &data->fileData);
|
||||
if (!decode_is_closing_tag_number(&apdu[len], 0))
|
||||
return -1;
|
||||
// a tag number is not extended so only one octet
|
||||
len++;
|
||||
} else if (decode_is_opening_tag_number(&apdu[len], 1)) {
|
||||
data->access = FILE_RECORD_ACCESS;
|
||||
// a tag number is not extended so only one octet
|
||||
len++;
|
||||
// fileStartRecord
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_SIGNED_INT)
|
||||
return -1;
|
||||
len += decode_signed(&apdu[len],
|
||||
len_value_type, &data->type.record.fileStartRecord);
|
||||
// returnedRecordCount
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT)
|
||||
return -1;
|
||||
len += decode_unsigned(&apdu[len],
|
||||
len_value_type, &data->type.record.RecordCount);
|
||||
// fileData
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_OCTET_STRING)
|
||||
return -1;
|
||||
len += decode_octet_string(&apdu[len],
|
||||
len_value_type, &data->fileData);
|
||||
if (!decode_is_closing_tag_number(&apdu[len], 1))
|
||||
return -1;
|
||||
// a tag number is not extended so only one octet
|
||||
len++;
|
||||
} else
|
||||
return -1;
|
||||
}
|
||||
else if (decode_is_opening_tag_number(&apdu[len], 1))
|
||||
{
|
||||
data->access = FILE_RECORD_ACCESS;
|
||||
// a tag number is not extended so only one octet
|
||||
len++;
|
||||
// fileStartRecord
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_SIGNED_INT)
|
||||
return -1;
|
||||
len += decode_signed(&apdu[len],
|
||||
len_value_type,
|
||||
&data->type.record.fileStartRecord);
|
||||
// returnedRecordCount
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT)
|
||||
return -1;
|
||||
len += decode_unsigned(&apdu[len],
|
||||
len_value_type,
|
||||
&data->type.record.RecordCount);
|
||||
// fileData
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_OCTET_STRING)
|
||||
return -1;
|
||||
len += decode_octet_string(&apdu[len],
|
||||
len_value_type,
|
||||
&data->fileData);
|
||||
if (!decode_is_closing_tag_number(&apdu[len], 1))
|
||||
return -1;
|
||||
// a tag number is not extended so only one octet
|
||||
len++;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
return len;
|
||||
return len;
|
||||
}
|
||||
|
||||
int arf_ack_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
BACNET_ATOMIC_READ_FILE_DATA *data)
|
||||
int arf_ack_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id, BACNET_ATOMIC_READ_FILE_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
unsigned offset = 0;
|
||||
int len = 0;
|
||||
unsigned offset = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu[0] != PDU_TYPE_COMPLEX_ACK)
|
||||
return -1;
|
||||
*invoke_id = apdu[1]; /* invoke id - filled in by net layer */
|
||||
if (apdu[2] != SERVICE_CONFIRMED_ATOMIC_READ_FILE)
|
||||
return -1;
|
||||
offset = 3;
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu[0] != PDU_TYPE_COMPLEX_ACK)
|
||||
return -1;
|
||||
*invoke_id = apdu[1]; /* invoke id - filled in by net layer */
|
||||
if (apdu[2] != SERVICE_CONFIRMED_ATOMIC_READ_FILE)
|
||||
return -1;
|
||||
offset = 3;
|
||||
|
||||
if (apdu_len > offset)
|
||||
{
|
||||
len = arf_ack_decode_service_request(
|
||||
&apdu[offset],
|
||||
apdu_len - offset,
|
||||
data);
|
||||
}
|
||||
|
||||
return len;
|
||||
if (apdu_len > offset) {
|
||||
len = arf_ack_decode_service_request(&apdu[offset],
|
||||
apdu_len - offset, data);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
@@ -368,143 +333,121 @@ int arf_ack_decode_apdu(
|
||||
#include "ctest.h"
|
||||
|
||||
void testAtomicReadFileAckAccess(Test * pTest,
|
||||
BACNET_ATOMIC_READ_FILE_DATA *data)
|
||||
BACNET_ATOMIC_READ_FILE_DATA * data)
|
||||
{
|
||||
BACNET_ATOMIC_READ_FILE_DATA test_data = {0};
|
||||
uint8_t apdu[480] = {0};
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 128;
|
||||
uint8_t test_invoke_id = 0;
|
||||
BACNET_ATOMIC_READ_FILE_DATA test_data = { 0 };
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 128;
|
||||
uint8_t test_invoke_id = 0;
|
||||
|
||||
len = arf_ack_encode_apdu(
|
||||
&apdu[0],
|
||||
invoke_id,
|
||||
data);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
len = arf_ack_encode_apdu(&apdu[0], invoke_id, data);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
|
||||
len = arf_ack_decode_apdu(
|
||||
&apdu[0],
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_data);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_data.endOfFile == data->endOfFile);
|
||||
ct_test(pTest, test_data.access == data->access);
|
||||
if (test_data.access == FILE_STREAM_ACCESS)
|
||||
{
|
||||
ct_test(pTest, test_data.type.stream.fileStartPosition ==
|
||||
data->type.stream.fileStartPosition);
|
||||
}
|
||||
else if (test_data.access == FILE_RECORD_ACCESS)
|
||||
{
|
||||
ct_test(pTest, test_data.type.record.fileStartRecord ==
|
||||
data->type.record.fileStartRecord);
|
||||
ct_test(pTest, test_data.type.record.RecordCount ==
|
||||
data->type.record.RecordCount);
|
||||
}
|
||||
ct_test(pTest, octetstring_length(&test_data.fileData) ==
|
||||
octetstring_length(&data->fileData));
|
||||
ct_test(pTest, memcmp(
|
||||
octetstring_value(&test_data.fileData),
|
||||
octetstring_value(&data->fileData),
|
||||
octetstring_length(&test_data.fileData)) == 0);
|
||||
len = arf_ack_decode_apdu(&apdu[0],
|
||||
apdu_len, &test_invoke_id, &test_data);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_data.endOfFile == data->endOfFile);
|
||||
ct_test(pTest, test_data.access == data->access);
|
||||
if (test_data.access == FILE_STREAM_ACCESS) {
|
||||
ct_test(pTest, test_data.type.stream.fileStartPosition ==
|
||||
data->type.stream.fileStartPosition);
|
||||
} else if (test_data.access == FILE_RECORD_ACCESS) {
|
||||
ct_test(pTest, test_data.type.record.fileStartRecord ==
|
||||
data->type.record.fileStartRecord);
|
||||
ct_test(pTest, test_data.type.record.RecordCount ==
|
||||
data->type.record.RecordCount);
|
||||
}
|
||||
ct_test(pTest, octetstring_length(&test_data.fileData) ==
|
||||
octetstring_length(&data->fileData));
|
||||
ct_test(pTest, memcmp(octetstring_value(&test_data.fileData),
|
||||
octetstring_value(&data->fileData),
|
||||
octetstring_length(&test_data.fileData)) == 0);
|
||||
}
|
||||
|
||||
void testAtomicReadFileAck(Test * pTest)
|
||||
{
|
||||
BACNET_ATOMIC_READ_FILE_DATA data = {0};
|
||||
uint8_t test_octet_string[32] = "Joshua-Mary-Anna-Christopher";
|
||||
|
||||
|
||||
data.endOfFile = true;
|
||||
data.access = FILE_STREAM_ACCESS;
|
||||
data.type.stream.fileStartPosition = 0;
|
||||
octetstring_init(&data.fileData,
|
||||
test_octet_string,
|
||||
sizeof(test_octet_string));
|
||||
testAtomicReadFileAckAccess(pTest, &data);
|
||||
BACNET_ATOMIC_READ_FILE_DATA data = { 0 };
|
||||
uint8_t test_octet_string[32] = "Joshua-Mary-Anna-Christopher";
|
||||
|
||||
data.endOfFile = false;
|
||||
data.access = FILE_RECORD_ACCESS;
|
||||
data.type.record.fileStartRecord = 1;
|
||||
data.type.record.RecordCount = 2;
|
||||
octetstring_init(&data.fileData,
|
||||
test_octet_string,
|
||||
sizeof(test_octet_string));
|
||||
testAtomicReadFileAckAccess(pTest, &data);
|
||||
|
||||
return;
|
||||
|
||||
data.endOfFile = true;
|
||||
data.access = FILE_STREAM_ACCESS;
|
||||
data.type.stream.fileStartPosition = 0;
|
||||
octetstring_init(&data.fileData,
|
||||
test_octet_string, sizeof(test_octet_string));
|
||||
testAtomicReadFileAckAccess(pTest, &data);
|
||||
|
||||
data.endOfFile = false;
|
||||
data.access = FILE_RECORD_ACCESS;
|
||||
data.type.record.fileStartRecord = 1;
|
||||
data.type.record.RecordCount = 2;
|
||||
octetstring_init(&data.fileData,
|
||||
test_octet_string, sizeof(test_octet_string));
|
||||
testAtomicReadFileAckAccess(pTest, &data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void testAtomicReadFileAccess(Test * pTest,
|
||||
BACNET_ATOMIC_READ_FILE_DATA *data)
|
||||
BACNET_ATOMIC_READ_FILE_DATA * data)
|
||||
{
|
||||
BACNET_ATOMIC_READ_FILE_DATA test_data = {0};
|
||||
uint8_t apdu[480] = {0};
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 128;
|
||||
uint8_t test_invoke_id = 0;
|
||||
BACNET_ATOMIC_READ_FILE_DATA test_data = { 0 };
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 128;
|
||||
uint8_t test_invoke_id = 0;
|
||||
|
||||
len = arf_encode_apdu(
|
||||
&apdu[0],
|
||||
invoke_id,
|
||||
data);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
len = arf_encode_apdu(&apdu[0], invoke_id, data);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
|
||||
len = arf_decode_apdu(
|
||||
&apdu[0],
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_data);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_data.object_type == data->object_type);
|
||||
ct_test(pTest, test_data.object_instance == data->object_instance);
|
||||
ct_test(pTest, test_data.access == data->access);
|
||||
if (test_data.access == FILE_STREAM_ACCESS)
|
||||
{
|
||||
ct_test(pTest, test_data.type.stream.fileStartPosition ==
|
||||
data->type.stream.fileStartPosition);
|
||||
ct_test(pTest, test_data.type.stream.requestedOctetCount ==
|
||||
data->type.stream.requestedOctetCount);
|
||||
}
|
||||
else if (test_data.access == FILE_RECORD_ACCESS)
|
||||
{
|
||||
ct_test(pTest, test_data.type.record.fileStartRecord ==
|
||||
data->type.record.fileStartRecord);
|
||||
ct_test(pTest, test_data.type.record.RecordCount ==
|
||||
data->type.record.RecordCount);
|
||||
}
|
||||
len = arf_decode_apdu(&apdu[0], apdu_len, &test_invoke_id, &test_data);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_data.object_type == data->object_type);
|
||||
ct_test(pTest, test_data.object_instance == data->object_instance);
|
||||
ct_test(pTest, test_data.access == data->access);
|
||||
if (test_data.access == FILE_STREAM_ACCESS) {
|
||||
ct_test(pTest, test_data.type.stream.fileStartPosition ==
|
||||
data->type.stream.fileStartPosition);
|
||||
ct_test(pTest, test_data.type.stream.requestedOctetCount ==
|
||||
data->type.stream.requestedOctetCount);
|
||||
} else if (test_data.access == FILE_RECORD_ACCESS) {
|
||||
ct_test(pTest, test_data.type.record.fileStartRecord ==
|
||||
data->type.record.fileStartRecord);
|
||||
ct_test(pTest, test_data.type.record.RecordCount ==
|
||||
data->type.record.RecordCount);
|
||||
}
|
||||
}
|
||||
|
||||
void testAtomicReadFile(Test * pTest)
|
||||
{
|
||||
BACNET_ATOMIC_READ_FILE_DATA data = {0};
|
||||
|
||||
data.object_type = OBJECT_FILE;
|
||||
data.object_instance = 1;
|
||||
data.access = FILE_STREAM_ACCESS;
|
||||
data.type.stream.fileStartPosition = 0;
|
||||
data.type.stream.requestedOctetCount = 128;
|
||||
testAtomicReadFileAccess(pTest, &data);
|
||||
BACNET_ATOMIC_READ_FILE_DATA data = { 0 };
|
||||
|
||||
data.object_type = OBJECT_FILE;
|
||||
data.object_instance = 2;
|
||||
data.access = FILE_RECORD_ACCESS;
|
||||
data.type.record.fileStartRecord = 1;
|
||||
data.type.record.RecordCount = 2;
|
||||
testAtomicReadFileAccess(pTest, &data);
|
||||
|
||||
return;
|
||||
data.object_type = OBJECT_FILE;
|
||||
data.object_instance = 1;
|
||||
data.access = FILE_STREAM_ACCESS;
|
||||
data.type.stream.fileStartPosition = 0;
|
||||
data.type.stream.requestedOctetCount = 128;
|
||||
testAtomicReadFileAccess(pTest, &data);
|
||||
|
||||
data.object_type = OBJECT_FILE;
|
||||
data.object_instance = 2;
|
||||
data.access = FILE_RECORD_ACCESS;
|
||||
data.type.record.fileStartRecord = 1;
|
||||
data.type.record.RecordCount = 2;
|
||||
testAtomicReadFileAccess(pTest, &data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_ATOMIC_READ_FILE
|
||||
uint16_t Device_Max_APDU_Length_Accepted(void)
|
||||
{
|
||||
return MAX_APDU;
|
||||
return MAX_APDU;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
|
||||
+36
-54
@@ -39,82 +39,64 @@
|
||||
#include "bacdcode.h"
|
||||
#include "bacstr.h"
|
||||
|
||||
typedef struct BACnet_Atomic_Read_File_Data
|
||||
{
|
||||
BACNET_OBJECT_TYPE object_type;
|
||||
uint32_t object_instance;
|
||||
BACNET_FILE_ACCESS_METHOD access;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
int32_t fileStartPosition;
|
||||
uint32_t requestedOctetCount;
|
||||
} stream;
|
||||
struct
|
||||
{
|
||||
int32_t fileStartRecord;
|
||||
// requested or returned record count
|
||||
uint32_t RecordCount;
|
||||
} record;
|
||||
} type;
|
||||
BACNET_OCTET_STRING fileData;
|
||||
bool endOfFile;
|
||||
typedef struct BACnet_Atomic_Read_File_Data {
|
||||
BACNET_OBJECT_TYPE object_type;
|
||||
uint32_t object_instance;
|
||||
BACNET_FILE_ACCESS_METHOD access;
|
||||
union {
|
||||
struct {
|
||||
int32_t fileStartPosition;
|
||||
uint32_t requestedOctetCount;
|
||||
} stream;
|
||||
struct {
|
||||
int32_t fileStartRecord;
|
||||
// requested or returned record count
|
||||
uint32_t RecordCount;
|
||||
} record;
|
||||
} type;
|
||||
BACNET_OCTET_STRING fileData;
|
||||
bool endOfFile;
|
||||
} BACNET_ATOMIC_READ_FILE_DATA;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
// Atomic Read File
|
||||
// encode service
|
||||
int arf_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint8_t invoke_id,
|
||||
BACNET_ATOMIC_READ_FILE_DATA *data);
|
||||
int arf_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, BACNET_ATOMIC_READ_FILE_DATA * data);
|
||||
|
||||
// decode the service request only
|
||||
int arf_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_ATOMIC_READ_FILE_DATA *data);
|
||||
|
||||
int arf_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
BACNET_ATOMIC_READ_FILE_DATA *data);
|
||||
int arf_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_ATOMIC_READ_FILE_DATA * data);
|
||||
|
||||
int arf_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id, BACNET_ATOMIC_READ_FILE_DATA * data);
|
||||
|
||||
// Atomic Read File Ack
|
||||
|
||||
// encode service
|
||||
int arf_ack_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint8_t invoke_id,
|
||||
BACNET_ATOMIC_READ_FILE_DATA *data);
|
||||
int arf_ack_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, BACNET_ATOMIC_READ_FILE_DATA * data);
|
||||
|
||||
// decode the service request only
|
||||
int arf_ack_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_ATOMIC_READ_FILE_DATA *data);
|
||||
int arf_ack_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_ATOMIC_READ_FILE_DATA * data);
|
||||
|
||||
int arf_ack_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
BACNET_ATOMIC_READ_FILE_DATA *data);
|
||||
int arf_ack_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id, BACNET_ATOMIC_READ_FILE_DATA * data);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
|
||||
void test_AtomicReadFile(Test * pTest);
|
||||
void test_AtomicReadFileAck(Test * pTest);
|
||||
void test_AtomicReadFile(Test * pTest);
|
||||
void test_AtomicReadFileAck(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
|
||||
+274
-331
@@ -41,267 +41,233 @@
|
||||
// Atomic Write File
|
||||
|
||||
// encode service
|
||||
int awf_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint8_t invoke_id,
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA *data)
|
||||
int awf_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, BACNET_ATOMIC_WRITE_FILE_DATA * data)
|
||||
{
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
|
||||
if (apdu)
|
||||
{
|
||||
apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
|
||||
apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted());
|
||||
apdu[2] = invoke_id;
|
||||
apdu[3] = SERVICE_CONFIRMED_ATOMIC_WRITE_FILE; // service choice
|
||||
apdu_len = 4;
|
||||
apdu_len += encode_tagged_object_id(&apdu[apdu_len],
|
||||
data->object_type, data->object_instance);
|
||||
switch (data->access)
|
||||
{
|
||||
case FILE_STREAM_ACCESS:
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 0);
|
||||
apdu_len += encode_tagged_signed(&apdu[apdu_len],
|
||||
data->type.stream.fileStartPosition);
|
||||
apdu_len += encode_tagged_octet_string(&apdu[apdu_len],
|
||||
&data->fileData);
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 0);
|
||||
break;
|
||||
case FILE_RECORD_ACCESS:
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 1);
|
||||
apdu_len += encode_tagged_signed(&apdu[apdu_len],
|
||||
data->type.record.fileStartRecord);
|
||||
apdu_len += encode_tagged_unsigned(&apdu[apdu_len],
|
||||
data->type.record.returnedRecordCount);
|
||||
apdu_len += encode_tagged_octet_string(&apdu[apdu_len],
|
||||
&data->fileData);
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (apdu) {
|
||||
apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
|
||||
apdu[1] =
|
||||
encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted());
|
||||
apdu[2] = invoke_id;
|
||||
apdu[3] = SERVICE_CONFIRMED_ATOMIC_WRITE_FILE; // service choice
|
||||
apdu_len = 4;
|
||||
apdu_len += encode_tagged_object_id(&apdu[apdu_len],
|
||||
data->object_type, data->object_instance);
|
||||
switch (data->access) {
|
||||
case FILE_STREAM_ACCESS:
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 0);
|
||||
apdu_len += encode_tagged_signed(&apdu[apdu_len],
|
||||
data->type.stream.fileStartPosition);
|
||||
apdu_len += encode_tagged_octet_string(&apdu[apdu_len],
|
||||
&data->fileData);
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 0);
|
||||
break;
|
||||
case FILE_RECORD_ACCESS:
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 1);
|
||||
apdu_len += encode_tagged_signed(&apdu[apdu_len],
|
||||
data->type.record.fileStartRecord);
|
||||
apdu_len += encode_tagged_unsigned(&apdu[apdu_len],
|
||||
data->type.record.returnedRecordCount);
|
||||
apdu_len += encode_tagged_octet_string(&apdu[apdu_len],
|
||||
&data->fileData);
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
// decode the service request only
|
||||
int awf_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA *data)
|
||||
int awf_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_ATOMIC_WRITE_FILE_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
int tag_len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value_type = 0;
|
||||
int type = 0; // for decoding
|
||||
int len = 0;
|
||||
int tag_len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value_type = 0;
|
||||
int type = 0; // for decoding
|
||||
|
||||
// check for value pointers
|
||||
if (apdu_len && data)
|
||||
{
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value_type);
|
||||
if (tag_number != BACNET_APPLICATION_TAG_OBJECT_ID)
|
||||
return -1;
|
||||
len += decode_object_id(&apdu[len], &type, &data->object_instance);
|
||||
data->object_type = type;
|
||||
if (decode_is_opening_tag_number(&apdu[len], 0))
|
||||
{
|
||||
data->access = FILE_STREAM_ACCESS;
|
||||
// a tag number of 2 is not extended so only one octet
|
||||
len++;
|
||||
// fileStartPosition
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_SIGNED_INT)
|
||||
return -1;
|
||||
len += decode_signed(&apdu[len],
|
||||
len_value_type,
|
||||
&data->type.stream.fileStartPosition);
|
||||
// fileData
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_OCTET_STRING)
|
||||
return -1;
|
||||
len += decode_octet_string(&apdu[len],
|
||||
len_value_type,
|
||||
&data->fileData);
|
||||
if (!decode_is_closing_tag_number(&apdu[len], 0))
|
||||
return -1;
|
||||
// a tag number is not extended so only one octet
|
||||
len++;
|
||||
// check for value pointers
|
||||
if (apdu_len && data) {
|
||||
len =
|
||||
decode_tag_number_and_value(&apdu[0], &tag_number,
|
||||
&len_value_type);
|
||||
if (tag_number != BACNET_APPLICATION_TAG_OBJECT_ID)
|
||||
return -1;
|
||||
len += decode_object_id(&apdu[len], &type, &data->object_instance);
|
||||
data->object_type = type;
|
||||
if (decode_is_opening_tag_number(&apdu[len], 0)) {
|
||||
data->access = FILE_STREAM_ACCESS;
|
||||
// a tag number of 2 is not extended so only one octet
|
||||
len++;
|
||||
// fileStartPosition
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_SIGNED_INT)
|
||||
return -1;
|
||||
len += decode_signed(&apdu[len],
|
||||
len_value_type, &data->type.stream.fileStartPosition);
|
||||
// fileData
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_OCTET_STRING)
|
||||
return -1;
|
||||
len += decode_octet_string(&apdu[len],
|
||||
len_value_type, &data->fileData);
|
||||
if (!decode_is_closing_tag_number(&apdu[len], 0))
|
||||
return -1;
|
||||
// a tag number is not extended so only one octet
|
||||
len++;
|
||||
} else if (decode_is_opening_tag_number(&apdu[len], 1)) {
|
||||
data->access = FILE_RECORD_ACCESS;
|
||||
// a tag number is not extended so only one octet
|
||||
len++;
|
||||
// fileStartRecord
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_SIGNED_INT)
|
||||
return -1;
|
||||
len += decode_signed(&apdu[len],
|
||||
len_value_type, &data->type.record.fileStartRecord);
|
||||
// returnedRecordCount
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT)
|
||||
return -1;
|
||||
len += decode_unsigned(&apdu[len],
|
||||
len_value_type, &data->type.record.returnedRecordCount);
|
||||
// fileData
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_OCTET_STRING)
|
||||
return -1;
|
||||
len += decode_octet_string(&apdu[len],
|
||||
len_value_type, &data->fileData);
|
||||
if (!decode_is_closing_tag_number(&apdu[len], 1))
|
||||
return -1;
|
||||
// a tag number is not extended so only one octet
|
||||
len++;
|
||||
} else
|
||||
return -1;
|
||||
}
|
||||
else if (decode_is_opening_tag_number(&apdu[len], 1))
|
||||
{
|
||||
data->access = FILE_RECORD_ACCESS;
|
||||
// a tag number is not extended so only one octet
|
||||
len++;
|
||||
// fileStartRecord
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_SIGNED_INT)
|
||||
return -1;
|
||||
len += decode_signed(&apdu[len],
|
||||
len_value_type,
|
||||
&data->type.record.fileStartRecord);
|
||||
// returnedRecordCount
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT)
|
||||
return -1;
|
||||
len += decode_unsigned(&apdu[len],
|
||||
len_value_type,
|
||||
&data->type.record.returnedRecordCount);
|
||||
// fileData
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_OCTET_STRING)
|
||||
return -1;
|
||||
len += decode_octet_string(&apdu[len],
|
||||
len_value_type,
|
||||
&data->fileData);
|
||||
if (!decode_is_closing_tag_number(&apdu[len], 1))
|
||||
return -1;
|
||||
// a tag number is not extended so only one octet
|
||||
len++;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
return len;
|
||||
return len;
|
||||
}
|
||||
|
||||
int awf_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA *data)
|
||||
int awf_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id, BACNET_ATOMIC_WRITE_FILE_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
unsigned offset = 0;
|
||||
int len = 0;
|
||||
unsigned offset = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
|
||||
return -1;
|
||||
// apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted());
|
||||
*invoke_id = apdu[2]; /* invoke id - filled in by net layer */
|
||||
if (apdu[3] != SERVICE_CONFIRMED_ATOMIC_WRITE_FILE)
|
||||
return -1;
|
||||
offset = 4;
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
|
||||
return -1;
|
||||
// apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted());
|
||||
*invoke_id = apdu[2]; /* invoke id - filled in by net layer */
|
||||
if (apdu[3] != SERVICE_CONFIRMED_ATOMIC_WRITE_FILE)
|
||||
return -1;
|
||||
offset = 4;
|
||||
|
||||
if (apdu_len > offset)
|
||||
{
|
||||
len = awf_decode_service_request(
|
||||
&apdu[offset],
|
||||
apdu_len - offset,
|
||||
data);
|
||||
}
|
||||
|
||||
return len;
|
||||
if (apdu_len > offset) {
|
||||
len = awf_decode_service_request(&apdu[offset],
|
||||
apdu_len - offset, data);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int awf_ack_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint8_t invoke_id,
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA *data)
|
||||
int awf_ack_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, BACNET_ATOMIC_WRITE_FILE_DATA * data)
|
||||
{
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
|
||||
if (apdu)
|
||||
{
|
||||
apdu[0] = PDU_TYPE_COMPLEX_ACK;
|
||||
apdu[1] = invoke_id;
|
||||
apdu[2] = SERVICE_CONFIRMED_ATOMIC_WRITE_FILE; // service choice
|
||||
apdu_len = 3;
|
||||
switch (data->access)
|
||||
{
|
||||
case FILE_STREAM_ACCESS:
|
||||
apdu_len += encode_context_signed(&apdu[apdu_len], 0,
|
||||
data->type.stream.fileStartPosition);
|
||||
break;
|
||||
case FILE_RECORD_ACCESS:
|
||||
apdu_len += encode_context_signed(&apdu[apdu_len], 1,
|
||||
data->type.record.fileStartRecord);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (apdu) {
|
||||
apdu[0] = PDU_TYPE_COMPLEX_ACK;
|
||||
apdu[1] = invoke_id;
|
||||
apdu[2] = SERVICE_CONFIRMED_ATOMIC_WRITE_FILE; // service choice
|
||||
apdu_len = 3;
|
||||
switch (data->access) {
|
||||
case FILE_STREAM_ACCESS:
|
||||
apdu_len += encode_context_signed(&apdu[apdu_len], 0,
|
||||
data->type.stream.fileStartPosition);
|
||||
break;
|
||||
case FILE_RECORD_ACCESS:
|
||||
apdu_len += encode_context_signed(&apdu[apdu_len], 1,
|
||||
data->type.record.fileStartRecord);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
// decode the service request only
|
||||
int awf_ack_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA *data)
|
||||
int awf_ack_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_ATOMIC_WRITE_FILE_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value_type = 0;
|
||||
int len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value_type = 0;
|
||||
|
||||
// check for value pointers
|
||||
if (apdu_len && data)
|
||||
{
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value_type);
|
||||
if (tag_number == 0)
|
||||
{
|
||||
data->access = FILE_STREAM_ACCESS;
|
||||
len += decode_signed(&apdu[len],
|
||||
len_value_type,
|
||||
&data->type.stream.fileStartPosition);
|
||||
// check for value pointers
|
||||
if (apdu_len && data) {
|
||||
len =
|
||||
decode_tag_number_and_value(&apdu[0], &tag_number,
|
||||
&len_value_type);
|
||||
if (tag_number == 0) {
|
||||
data->access = FILE_STREAM_ACCESS;
|
||||
len += decode_signed(&apdu[len],
|
||||
len_value_type, &data->type.stream.fileStartPosition);
|
||||
} else if (tag_number == 1) {
|
||||
data->access = FILE_RECORD_ACCESS;
|
||||
len += decode_signed(&apdu[len],
|
||||
len_value_type, &data->type.record.fileStartRecord);
|
||||
} else
|
||||
return -1;
|
||||
}
|
||||
else if (tag_number == 1)
|
||||
{
|
||||
data->access = FILE_RECORD_ACCESS;
|
||||
len += decode_signed(&apdu[len],
|
||||
len_value_type,
|
||||
&data->type.record.fileStartRecord);
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
return len;
|
||||
return len;
|
||||
}
|
||||
|
||||
int awf_ack_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA *data)
|
||||
int awf_ack_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id, BACNET_ATOMIC_WRITE_FILE_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
unsigned offset = 0;
|
||||
int len = 0;
|
||||
unsigned offset = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu[0] != PDU_TYPE_COMPLEX_ACK)
|
||||
return -1;
|
||||
*invoke_id = apdu[1]; /* invoke id - filled in by net layer */
|
||||
if (apdu[2] != SERVICE_CONFIRMED_ATOMIC_WRITE_FILE)
|
||||
return -1;
|
||||
offset = 3;
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu[0] != PDU_TYPE_COMPLEX_ACK)
|
||||
return -1;
|
||||
*invoke_id = apdu[1]; /* invoke id - filled in by net layer */
|
||||
if (apdu[2] != SERVICE_CONFIRMED_ATOMIC_WRITE_FILE)
|
||||
return -1;
|
||||
offset = 3;
|
||||
|
||||
if (apdu_len > offset)
|
||||
{
|
||||
len = awf_decode_service_request(
|
||||
&apdu[offset],
|
||||
apdu_len - offset,
|
||||
data);
|
||||
}
|
||||
|
||||
return len;
|
||||
if (apdu_len > offset) {
|
||||
len = awf_decode_service_request(&apdu[offset],
|
||||
apdu_len - offset, data);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
@@ -310,133 +276,110 @@ int awf_ack_decode_apdu(
|
||||
#include "ctest.h"
|
||||
|
||||
void testAtomicWriteFileAccess(Test * pTest,
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA *data)
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA * data)
|
||||
{
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA test_data = {0};
|
||||
uint8_t apdu[480] = {0};
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 128;
|
||||
uint8_t test_invoke_id = 0;
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA test_data = { 0 };
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 128;
|
||||
uint8_t test_invoke_id = 0;
|
||||
|
||||
len = awf_encode_apdu(
|
||||
&apdu[0],
|
||||
invoke_id,
|
||||
data);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
len = awf_encode_apdu(&apdu[0], invoke_id, data);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
|
||||
len = awf_decode_apdu(
|
||||
&apdu[0],
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_data);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_data.object_type == data->object_type);
|
||||
ct_test(pTest, test_data.object_instance == data->object_instance);
|
||||
ct_test(pTest, test_data.access == data->access);
|
||||
if (test_data.access == FILE_STREAM_ACCESS)
|
||||
{
|
||||
ct_test(pTest, test_data.type.stream.fileStartPosition ==
|
||||
data->type.stream.fileStartPosition);
|
||||
}
|
||||
else if (test_data.access == FILE_RECORD_ACCESS)
|
||||
{
|
||||
ct_test(pTest, test_data.type.record.fileStartRecord ==
|
||||
data->type.record.fileStartRecord);
|
||||
ct_test(pTest, test_data.type.record.returnedRecordCount ==
|
||||
data->type.record.returnedRecordCount);
|
||||
}
|
||||
ct_test(pTest, octetstring_length(&test_data.fileData) ==
|
||||
octetstring_length(&data->fileData));
|
||||
ct_test(pTest, memcmp(
|
||||
octetstring_value(&test_data.fileData),
|
||||
octetstring_value(&data->fileData),
|
||||
octetstring_length(&test_data.fileData)) == 0);
|
||||
len = awf_decode_apdu(&apdu[0], apdu_len, &test_invoke_id, &test_data);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_data.object_type == data->object_type);
|
||||
ct_test(pTest, test_data.object_instance == data->object_instance);
|
||||
ct_test(pTest, test_data.access == data->access);
|
||||
if (test_data.access == FILE_STREAM_ACCESS) {
|
||||
ct_test(pTest, test_data.type.stream.fileStartPosition ==
|
||||
data->type.stream.fileStartPosition);
|
||||
} else if (test_data.access == FILE_RECORD_ACCESS) {
|
||||
ct_test(pTest, test_data.type.record.fileStartRecord ==
|
||||
data->type.record.fileStartRecord);
|
||||
ct_test(pTest, test_data.type.record.returnedRecordCount ==
|
||||
data->type.record.returnedRecordCount);
|
||||
}
|
||||
ct_test(pTest, octetstring_length(&test_data.fileData) ==
|
||||
octetstring_length(&data->fileData));
|
||||
ct_test(pTest, memcmp(octetstring_value(&test_data.fileData),
|
||||
octetstring_value(&data->fileData),
|
||||
octetstring_length(&test_data.fileData)) == 0);
|
||||
}
|
||||
|
||||
void testAtomicWriteFile(Test * pTest)
|
||||
{
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA data = {0};
|
||||
uint8_t test_octet_string[32] = "Joshua-Mary-Anna-Christopher";
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA data = { 0 };
|
||||
uint8_t test_octet_string[32] = "Joshua-Mary-Anna-Christopher";
|
||||
|
||||
data.object_type = OBJECT_FILE;
|
||||
data.object_instance = 1;
|
||||
data.access = FILE_STREAM_ACCESS;
|
||||
data.type.stream.fileStartPosition = 0;
|
||||
octetstring_init(&data.fileData,
|
||||
test_octet_string,
|
||||
sizeof(test_octet_string));
|
||||
testAtomicWriteFileAccess(pTest, &data);
|
||||
data.object_type = OBJECT_FILE;
|
||||
data.object_instance = 1;
|
||||
data.access = FILE_STREAM_ACCESS;
|
||||
data.type.stream.fileStartPosition = 0;
|
||||
octetstring_init(&data.fileData,
|
||||
test_octet_string, sizeof(test_octet_string));
|
||||
testAtomicWriteFileAccess(pTest, &data);
|
||||
|
||||
data.object_type = OBJECT_FILE;
|
||||
data.object_instance = 1;
|
||||
data.access = FILE_RECORD_ACCESS;
|
||||
data.type.record.fileStartRecord = 1;
|
||||
data.type.record.returnedRecordCount = 2;
|
||||
octetstring_init(&data.fileData,
|
||||
test_octet_string,
|
||||
sizeof(test_octet_string));
|
||||
testAtomicWriteFileAccess(pTest, &data);
|
||||
|
||||
return;
|
||||
data.object_type = OBJECT_FILE;
|
||||
data.object_instance = 1;
|
||||
data.access = FILE_RECORD_ACCESS;
|
||||
data.type.record.fileStartRecord = 1;
|
||||
data.type.record.returnedRecordCount = 2;
|
||||
octetstring_init(&data.fileData,
|
||||
test_octet_string, sizeof(test_octet_string));
|
||||
testAtomicWriteFileAccess(pTest, &data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void testAtomicWriteFileAckAccess(Test * pTest,
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA *data)
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA * data)
|
||||
{
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA test_data = {0};
|
||||
uint8_t apdu[480] = {0};
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 128;
|
||||
uint8_t test_invoke_id = 0;
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA test_data = { 0 };
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 128;
|
||||
uint8_t test_invoke_id = 0;
|
||||
|
||||
len = awf_encode_apdu(
|
||||
&apdu[0],
|
||||
invoke_id,
|
||||
data);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
len = awf_encode_apdu(&apdu[0], invoke_id, data);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
|
||||
len = awf_decode_apdu(
|
||||
&apdu[0],
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_data);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_data.access == data->access);
|
||||
if (test_data.access == FILE_STREAM_ACCESS)
|
||||
{
|
||||
ct_test(pTest, test_data.type.stream.fileStartPosition ==
|
||||
data->type.stream.fileStartPosition);
|
||||
}
|
||||
else if (test_data.access == FILE_RECORD_ACCESS)
|
||||
{
|
||||
ct_test(pTest, test_data.type.record.fileStartRecord ==
|
||||
data->type.record.fileStartRecord);
|
||||
}
|
||||
len = awf_decode_apdu(&apdu[0], apdu_len, &test_invoke_id, &test_data);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_data.access == data->access);
|
||||
if (test_data.access == FILE_STREAM_ACCESS) {
|
||||
ct_test(pTest, test_data.type.stream.fileStartPosition ==
|
||||
data->type.stream.fileStartPosition);
|
||||
} else if (test_data.access == FILE_RECORD_ACCESS) {
|
||||
ct_test(pTest, test_data.type.record.fileStartRecord ==
|
||||
data->type.record.fileStartRecord);
|
||||
}
|
||||
}
|
||||
|
||||
void testAtomicWriteFileAck(Test * pTest)
|
||||
{
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA data = {0};
|
||||
|
||||
data.access = FILE_STREAM_ACCESS;
|
||||
data.type.stream.fileStartPosition = 42;
|
||||
testAtomicWriteFileAckAccess(pTest, &data);
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA data = { 0 };
|
||||
|
||||
data.access = FILE_RECORD_ACCESS;
|
||||
data.type.record.fileStartRecord = 54;
|
||||
testAtomicWriteFileAckAccess(pTest, &data);
|
||||
|
||||
return;
|
||||
data.access = FILE_STREAM_ACCESS;
|
||||
data.type.stream.fileStartPosition = 42;
|
||||
testAtomicWriteFileAckAccess(pTest, &data);
|
||||
|
||||
data.access = FILE_RECORD_ACCESS;
|
||||
data.type.record.fileStartRecord = 54;
|
||||
testAtomicWriteFileAckAccess(pTest, &data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_ATOMIC_WRITE_FILE
|
||||
uint16_t Device_Max_APDU_Length_Accepted(void)
|
||||
{
|
||||
return MAX_APDU;
|
||||
return MAX_APDU;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
|
||||
+33
-51
@@ -38,78 +38,60 @@
|
||||
#include <stdbool.h>
|
||||
#include "bacdcode.h"
|
||||
|
||||
typedef struct BACnet_Atomic_Write_File_Data
|
||||
{
|
||||
BACNET_OBJECT_TYPE object_type;
|
||||
uint32_t object_instance;
|
||||
BACNET_FILE_ACCESS_METHOD access;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
int32_t fileStartPosition;
|
||||
} stream;
|
||||
struct
|
||||
{
|
||||
int32_t fileStartRecord;
|
||||
uint32_t returnedRecordCount;
|
||||
} record;
|
||||
} type;
|
||||
BACNET_OCTET_STRING fileData;
|
||||
typedef struct BACnet_Atomic_Write_File_Data {
|
||||
BACNET_OBJECT_TYPE object_type;
|
||||
uint32_t object_instance;
|
||||
BACNET_FILE_ACCESS_METHOD access;
|
||||
union {
|
||||
struct {
|
||||
int32_t fileStartPosition;
|
||||
} stream;
|
||||
struct {
|
||||
int32_t fileStartRecord;
|
||||
uint32_t returnedRecordCount;
|
||||
} record;
|
||||
} type;
|
||||
BACNET_OCTET_STRING fileData;
|
||||
} BACNET_ATOMIC_WRITE_FILE_DATA;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
// Atomic Write File
|
||||
// encode service
|
||||
int awf_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint8_t invoke_id,
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA *data);
|
||||
int awf_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, BACNET_ATOMIC_WRITE_FILE_DATA * data);
|
||||
|
||||
// decode the service request only
|
||||
int awf_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA *data);
|
||||
|
||||
int awf_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA *data);
|
||||
int awf_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_ATOMIC_WRITE_FILE_DATA * data);
|
||||
|
||||
int awf_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id, BACNET_ATOMIC_WRITE_FILE_DATA * data);
|
||||
|
||||
// Atomic Write File Ack
|
||||
// encode service
|
||||
int awf_ack_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint8_t invoke_id,
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA *data);
|
||||
int awf_ack_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, BACNET_ATOMIC_WRITE_FILE_DATA * data);
|
||||
|
||||
// decode the service request only
|
||||
int awf_ack_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA *data);
|
||||
int awf_ack_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_ATOMIC_WRITE_FILE_DATA * data);
|
||||
|
||||
int awf_ack_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA *data);
|
||||
int awf_ack_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id, BACNET_ATOMIC_WRITE_FILE_DATA * data);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
|
||||
void test_AtomicWriteFile(Test * pTest);
|
||||
void test_AtomicWriteFileAck(Test * pTest);
|
||||
void test_AtomicWriteFile(Test * pTest);
|
||||
void test_AtomicWriteFileAck(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
|
||||
+567
-659
File diff suppressed because it is too large
Load Diff
+33
-45
@@ -40,66 +40,54 @@
|
||||
#include "bacdef.h"
|
||||
#include "bacstr.h"
|
||||
|
||||
typedef struct BACnet_Application_Data_Value
|
||||
{
|
||||
uint8_t tag;
|
||||
union
|
||||
{
|
||||
/* NULL - not needed as it is encoded in the tag alone */
|
||||
bool Boolean;
|
||||
uint32_t Unsigned_Int;
|
||||
int32_t Signed_Int;
|
||||
float Real;
|
||||
double Double;
|
||||
BACNET_OCTET_STRING Octet_String;
|
||||
BACNET_CHARACTER_STRING Character_String;
|
||||
BACNET_BIT_STRING Bit_String;
|
||||
int Enumerated;
|
||||
BACNET_DATE Date;
|
||||
BACNET_TIME Time;
|
||||
BACNET_OBJECT_ID Object_Id;
|
||||
} type;
|
||||
typedef struct BACnet_Application_Data_Value {
|
||||
uint8_t tag;
|
||||
union {
|
||||
/* NULL - not needed as it is encoded in the tag alone */
|
||||
bool Boolean;
|
||||
uint32_t Unsigned_Int;
|
||||
int32_t Signed_Int;
|
||||
float Real;
|
||||
double Double;
|
||||
BACNET_OCTET_STRING Octet_String;
|
||||
BACNET_CHARACTER_STRING Character_String;
|
||||
BACNET_BIT_STRING Bit_String;
|
||||
int Enumerated;
|
||||
BACNET_DATE Date;
|
||||
BACNET_TIME Time;
|
||||
BACNET_OBJECT_ID Object_Id;
|
||||
} type;
|
||||
} BACNET_APPLICATION_DATA_VALUE;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int bacapp_decode_application_data(
|
||||
uint8_t *apdu,
|
||||
uint8_t apdu_len,
|
||||
BACNET_APPLICATION_DATA_VALUE *value);
|
||||
int bacapp_decode_application_data(uint8_t * apdu,
|
||||
uint8_t apdu_len, BACNET_APPLICATION_DATA_VALUE * value);
|
||||
|
||||
int bacapp_encode_application_data(
|
||||
uint8_t *apdu,
|
||||
BACNET_APPLICATION_DATA_VALUE *value);
|
||||
int bacapp_encode_application_data(uint8_t * apdu,
|
||||
BACNET_APPLICATION_DATA_VALUE * value);
|
||||
|
||||
bool bacapp_copy(
|
||||
BACNET_APPLICATION_DATA_VALUE *dest_value,
|
||||
BACNET_APPLICATION_DATA_VALUE *src_value);
|
||||
bool bacapp_copy(BACNET_APPLICATION_DATA_VALUE * dest_value,
|
||||
BACNET_APPLICATION_DATA_VALUE * src_value);
|
||||
|
||||
bool bacapp_compare(
|
||||
BACNET_APPLICATION_DATA_VALUE *value,
|
||||
BACNET_APPLICATION_DATA_VALUE *test_value);
|
||||
bool bacapp_compare(BACNET_APPLICATION_DATA_VALUE * value,
|
||||
BACNET_APPLICATION_DATA_VALUE * test_value);
|
||||
|
||||
bool bacapp_parse_application_data(
|
||||
BACNET_APPLICATION_TAG tag_number,
|
||||
const char *argv,
|
||||
BACNET_APPLICATION_DATA_VALUE *value);
|
||||
bool bacapp_parse_application_data(BACNET_APPLICATION_TAG tag_number,
|
||||
const char *argv, BACNET_APPLICATION_DATA_VALUE * value);
|
||||
|
||||
bool bacapp_print_value(
|
||||
FILE *stream,
|
||||
BACNET_APPLICATION_DATA_VALUE *value,
|
||||
BACNET_PROPERTY_ID property);
|
||||
bool bacapp_print_value(FILE * stream,
|
||||
BACNET_APPLICATION_DATA_VALUE * value,
|
||||
BACNET_PROPERTY_ID property);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testBACnetApplicationData(Test * pTest);
|
||||
void testBACnetApplicationData(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
|
||||
+554
-553
File diff suppressed because it is too large
Load Diff
+84
-77
@@ -42,117 +42,125 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
// from clause 20.2.1 General Rules for Encoding BACnet Tags
|
||||
// returns the number of apdu bytes consumed
|
||||
int encode_tag(uint8_t * apdu, uint8_t tag_number, bool context_specific,
|
||||
uint32_t len_value_type);
|
||||
int encode_tag(uint8_t * apdu, uint8_t tag_number,
|
||||
bool context_specific, uint32_t len_value_type);
|
||||
|
||||
// from clause 20.2.1.3.2 Constructed Data
|
||||
// returns the number of apdu bytes consumed
|
||||
int encode_opening_tag(uint8_t * apdu, uint8_t tag_number);
|
||||
int encode_closing_tag(uint8_t * apdu, uint8_t tag_number);
|
||||
int decode_tag_number_and_value(uint8_t * apdu, uint8_t * tag_number,
|
||||
uint32_t * value);
|
||||
int encode_opening_tag(uint8_t * apdu, uint8_t tag_number);
|
||||
int encode_closing_tag(uint8_t * apdu, uint8_t tag_number);
|
||||
int decode_tag_number_and_value(uint8_t * apdu, uint8_t * tag_number,
|
||||
uint32_t * value);
|
||||
// returns true if the tag is context specific
|
||||
bool decode_is_context_specific(uint8_t * apdu);
|
||||
bool decode_is_context_specific(uint8_t * apdu);
|
||||
// returns true if the tag is an opening tag and matches
|
||||
bool decode_is_opening_tag_number(uint8_t * apdu, uint8_t tag_number);
|
||||
bool decode_is_opening_tag_number(uint8_t * apdu, uint8_t tag_number);
|
||||
// returns true if the tag is a closing tag and matches
|
||||
bool decode_is_closing_tag_number(uint8_t * apdu, uint8_t tag_number);
|
||||
bool decode_is_closing_tag_number(uint8_t * apdu, uint8_t tag_number);
|
||||
// returns true if the tag is context specific and matches
|
||||
bool decode_is_context_tag(uint8_t * apdu, uint8_t tag_number);
|
||||
bool decode_is_context_tag(uint8_t * apdu, uint8_t tag_number);
|
||||
|
||||
// from clause 20.2.2 Encoding of a Null Value
|
||||
int encode_tagged_null(uint8_t * apdu);
|
||||
int encode_tagged_null(uint8_t * apdu);
|
||||
|
||||
// from clause 20.2.3 Encoding of a Boolean Value
|
||||
int encode_tagged_boolean(uint8_t * apdu, bool boolean_value);
|
||||
bool decode_boolean(uint32_t len_value);
|
||||
int encode_context_boolean(uint8_t * apdu, bool boolean_value);
|
||||
bool decode_context_boolean(uint8_t * apdu);
|
||||
int encode_tagged_boolean(uint8_t * apdu, bool boolean_value);
|
||||
bool decode_boolean(uint32_t len_value);
|
||||
int encode_context_boolean(uint8_t * apdu, bool boolean_value);
|
||||
bool decode_context_boolean(uint8_t * apdu);
|
||||
|
||||
// from clause 20.2.10 Encoding of a Bit String Value
|
||||
// returns the number of apdu bytes consumed
|
||||
int decode_bitstring(uint8_t * apdu, uint32_t len_value,
|
||||
BACNET_BIT_STRING *bit_string);
|
||||
int decode_bitstring(uint8_t * apdu, uint32_t len_value,
|
||||
BACNET_BIT_STRING * bit_string);
|
||||
// returns the number of apdu bytes consumed
|
||||
int encode_bitstring(uint8_t * apdu, BACNET_BIT_STRING *bit_string);
|
||||
int encode_tagged_bitstring(uint8_t * apdu, BACNET_BIT_STRING *bit_string);
|
||||
int encode_bitstring(uint8_t * apdu, BACNET_BIT_STRING * bit_string);
|
||||
int encode_tagged_bitstring(uint8_t * apdu,
|
||||
BACNET_BIT_STRING * bit_string);
|
||||
|
||||
// from clause 20.2.6 Encoding of a Real Number Value
|
||||
// and 20.2.1 General Rules for Encoding BACnet Tags
|
||||
// returns the number of apdu bytes consumed
|
||||
int decode_real(uint8_t * apdu, float *real_value);
|
||||
int encode_bacnet_real(float value, uint8_t * apdu);
|
||||
int encode_tagged_real(uint8_t * apdu, float value);
|
||||
int decode_real(uint8_t * apdu, float *real_value);
|
||||
int encode_bacnet_real(float value, uint8_t * apdu);
|
||||
int encode_tagged_real(uint8_t * apdu, float value);
|
||||
|
||||
// from clause 20.2.14 Encoding of an Object Identifier Value
|
||||
// and 20.2.1 General Rules for Encoding BACnet Tags
|
||||
// returns the number of apdu bytes consumed
|
||||
int decode_object_id(uint8_t * apdu, int *object_type, uint32_t *instance);
|
||||
int encode_bacnet_object_id(uint8_t * apdu, int object_type, uint32_t instance);
|
||||
int encode_context_object_id(uint8_t * apdu, int tag_number,
|
||||
int object_type, uint32_t instance);
|
||||
int encode_tagged_object_id(uint8_t * apdu, int object_type, uint32_t instance);
|
||||
int decode_object_id(uint8_t * apdu, int *object_type,
|
||||
uint32_t * instance);
|
||||
int encode_bacnet_object_id(uint8_t * apdu, int object_type,
|
||||
uint32_t instance);
|
||||
int encode_context_object_id(uint8_t * apdu, int tag_number,
|
||||
int object_type, uint32_t instance);
|
||||
int encode_tagged_object_id(uint8_t * apdu, int object_type,
|
||||
uint32_t instance);
|
||||
|
||||
// from clause 20.2.8 Encoding of an Octet String Value
|
||||
// and 20.2.1 General Rules for Encoding BACnet Tags
|
||||
// returns the number of apdu bytes consumed
|
||||
int encode_octet_string(uint8_t * apdu,
|
||||
BACNET_OCTET_STRING *octet_string);
|
||||
int encode_tagged_octet_string(uint8_t * apdu,
|
||||
BACNET_OCTET_STRING *octet_string);
|
||||
int decode_octet_string(uint8_t * apdu, uint32_t len_value,
|
||||
BACNET_OCTET_STRING *octet_string);
|
||||
int encode_octet_string(uint8_t * apdu,
|
||||
BACNET_OCTET_STRING * octet_string);
|
||||
int encode_tagged_octet_string(uint8_t * apdu,
|
||||
BACNET_OCTET_STRING * octet_string);
|
||||
int decode_octet_string(uint8_t * apdu, uint32_t len_value,
|
||||
BACNET_OCTET_STRING * octet_string);
|
||||
|
||||
|
||||
// from clause 20.2.9 Encoding of a Character String Value
|
||||
// and 20.2.1 General Rules for Encoding BACnet Tags
|
||||
// returns the number of apdu bytes consumed
|
||||
int encode_bacnet_character_string(uint8_t * apdu,
|
||||
BACNET_CHARACTER_STRING *char_string);
|
||||
int encode_tagged_character_string(uint8_t * apdu,
|
||||
BACNET_CHARACTER_STRING *char_string);
|
||||
int encode_context_character_string(uint8_t * apdu, int tag_number,
|
||||
BACNET_CHARACTER_STRING *char_string);
|
||||
int decode_character_string(uint8_t * apdu, uint32_t len_value,
|
||||
BACNET_CHARACTER_STRING *char_string);
|
||||
int encode_bacnet_character_string(uint8_t * apdu,
|
||||
BACNET_CHARACTER_STRING * char_string);
|
||||
int encode_tagged_character_string(uint8_t * apdu,
|
||||
BACNET_CHARACTER_STRING * char_string);
|
||||
int encode_context_character_string(uint8_t * apdu, int tag_number,
|
||||
BACNET_CHARACTER_STRING * char_string);
|
||||
int decode_character_string(uint8_t * apdu, uint32_t len_value,
|
||||
BACNET_CHARACTER_STRING * char_string);
|
||||
|
||||
// from clause 20.2.4 Encoding of an Unsigned Integer Value
|
||||
// and 20.2.1 General Rules for Encoding BACnet Tags
|
||||
// returns the number of apdu bytes consumed
|
||||
int encode_bacnet_unsigned(uint8_t * apdu, uint32_t value);
|
||||
int encode_context_unsigned(uint8_t * apdu, int tag_number, uint32_t value);
|
||||
int encode_tagged_unsigned(uint8_t * apdu, uint32_t value);
|
||||
int decode_unsigned(uint8_t * apdu, uint32_t len_value, uint32_t *value);
|
||||
int encode_bacnet_unsigned(uint8_t * apdu, uint32_t value);
|
||||
int encode_context_unsigned(uint8_t * apdu, int tag_number,
|
||||
uint32_t value);
|
||||
int encode_tagged_unsigned(uint8_t * apdu, uint32_t value);
|
||||
int decode_unsigned(uint8_t * apdu, uint32_t len_value,
|
||||
uint32_t * value);
|
||||
|
||||
// from clause 20.2.5 Encoding of a Signed Integer Value
|
||||
// and 20.2.1 General Rules for Encoding BACnet Tags
|
||||
// returns the number of apdu bytes consumed
|
||||
int encode_bacnet_signed(uint8_t * apdu, int32_t value);
|
||||
int encode_tagged_signed(uint8_t * apdu, int32_t value);
|
||||
int encode_context_signed(uint8_t * apdu, int tag_number, int32_t value);
|
||||
int decode_signed(uint8_t * apdu, uint32_t len_value, int32_t *value);
|
||||
int encode_bacnet_signed(uint8_t * apdu, int32_t value);
|
||||
int encode_tagged_signed(uint8_t * apdu, int32_t value);
|
||||
int encode_context_signed(uint8_t * apdu, int tag_number,
|
||||
int32_t value);
|
||||
int decode_signed(uint8_t * apdu, uint32_t len_value, int32_t * value);
|
||||
|
||||
// from clause 20.2.11 Encoding of an Enumerated Value
|
||||
// and 20.2.1 General Rules for Encoding BACnet Tags
|
||||
// returns the number of apdu bytes consumed
|
||||
int decode_enumerated(uint8_t * apdu, uint32_t len_value, int *value);
|
||||
int encode_bacnet_enumerated(uint8_t * apdu, int value);
|
||||
int encode_tagged_enumerated(uint8_t * apdu, int value);
|
||||
int encode_context_enumerated(uint8_t * apdu, int tag_number, int value);
|
||||
int decode_enumerated(uint8_t * apdu, uint32_t len_value, int *value);
|
||||
int encode_bacnet_enumerated(uint8_t * apdu, int value);
|
||||
int encode_tagged_enumerated(uint8_t * apdu, int value);
|
||||
int encode_context_enumerated(uint8_t * apdu, int tag_number,
|
||||
int value);
|
||||
|
||||
// from clause 20.2.13 Encoding of a Time Value
|
||||
// and 20.2.1 General Rules for Encoding BACnet Tags
|
||||
// returns the number of apdu bytes consumed
|
||||
int encode_bacnet_time(uint8_t * apdu, int hour, int min, int sec,
|
||||
int hundredths);
|
||||
int encode_tagged_time(uint8_t * apdu, int hour, int min, int sec,
|
||||
int hundredths);
|
||||
int decode_bacnet_time(uint8_t * apdu, int *hour, int *min, int *sec,
|
||||
int *hundredths);
|
||||
int encode_bacnet_time(uint8_t * apdu, int hour, int min, int sec,
|
||||
int hundredths);
|
||||
int encode_tagged_time(uint8_t * apdu, int hour, int min, int sec,
|
||||
int hundredths);
|
||||
int decode_bacnet_time(uint8_t * apdu, int *hour, int *min, int *sec,
|
||||
int *hundredths);
|
||||
|
||||
// BACnet Date
|
||||
// year = years since 1900
|
||||
@@ -163,33 +171,32 @@ int decode_bacnet_time(uint8_t * apdu, int *hour, int *min, int *sec,
|
||||
// from clause 20.2.12 Encoding of a Date Value
|
||||
// and 20.2.1 General Rules for Encoding BACnet Tags
|
||||
// returns the number of apdu bytes consumed
|
||||
int encode_bacnet_date(uint8_t * apdu, int year, int month, int day,
|
||||
int wday);
|
||||
int encode_tagged_date(uint8_t * apdu, int year, int month, int day,
|
||||
int wday);
|
||||
int decode_date(uint8_t * apdu, int *year, int *month, int *day,
|
||||
int *wday);
|
||||
int encode_bacnet_date(uint8_t * apdu, int year, int month, int day,
|
||||
int wday);
|
||||
int encode_tagged_date(uint8_t * apdu, int year, int month, int day,
|
||||
int wday);
|
||||
int decode_date(uint8_t * apdu, int *year, int *month, int *day,
|
||||
int *wday);
|
||||
|
||||
// two octet unsigned16
|
||||
int encode_unsigned16(uint8_t * apdu, uint16_t value);
|
||||
int decode_unsigned16(uint8_t * apdu, uint16_t *value);
|
||||
int encode_unsigned16(uint8_t * apdu, uint16_t value);
|
||||
int decode_unsigned16(uint8_t * apdu, uint16_t * value);
|
||||
// four octet unsigned32
|
||||
int encode_unsigned32(uint8_t * apdu, uint32_t value);
|
||||
int decode_unsigned32(uint8_t * apdu, uint32_t *value);
|
||||
int encode_unsigned32(uint8_t * apdu, uint32_t value);
|
||||
int decode_unsigned32(uint8_t * apdu, uint32_t * value);
|
||||
|
||||
// from clause 20.1.2.4 max-segments-accepted
|
||||
// and clause 20.1.2.5 max-APDU-length-accepted
|
||||
// returns the encoded octet
|
||||
uint8_t encode_max_segs_max_apdu(int max_segs, int max_apdu);
|
||||
int decode_max_segs(uint8_t octet);
|
||||
int decode_max_apdu(uint8_t octet);
|
||||
uint8_t encode_max_segs_max_apdu(int max_segs, int max_apdu);
|
||||
int decode_max_segs(uint8_t octet);
|
||||
int decode_max_apdu(uint8_t octet);
|
||||
|
||||
// returns the number of apdu bytes consumed
|
||||
int encode_simple_ack(uint8_t * apdu, uint8_t invoke_id,
|
||||
uint8_t service_choice);
|
||||
int encode_simple_ack(uint8_t * apdu, uint8_t invoke_id,
|
||||
uint8_t service_choice);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
+20
-24
@@ -56,11 +56,10 @@
|
||||
// embedded systems need fixed name sizes
|
||||
#define MAX_OBJECT_NAME 10
|
||||
// common object properties
|
||||
typedef struct BACnet_Object_Data
|
||||
{
|
||||
uint32_t Object_Identifier;
|
||||
char Object_Name[MAX_OBJECT_NAME];
|
||||
BACNET_OBJECT_TYPE Object_Type;
|
||||
typedef struct BACnet_Object_Data {
|
||||
uint32_t Object_Identifier;
|
||||
char Object_Name[MAX_OBJECT_NAME];
|
||||
BACNET_OBJECT_TYPE Object_Type;
|
||||
} BACNET_OBJECT_DATA;
|
||||
|
||||
#define BACNET_BROADCAST_NETWORK 0xFFFF
|
||||
@@ -75,39 +74,36 @@ struct BACnet_Device_Address {
|
||||
// DNET,DLEN,DADR or SNET,SLEN,SADR
|
||||
// the following are used if the device is behind a router
|
||||
// net = 0 indicates local
|
||||
uint16_t net; /* BACnet network number */
|
||||
uint16_t net; /* BACnet network number */
|
||||
// LEN = 0 denotes broadcast MAC ADR and ADR field is absent
|
||||
// LEN > 0 specifies length of ADR field
|
||||
int len; /* length of MAC address */
|
||||
uint8_t adr[MAX_MAC_LEN]; /* hwaddr (MAC) address */
|
||||
int len; /* length of MAC address */
|
||||
uint8_t adr[MAX_MAC_LEN]; /* hwaddr (MAC) address */
|
||||
};
|
||||
typedef struct BACnet_Device_Address BACNET_ADDRESS;
|
||||
|
||||
/* date */
|
||||
typedef struct BACnet_Date
|
||||
{
|
||||
uint16_t year; /* AD */
|
||||
uint8_t month; /* 1=Jan */
|
||||
uint8_t day; /* 1..31 */
|
||||
uint8_t wday; /* 1=Monday */
|
||||
typedef struct BACnet_Date {
|
||||
uint16_t year; /* AD */
|
||||
uint8_t month; /* 1=Jan */
|
||||
uint8_t day; /* 1..31 */
|
||||
uint8_t wday; /* 1=Monday */
|
||||
} BACNET_DATE;
|
||||
|
||||
/* time */
|
||||
typedef struct BACnet_Time
|
||||
{
|
||||
uint8_t hour;
|
||||
uint8_t min;
|
||||
uint8_t sec;
|
||||
uint8_t hundredths;
|
||||
typedef struct BACnet_Time {
|
||||
uint8_t hour;
|
||||
uint8_t min;
|
||||
uint8_t sec;
|
||||
uint8_t hundredths;
|
||||
} BACNET_TIME;
|
||||
|
||||
/* note: with microprocessors having lots more code space than memory,
|
||||
it might be better to have a packed encoding with a library to
|
||||
easily access the data. */
|
||||
typedef struct BACnet_Object_Id
|
||||
{
|
||||
uint16_t type;
|
||||
uint32_t instance;
|
||||
typedef struct BACnet_Object_Id {
|
||||
uint16_t type;
|
||||
uint32_t instance;
|
||||
} BACNET_OBJECT_ID;
|
||||
|
||||
#define MAX_NPDU (1+1+2+1+MAX_MAC_LEN+2+1+MAX_MAC_LEN+1+1+2)
|
||||
|
||||
+901
-928
File diff suppressed because it is too large
Load Diff
+165
-226
@@ -37,125 +37,104 @@
|
||||
#include "bacdef.h"
|
||||
|
||||
// encode service
|
||||
int bacerror_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint8_t invoke_id,
|
||||
BACNET_CONFIRMED_SERVICE service,
|
||||
BACNET_ERROR_CLASS error_class,
|
||||
BACNET_ERROR_CODE error_code)
|
||||
int bacerror_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id,
|
||||
BACNET_CONFIRMED_SERVICE service,
|
||||
BACNET_ERROR_CLASS error_class, BACNET_ERROR_CODE error_code)
|
||||
{
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
|
||||
if (apdu)
|
||||
{
|
||||
apdu[0] = PDU_TYPE_ERROR;
|
||||
apdu[1] = invoke_id;
|
||||
apdu[2] = service;
|
||||
apdu_len = 3;
|
||||
// service parameters
|
||||
apdu_len += encode_tagged_enumerated(&apdu[apdu_len],
|
||||
error_class);
|
||||
apdu_len += encode_tagged_enumerated(&apdu[apdu_len],
|
||||
error_code);
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
if (apdu) {
|
||||
apdu[0] = PDU_TYPE_ERROR;
|
||||
apdu[1] = invoke_id;
|
||||
apdu[2] = service;
|
||||
apdu_len = 3;
|
||||
// service parameters
|
||||
apdu_len += encode_tagged_enumerated(&apdu[apdu_len], error_class);
|
||||
apdu_len += encode_tagged_enumerated(&apdu[apdu_len], error_code);
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
// decode the application class and code
|
||||
int bacerror_decode_error_class_and_code(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_ERROR_CLASS *error_class,
|
||||
BACNET_ERROR_CODE *error_code)
|
||||
int bacerror_decode_error_class_and_code(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value_type = 0;
|
||||
int decoded_value = 0;
|
||||
int len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value_type = 0;
|
||||
int decoded_value = 0;
|
||||
|
||||
if (apdu_len)
|
||||
{
|
||||
// error class
|
||||
len += decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
if (tag_number != BACNET_APPLICATION_TAG_ENUMERATED)
|
||||
return 0;
|
||||
len += decode_enumerated(&apdu[len],len_value_type, &decoded_value);
|
||||
if (error_class)
|
||||
*error_class = decoded_value;
|
||||
// error code
|
||||
len += decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
if (tag_number != BACNET_APPLICATION_TAG_ENUMERATED)
|
||||
return 0;
|
||||
len += decode_enumerated(&apdu[len],len_value_type, &decoded_value);
|
||||
if (error_code)
|
||||
*error_code = decoded_value;
|
||||
}
|
||||
|
||||
return len;
|
||||
if (apdu_len) {
|
||||
// error class
|
||||
len += decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
if (tag_number != BACNET_APPLICATION_TAG_ENUMERATED)
|
||||
return 0;
|
||||
len +=
|
||||
decode_enumerated(&apdu[len], len_value_type, &decoded_value);
|
||||
if (error_class)
|
||||
*error_class = decoded_value;
|
||||
// error code
|
||||
len += decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
if (tag_number != BACNET_APPLICATION_TAG_ENUMERATED)
|
||||
return 0;
|
||||
len +=
|
||||
decode_enumerated(&apdu[len], len_value_type, &decoded_value);
|
||||
if (error_code)
|
||||
*error_code = decoded_value;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
// decode the service request only
|
||||
int bacerror_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
BACNET_CONFIRMED_SERVICE *service,
|
||||
BACNET_ERROR_CLASS *error_class,
|
||||
BACNET_ERROR_CODE *error_code)
|
||||
int bacerror_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id,
|
||||
BACNET_CONFIRMED_SERVICE * service,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int len = 0;
|
||||
int len = 0;
|
||||
|
||||
if (apdu_len > 2)
|
||||
{
|
||||
if (invoke_id)
|
||||
*invoke_id = apdu[0];
|
||||
if (service)
|
||||
*service = apdu[1];
|
||||
// decode the application class and code
|
||||
len = bacerror_decode_error_class_and_code(
|
||||
&apdu[2],
|
||||
apdu_len - 2,
|
||||
error_class,
|
||||
error_code);
|
||||
}
|
||||
|
||||
return len;
|
||||
if (apdu_len > 2) {
|
||||
if (invoke_id)
|
||||
*invoke_id = apdu[0];
|
||||
if (service)
|
||||
*service = apdu[1];
|
||||
// decode the application class and code
|
||||
len = bacerror_decode_error_class_and_code(&apdu[2],
|
||||
apdu_len - 2, error_class, error_code);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
// decode the whole APDU - mainly used for unit testing
|
||||
int bacerror_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
BACNET_CONFIRMED_SERVICE *service,
|
||||
BACNET_ERROR_CLASS *error_class,
|
||||
BACNET_ERROR_CODE *error_code)
|
||||
int bacerror_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id,
|
||||
BACNET_CONFIRMED_SERVICE * service,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int len = 0;
|
||||
int len = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu_len)
|
||||
{
|
||||
if (apdu[0] != PDU_TYPE_ERROR)
|
||||
return -1;
|
||||
if (apdu_len > 1)
|
||||
{
|
||||
len = bacerror_decode_service_request(
|
||||
&apdu[1],
|
||||
apdu_len - 1,
|
||||
invoke_id,
|
||||
service,
|
||||
error_class,
|
||||
error_code);
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu_len) {
|
||||
if (apdu[0] != PDU_TYPE_ERROR)
|
||||
return -1;
|
||||
if (apdu_len > 1) {
|
||||
len = bacerror_decode_service_request(&apdu[1],
|
||||
apdu_len - 1, invoke_id, service, error_class, error_code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
@@ -165,137 +144,97 @@ int bacerror_decode_apdu(
|
||||
|
||||
void testBACError(Test * pTest)
|
||||
{
|
||||
uint8_t apdu[480] = {0};
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 0;
|
||||
BACNET_CONFIRMED_SERVICE service = 0;
|
||||
BACNET_ERROR_CLASS error_class = 0;
|
||||
BACNET_ERROR_CODE error_code = 0;
|
||||
uint8_t test_invoke_id = 0;
|
||||
BACNET_CONFIRMED_SERVICE test_service = 0;
|
||||
BACNET_ERROR_CLASS test_error_class = 0;
|
||||
BACNET_ERROR_CODE test_error_code = 0;
|
||||
|
||||
len = bacerror_encode_apdu(
|
||||
&apdu[0],
|
||||
invoke_id,
|
||||
service,
|
||||
error_class,
|
||||
error_code);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 0;
|
||||
BACNET_CONFIRMED_SERVICE service = 0;
|
||||
BACNET_ERROR_CLASS error_class = 0;
|
||||
BACNET_ERROR_CODE error_code = 0;
|
||||
uint8_t test_invoke_id = 0;
|
||||
BACNET_CONFIRMED_SERVICE test_service = 0;
|
||||
BACNET_ERROR_CLASS test_error_class = 0;
|
||||
BACNET_ERROR_CODE test_error_code = 0;
|
||||
|
||||
len = bacerror_decode_apdu(
|
||||
&apdu[0],
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_service,
|
||||
&test_error_class,
|
||||
&test_error_code);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
ct_test(pTest, test_service == service);
|
||||
ct_test(pTest, test_error_class == error_class);
|
||||
ct_test(pTest, test_error_code == error_code);
|
||||
len = bacerror_encode_apdu(&apdu[0],
|
||||
invoke_id, service, error_class, error_code);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
|
||||
// change type to get negative response
|
||||
apdu[0] = PDU_TYPE_ABORT;
|
||||
len = bacerror_decode_apdu(
|
||||
&apdu[0],
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_service,
|
||||
&test_error_class,
|
||||
&test_error_code);
|
||||
ct_test(pTest, len == -1);
|
||||
len = bacerror_decode_apdu(&apdu[0],
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_service, &test_error_class, &test_error_code);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
ct_test(pTest, test_service == service);
|
||||
ct_test(pTest, test_error_class == error_class);
|
||||
ct_test(pTest, test_error_code == error_code);
|
||||
|
||||
// test NULL APDU
|
||||
len = bacerror_decode_apdu(
|
||||
NULL,
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_service,
|
||||
&test_error_class,
|
||||
&test_error_code);
|
||||
ct_test(pTest, len == -1);
|
||||
// change type to get negative response
|
||||
apdu[0] = PDU_TYPE_ABORT;
|
||||
len = bacerror_decode_apdu(&apdu[0],
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_service, &test_error_class, &test_error_code);
|
||||
ct_test(pTest, len == -1);
|
||||
|
||||
// force a zero length
|
||||
len = bacerror_decode_apdu(
|
||||
&apdu[0],
|
||||
0,
|
||||
&test_invoke_id,
|
||||
&test_service,
|
||||
&test_error_class,
|
||||
&test_error_code);
|
||||
ct_test(pTest, len == 0);
|
||||
|
||||
|
||||
// check them all...
|
||||
for (
|
||||
service = 0;
|
||||
service < MAX_BACNET_CONFIRMED_SERVICE;
|
||||
service++)
|
||||
{
|
||||
for (
|
||||
error_class = 0;
|
||||
error_class < MAX_BACNET_ERROR_CLASS;
|
||||
error_class++)
|
||||
{
|
||||
for (
|
||||
error_code = 0;
|
||||
error_code < MAX_BACNET_ERROR_CODE;
|
||||
error_code++)
|
||||
{
|
||||
len = bacerror_encode_apdu(
|
||||
&apdu[0],
|
||||
invoke_id,
|
||||
service,
|
||||
error_class,
|
||||
error_code);
|
||||
apdu_len = len;
|
||||
ct_test(pTest, len != 0);
|
||||
len = bacerror_decode_apdu(
|
||||
&apdu[0],
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_service,
|
||||
&test_error_class,
|
||||
&test_error_code);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
ct_test(pTest, test_service == service);
|
||||
ct_test(pTest, test_error_class == error_class);
|
||||
ct_test(pTest, test_error_code == error_code);
|
||||
}
|
||||
// test NULL APDU
|
||||
len = bacerror_decode_apdu(NULL,
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_service, &test_error_class, &test_error_code);
|
||||
ct_test(pTest, len == -1);
|
||||
|
||||
// force a zero length
|
||||
len = bacerror_decode_apdu(&apdu[0],
|
||||
0,
|
||||
&test_invoke_id,
|
||||
&test_service, &test_error_class, &test_error_code);
|
||||
ct_test(pTest, len == 0);
|
||||
|
||||
|
||||
// check them all...
|
||||
for (service = 0; service < MAX_BACNET_CONFIRMED_SERVICE; service++) {
|
||||
for (error_class = 0;
|
||||
error_class < MAX_BACNET_ERROR_CLASS; error_class++) {
|
||||
for (error_code = 0;
|
||||
error_code < MAX_BACNET_ERROR_CODE; error_code++) {
|
||||
len = bacerror_encode_apdu(&apdu[0],
|
||||
invoke_id, service, error_class, error_code);
|
||||
apdu_len = len;
|
||||
ct_test(pTest, len != 0);
|
||||
len = bacerror_decode_apdu(&apdu[0],
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_service, &test_error_class, &test_error_code);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
ct_test(pTest, test_service == service);
|
||||
ct_test(pTest, test_error_class == error_class);
|
||||
ct_test(pTest, test_error_code == error_code);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// max boundaries
|
||||
service = 255;
|
||||
error_class = LAST_PROPRIETARY_ERROR_CLASS;
|
||||
error_code = LAST_PROPRIETARY_ERROR_CODE;
|
||||
len = bacerror_encode_apdu(
|
||||
&apdu[0],
|
||||
invoke_id,
|
||||
service,
|
||||
error_class,
|
||||
error_code);
|
||||
apdu_len = len;
|
||||
ct_test(pTest, len != 0);
|
||||
len = bacerror_decode_apdu(
|
||||
&apdu[0],
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_service,
|
||||
&test_error_class,
|
||||
&test_error_code);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
ct_test(pTest, test_service == service);
|
||||
ct_test(pTest, test_error_class == error_class);
|
||||
ct_test(pTest, test_error_code == error_code);
|
||||
|
||||
// max boundaries
|
||||
service = 255;
|
||||
error_class = LAST_PROPRIETARY_ERROR_CLASS;
|
||||
error_code = LAST_PROPRIETARY_ERROR_CODE;
|
||||
len = bacerror_encode_apdu(&apdu[0],
|
||||
invoke_id, service, error_class, error_code);
|
||||
apdu_len = len;
|
||||
ct_test(pTest, len != 0);
|
||||
len = bacerror_decode_apdu(&apdu[0],
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_service, &test_error_class, &test_error_code);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
ct_test(pTest, test_service == service);
|
||||
ct_test(pTest, test_error_class == error_class);
|
||||
ct_test(pTest, test_error_code == error_code);
|
||||
|
||||
}
|
||||
|
||||
#ifdef TEST_BACERROR
|
||||
|
||||
+22
-32
@@ -40,45 +40,35 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int bacerror_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint8_t invoke_id,
|
||||
BACNET_CONFIRMED_SERVICE service,
|
||||
BACNET_ERROR_CLASS error_class,
|
||||
BACNET_ERROR_CODE error_code);
|
||||
int bacerror_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id,
|
||||
BACNET_CONFIRMED_SERVICE service,
|
||||
BACNET_ERROR_CLASS error_class, BACNET_ERROR_CODE error_code);
|
||||
|
||||
int bacerror_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
BACNET_CONFIRMED_SERVICE *service,
|
||||
BACNET_ERROR_CLASS *error_class,
|
||||
BACNET_ERROR_CODE *error_code);
|
||||
|
||||
int bacerror_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
BACNET_CONFIRMED_SERVICE *service,
|
||||
BACNET_ERROR_CLASS *error_class,
|
||||
BACNET_ERROR_CODE *error_code);
|
||||
int bacerror_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id,
|
||||
BACNET_CONFIRMED_SERVICE * service,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code);
|
||||
|
||||
int bacerror_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id,
|
||||
BACNET_CONFIRMED_SERVICE * service,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code);
|
||||
|
||||
int bacerror_decode_error_class_and_code(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code);
|
||||
|
||||
int bacerror_decode_error_class_and_code(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_ERROR_CLASS *error_class,
|
||||
BACNET_ERROR_CODE *error_code);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testBACError(Test * pTest);
|
||||
void testBACError(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
|
||||
+58
-46
@@ -37,63 +37,75 @@
|
||||
#include "bacprop.h"
|
||||
|
||||
PROP_TAG_DATA bacnet_object_device_property_tag_map[] = {
|
||||
{PROP_OBJECT_IDENTIFIER, BACNET_APPLICATION_TAG_OBJECT_ID},
|
||||
{PROP_OBJECT_NAME, BACNET_APPLICATION_TAG_CHARACTER_STRING},
|
||||
{PROP_OBJECT_TYPE, BACNET_APPLICATION_TAG_ENUMERATED},
|
||||
{PROP_SYSTEM_STATUS, BACNET_APPLICATION_TAG_ENUMERATED},
|
||||
{PROP_VENDOR_NAME, BACNET_APPLICATION_TAG_CHARACTER_STRING},
|
||||
{PROP_VENDOR_IDENTIFIER, BACNET_APPLICATION_TAG_UNSIGNED_INT},
|
||||
{PROP_MODEL_NAME, BACNET_APPLICATION_TAG_CHARACTER_STRING},
|
||||
{PROP_FIRMWARE_REVISION, BACNET_APPLICATION_TAG_CHARACTER_STRING},
|
||||
{PROP_APPLICATION_SOFTWARE_VERSION, BACNET_APPLICATION_TAG_CHARACTER_STRING},
|
||||
{PROP_PROTOCOL_VERSION, BACNET_APPLICATION_TAG_UNSIGNED_INT},
|
||||
{PROP_PROTOCOL_CONFORMANCE_CLASS, BACNET_APPLICATION_TAG_UNSIGNED_INT},
|
||||
{PROP_PROTOCOL_SERVICES_SUPPORTED, BACNET_APPLICATION_TAG_BIT_STRING},
|
||||
{PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED, BACNET_APPLICATION_TAG_BIT_STRING},
|
||||
{PROP_MAX_APDU_LENGTH_ACCEPTED, BACNET_APPLICATION_TAG_UNSIGNED_INT},
|
||||
{PROP_SEGMENTATION_SUPPORTED, BACNET_APPLICATION_TAG_ENUMERATED},
|
||||
{PROP_APDU_TIMEOUT, BACNET_APPLICATION_TAG_UNSIGNED_INT},
|
||||
{PROP_NUMBER_OF_APDU_RETRIES, BACNET_APPLICATION_TAG_UNSIGNED_INT},
|
||||
{ -1, -1 }
|
||||
{PROP_OBJECT_IDENTIFIER, BACNET_APPLICATION_TAG_OBJECT_ID}
|
||||
,
|
||||
{PROP_OBJECT_NAME, BACNET_APPLICATION_TAG_CHARACTER_STRING}
|
||||
,
|
||||
{PROP_OBJECT_TYPE, BACNET_APPLICATION_TAG_ENUMERATED}
|
||||
,
|
||||
{PROP_SYSTEM_STATUS, BACNET_APPLICATION_TAG_ENUMERATED}
|
||||
,
|
||||
{PROP_VENDOR_NAME, BACNET_APPLICATION_TAG_CHARACTER_STRING}
|
||||
,
|
||||
{PROP_VENDOR_IDENTIFIER, BACNET_APPLICATION_TAG_UNSIGNED_INT}
|
||||
,
|
||||
{PROP_MODEL_NAME, BACNET_APPLICATION_TAG_CHARACTER_STRING}
|
||||
,
|
||||
{PROP_FIRMWARE_REVISION, BACNET_APPLICATION_TAG_CHARACTER_STRING}
|
||||
,
|
||||
{PROP_APPLICATION_SOFTWARE_VERSION,
|
||||
BACNET_APPLICATION_TAG_CHARACTER_STRING}
|
||||
,
|
||||
{PROP_PROTOCOL_VERSION, BACNET_APPLICATION_TAG_UNSIGNED_INT}
|
||||
,
|
||||
{PROP_PROTOCOL_CONFORMANCE_CLASS, BACNET_APPLICATION_TAG_UNSIGNED_INT}
|
||||
,
|
||||
{PROP_PROTOCOL_SERVICES_SUPPORTED, BACNET_APPLICATION_TAG_BIT_STRING}
|
||||
,
|
||||
{PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED,
|
||||
BACNET_APPLICATION_TAG_BIT_STRING}
|
||||
,
|
||||
{PROP_MAX_APDU_LENGTH_ACCEPTED, BACNET_APPLICATION_TAG_UNSIGNED_INT}
|
||||
,
|
||||
{PROP_SEGMENTATION_SUPPORTED, BACNET_APPLICATION_TAG_ENUMERATED}
|
||||
,
|
||||
{PROP_APDU_TIMEOUT, BACNET_APPLICATION_TAG_UNSIGNED_INT}
|
||||
,
|
||||
{PROP_NUMBER_OF_APDU_RETRIES, BACNET_APPLICATION_TAG_UNSIGNED_INT}
|
||||
,
|
||||
{-1, -1}
|
||||
};
|
||||
|
||||
signed bacprop_tag_by_index_default(
|
||||
PROP_TAG_DATA *data_list,
|
||||
signed index,
|
||||
signed default_ret)
|
||||
signed bacprop_tag_by_index_default(PROP_TAG_DATA * data_list,
|
||||
signed index, signed default_ret)
|
||||
{
|
||||
signed pUnsigned = 0;
|
||||
signed pUnsigned = 0;
|
||||
|
||||
if (data_list)
|
||||
{
|
||||
while (data_list->prop_id != -1)
|
||||
{
|
||||
if (data_list->prop_id == index)
|
||||
{
|
||||
pUnsigned = data_list->tag_id;
|
||||
break;
|
||||
}
|
||||
data_list++;
|
||||
if (data_list) {
|
||||
while (data_list->prop_id != -1) {
|
||||
if (data_list->prop_id == index) {
|
||||
pUnsigned = data_list->tag_id;
|
||||
break;
|
||||
}
|
||||
data_list++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pUnsigned?pUnsigned:default_ret;
|
||||
return pUnsigned ? pUnsigned : default_ret;
|
||||
}
|
||||
|
||||
|
||||
signed bacprop_property_tag(BACNET_OBJECT_TYPE type, signed prop)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case OBJECT_DEVICE:
|
||||
return bacprop_tag_by_index_default(
|
||||
bacnet_object_device_property_tag_map,
|
||||
prop,
|
||||
-1);
|
||||
switch (type) {
|
||||
case OBJECT_DEVICE:
|
||||
return
|
||||
bacprop_tag_by_index_default
|
||||
(bacnet_object_device_property_tag_map, prop, -1);
|
||||
default:
|
||||
fprintf(stderr, "Unsupported object type");
|
||||
break;
|
||||
}
|
||||
fprintf(stderr, "Unsupported object type");
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
+8
-12
@@ -38,25 +38,21 @@
|
||||
#include <stdint.h>
|
||||
#include "bacenum.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
signed prop_id; /* index number that matches the text */
|
||||
signed tag_id; /* text pair - use NULL to end the list */
|
||||
typedef struct {
|
||||
signed prop_id; /* index number that matches the text */
|
||||
signed tag_id; /* text pair - use NULL to end the list */
|
||||
} PROP_TAG_DATA;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
signed bacprop_tag_by_index_default(
|
||||
PROP_TAG_DATA *data_list,
|
||||
signed index,
|
||||
signed default_ret);
|
||||
signed bacprop_tag_by_index_default(PROP_TAG_DATA * data_list,
|
||||
signed index, signed default_ret);
|
||||
|
||||
signed bacprop_property_tag(BACNET_OBJECT_TYPE type, signed prop);
|
||||
signed bacprop_property_tag(BACNET_OBJECT_TYPE type, signed prop);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
+413
-505
File diff suppressed because it is too large
Load Diff
+59
-81
@@ -42,122 +42,100 @@
|
||||
/* bit strings
|
||||
They could be as large as 256/8=32 octets */
|
||||
#define MAX_BITSTRING_BYTES 15
|
||||
typedef struct BACnet_Bit_String
|
||||
{
|
||||
uint8_t bits_used;
|
||||
uint8_t value[MAX_BITSTRING_BYTES];
|
||||
typedef struct BACnet_Bit_String {
|
||||
uint8_t bits_used;
|
||||
uint8_t value[MAX_BITSTRING_BYTES];
|
||||
} BACNET_BIT_STRING;
|
||||
|
||||
#define MAX_CHARACTER_STRING_BYTES (MAX_APDU-6)
|
||||
typedef struct BACnet_Character_String
|
||||
{
|
||||
size_t length;
|
||||
uint8_t encoding;
|
||||
/* limit - 6 octets is the most our tag and type could be */
|
||||
char value[MAX_CHARACTER_STRING_BYTES];
|
||||
typedef struct BACnet_Character_String {
|
||||
size_t length;
|
||||
uint8_t encoding;
|
||||
/* limit - 6 octets is the most our tag and type could be */
|
||||
char value[MAX_CHARACTER_STRING_BYTES];
|
||||
} BACNET_CHARACTER_STRING;
|
||||
|
||||
/* FIXME: convert the bacdcode library to use BACNET_OCTET_STRING
|
||||
for APDU buffer to prevent buffer overflows */
|
||||
typedef struct BACnet_Octet_String
|
||||
{
|
||||
size_t length;
|
||||
/* limit - 6 octets is the most our tag and type could be */
|
||||
uint8_t value[MAX_APDU-6];
|
||||
typedef struct BACnet_Octet_String {
|
||||
size_t length;
|
||||
/* limit - 6 octets is the most our tag and type could be */
|
||||
uint8_t value[MAX_APDU - 6];
|
||||
} BACNET_OCTET_STRING;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void bitstring_init(BACNET_BIT_STRING *bit_string);
|
||||
void bitstring_set_bit(BACNET_BIT_STRING *bit_string, uint8_t bit, bool value);
|
||||
bool bitstring_bit(BACNET_BIT_STRING *bit_string, uint8_t bit);
|
||||
uint8_t bitstring_bits_used(BACNET_BIT_STRING *bit_string);
|
||||
void bitstring_init(BACNET_BIT_STRING * bit_string);
|
||||
void bitstring_set_bit(BACNET_BIT_STRING * bit_string, uint8_t bit,
|
||||
bool value);
|
||||
bool bitstring_bit(BACNET_BIT_STRING * bit_string, uint8_t bit);
|
||||
uint8_t bitstring_bits_used(BACNET_BIT_STRING * bit_string);
|
||||
// returns the number of bytes that a bit string is using
|
||||
int bitstring_bytes_used(BACNET_BIT_STRING *bit_string);
|
||||
uint8_t bitstring_bits_capacity(BACNET_BIT_STRING *bit_string);
|
||||
int bitstring_bytes_used(BACNET_BIT_STRING * bit_string);
|
||||
uint8_t bitstring_bits_capacity(BACNET_BIT_STRING * bit_string);
|
||||
/* used for encoding and decoding from the APDU */
|
||||
uint8_t bitstring_octet(BACNET_BIT_STRING *bit_string, uint8_t octet_index);
|
||||
bool bitstring_set_octet(
|
||||
BACNET_BIT_STRING *bit_string,
|
||||
uint8_t index,
|
||||
uint8_t octet);
|
||||
bool bitstring_set_bits_used(
|
||||
BACNET_BIT_STRING *bit_string,
|
||||
uint8_t bytes_used,
|
||||
uint8_t unused_bits);
|
||||
uint8_t bitstring_octet(BACNET_BIT_STRING * bit_string,
|
||||
uint8_t octet_index);
|
||||
bool bitstring_set_octet(BACNET_BIT_STRING * bit_string, uint8_t index,
|
||||
uint8_t octet);
|
||||
bool bitstring_set_bits_used(BACNET_BIT_STRING * bit_string,
|
||||
uint8_t bytes_used, uint8_t unused_bits);
|
||||
|
||||
/* returns false if the string exceeds capacity
|
||||
initialize by using length=0 */
|
||||
bool characterstring_init(
|
||||
BACNET_CHARACTER_STRING *char_string,
|
||||
uint8_t encoding,
|
||||
char *value,
|
||||
size_t length);
|
||||
bool characterstring_init(BACNET_CHARACTER_STRING * char_string,
|
||||
uint8_t encoding, char *value, size_t length);
|
||||
/* used for ANSI C-Strings */
|
||||
bool characterstring_init_ansi(
|
||||
BACNET_CHARACTER_STRING *char_string,
|
||||
char *value);
|
||||
bool characterstring_copy(
|
||||
BACNET_CHARACTER_STRING *dest,
|
||||
BACNET_CHARACTER_STRING *src);
|
||||
bool characterstring_init_ansi(BACNET_CHARACTER_STRING * char_string,
|
||||
char *value);
|
||||
bool characterstring_copy(BACNET_CHARACTER_STRING * dest,
|
||||
BACNET_CHARACTER_STRING * src);
|
||||
/* returns true if the strings are the same length, encoding, value */
|
||||
bool characterstring_same(
|
||||
BACNET_CHARACTER_STRING *dest,
|
||||
BACNET_CHARACTER_STRING *src);
|
||||
bool characterstring_ansi_same(
|
||||
BACNET_CHARACTER_STRING *dest,
|
||||
const char *src);
|
||||
bool characterstring_same(BACNET_CHARACTER_STRING * dest,
|
||||
BACNET_CHARACTER_STRING * src);
|
||||
bool characterstring_ansi_same(BACNET_CHARACTER_STRING * dest,
|
||||
const char *src);
|
||||
/* returns false if the string exceeds capacity */
|
||||
bool characterstring_append(
|
||||
BACNET_CHARACTER_STRING *char_string,
|
||||
char *value,
|
||||
size_t length);
|
||||
bool characterstring_append(BACNET_CHARACTER_STRING * char_string,
|
||||
char *value, size_t length);
|
||||
/* This function sets a new length without changing the value.
|
||||
If length exceeds capacity, no modification happens and
|
||||
function returns false. */
|
||||
bool characterstring_truncate(
|
||||
BACNET_CHARACTER_STRING *char_string,
|
||||
size_t length);
|
||||
bool characterstring_set_encoding(
|
||||
BACNET_CHARACTER_STRING *char_string,
|
||||
uint8_t encoding);
|
||||
bool characterstring_truncate(BACNET_CHARACTER_STRING * char_string,
|
||||
size_t length);
|
||||
bool characterstring_set_encoding(BACNET_CHARACTER_STRING *
|
||||
char_string, uint8_t encoding);
|
||||
/* Returns the value */
|
||||
char *characterstring_value(BACNET_CHARACTER_STRING *char_string);
|
||||
char *characterstring_value(BACNET_CHARACTER_STRING * char_string);
|
||||
/* returns the length */
|
||||
size_t characterstring_length(BACNET_CHARACTER_STRING *char_string);
|
||||
uint8_t characterstring_encoding(BACNET_CHARACTER_STRING *char_string);
|
||||
size_t characterstring_capacity(BACNET_CHARACTER_STRING *char_string);
|
||||
size_t characterstring_length(BACNET_CHARACTER_STRING * char_string);
|
||||
uint8_t characterstring_encoding(BACNET_CHARACTER_STRING *
|
||||
char_string);
|
||||
size_t characterstring_capacity(BACNET_CHARACTER_STRING * char_string);
|
||||
|
||||
/* returns false if the string exceeds capacity
|
||||
initialize by using length=0 */
|
||||
bool octetstring_init(
|
||||
BACNET_OCTET_STRING *octet_string,
|
||||
uint8_t *value,
|
||||
size_t length);
|
||||
bool octetstring_copy(
|
||||
BACNET_OCTET_STRING *dest,
|
||||
BACNET_OCTET_STRING *src);
|
||||
bool octetstring_init(BACNET_OCTET_STRING * octet_string,
|
||||
uint8_t * value, size_t length);
|
||||
bool octetstring_copy(BACNET_OCTET_STRING * dest,
|
||||
BACNET_OCTET_STRING * src);
|
||||
/* returns false if the string exceeds capacity */
|
||||
bool octetstring_append(
|
||||
BACNET_OCTET_STRING *octet_string,
|
||||
uint8_t *value,
|
||||
size_t length);
|
||||
bool octetstring_append(BACNET_OCTET_STRING * octet_string,
|
||||
uint8_t * value, size_t length);
|
||||
/* This function sets a new length without changing the value.
|
||||
If length exceeds capacity, no modification happens and
|
||||
function returns false. */
|
||||
bool octetstring_truncate(
|
||||
BACNET_OCTET_STRING *octet_string,
|
||||
size_t length);
|
||||
bool octetstring_truncate(BACNET_OCTET_STRING * octet_string,
|
||||
size_t length);
|
||||
/* Returns the value */
|
||||
uint8_t *octetstring_value(BACNET_OCTET_STRING *octet_string);
|
||||
uint8_t *octetstring_value(BACNET_OCTET_STRING * octet_string);
|
||||
/* Returns the length.*/
|
||||
size_t octetstring_length(BACNET_OCTET_STRING *octet_string);
|
||||
size_t octetstring_capacity(BACNET_OCTET_STRING *octet_string);
|
||||
size_t octetstring_length(BACNET_OCTET_STRING * octet_string);
|
||||
size_t octetstring_capacity(BACNET_OCTET_STRING * octet_string);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
+1199
-678
File diff suppressed because it is too large
Load Diff
+21
-22
@@ -40,31 +40,30 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
const char *bactext_confirmed_service_name(int index);
|
||||
const char *bactext_unconfirmed_service_name(int index);
|
||||
const char *bactext_application_tag_name(int index);
|
||||
const char *bactext_object_type_name(int index);
|
||||
const char *bactext_property_name(int index);
|
||||
const char *bactext_engineering_unit_name(int index);
|
||||
const char *bactext_reject_reason_name(int index);
|
||||
const char *bactext_abort_reason_name(int index);
|
||||
const char *bactext_error_class_name(int index);
|
||||
const char *bactext_error_code_name(int index);
|
||||
unsigned bactext_property_id(const char* name);
|
||||
const char *bactext_month_name(int index);
|
||||
const char *bactext_week_of_month_name(int index);
|
||||
const char *bactext_day_of_week_name(int index);
|
||||
const char *bactext_event_state_name(int index);
|
||||
const char *bactext_binary_present_value_name(int index);
|
||||
const char *bactext_reliability_name(int index);
|
||||
const char *bactext_device_status_name(int index);
|
||||
const char *bactext_segmentation_name(int index);
|
||||
const char *bactext_confirmed_service_name(int index);
|
||||
const char *bactext_unconfirmed_service_name(int index);
|
||||
const char *bactext_application_tag_name(int index);
|
||||
const char *bactext_object_type_name(int index);
|
||||
const char *bactext_property_name(int index);
|
||||
const char *bactext_engineering_unit_name(int index);
|
||||
const char *bactext_reject_reason_name(int index);
|
||||
const char *bactext_abort_reason_name(int index);
|
||||
const char *bactext_error_class_name(int index);
|
||||
const char *bactext_error_code_name(int index);
|
||||
unsigned bactext_property_id(const char *name);
|
||||
const char *bactext_month_name(int index);
|
||||
const char *bactext_week_of_month_name(int index);
|
||||
const char *bactext_day_of_week_name(int index);
|
||||
const char *bactext_event_state_name(int index);
|
||||
const char *bactext_binary_present_value_name(int index);
|
||||
const char *bactext_reliability_name(int index);
|
||||
const char *bactext_device_status_name(int index);
|
||||
const char *bactext_segmentation_name(int index);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
// Big-Endian systems save the most significant byte first.
|
||||
// Sun and Motorola processors, IBM-370s and PDP-10s are big-endian.
|
||||
@@ -21,10 +21,9 @@ extern "C" {
|
||||
// x[2] = 0x03
|
||||
// x[3] = 0x04
|
||||
|
||||
int big_endian(void);
|
||||
int big_endian(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
+96
-118
@@ -36,7 +36,7 @@
|
||||
#include <stdbool.h> // for the standard bool type.
|
||||
#include "bacdcode.h"
|
||||
#include "bip.h"
|
||||
#include "net.h" // custom per port
|
||||
#include "net.h" // custom per port
|
||||
|
||||
static int BIP_Socket = -1;
|
||||
/* port to use - stored in host byte order */
|
||||
@@ -48,21 +48,21 @@ static struct in_addr BIP_Broadcast_Address;
|
||||
|
||||
void bip_set_socket(int sock_fd)
|
||||
{
|
||||
BIP_Socket = sock_fd;
|
||||
BIP_Socket = sock_fd;
|
||||
}
|
||||
|
||||
bool bip_valid(void)
|
||||
{
|
||||
return (BIP_Socket != -1);
|
||||
return (BIP_Socket != -1);
|
||||
}
|
||||
|
||||
void bip_cleanup(void)
|
||||
{
|
||||
if (bip_valid())
|
||||
close(BIP_Socket);
|
||||
BIP_Socket = -1;
|
||||
if (bip_valid())
|
||||
close(BIP_Socket);
|
||||
BIP_Socket = -1;
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
static void set_network_address(struct in_addr *net_address,
|
||||
@@ -71,32 +71,28 @@ static void set_network_address(struct in_addr *net_address,
|
||||
union {
|
||||
uint8_t byte[4];
|
||||
uint32_t value;
|
||||
} long_data = {{0}};
|
||||
} long_data = { {
|
||||
0}};
|
||||
|
||||
long_data.byte[0] = octet1;
|
||||
long_data.byte[1] = octet2;
|
||||
long_data.byte[2] = octet3;
|
||||
long_data.byte[3] = octet4;
|
||||
|
||||
|
||||
net_address->s_addr = long_data.value;
|
||||
}
|
||||
|
||||
void bip_set_address(
|
||||
uint8_t octet1,
|
||||
uint8_t octet2,
|
||||
uint8_t octet3,
|
||||
uint8_t octet4)
|
||||
void bip_set_address(uint8_t octet1,
|
||||
uint8_t octet2, uint8_t octet3, uint8_t octet4)
|
||||
{
|
||||
set_network_address(&BIP_Address, octet1, octet2, octet3, octet4);
|
||||
}
|
||||
|
||||
void bip_set_broadcast_address(
|
||||
uint8_t octet1,
|
||||
uint8_t octet2,
|
||||
uint8_t octet3,
|
||||
uint8_t octet4)
|
||||
void bip_set_broadcast_address(uint8_t octet1,
|
||||
uint8_t octet2, uint8_t octet3, uint8_t octet4)
|
||||
{
|
||||
set_network_address(&BIP_Broadcast_Address, octet1, octet2, octet3, octet4);
|
||||
set_network_address(&BIP_Broadcast_Address, octet1, octet2, octet3,
|
||||
octet4);
|
||||
}
|
||||
|
||||
// set using network byte order
|
||||
@@ -137,86 +133,81 @@ uint16_t bip_get_port(void)
|
||||
|
||||
/* 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
|
||||
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] = 0x81; /* BVLL for BACnet/IP */
|
||||
mtu[0] = 0x81; /* BVLL for BACnet/IP */
|
||||
if (bip_dest->sin_addr.s_addr == htonl(BIP_Broadcast_Address.s_addr))
|
||||
mtu[1] = 0x0B; /* Original-Broadcast-NPDU */
|
||||
mtu[1] = 0x0B; /* Original-Broadcast-NPDU */
|
||||
else
|
||||
mtu[1] = 0x0A; /* Original-Unicast-NPDU */
|
||||
mtu[1] = 0x0A; /* Original-Unicast-NPDU */
|
||||
mtu_len = 2;
|
||||
mtu_len += encode_unsigned16(&mtu[mtu_len], (uint16_t)(pdu_len + 4/*inclusive*/) );
|
||||
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));
|
||||
|
||||
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
|
||||
uint8_t *pdu, // any data to be sent - may be null
|
||||
unsigned pdu_len) // number of bytes of data
|
||||
int bip_send_pdu(BACNET_ADDRESS * dest, // destination address
|
||||
uint8_t * pdu, // any data to be sent - may be null
|
||||
unsigned pdu_len) // number of bytes of data
|
||||
{
|
||||
struct sockaddr_in bip_dest;
|
||||
|
||||
/* load destination IP address */
|
||||
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));
|
||||
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);
|
||||
}
|
||||
/* broadcast */
|
||||
else if (dest->mac_len == 0)
|
||||
{
|
||||
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);
|
||||
}
|
||||
else
|
||||
} 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
|
||||
pdu, // any data to be sent - may be null
|
||||
pdu_len); // number of bytes of data
|
||||
}
|
||||
|
||||
// receives a BACnet/IP packet
|
||||
// returns the number of octets in the PDU, or zero on failure
|
||||
uint16_t bip_receive(
|
||||
BACNET_ADDRESS *src, // source address
|
||||
uint8_t *pdu, // PDU data
|
||||
uint16_t max_pdu, // amount of space available in the PDU
|
||||
unsigned timeout) // number of milliseconds to wait for a packet
|
||||
uint16_t bip_receive(BACNET_ADDRESS * src, // source address
|
||||
uint8_t * pdu, // PDU data
|
||||
uint16_t max_pdu, // amount of space available in the PDU
|
||||
unsigned timeout) // number of milliseconds to wait for a packet
|
||||
{
|
||||
int received_bytes;
|
||||
uint8_t buf[MAX_MPDU] = {0}; // data
|
||||
uint16_t pdu_len = 0; // return value
|
||||
uint8_t buf[MAX_MPDU] = { 0 }; // data
|
||||
uint16_t pdu_len = 0; // return value
|
||||
fd_set read_fds;
|
||||
int max;
|
||||
struct timeval select_timeout;
|
||||
struct sockaddr_in sin = {-1};
|
||||
struct sockaddr_in sin = { -1 };
|
||||
socklen_t sin_len = sizeof(sin);
|
||||
|
||||
/* Make sure the socket is open */
|
||||
@@ -226,25 +217,22 @@ uint16_t bip_receive(
|
||||
/* we could just use a non-blocking socket, but that consumes all
|
||||
the CPU time. We can use a timeout; it is only supported as
|
||||
a select. */
|
||||
if (timeout >= 1000)
|
||||
{
|
||||
if (timeout >= 1000) {
|
||||
select_timeout.tv_sec = timeout / 1000;
|
||||
select_timeout.tv_usec =
|
||||
1000 * (timeout - select_timeout.tv_sec * 1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
select_timeout.tv_usec =
|
||||
1000 * (timeout - select_timeout.tv_sec * 1000);
|
||||
} else {
|
||||
select_timeout.tv_sec = 0;
|
||||
select_timeout.tv_usec = 1000 * timeout;
|
||||
}
|
||||
FD_ZERO(&read_fds);
|
||||
FD_SET((unsigned int)BIP_Socket, &read_fds);
|
||||
FD_SET((unsigned int) BIP_Socket, &read_fds);
|
||||
max = BIP_Socket;
|
||||
/* see if there is a packet for us */
|
||||
if (select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0)
|
||||
received_bytes = recvfrom(BIP_Socket,
|
||||
(char *)&buf[0], MAX_MPDU, 0,
|
||||
(struct sockaddr *)&sin, &sin_len);
|
||||
received_bytes = recvfrom(BIP_Socket,
|
||||
(char *) &buf[0], MAX_MPDU, 0,
|
||||
(struct sockaddr *) &sin, &sin_len);
|
||||
else
|
||||
return 0;
|
||||
|
||||
@@ -256,33 +244,29 @@ uint16_t bip_receive(
|
||||
/* no problem, just no bytes */
|
||||
if (received_bytes == 0)
|
||||
return 0;
|
||||
|
||||
|
||||
/* the signature of a BACnet/IP packet */
|
||||
if (buf[0] != 0x81)
|
||||
return 0;
|
||||
/* Original-Broadcast-NPDU or Original-Unicast-NPDU */
|
||||
if ((buf[1] == 0x0B) || (buf[1] == 0x0A))
|
||||
{
|
||||
if ((buf[1] == 0x0B) || (buf[1] == 0x0A)) {
|
||||
/* ignore messages from me */
|
||||
if (sin.sin_addr.s_addr == BIP_Address.s_addr)
|
||||
pdu_len = 0;
|
||||
else
|
||||
{
|
||||
else {
|
||||
/* copy the source address
|
||||
FIXME: IPv6? */
|
||||
FIXME: IPv6? */
|
||||
src->mac_len = 6;
|
||||
(void)encode_unsigned32(&src->mac[0],
|
||||
sin.sin_addr.s_addr);
|
||||
(void)encode_unsigned16(&src->mac[4],
|
||||
sin.sin_port);
|
||||
(void) encode_unsigned32(&src->mac[0], sin.sin_addr.s_addr);
|
||||
(void) encode_unsigned16(&src->mac[4], sin.sin_port);
|
||||
// FIXME: check destination address
|
||||
// see if it is broadcast or for us
|
||||
/* decode the length of the PDU - length is inclusive of BVLC */
|
||||
(void)decode_unsigned16(&buf[2],&pdu_len);
|
||||
(void) decode_unsigned16(&buf[2], &pdu_len);
|
||||
/* copy the buffer into the PDU */
|
||||
pdu_len -= 4; /* BVLC header */
|
||||
pdu_len -= 4; /* BVLC header */
|
||||
if (pdu_len < max_pdu)
|
||||
memmove(&pdu[0],&buf[4],pdu_len);
|
||||
memmove(&pdu[0], &buf[4], pdu_len);
|
||||
// ignore packets that are too large
|
||||
// clients should check my max-apdu first
|
||||
else
|
||||
@@ -293,46 +277,40 @@ uint16_t bip_receive(
|
||||
return pdu_len;
|
||||
}
|
||||
|
||||
void bip_get_my_address(BACNET_ADDRESS *my_address)
|
||||
void bip_get_my_address(BACNET_ADDRESS * my_address)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
my_address->mac_len = 6;
|
||||
(void)encode_unsigned32(&my_address->mac[0],
|
||||
htonl(BIP_Address.s_addr));
|
||||
(void)encode_unsigned16(&my_address->mac[4],
|
||||
htons(BIP_Port));
|
||||
my_address->net = 0; /* local only, no routing */
|
||||
my_address->len = 0; /* no SLEN */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++)
|
||||
{
|
||||
/* no SADR */
|
||||
my_address->adr[i] = 0;
|
||||
}
|
||||
int i = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void bip_get_broadcast_address(
|
||||
BACNET_ADDRESS *dest) // destination address
|
||||
{
|
||||
int i = 0; // counter
|
||||
|
||||
if (dest)
|
||||
{
|
||||
dest->mac_len = 6;
|
||||
(void)encode_unsigned32(&dest->mac[0],
|
||||
htonl(BIP_Broadcast_Address.s_addr));
|
||||
(void)encode_unsigned16(&dest->mac[4],
|
||||
htons(BIP_Port));
|
||||
dest->net = BACNET_BROADCAST_NETWORK;
|
||||
dest->len = 0; /* no SLEN */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++)
|
||||
{
|
||||
/* no SADR */
|
||||
dest->adr[i] = 0;
|
||||
my_address->mac_len = 6;
|
||||
(void) encode_unsigned32(&my_address->mac[0],
|
||||
htonl(BIP_Address.s_addr));
|
||||
(void) encode_unsigned16(&my_address->mac[4], htons(BIP_Port));
|
||||
my_address->net = 0; /* local only, no routing */
|
||||
my_address->len = 0; /* no SLEN */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
/* no SADR */
|
||||
my_address->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
void bip_get_broadcast_address(BACNET_ADDRESS * dest) // destination address
|
||||
{
|
||||
int i = 0; // counter
|
||||
|
||||
if (dest) {
|
||||
dest->mac_len = 6;
|
||||
(void) encode_unsigned32(&dest->mac[0],
|
||||
htonl(BIP_Broadcast_Address.s_addr));
|
||||
(void) encode_unsigned16(&dest->mac[4], htons(BIP_Port));
|
||||
dest->net = BACNET_BROADCAST_NETWORK;
|
||||
dest->len = 0; /* no SLEN */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
/* no SADR */
|
||||
dest->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
+27
-31
@@ -46,58 +46,54 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
// note: define init and cleanup in your ports section
|
||||
bool bip_init(void);
|
||||
bool bip_init(void);
|
||||
|
||||
// normal functions...
|
||||
void bip_cleanup(void);
|
||||
void bip_set_socket(int sock_fd);
|
||||
bool bip_valid(void);
|
||||
void bip_get_broadcast_address(
|
||||
BACNET_ADDRESS *dest); // destination address
|
||||
void bip_get_my_address(BACNET_ADDRESS *my_address);
|
||||
void bip_cleanup(void);
|
||||
void bip_set_socket(int sock_fd);
|
||||
bool bip_valid(void);
|
||||
void bip_get_broadcast_address(BACNET_ADDRESS * dest); // destination address
|
||||
void bip_get_my_address(BACNET_ADDRESS * my_address);
|
||||
|
||||
/* 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
|
||||
uint8_t *pdu, // any data to be sent - may be null
|
||||
unsigned pdu_len); // number of bytes of data
|
||||
int bip_send_pdu(BACNET_ADDRESS * dest, // destination address
|
||||
uint8_t * pdu, // any data to be sent - may be null
|
||||
unsigned pdu_len); // number of bytes of data
|
||||
|
||||
// receives a BACnet/IP packet
|
||||
// returns the number of octets in the PDU, or zero on failure
|
||||
uint16_t bip_receive(
|
||||
BACNET_ADDRESS *src, // source address
|
||||
uint8_t *pdu, // PDU data
|
||||
uint16_t max_pdu, // amount of space available in the PDU
|
||||
unsigned timeout); // milliseconds to wait for a packet
|
||||
uint16_t bip_receive(BACNET_ADDRESS * src, // source address
|
||||
uint8_t * pdu, // PDU data
|
||||
uint16_t max_pdu, // amount of space available in the PDU
|
||||
unsigned timeout); // milliseconds to wait for a packet
|
||||
|
||||
void bip_set_address(uint8_t octet1, uint8_t octet2,
|
||||
uint8_t octet3, uint8_t octet4);
|
||||
void bip_set_broadcast_address(uint8_t octet1, uint8_t octet2,
|
||||
uint8_t octet3, uint8_t octet4);
|
||||
|
||||
void bip_set_address(uint8_t octet1, uint8_t octet2,
|
||||
uint8_t octet3, uint8_t octet4);
|
||||
void bip_set_broadcast_address(uint8_t octet1, uint8_t octet2,
|
||||
uint8_t octet3, uint8_t octet4);
|
||||
|
||||
// use host byte order for setting
|
||||
void bip_set_port(uint16_t port);
|
||||
void bip_set_port(uint16_t port);
|
||||
// returns host byte order
|
||||
uint16_t bip_get_port(void);
|
||||
uint16_t bip_get_port(void);
|
||||
|
||||
// use network byte order for setting
|
||||
void bip_set_addr(uint32_t net_address);
|
||||
void bip_set_addr(uint32_t net_address);
|
||||
// returns host byte order
|
||||
uint32_t bip_get_addr(void);
|
||||
uint32_t bip_get_addr(void);
|
||||
|
||||
// use network byte order for setting
|
||||
void bip_set_broadcast_addr(uint32_t net_address);
|
||||
void bip_set_broadcast_addr(uint32_t net_address);
|
||||
// returns host byte order
|
||||
uint32_t bip_get_broadcast_addr(void);
|
||||
uint32_t bip_get_broadcast_addr(void);
|
||||
|
||||
void bip_set_interface(char *ifname);
|
||||
void bip_set_interface(char *ifname);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
+9
-10
@@ -7,11 +7,11 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef LO_NIB
|
||||
#define LO_NIB(b) ((b) & 0xF)
|
||||
#define LO_NIB(b) ((b) & 0xF)
|
||||
#endif
|
||||
|
||||
#ifndef HI_NIB
|
||||
#define HI_NIB(b) ((b) >> 4)
|
||||
#define HI_NIB(b) ((b) >> 4)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#ifndef LO_BYTE
|
||||
|
||||
#define LO_BYTE(w) ((uint8_t)(w))
|
||||
#define LO_BYTE(w) ((uint8_t)(w))
|
||||
|
||||
#endif
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
#ifndef HI_BYTE
|
||||
|
||||
#define HI_BYTE(w) ((uint8_t)((uint16_t)(w) >> 8))
|
||||
#define HI_BYTE(w) ((uint8_t)((uint16_t)(w) >> 8))
|
||||
|
||||
#endif
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
#ifndef LO_WORD
|
||||
|
||||
#define LO_WORD(x) ((uint16_t)(x))
|
||||
#define LO_WORD(x) ((uint16_t)(x))
|
||||
|
||||
#endif
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
#ifndef HI_WORD
|
||||
|
||||
#define HI_WORD(x) ((uint16_t)((uint32_t)(x) >> 16))
|
||||
#define HI_WORD(x) ((uint16_t)((uint32_t)(x) >> 16))
|
||||
|
||||
#endif
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
|
||||
#ifndef MAKE_WORD
|
||||
|
||||
#define MAKE_WORD(lo,hi) \
|
||||
#define MAKE_WORD(lo,hi) \
|
||||
((uint16_t)(((uint8_t)(lo))|(((uint16_t)((uint8_t)(hi)))<<8)))
|
||||
|
||||
#endif
|
||||
@@ -60,12 +60,11 @@
|
||||
|
||||
#ifndef MAKE_LONG
|
||||
|
||||
#define MAKE_LONG(lo,hi) \
|
||||
#define MAKE_LONG(lo,hi) \
|
||||
((uint32_t)(((uint16_t)(lo))|(((uint32_t)((uint16_t)(hi)))<<16)))
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif // end of header file
|
||||
|
||||
#endif // end of header file
|
||||
|
||||
+64
-64
@@ -43,17 +43,17 @@
|
||||
// Note: This function is copied directly from the BACnet standard.
|
||||
uint8_t CRC_Calc_Header(uint8_t dataValue, uint8_t crcValue)
|
||||
{
|
||||
uint16_t crc;
|
||||
uint16_t crc;
|
||||
|
||||
crc = crcValue ^ dataValue; /* XOR C7..C0 with D7..D0 */
|
||||
crc = crcValue ^ dataValue; /* XOR C7..C0 with D7..D0 */
|
||||
|
||||
/* Exclusive OR the terms in the table (top down) */
|
||||
crc = crc ^ (crc << 1) ^ (crc << 2) ^ (crc << 3)
|
||||
^ (crc << 4) ^ (crc << 5) ^ (crc << 6)
|
||||
^ (crc << 7);
|
||||
/* Exclusive OR the terms in the table (top down) */
|
||||
crc = crc ^ (crc << 1) ^ (crc << 2) ^ (crc << 3)
|
||||
^ (crc << 4) ^ (crc << 5) ^ (crc << 6)
|
||||
^ (crc << 7);
|
||||
|
||||
/* Combine bits shifted out left hand end */
|
||||
return (crc & 0xfe) ^ ((crc >> 8) & 1);
|
||||
/* Combine bits shifted out left hand end */
|
||||
return (crc & 0xfe) ^ ((crc >> 8) & 1);
|
||||
}
|
||||
|
||||
// Accumulate "dataValue" into the CRC in crcValue.
|
||||
@@ -63,14 +63,14 @@ uint8_t CRC_Calc_Header(uint8_t dataValue, uint8_t crcValue)
|
||||
// Note: This function is copied directly from the BACnet standard.
|
||||
uint16_t CRC_Calc_Data(uint8_t dataValue, uint16_t crcValue)
|
||||
{
|
||||
uint16_t crcLow;
|
||||
uint16_t crcLow;
|
||||
|
||||
crcLow = (crcValue & 0xff) ^ dataValue; /* XOR C7..C0 with D7..D0 */
|
||||
crcLow = (crcValue & 0xff) ^ dataValue; /* XOR C7..C0 with D7..D0 */
|
||||
|
||||
/* Exclusive OR the terms in the table (top down) */
|
||||
return (crcValue >>8) ^ (crcLow << 8) ^ (crcLow <<3)
|
||||
^ (crcLow <<12) ^ (crcLow >> 4)
|
||||
^ (crcLow & 0x0f) ^ ((crcLow & 0x0f) << 7);
|
||||
/* Exclusive OR the terms in the table (top down) */
|
||||
return (crcValue >> 8) ^ (crcLow << 8) ^ (crcLow << 3)
|
||||
^ (crcLow << 12) ^ (crcLow >> 4)
|
||||
^ (crcLow & 0x0f) ^ ((crcLow & 0x0f) << 7);
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
@@ -80,50 +80,50 @@ uint16_t CRC_Calc_Data(uint8_t dataValue, uint16_t crcValue)
|
||||
#include "bytes.h"
|
||||
|
||||
// test from Annex G 1.0 of BACnet Standard
|
||||
void testCRC8(Test* pTest)
|
||||
void testCRC8(Test * pTest)
|
||||
{
|
||||
uint8_t crc = 0xff; // accumulates the crc value
|
||||
uint8_t frame_crc; // appended to the end of the frame
|
||||
uint8_t crc = 0xff; // accumulates the crc value
|
||||
uint8_t frame_crc; // appended to the end of the frame
|
||||
|
||||
crc = CRC_Calc_Header(0x00,crc);
|
||||
ct_test(pTest,crc == 0x55);
|
||||
crc = CRC_Calc_Header(0x10,crc);
|
||||
ct_test(pTest,crc == 0xC2);
|
||||
crc = CRC_Calc_Header(0x05,crc);
|
||||
ct_test(pTest,crc == 0xBC);
|
||||
crc = CRC_Calc_Header(0x00,crc);
|
||||
ct_test(pTest,crc == 0x95);
|
||||
crc = CRC_Calc_Header(0x00,crc);
|
||||
ct_test(pTest,crc == 0x73);
|
||||
// send the ones complement of the CRC in place of
|
||||
// the CRC, and the resulting CRC will always equal 0x55.
|
||||
frame_crc = ~crc;
|
||||
ct_test(pTest,frame_crc == 0x8C);
|
||||
// use the ones complement value and the next to last CRC value
|
||||
crc = CRC_Calc_Header(frame_crc,crc);
|
||||
ct_test(pTest,crc == 0x55);
|
||||
crc = CRC_Calc_Header(0x00, crc);
|
||||
ct_test(pTest, crc == 0x55);
|
||||
crc = CRC_Calc_Header(0x10, crc);
|
||||
ct_test(pTest, crc == 0xC2);
|
||||
crc = CRC_Calc_Header(0x05, crc);
|
||||
ct_test(pTest, crc == 0xBC);
|
||||
crc = CRC_Calc_Header(0x00, crc);
|
||||
ct_test(pTest, crc == 0x95);
|
||||
crc = CRC_Calc_Header(0x00, crc);
|
||||
ct_test(pTest, crc == 0x73);
|
||||
// send the ones complement of the CRC in place of
|
||||
// the CRC, and the resulting CRC will always equal 0x55.
|
||||
frame_crc = ~crc;
|
||||
ct_test(pTest, frame_crc == 0x8C);
|
||||
// use the ones complement value and the next to last CRC value
|
||||
crc = CRC_Calc_Header(frame_crc, crc);
|
||||
ct_test(pTest, crc == 0x55);
|
||||
}
|
||||
|
||||
// test from Annex G 2.0 of BACnet Standard
|
||||
void testCRC16(Test* pTest)
|
||||
void testCRC16(Test * pTest)
|
||||
{
|
||||
uint16_t crc = 0xffff;
|
||||
uint16_t data_crc;
|
||||
uint16_t crc = 0xffff;
|
||||
uint16_t data_crc;
|
||||
|
||||
crc = CRC_Calc_Data(0x01,crc);
|
||||
ct_test(pTest,crc == 0x1E0E);
|
||||
crc = CRC_Calc_Data(0x22,crc);
|
||||
ct_test(pTest,crc == 0xEB70);
|
||||
crc = CRC_Calc_Data(0x30,crc);
|
||||
ct_test(pTest,crc == 0x42EF);
|
||||
// send the ones complement of the CRC in place of
|
||||
// the CRC, and the resulting CRC will always equal 0xF0B8.
|
||||
data_crc = ~crc;
|
||||
ct_test(pTest,data_crc == 0xBD10);
|
||||
crc = CRC_Calc_Data(LO_BYTE(data_crc),crc);
|
||||
ct_test(pTest,crc == 0x0F3A);
|
||||
crc = CRC_Calc_Data(HI_BYTE(data_crc),crc);
|
||||
ct_test(pTest,crc == 0xF0B8);
|
||||
crc = CRC_Calc_Data(0x01, crc);
|
||||
ct_test(pTest, crc == 0x1E0E);
|
||||
crc = CRC_Calc_Data(0x22, crc);
|
||||
ct_test(pTest, crc == 0xEB70);
|
||||
crc = CRC_Calc_Data(0x30, crc);
|
||||
ct_test(pTest, crc == 0x42EF);
|
||||
// send the ones complement of the CRC in place of
|
||||
// the CRC, and the resulting CRC will always equal 0xF0B8.
|
||||
data_crc = ~crc;
|
||||
ct_test(pTest, data_crc == 0xBD10);
|
||||
crc = CRC_Calc_Data(LO_BYTE(data_crc), crc);
|
||||
ct_test(pTest, crc == 0x0F3A);
|
||||
crc = CRC_Calc_Data(HI_BYTE(data_crc), crc);
|
||||
ct_test(pTest, crc == 0xF0B8);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -131,23 +131,23 @@ void testCRC16(Test* pTest)
|
||||
#ifdef TEST_CRC
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("crc", NULL);
|
||||
pTest = ct_create("crc", NULL);
|
||||
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testCRC8);
|
||||
assert(rc);
|
||||
rc = ct_addTestFunction(pTest, testCRC16);
|
||||
assert(rc);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testCRC8);
|
||||
assert(rc);
|
||||
rc = ct_addTestFunction(pTest, testCRC16);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void)ct_report(pTest);
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
|
||||
ct_destroy(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
+4
-5
@@ -40,13 +40,12 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
uint8_t CRC_Calc_Header(uint8_t dataValue, uint8_t crcValue);
|
||||
uint16_t CRC_Calc_Data(uint8_t dataValue, uint16_t crcValue);
|
||||
uint8_t CRC_Calc_Header(uint8_t dataValue, uint8_t crcValue);
|
||||
uint16_t CRC_Calc_Data(uint8_t dataValue, uint16_t crcValue);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
+37
-70
@@ -41,121 +41,88 @@
|
||||
// as part of the calls.
|
||||
|
||||
/* returns number of bytes sent on success, negative on failure */
|
||||
int datalink_send_pdu(
|
||||
BACNET_ADDRESS *dest, // destination address
|
||||
uint8_t *pdu, // any data to be sent - may be null
|
||||
unsigned pdu_len) // number of bytes of data
|
||||
int datalink_send_pdu(BACNET_ADDRESS * dest, // destination address
|
||||
uint8_t * pdu, // any data to be sent - may be null
|
||||
unsigned pdu_len) // number of bytes of data
|
||||
{
|
||||
#ifdef BACDL_ARCNET
|
||||
return arcnet_send_pdu(
|
||||
dest,
|
||||
pdu,
|
||||
pdu_len);
|
||||
return arcnet_send_pdu(dest, pdu, pdu_len);
|
||||
#endif
|
||||
#ifdef BACDL_MSTP
|
||||
return dlmstp_send_pdu(
|
||||
dest,
|
||||
pdu,
|
||||
pdu_len);
|
||||
return dlmstp_send_pdu(dest, pdu, pdu_len);
|
||||
#endif
|
||||
#ifdef BACDL_ETHERNET
|
||||
return ethernet_send_pdu(
|
||||
dest,
|
||||
pdu,
|
||||
pdu_len);
|
||||
return ethernet_send_pdu(dest, pdu, pdu_len);
|
||||
#endif
|
||||
#ifdef BACDL_BIP
|
||||
return bip_send_pdu(
|
||||
dest,
|
||||
pdu,
|
||||
pdu_len);
|
||||
return bip_send_pdu(dest, pdu, pdu_len);
|
||||
#endif
|
||||
}
|
||||
|
||||
// returns the number of octets in the PDU, or zero on failure
|
||||
uint16_t datalink_receive(
|
||||
BACNET_ADDRESS *src, // source address
|
||||
uint8_t *pdu, // PDU data
|
||||
uint16_t max_pdu, // amount of space available in the PDU
|
||||
unsigned timeout) // number of milliseconds to wait for a packet
|
||||
uint16_t datalink_receive(BACNET_ADDRESS * src, // source address
|
||||
uint8_t * pdu, // PDU data
|
||||
uint16_t max_pdu, // amount of space available in the PDU
|
||||
unsigned timeout) // number of milliseconds to wait for a packet
|
||||
{
|
||||
#ifdef BACDL_ARCNET
|
||||
return arcnet_receive(
|
||||
src,
|
||||
pdu,
|
||||
max_pdu,
|
||||
timeout);
|
||||
#endif
|
||||
#ifdef BACDL_MSTP
|
||||
return dlmstp_receive(
|
||||
src,
|
||||
pdu,
|
||||
max_pdu,
|
||||
timeout);
|
||||
#endif
|
||||
#ifdef BACDL_ETHERNET
|
||||
return ethernet_receive(
|
||||
src,
|
||||
pdu,
|
||||
max_pdu,
|
||||
timeout);
|
||||
#endif
|
||||
#ifdef BACDL_BIP
|
||||
return bip_receive(
|
||||
src,
|
||||
pdu,
|
||||
max_pdu,
|
||||
timeout);
|
||||
#endif
|
||||
#ifdef BACDL_ARCNET
|
||||
return arcnet_receive(src, pdu, max_pdu, timeout);
|
||||
#endif
|
||||
#ifdef BACDL_MSTP
|
||||
return dlmstp_receive(src, pdu, max_pdu, timeout);
|
||||
#endif
|
||||
#ifdef BACDL_ETHERNET
|
||||
return ethernet_receive(src, pdu, max_pdu, timeout);
|
||||
#endif
|
||||
#ifdef BACDL_BIP
|
||||
return bip_receive(src, pdu, max_pdu, timeout);
|
||||
#endif
|
||||
}
|
||||
|
||||
void datalink_cleanup(void)
|
||||
{
|
||||
#ifdef BACDL_ETHERNET
|
||||
ethernet_cleanup();
|
||||
ethernet_cleanup();
|
||||
#endif
|
||||
#ifdef BACDL_BIP
|
||||
bip_cleanup();
|
||||
bip_cleanup();
|
||||
#endif
|
||||
#ifdef BACDL_ARCNET
|
||||
arcnet_cleanup();
|
||||
arcnet_cleanup();
|
||||
#endif
|
||||
#ifdef BACDL_MSTP
|
||||
dlmstp_cleanup();
|
||||
dlmstp_cleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
void datalink_get_broadcast_address(
|
||||
BACNET_ADDRESS *dest) // destination address
|
||||
void datalink_get_broadcast_address(BACNET_ADDRESS * dest) // destination address
|
||||
{
|
||||
#ifdef BACDL_ARCNET
|
||||
arcnet_get_broadcast_address(dest);
|
||||
arcnet_get_broadcast_address(dest);
|
||||
#endif
|
||||
#ifdef BACDL_MSTP
|
||||
dlmstp_get_broadcast_address(dest);
|
||||
dlmstp_get_broadcast_address(dest);
|
||||
#endif
|
||||
#ifdef BACDL_ETHERNET
|
||||
ethernet_get_broadcast_address(dest);
|
||||
ethernet_get_broadcast_address(dest);
|
||||
#endif
|
||||
#ifdef BACDL_BIP
|
||||
bip_get_broadcast_address(dest);
|
||||
bip_get_broadcast_address(dest);
|
||||
#endif
|
||||
}
|
||||
|
||||
void datalink_get_my_address(
|
||||
BACNET_ADDRESS *my_address)
|
||||
void datalink_get_my_address(BACNET_ADDRESS * my_address)
|
||||
{
|
||||
#ifdef BACDL_ARCNET
|
||||
arcnet_get_my_address(my_address);
|
||||
arcnet_get_my_address(my_address);
|
||||
#endif
|
||||
#ifdef BACDL_MSTP
|
||||
dlmstp_get_my_address(my_address);
|
||||
dlmstp_get_my_address(my_address);
|
||||
#endif
|
||||
#ifdef BACDL_ETHERNET
|
||||
ethernet_get_my_address(my_address);
|
||||
ethernet_get_my_address(my_address);
|
||||
#endif
|
||||
#ifdef BACDL_BIP
|
||||
bip_get_my_address(my_address);
|
||||
bip_get_my_address(my_address);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+12
-17
@@ -57,31 +57,26 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* returns number of bytes sent on success, negative on failure */
|
||||
int datalink_send_pdu(
|
||||
BACNET_ADDRESS *dest, // destination address
|
||||
uint8_t *pdu, // any data to be sent - may be null
|
||||
unsigned pdu_len); // number of bytes of data
|
||||
int datalink_send_pdu(BACNET_ADDRESS * dest, // destination address
|
||||
uint8_t * pdu, // any data to be sent - may be null
|
||||
unsigned pdu_len); // number of bytes of data
|
||||
|
||||
// returns the number of octets in the PDU, or zero on failure
|
||||
uint16_t datalink_receive(
|
||||
BACNET_ADDRESS *src, // source address
|
||||
uint8_t *pdu, // PDU data
|
||||
uint16_t max_pdu, // amount of space available in the PDU
|
||||
unsigned timeout); // number of milliseconds to wait for a packet
|
||||
uint16_t datalink_receive(BACNET_ADDRESS * src, // source address
|
||||
uint8_t * pdu, // PDU data
|
||||
uint16_t max_pdu, // amount of space available in the PDU
|
||||
unsigned timeout); // number of milliseconds to wait for a packet
|
||||
|
||||
void datalink_cleanup(void);
|
||||
void datalink_cleanup(void);
|
||||
|
||||
void datalink_get_broadcast_address(
|
||||
BACNET_ADDRESS *dest); // destination address
|
||||
void datalink_get_broadcast_address(BACNET_ADDRESS * dest); // destination address
|
||||
|
||||
void datalink_get_my_address(
|
||||
BACNET_ADDRESS *my_address);
|
||||
void datalink_get_my_address(BACNET_ADDRESS * my_address);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
+168
-199
@@ -42,18 +42,18 @@
|
||||
/* note: time duration is given in Minutes, but in order to be accurate,
|
||||
we need to count down in seconds. */
|
||||
static uint32_t DCC_Time_Duration_Seconds = 0;
|
||||
static BACNET_COMMUNICATION_ENABLE_DISABLE DCC_Enable_Disable =
|
||||
COMMUNICATION_ENABLE;
|
||||
static BACNET_COMMUNICATION_ENABLE_DISABLE DCC_Enable_Disable =
|
||||
COMMUNICATION_ENABLE;
|
||||
/* password is optionally supported */
|
||||
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE dcc_enable_status(void)
|
||||
{
|
||||
return DCC_Enable_Disable;
|
||||
return DCC_Enable_Disable;
|
||||
}
|
||||
|
||||
bool dcc_communication_enabled(void)
|
||||
{
|
||||
return (DCC_Enable_Disable == COMMUNICATION_ENABLE);
|
||||
return (DCC_Enable_Disable == COMMUNICATION_ENABLE);
|
||||
}
|
||||
|
||||
/* When network communications are completely disabled,
|
||||
@@ -61,7 +61,7 @@ bool dcc_communication_enabled(void)
|
||||
shall be processed and no messages shall be initiated.*/
|
||||
bool dcc_communication_disabled(void)
|
||||
{
|
||||
return (DCC_Enable_Disable == COMMUNICATION_DISABLE);
|
||||
return (DCC_Enable_Disable == COMMUNICATION_DISABLE);
|
||||
}
|
||||
|
||||
/* When the initiation of communications is disabled,
|
||||
@@ -75,174 +75,159 @@ bool dcc_communication_disabled(void)
|
||||
the device is included in the address range. */
|
||||
bool dcc_communication_initiation_disabled(void)
|
||||
{
|
||||
return (DCC_Enable_Disable == COMMUNICATION_DISABLE_INITIATION);
|
||||
return (DCC_Enable_Disable == COMMUNICATION_DISABLE_INITIATION);
|
||||
}
|
||||
|
||||
uint32_t dcc_duration_seconds(void)
|
||||
{
|
||||
return DCC_Time_Duration_Seconds;
|
||||
return DCC_Time_Duration_Seconds;
|
||||
}
|
||||
|
||||
/* called every second or so. If more than one second,
|
||||
then seconds should be the number of seconds to tick away */
|
||||
void dcc_timer_seconds(uint32_t seconds)
|
||||
{
|
||||
if (DCC_Time_Duration_Seconds)
|
||||
{
|
||||
if (DCC_Time_Duration_Seconds > seconds)
|
||||
DCC_Time_Duration_Seconds -= seconds;
|
||||
else
|
||||
DCC_Time_Duration_Seconds = 0;
|
||||
/* just expired - do something */
|
||||
if (DCC_Time_Duration_Seconds == 0)
|
||||
DCC_Enable_Disable = COMMUNICATION_ENABLE;
|
||||
}
|
||||
if (DCC_Time_Duration_Seconds) {
|
||||
if (DCC_Time_Duration_Seconds > seconds)
|
||||
DCC_Time_Duration_Seconds -= seconds;
|
||||
else
|
||||
DCC_Time_Duration_Seconds = 0;
|
||||
/* just expired - do something */
|
||||
if (DCC_Time_Duration_Seconds == 0)
|
||||
DCC_Enable_Disable = COMMUNICATION_ENABLE;
|
||||
}
|
||||
}
|
||||
|
||||
bool dcc_set_status_duration(
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE status,
|
||||
uint16_t minutes)
|
||||
bool dcc_set_status_duration(BACNET_COMMUNICATION_ENABLE_DISABLE status,
|
||||
uint16_t minutes)
|
||||
{
|
||||
bool valid = false;
|
||||
bool valid = false;
|
||||
|
||||
/* valid? */
|
||||
if (status < MAX_BACNET_COMMUNICATION_ENABLE_DISABLE)
|
||||
{
|
||||
DCC_Enable_Disable = status;
|
||||
if (status == COMMUNICATION_ENABLE)
|
||||
DCC_Time_Duration_Seconds = 0;
|
||||
else
|
||||
DCC_Time_Duration_Seconds = minutes * 60;
|
||||
valid = true;
|
||||
}
|
||||
/* valid? */
|
||||
if (status < MAX_BACNET_COMMUNICATION_ENABLE_DISABLE) {
|
||||
DCC_Enable_Disable = status;
|
||||
if (status == COMMUNICATION_ENABLE)
|
||||
DCC_Time_Duration_Seconds = 0;
|
||||
else
|
||||
DCC_Time_Duration_Seconds = minutes * 60;
|
||||
valid = true;
|
||||
}
|
||||
|
||||
return valid;
|
||||
return valid;
|
||||
}
|
||||
|
||||
/* encode service */
|
||||
int dcc_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint8_t invoke_id,
|
||||
uint16_t timeDuration, /* 0=optional */
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE enable_disable,
|
||||
BACNET_CHARACTER_STRING *password) /* NULL=optional */
|
||||
{
|
||||
int len = 0; /* length of each encoding */
|
||||
int apdu_len = 0; /* total length of the apdu, return value */
|
||||
int dcc_encode_apdu(uint8_t * apdu, uint8_t invoke_id, uint16_t timeDuration, /* 0=optional */
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE enable_disable,
|
||||
BACNET_CHARACTER_STRING * password)
|
||||
{ /* NULL=optional */
|
||||
int len = 0; /* length of each encoding */
|
||||
int apdu_len = 0; /* total length of the apdu, return value */
|
||||
|
||||
if (apdu)
|
||||
{
|
||||
apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
|
||||
apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU);
|
||||
apdu[2] = invoke_id;
|
||||
apdu[3] = SERVICE_CONFIRMED_REINITIALIZE_DEVICE;
|
||||
apdu_len = 4;
|
||||
/* optional timeDuration */
|
||||
if (timeDuration)
|
||||
{
|
||||
len = encode_context_unsigned(&apdu[apdu_len], 0, timeDuration);
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
|
||||
apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU);
|
||||
apdu[2] = invoke_id;
|
||||
apdu[3] = SERVICE_CONFIRMED_REINITIALIZE_DEVICE;
|
||||
apdu_len = 4;
|
||||
/* optional timeDuration */
|
||||
if (timeDuration) {
|
||||
len =
|
||||
encode_context_unsigned(&apdu[apdu_len], 0, timeDuration);
|
||||
apdu_len += len;
|
||||
}
|
||||
/* enable disable */
|
||||
len =
|
||||
encode_context_enumerated(&apdu[apdu_len], 1, enable_disable);
|
||||
apdu_len += len;
|
||||
/* optional password */
|
||||
if (password) {
|
||||
/* FIXME: must be at least 1 character, limited to 20 characters */
|
||||
len =
|
||||
encode_context_character_string(&apdu[apdu_len], 2,
|
||||
password);
|
||||
apdu_len += len;
|
||||
}
|
||||
}
|
||||
/* enable disable */
|
||||
len = encode_context_enumerated(&apdu[apdu_len], 1, enable_disable);
|
||||
apdu_len += len;
|
||||
/* optional password */
|
||||
if (password)
|
||||
{
|
||||
/* FIXME: must be at least 1 character, limited to 20 characters */
|
||||
len = encode_context_character_string(&apdu[apdu_len], 2, password);
|
||||
apdu_len += len;
|
||||
}
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* decode the service request only */
|
||||
int dcc_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint16_t *timeDuration,
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE *enable_disable,
|
||||
BACNET_CHARACTER_STRING *password)
|
||||
int dcc_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint16_t * timeDuration,
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE * enable_disable,
|
||||
BACNET_CHARACTER_STRING * password)
|
||||
{
|
||||
unsigned len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value_type = 0;
|
||||
int value = 0;
|
||||
uint32_t value32 = 0;
|
||||
|
||||
/* check for value pointers */
|
||||
if (apdu_len)
|
||||
{
|
||||
/* Tag 0: timeDuration --optional-- */
|
||||
if (decode_is_context_tag(&apdu[len], 0))
|
||||
{
|
||||
len += decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value_type);
|
||||
len += decode_unsigned(&apdu[len], len_value_type, &value32);
|
||||
if (timeDuration)
|
||||
*timeDuration = value32;
|
||||
}
|
||||
else if (timeDuration)
|
||||
*timeDuration = 0;
|
||||
/* Tag 1: enable_disable */
|
||||
if (!decode_is_context_tag(&apdu[len], 1))
|
||||
return -1;
|
||||
len += decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += decode_enumerated(&apdu[len], len_value_type, &value);
|
||||
if (enable_disable)
|
||||
*enable_disable = value;
|
||||
/* Tag 2: password --optional-- */
|
||||
if (len < apdu_len)
|
||||
{
|
||||
if (!decode_is_context_tag(&apdu[len], 2))
|
||||
return -1;
|
||||
len += decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += decode_character_string(&apdu[len], len_value_type, password);
|
||||
}
|
||||
else if (password)
|
||||
characterstring_init_ansi(password,NULL);
|
||||
}
|
||||
unsigned len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value_type = 0;
|
||||
int value = 0;
|
||||
uint32_t value32 = 0;
|
||||
|
||||
return (int)len;
|
||||
/* check for value pointers */
|
||||
if (apdu_len) {
|
||||
/* Tag 0: timeDuration --optional-- */
|
||||
if (decode_is_context_tag(&apdu[len], 0)) {
|
||||
len += decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value_type);
|
||||
len += decode_unsigned(&apdu[len], len_value_type, &value32);
|
||||
if (timeDuration)
|
||||
*timeDuration = value32;
|
||||
} else if (timeDuration)
|
||||
*timeDuration = 0;
|
||||
/* Tag 1: enable_disable */
|
||||
if (!decode_is_context_tag(&apdu[len], 1))
|
||||
return -1;
|
||||
len += decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += decode_enumerated(&apdu[len], len_value_type, &value);
|
||||
if (enable_disable)
|
||||
*enable_disable = value;
|
||||
/* Tag 2: password --optional-- */
|
||||
if (len < apdu_len) {
|
||||
if (!decode_is_context_tag(&apdu[len], 2))
|
||||
return -1;
|
||||
len += decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len +=
|
||||
decode_character_string(&apdu[len], len_value_type,
|
||||
password);
|
||||
} else if (password)
|
||||
characterstring_init_ansi(password, NULL);
|
||||
}
|
||||
|
||||
return (int) len;
|
||||
}
|
||||
|
||||
int dcc_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
uint16_t *timeDuration,
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE *enable_disable,
|
||||
BACNET_CHARACTER_STRING *password)
|
||||
int dcc_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id,
|
||||
uint16_t * timeDuration,
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE * enable_disable,
|
||||
BACNET_CHARACTER_STRING * password)
|
||||
{
|
||||
int len = 0;
|
||||
unsigned offset = 0;
|
||||
int len = 0;
|
||||
unsigned offset = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
|
||||
return -1;
|
||||
// apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted());
|
||||
*invoke_id = apdu[2]; /* invoke id - filled in by net layer */
|
||||
if (apdu[3] != SERVICE_CONFIRMED_REINITIALIZE_DEVICE)
|
||||
return -1;
|
||||
offset = 4;
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
|
||||
return -1;
|
||||
// apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted());
|
||||
*invoke_id = apdu[2]; /* invoke id - filled in by net layer */
|
||||
if (apdu[3] != SERVICE_CONFIRMED_REINITIALIZE_DEVICE)
|
||||
return -1;
|
||||
offset = 4;
|
||||
|
||||
if (apdu_len > offset)
|
||||
{
|
||||
len = dcc_decode_service_request(
|
||||
&apdu[offset],
|
||||
apdu_len - offset,
|
||||
timeDuration,
|
||||
enable_disable,
|
||||
password);
|
||||
}
|
||||
if (apdu_len > offset) {
|
||||
len = dcc_decode_service_request(&apdu[offset],
|
||||
apdu_len - offset, timeDuration, enable_disable, password);
|
||||
}
|
||||
|
||||
return len;
|
||||
return len;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
@@ -250,71 +235,55 @@ int dcc_decode_apdu(
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
void test_DeviceCommunicationControlData(
|
||||
Test * pTest,
|
||||
uint8_t invoke_id,
|
||||
uint16_t timeDuration,
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE enable_disable,
|
||||
BACNET_CHARACTER_STRING *password)
|
||||
void test_DeviceCommunicationControlData(Test * pTest,
|
||||
uint8_t invoke_id,
|
||||
uint16_t timeDuration,
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE enable_disable,
|
||||
BACNET_CHARACTER_STRING * password)
|
||||
{
|
||||
uint8_t apdu[480] = {0};
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t test_invoke_id = 0;
|
||||
uint16_t test_timeDuration = 0;
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE test_enable_disable;
|
||||
BACNET_CHARACTER_STRING test_password;
|
||||
|
||||
len = dcc_encode_apdu(
|
||||
&apdu[0],
|
||||
invoke_id,
|
||||
timeDuration,
|
||||
enable_disable,
|
||||
password);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t test_invoke_id = 0;
|
||||
uint16_t test_timeDuration = 0;
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE test_enable_disable;
|
||||
BACNET_CHARACTER_STRING test_password;
|
||||
|
||||
len = dcc_decode_apdu(
|
||||
&apdu[0],
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_timeDuration,
|
||||
&test_enable_disable,
|
||||
&test_password);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
ct_test(pTest, test_timeDuration == timeDuration);
|
||||
ct_test(pTest, test_enable_disable == enable_disable);
|
||||
ct_test(pTest, characterstring_same(&test_password,password));
|
||||
len = dcc_encode_apdu(&apdu[0],
|
||||
invoke_id, timeDuration, enable_disable, password);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
|
||||
len = dcc_decode_apdu(&apdu[0],
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_timeDuration, &test_enable_disable, &test_password);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
ct_test(pTest, test_timeDuration == timeDuration);
|
||||
ct_test(pTest, test_enable_disable == enable_disable);
|
||||
ct_test(pTest, characterstring_same(&test_password, password));
|
||||
}
|
||||
|
||||
void test_DeviceCommunicationControl(Test * pTest)
|
||||
{
|
||||
uint8_t invoke_id = 128;
|
||||
uint16_t timeDuration = 0;
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE enable_disable;
|
||||
BACNET_CHARACTER_STRING password;
|
||||
uint8_t invoke_id = 128;
|
||||
uint16_t timeDuration = 0;
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE enable_disable;
|
||||
BACNET_CHARACTER_STRING password;
|
||||
|
||||
timeDuration = 0;
|
||||
enable_disable = COMMUNICATION_DISABLE_INITIATION;
|
||||
characterstring_init_ansi(&password,"John 3:16");
|
||||
test_DeviceCommunicationControlData(
|
||||
pTest,
|
||||
invoke_id,
|
||||
timeDuration,
|
||||
enable_disable,
|
||||
&password);
|
||||
timeDuration = 0;
|
||||
enable_disable = COMMUNICATION_DISABLE_INITIATION;
|
||||
characterstring_init_ansi(&password, "John 3:16");
|
||||
test_DeviceCommunicationControlData(pTest,
|
||||
invoke_id, timeDuration, enable_disable, &password);
|
||||
|
||||
timeDuration = 12345;
|
||||
enable_disable = COMMUNICATION_DISABLE;
|
||||
test_DeviceCommunicationControlData(
|
||||
pTest,
|
||||
invoke_id,
|
||||
timeDuration,
|
||||
enable_disable,
|
||||
NULL);
|
||||
timeDuration = 12345;
|
||||
enable_disable = COMMUNICATION_DISABLE;
|
||||
test_DeviceCommunicationControlData(pTest,
|
||||
invoke_id, timeDuration, enable_disable, NULL);
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_DEVICE_COMMUNICATION_CONTROL
|
||||
@@ -335,5 +304,5 @@ int main(void)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_DEVICE_COMMUNICATION_CONTROL */
|
||||
#endif /* TEST */
|
||||
#endif /* TEST_DEVICE_COMMUNICATION_CONTROL */
|
||||
#endif /* TEST */
|
||||
|
||||
+25
-34
@@ -41,55 +41,46 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* return the status */
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE dcc_enable_status(void);
|
||||
bool dcc_communication_enabled(void);
|
||||
bool dcc_communication_disabled(void);
|
||||
bool dcc_communication_initiation_disabled(void);
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE dcc_enable_status(void);
|
||||
bool dcc_communication_enabled(void);
|
||||
bool dcc_communication_disabled(void);
|
||||
bool dcc_communication_initiation_disabled(void);
|
||||
/* return the time */
|
||||
uint32_t dcc_duration_seconds(void);
|
||||
uint32_t dcc_duration_seconds(void);
|
||||
/* called every second or so. If more than one second,
|
||||
then seconds should be the number of seconds to tick away */
|
||||
void dcc_timer_seconds(uint32_t seconds);
|
||||
void dcc_timer_seconds(uint32_t seconds);
|
||||
/* setup the communication values */
|
||||
bool dcc_set_status_duration(
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE status,
|
||||
uint16_t minutes);
|
||||
bool dcc_set_status_duration(BACNET_COMMUNICATION_ENABLE_DISABLE
|
||||
status, uint16_t minutes);
|
||||
|
||||
// encode service
|
||||
int dcc_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint8_t invoke_id,
|
||||
uint16_t timeDuration, /* 0=optional */
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE enable_disable,
|
||||
BACNET_CHARACTER_STRING *password); /* NULL=optional */
|
||||
int dcc_encode_apdu(uint8_t * apdu, uint8_t invoke_id, uint16_t timeDuration, /* 0=optional */
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE enable_disable, BACNET_CHARACTER_STRING * password); /* NULL=optional */
|
||||
|
||||
// decode the service request only
|
||||
int dcc_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint16_t *timeDuration,
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE *enable_disable,
|
||||
BACNET_CHARACTER_STRING *password);
|
||||
|
||||
int dcc_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
uint16_t *timeDuration,
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE *enable_disable,
|
||||
BACNET_CHARACTER_STRING *password);
|
||||
int dcc_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint16_t * timeDuration,
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE * enable_disable,
|
||||
BACNET_CHARACTER_STRING * password);
|
||||
|
||||
int dcc_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id,
|
||||
uint16_t * timeDuration,
|
||||
BACNET_COMMUNICATION_ENABLE_DISABLE * enable_disable,
|
||||
BACNET_CHARACTER_STRING * password);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void test_DeviceCommunicationControl(Test * pTest);
|
||||
void test_DeviceCommunicationControl(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
|
||||
+25
-28
@@ -41,55 +41,52 @@
|
||||
|
||||
void dlmstp_init(void)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
void dlmstp_cleanup(void)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* returns number of bytes sent on success, negative on failure */
|
||||
int dlmstp_send_pdu(
|
||||
BACNET_ADDRESS *dest, // destination address
|
||||
uint8_t *pdu, // any data to be sent - may be null
|
||||
unsigned pdu_len) // number of bytes of data
|
||||
int dlmstp_send_pdu(BACNET_ADDRESS * dest, // destination address
|
||||
uint8_t * pdu, // any data to be sent - may be null
|
||||
unsigned pdu_len) // number of bytes of data
|
||||
{
|
||||
|
||||
(void)dest;
|
||||
(void)pdu;
|
||||
(void)pdu_len;
|
||||
(void) dest;
|
||||
(void) pdu;
|
||||
(void) pdu_len;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// returns the number of octets in the PDU, or zero on failure
|
||||
uint16_t dlmstp_receive(
|
||||
BACNET_ADDRESS *src, // source address
|
||||
uint8_t *pdu, // PDU data
|
||||
uint16_t max_pdu, // amount of space available in the PDU
|
||||
unsigned timeout) // milliseconds to wait for a packet
|
||||
uint16_t dlmstp_receive(BACNET_ADDRESS * src, // source address
|
||||
uint8_t * pdu, // PDU data
|
||||
uint16_t max_pdu, // amount of space available in the PDU
|
||||
unsigned timeout) // milliseconds to wait for a packet
|
||||
{
|
||||
(void)src;
|
||||
(void)pdu;
|
||||
(void)max_pdu;
|
||||
(void)timeout;
|
||||
|
||||
return 0;
|
||||
(void) src;
|
||||
(void) pdu;
|
||||
(void) max_pdu;
|
||||
(void) timeout;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dlmstp_set_my_address(BACNET_ADDRESS *my_address)
|
||||
void dlmstp_set_my_address(BACNET_ADDRESS * my_address)
|
||||
{
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
void dlmstp_get_my_address(BACNET_ADDRESS *my_address)
|
||||
void dlmstp_get_my_address(BACNET_ADDRESS * my_address)
|
||||
{
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
void dlmstp_get_broadcast_address(
|
||||
BACNET_ADDRESS *dest) // destination address
|
||||
void dlmstp_get_broadcast_address(BACNET_ADDRESS * dest) // destination address
|
||||
{
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
+14
-18
@@ -46,31 +46,27 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void dlmstp_init(void);
|
||||
void dlmstp_cleanup(void);
|
||||
void dlmstp_init(void);
|
||||
void dlmstp_cleanup(void);
|
||||
|
||||
/* returns number of bytes sent on success, negative on failure */
|
||||
int dlmstp_send_pdu(
|
||||
BACNET_ADDRESS *dest, // destination address
|
||||
uint8_t *pdu, // any data to be sent - may be null
|
||||
unsigned pdu_len); // number of bytes of data
|
||||
int dlmstp_send_pdu(BACNET_ADDRESS * dest, // destination address
|
||||
uint8_t * pdu, // any data to be sent - may be null
|
||||
unsigned pdu_len); // number of bytes of data
|
||||
|
||||
// returns the number of octets in the PDU, or zero on failure
|
||||
uint16_t dlmstp_receive(
|
||||
BACNET_ADDRESS *src, // source address
|
||||
uint8_t *pdu, // PDU data
|
||||
uint16_t max_pdu, // amount of space available in the PDU
|
||||
unsigned timeout); // milliseconds to wait for a packet
|
||||
uint16_t dlmstp_receive(BACNET_ADDRESS * src, // source address
|
||||
uint8_t * pdu, // PDU data
|
||||
uint16_t max_pdu, // amount of space available in the PDU
|
||||
unsigned timeout); // milliseconds to wait for a packet
|
||||
|
||||
void dlmstp_set_my_address(BACNET_ADDRESS *my_address);
|
||||
void dlmstp_get_my_address(BACNET_ADDRESS *my_address);
|
||||
void dlmstp_get_broadcast_address(
|
||||
BACNET_ADDRESS *dest); // destination address
|
||||
void dlmstp_set_my_address(BACNET_ADDRESS * my_address);
|
||||
void dlmstp_get_my_address(BACNET_ADDRESS * my_address);
|
||||
void dlmstp_get_broadcast_address(BACNET_ADDRESS * dest); // destination address
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
+19
-24
@@ -45,42 +45,37 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
bool ethernet_valid(void);
|
||||
void ethernet_cleanup(void);
|
||||
bool ethernet_init(char *interface_name);
|
||||
bool ethernet_valid(void);
|
||||
void ethernet_cleanup(void);
|
||||
bool ethernet_init(char *interface_name);
|
||||
|
||||
/* function to send a packet out the 802.2 socket */
|
||||
/* returns number of bytes sent on success, negative on failure */
|
||||
int ethernet_send(
|
||||
BACNET_ADDRESS *dest, // destination address
|
||||
BACNET_ADDRESS *src, // source address
|
||||
uint8_t *pdu, // any data to be sent - may be null
|
||||
unsigned pdu_len); // number of bytes of data
|
||||
int ethernet_send(BACNET_ADDRESS * dest, // destination address
|
||||
BACNET_ADDRESS * src, // source address
|
||||
uint8_t * pdu, // any data to be sent - may be null
|
||||
unsigned pdu_len); // number of bytes of data
|
||||
|
||||
/* function to send a packet out the 802.2 socket */
|
||||
/* returns number of bytes sent on success, negative on failure */
|
||||
int ethernet_send_pdu(
|
||||
BACNET_ADDRESS *dest, // destination address
|
||||
uint8_t *pdu, // any data to be sent - may be null
|
||||
unsigned pdu_len); // number of bytes of data
|
||||
int ethernet_send_pdu(BACNET_ADDRESS * dest, // destination address
|
||||
uint8_t * pdu, // any data to be sent - may be null
|
||||
unsigned pdu_len); // number of bytes of data
|
||||
|
||||
// receives an 802.2 framed packet
|
||||
// returns the number of octets in the PDU, or zero on failure
|
||||
uint16_t ethernet_receive(
|
||||
BACNET_ADDRESS *src, // source address
|
||||
uint8_t *pdu, // PDU data
|
||||
uint16_t max_pdu, // amount of space available in the PDU
|
||||
unsigned timeout); // milliseconds to wait for a packet
|
||||
uint16_t ethernet_receive(BACNET_ADDRESS * src, // source address
|
||||
uint8_t * pdu, // PDU data
|
||||
uint16_t max_pdu, // amount of space available in the PDU
|
||||
unsigned timeout); // milliseconds to wait for a packet
|
||||
|
||||
void ethernet_set_my_address(BACNET_ADDRESS *my_address);
|
||||
void ethernet_get_my_address(BACNET_ADDRESS *my_address);
|
||||
void ethernet_get_broadcast_address(
|
||||
BACNET_ADDRESS *dest); // destination address
|
||||
void ethernet_set_my_address(BACNET_ADDRESS * my_address);
|
||||
void ethernet_get_my_address(BACNET_ADDRESS * my_address);
|
||||
void ethernet_get_broadcast_address(BACNET_ADDRESS * dest); // destination address
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
+39
-41
@@ -36,20 +36,19 @@
|
||||
|
||||
char *filename_remove_path(const char *filename_in)
|
||||
{
|
||||
char *filename_out = NULL;
|
||||
char *filename_out = NULL;
|
||||
|
||||
/* allow the device ID to be set */
|
||||
if (filename_in)
|
||||
{
|
||||
filename_out = strrchr(filename_in,'\\');
|
||||
if (!filename_out)
|
||||
filename_out = strrchr(filename_in,'/');
|
||||
/* go beyond the slash */
|
||||
if (filename_out)
|
||||
filename_out++;
|
||||
}
|
||||
/* allow the device ID to be set */
|
||||
if (filename_in) {
|
||||
filename_out = strrchr(filename_in, '\\');
|
||||
if (!filename_out)
|
||||
filename_out = strrchr(filename_in, '/');
|
||||
/* go beyond the slash */
|
||||
if (filename_out)
|
||||
filename_out++;
|
||||
}
|
||||
|
||||
return filename_out;
|
||||
return filename_out;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
@@ -58,46 +57,45 @@ char *filename_remove_path(const char *filename_in)
|
||||
|
||||
#include "ctest.h"
|
||||
|
||||
void testFilename(Test* pTest)
|
||||
void testFilename(Test * pTest)
|
||||
{
|
||||
char *data1 = "c:\\Joshua\\run";
|
||||
char *data2 = "/home/Anna/run";
|
||||
char *data3 = "c:\\Program Files\\Christopher\\run.exe";
|
||||
char *data4 = "//Mary/data/run";
|
||||
char *filename = NULL;
|
||||
char *data1 = "c:\\Joshua\\run";
|
||||
char *data2 = "/home/Anna/run";
|
||||
char *data3 = "c:\\Program Files\\Christopher\\run.exe";
|
||||
char *data4 = "//Mary/data/run";
|
||||
char *filename = NULL;
|
||||
|
||||
filename = filename_remove_path(data1);
|
||||
ct_test(pTest,strcmp("run",filename) == 0);
|
||||
filename = filename_remove_path(data2);
|
||||
ct_test(pTest,strcmp("run",filename) == 0);
|
||||
filename = filename_remove_path(data3);
|
||||
ct_test(pTest,strcmp("run.exe",filename) == 0);
|
||||
filename = filename_remove_path(data4);
|
||||
ct_test(pTest,strcmp("run",filename) == 0);
|
||||
filename = filename_remove_path(data1);
|
||||
ct_test(pTest, strcmp("run", filename) == 0);
|
||||
filename = filename_remove_path(data2);
|
||||
ct_test(pTest, strcmp("run", filename) == 0);
|
||||
filename = filename_remove_path(data3);
|
||||
ct_test(pTest, strcmp("run.exe", filename) == 0);
|
||||
filename = filename_remove_path(data4);
|
||||
ct_test(pTest, strcmp("run", filename) == 0);
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_FILENAME
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("filename remove path", NULL);
|
||||
pTest = ct_create("filename remove path", NULL);
|
||||
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testFilename);
|
||||
assert(rc);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testFilename);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void)ct_report(pTest);
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
|
||||
ct_destroy(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_FILENAME */
|
||||
#endif /* TEST */
|
||||
|
||||
#endif /* TEST_FILENAME */
|
||||
#endif /* TEST */
|
||||
|
||||
@@ -36,12 +36,11 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
char *filename_remove_path(const char *filename_in);
|
||||
char *filename_remove_path(const char *filename_in);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
+158
-190
@@ -41,162 +41,141 @@
|
||||
#include "address.h"
|
||||
|
||||
// encode I-Am service
|
||||
int iam_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint32_t device_id,
|
||||
unsigned max_apdu,
|
||||
int segmentation,
|
||||
uint16_t vendor_id)
|
||||
int iam_encode_apdu(uint8_t * apdu,
|
||||
uint32_t device_id,
|
||||
unsigned max_apdu, int segmentation, uint16_t vendor_id)
|
||||
{
|
||||
int len = 0; // length of each encoding
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
int len = 0; // length of each encoding
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
|
||||
if (apdu) {
|
||||
apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST;
|
||||
apdu[1] = SERVICE_UNCONFIRMED_I_AM; // service choice
|
||||
apdu_len = 2;
|
||||
len = encode_tagged_object_id(
|
||||
&apdu[apdu_len],
|
||||
OBJECT_DEVICE,
|
||||
device_id);
|
||||
apdu_len += len;
|
||||
len = encode_tagged_unsigned(
|
||||
&apdu[apdu_len],
|
||||
max_apdu);
|
||||
apdu_len += len;
|
||||
len = encode_tagged_enumerated(
|
||||
&apdu[apdu_len],
|
||||
segmentation);
|
||||
apdu_len += len;
|
||||
len = encode_tagged_unsigned(
|
||||
&apdu[apdu_len],
|
||||
vendor_id);
|
||||
apdu_len += len;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
if (apdu) {
|
||||
apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST;
|
||||
apdu[1] = SERVICE_UNCONFIRMED_I_AM; // service choice
|
||||
apdu_len = 2;
|
||||
len = encode_tagged_object_id(&apdu[apdu_len],
|
||||
OBJECT_DEVICE, device_id);
|
||||
apdu_len += len;
|
||||
len = encode_tagged_unsigned(&apdu[apdu_len], max_apdu);
|
||||
apdu_len += len;
|
||||
len = encode_tagged_enumerated(&apdu[apdu_len], segmentation);
|
||||
apdu_len += len;
|
||||
len = encode_tagged_unsigned(&apdu[apdu_len], vendor_id);
|
||||
apdu_len += len;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
int iam_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
uint32_t *pDevice_id,
|
||||
unsigned *pMax_apdu,
|
||||
int *pSegmentation,
|
||||
uint16_t *pVendor_id)
|
||||
int iam_decode_service_request(uint8_t * apdu,
|
||||
uint32_t * pDevice_id,
|
||||
unsigned *pMax_apdu, int *pSegmentation, uint16_t * pVendor_id)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
int object_type = 0; // should be a Device Object
|
||||
uint32_t object_instance = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint32_t decoded_value = 0;
|
||||
int decoded_integer = 0;
|
||||
int len = 0;
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
int object_type = 0; // should be a Device Object
|
||||
uint32_t object_instance = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint32_t decoded_value = 0;
|
||||
int decoded_integer = 0;
|
||||
|
||||
// OBJECT ID - object id
|
||||
len = decode_tag_number_and_value(&apdu[apdu_len], &tag_number, &len_value);
|
||||
apdu_len += len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_OBJECT_ID)
|
||||
return -1;
|
||||
len = decode_object_id(&apdu[apdu_len], &object_type, &object_instance);
|
||||
apdu_len += len;
|
||||
if (object_type != OBJECT_DEVICE)
|
||||
return -1;
|
||||
if (pDevice_id)
|
||||
*pDevice_id = object_instance;
|
||||
// MAX APDU - unsigned
|
||||
len = decode_tag_number_and_value(&apdu[apdu_len], &tag_number, &len_value);
|
||||
apdu_len += len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT)
|
||||
return -1;
|
||||
len = decode_unsigned(&apdu[apdu_len], len_value, &decoded_value);
|
||||
apdu_len += len;
|
||||
if (pMax_apdu)
|
||||
*pMax_apdu = decoded_value;
|
||||
// Segmentation - enumerated
|
||||
len = decode_tag_number_and_value(&apdu[apdu_len], &tag_number, &len_value);
|
||||
apdu_len += len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_ENUMERATED)
|
||||
return -1;
|
||||
len = decode_enumerated(&apdu[apdu_len],len_value, &decoded_integer);
|
||||
apdu_len += len;
|
||||
if (decoded_integer >= MAX_BACNET_SEGMENTATION)
|
||||
return -1;
|
||||
if (pSegmentation)
|
||||
*pSegmentation = decoded_integer;
|
||||
// Vendor ID - unsigned16
|
||||
len = decode_tag_number_and_value(&apdu[apdu_len], &tag_number, &len_value);
|
||||
apdu_len += len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT)
|
||||
return -1;
|
||||
len = decode_unsigned(&apdu[apdu_len], len_value, &decoded_value);
|
||||
apdu_len += len;
|
||||
if (decoded_value > 0xFFFF)
|
||||
return -1;
|
||||
if (pVendor_id)
|
||||
*pVendor_id = (uint16_t)decoded_value;
|
||||
|
||||
return apdu_len;
|
||||
// OBJECT ID - object id
|
||||
len =
|
||||
decode_tag_number_and_value(&apdu[apdu_len], &tag_number,
|
||||
&len_value);
|
||||
apdu_len += len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_OBJECT_ID)
|
||||
return -1;
|
||||
len =
|
||||
decode_object_id(&apdu[apdu_len], &object_type, &object_instance);
|
||||
apdu_len += len;
|
||||
if (object_type != OBJECT_DEVICE)
|
||||
return -1;
|
||||
if (pDevice_id)
|
||||
*pDevice_id = object_instance;
|
||||
// MAX APDU - unsigned
|
||||
len =
|
||||
decode_tag_number_and_value(&apdu[apdu_len], &tag_number,
|
||||
&len_value);
|
||||
apdu_len += len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT)
|
||||
return -1;
|
||||
len = decode_unsigned(&apdu[apdu_len], len_value, &decoded_value);
|
||||
apdu_len += len;
|
||||
if (pMax_apdu)
|
||||
*pMax_apdu = decoded_value;
|
||||
// Segmentation - enumerated
|
||||
len =
|
||||
decode_tag_number_and_value(&apdu[apdu_len], &tag_number,
|
||||
&len_value);
|
||||
apdu_len += len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_ENUMERATED)
|
||||
return -1;
|
||||
len = decode_enumerated(&apdu[apdu_len], len_value, &decoded_integer);
|
||||
apdu_len += len;
|
||||
if (decoded_integer >= MAX_BACNET_SEGMENTATION)
|
||||
return -1;
|
||||
if (pSegmentation)
|
||||
*pSegmentation = decoded_integer;
|
||||
// Vendor ID - unsigned16
|
||||
len =
|
||||
decode_tag_number_and_value(&apdu[apdu_len], &tag_number,
|
||||
&len_value);
|
||||
apdu_len += len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT)
|
||||
return -1;
|
||||
len = decode_unsigned(&apdu[apdu_len], len_value, &decoded_value);
|
||||
apdu_len += len;
|
||||
if (decoded_value > 0xFFFF)
|
||||
return -1;
|
||||
if (pVendor_id)
|
||||
*pVendor_id = (uint16_t) decoded_value;
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
int iam_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint32_t *pDevice_id,
|
||||
unsigned *pMax_apdu,
|
||||
int *pSegmentation,
|
||||
uint16_t *pVendor_id)
|
||||
int iam_decode_apdu(uint8_t * apdu,
|
||||
uint32_t * pDevice_id,
|
||||
unsigned *pMax_apdu, int *pSegmentation, uint16_t * pVendor_id)
|
||||
{
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
|
||||
// valid data?
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu[0] != PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST)
|
||||
return -1;
|
||||
if (apdu[1] != SERVICE_UNCONFIRMED_I_AM)
|
||||
return -1;
|
||||
apdu_len = iam_decode_service_request(
|
||||
&apdu[2],
|
||||
pDevice_id,
|
||||
pMax_apdu,
|
||||
pSegmentation,
|
||||
pVendor_id);
|
||||
|
||||
return apdu_len;
|
||||
// valid data?
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu[0] != PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST)
|
||||
return -1;
|
||||
if (apdu[1] != SERVICE_UNCONFIRMED_I_AM)
|
||||
return -1;
|
||||
apdu_len = iam_decode_service_request(&apdu[2],
|
||||
pDevice_id, pMax_apdu, pSegmentation, pVendor_id);
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
int iam_send(uint8_t *buffer)
|
||||
int iam_send(uint8_t * buffer)
|
||||
{
|
||||
int pdu_len = 0;
|
||||
BACNET_ADDRESS dest;
|
||||
int bytes_sent = 0;
|
||||
int pdu_len = 0;
|
||||
BACNET_ADDRESS dest;
|
||||
int bytes_sent = 0;
|
||||
|
||||
// I-Am is a global broadcast
|
||||
datalink_get_broadcast_address(&dest);
|
||||
// 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 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],
|
||||
Device_Object_Instance_Number(),
|
||||
MAX_APDU,
|
||||
SEGMENTATION_NONE,
|
||||
Device_Vendor_Identifier());
|
||||
// encode the APDU portion of the packet
|
||||
pdu_len += iam_encode_apdu(&buffer[pdu_len],
|
||||
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
|
||||
|
||||
return bytes_sent;
|
||||
bytes_sent = datalink_send_pdu(&dest, // destination address
|
||||
&buffer[0], pdu_len); // number of bytes of data
|
||||
|
||||
return bytes_sent;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
@@ -206,83 +185,72 @@ int iam_send(uint8_t *buffer)
|
||||
|
||||
void testIAm(Test * pTest)
|
||||
{
|
||||
uint8_t apdu[480] = {0};
|
||||
int len = 0;
|
||||
uint32_t device_id = 42;
|
||||
unsigned max_apdu = 480;
|
||||
int segmentation = SEGMENTATION_NONE;
|
||||
uint16_t vendor_id = 42;
|
||||
uint32_t test_device_id = 0;
|
||||
unsigned test_max_apdu = 0;
|
||||
int test_segmentation = 0;
|
||||
uint16_t test_vendor_id = 0;
|
||||
|
||||
len = iam_encode_apdu(
|
||||
&apdu[0],
|
||||
device_id,
|
||||
max_apdu,
|
||||
segmentation,
|
||||
vendor_id);
|
||||
ct_test(pTest, len != 0);
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
uint32_t device_id = 42;
|
||||
unsigned max_apdu = 480;
|
||||
int segmentation = SEGMENTATION_NONE;
|
||||
uint16_t vendor_id = 42;
|
||||
uint32_t test_device_id = 0;
|
||||
unsigned test_max_apdu = 0;
|
||||
int test_segmentation = 0;
|
||||
uint16_t test_vendor_id = 0;
|
||||
|
||||
len = iam_decode_apdu(
|
||||
&apdu[0],
|
||||
&test_device_id,
|
||||
&test_max_apdu,
|
||||
&test_segmentation,
|
||||
&test_vendor_id);
|
||||
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_device_id == device_id);
|
||||
ct_test(pTest, test_vendor_id == vendor_id);
|
||||
ct_test(pTest, test_max_apdu == max_apdu);
|
||||
ct_test(pTest, test_segmentation == segmentation);
|
||||
len = iam_encode_apdu(&apdu[0],
|
||||
device_id, max_apdu, segmentation, vendor_id);
|
||||
ct_test(pTest, len != 0);
|
||||
|
||||
len = iam_decode_apdu(&apdu[0],
|
||||
&test_device_id,
|
||||
&test_max_apdu, &test_segmentation, &test_vendor_id);
|
||||
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_device_id == device_id);
|
||||
ct_test(pTest, test_vendor_id == vendor_id);
|
||||
ct_test(pTest, test_max_apdu == max_apdu);
|
||||
ct_test(pTest, test_segmentation == segmentation);
|
||||
}
|
||||
|
||||
#ifdef TEST_IAM
|
||||
// Dummy stubs to eliminate depencies
|
||||
void datalink_get_broadcast_address(
|
||||
BACNET_ADDRESS *dest) // destination address
|
||||
void datalink_get_broadcast_address(BACNET_ADDRESS * dest) // destination address
|
||||
{
|
||||
(void)dest;
|
||||
(void) dest;
|
||||
}
|
||||
|
||||
int datalink_send_pdu(
|
||||
BACNET_ADDRESS *dest, // destination address
|
||||
uint8_t *pdu, // any data to be sent - may be null
|
||||
unsigned pdu_len) // number of bytes of data
|
||||
int datalink_send_pdu(BACNET_ADDRESS * dest, // destination address
|
||||
uint8_t * pdu, // any data to be sent - may be null
|
||||
unsigned pdu_len) // number of bytes of data
|
||||
{
|
||||
(void)dest;
|
||||
(void)pdu;
|
||||
(void) dest;
|
||||
(void) pdu;
|
||||
|
||||
return pdu_len;
|
||||
return pdu_len;
|
||||
}
|
||||
|
||||
uint16_t Device_Vendor_Identifier(void)
|
||||
{
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t Device_Object_Instance_Number(void)
|
||||
{
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void address_add_binding(
|
||||
uint32_t device_id,
|
||||
unsigned max_apdu,
|
||||
BACNET_ADDRESS *src)
|
||||
void address_add_binding(uint32_t device_id,
|
||||
unsigned max_apdu, BACNET_ADDRESS * src)
|
||||
{
|
||||
(void)device_id;
|
||||
(void)max_apdu;
|
||||
(void)src;
|
||||
(void) device_id;
|
||||
(void) max_apdu;
|
||||
(void) src;
|
||||
}
|
||||
|
||||
// dummy for apdu dependency
|
||||
void tsm_free_invoke_id(uint8_t invokeID)
|
||||
{
|
||||
// dummy stub for testing
|
||||
(void)invokeID;
|
||||
// dummy stub for testing
|
||||
(void) invokeID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+15
-25
@@ -40,38 +40,28 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int iam_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint32_t device_id,
|
||||
unsigned max_apdu,
|
||||
int segmentation,
|
||||
uint16_t vendor_id);
|
||||
int iam_encode_apdu(uint8_t * apdu,
|
||||
uint32_t device_id,
|
||||
unsigned max_apdu, int segmentation, uint16_t vendor_id);
|
||||
|
||||
int iam_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
uint32_t *pDevice_id,
|
||||
unsigned *pMax_apdu,
|
||||
int *pSegmentation,
|
||||
uint16_t *pVendor_id);
|
||||
|
||||
int iam_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint32_t *pDevice_id,
|
||||
unsigned *pMax_apdu,
|
||||
int *pSegmentation,
|
||||
uint16_t *pVendor_id);
|
||||
|
||||
int iam_send(uint8_t *buffer);
|
||||
int iam_decode_service_request(uint8_t * apdu,
|
||||
uint32_t * pDevice_id,
|
||||
unsigned *pMax_apdu, int *pSegmentation, uint16_t * pVendor_id);
|
||||
|
||||
int iam_decode_apdu(uint8_t * apdu,
|
||||
uint32_t * pDevice_id,
|
||||
unsigned *pMax_apdu, int *pSegmentation, uint16_t * pVendor_id);
|
||||
|
||||
int iam_send(uint8_t * buffer);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testIAm(Test * pTest);
|
||||
void testIAm(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
+105
-135
@@ -37,108 +37,92 @@
|
||||
#include "bacdef.h"
|
||||
#include "ihave.h"
|
||||
|
||||
int ihave_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
BACNET_I_HAVE_DATA *data)
|
||||
int ihave_encode_apdu(uint8_t * apdu, BACNET_I_HAVE_DATA * data)
|
||||
{
|
||||
int len = 0; /* length of each encoding */
|
||||
int apdu_len = 0; /* total length of the apdu, return value */
|
||||
int len = 0; /* length of each encoding */
|
||||
int apdu_len = 0; /* total length of the apdu, return value */
|
||||
|
||||
if (apdu && data) {
|
||||
apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST;
|
||||
apdu[1] = SERVICE_UNCONFIRMED_I_HAVE;
|
||||
apdu_len = 2;
|
||||
/* deviceIdentifier */
|
||||
len = encode_tagged_object_id(
|
||||
&apdu[apdu_len],
|
||||
data->device_id.type,
|
||||
data->device_id.instance);
|
||||
apdu_len += len;
|
||||
/* objectIdentifier */
|
||||
len = encode_tagged_object_id(
|
||||
&apdu[apdu_len],
|
||||
data->object_id.type,
|
||||
data->object_id.instance);
|
||||
apdu_len += len;
|
||||
/* objectName */
|
||||
len = encode_tagged_character_string(
|
||||
&apdu[apdu_len],
|
||||
&data->object_name);
|
||||
apdu_len += len;
|
||||
}
|
||||
if (apdu && data) {
|
||||
apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST;
|
||||
apdu[1] = SERVICE_UNCONFIRMED_I_HAVE;
|
||||
apdu_len = 2;
|
||||
/* deviceIdentifier */
|
||||
len = encode_tagged_object_id(&apdu[apdu_len],
|
||||
data->device_id.type, data->device_id.instance);
|
||||
apdu_len += len;
|
||||
/* objectIdentifier */
|
||||
len = encode_tagged_object_id(&apdu[apdu_len],
|
||||
data->object_id.type, data->object_id.instance);
|
||||
apdu_len += len;
|
||||
/* objectName */
|
||||
len = encode_tagged_character_string(&apdu[apdu_len],
|
||||
&data->object_name);
|
||||
apdu_len += len;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* decode the service request only */
|
||||
int ihave_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_I_HAVE_DATA *data)
|
||||
int ihave_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_I_HAVE_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value = 0;
|
||||
int decoded_type = 0; /* for decoding */
|
||||
int len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value = 0;
|
||||
int decoded_type = 0; /* for decoding */
|
||||
|
||||
if (apdu_len && data)
|
||||
{
|
||||
/* deviceIdentifier */
|
||||
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value);
|
||||
if (tag_number == BACNET_APPLICATION_TAG_OBJECT_ID)
|
||||
{
|
||||
len += decode_object_id(&apdu[len], &decoded_type,
|
||||
&data->device_id.instance);
|
||||
data->device_id.type = decoded_type;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
/* objectIdentifier */
|
||||
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value);
|
||||
if (tag_number == BACNET_APPLICATION_TAG_OBJECT_ID)
|
||||
{
|
||||
len += decode_object_id(&apdu[len], &decoded_type,
|
||||
&data->object_id.instance);
|
||||
data->object_id.type = decoded_type;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
/* objectName */
|
||||
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value);
|
||||
if (tag_number == BACNET_APPLICATION_TAG_CHARACTER_STRING)
|
||||
{
|
||||
len += decode_character_string(&apdu[len], len_value,
|
||||
&data->object_name);
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
if (apdu_len && data) {
|
||||
/* deviceIdentifier */
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
if (tag_number == BACNET_APPLICATION_TAG_OBJECT_ID) {
|
||||
len += decode_object_id(&apdu[len], &decoded_type,
|
||||
&data->device_id.instance);
|
||||
data->device_id.type = decoded_type;
|
||||
} else
|
||||
return -1;
|
||||
/* objectIdentifier */
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
if (tag_number == BACNET_APPLICATION_TAG_OBJECT_ID) {
|
||||
len += decode_object_id(&apdu[len], &decoded_type,
|
||||
&data->object_id.instance);
|
||||
data->object_id.type = decoded_type;
|
||||
} else
|
||||
return -1;
|
||||
/* objectName */
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
if (tag_number == BACNET_APPLICATION_TAG_CHARACTER_STRING) {
|
||||
len += decode_character_string(&apdu[len], len_value,
|
||||
&data->object_name);
|
||||
} else
|
||||
return -1;
|
||||
} else
|
||||
return -1;
|
||||
|
||||
return len;
|
||||
return len;
|
||||
}
|
||||
|
||||
int ihave_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_I_HAVE_DATA *data)
|
||||
int ihave_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_I_HAVE_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
int len = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
/* optional checking - most likely was already done prior to this call */
|
||||
if (apdu[0] != PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST)
|
||||
return -1;
|
||||
if (apdu[1] != SERVICE_UNCONFIRMED_I_HAVE)
|
||||
return -1;
|
||||
len = ihave_decode_service_request(
|
||||
&apdu[2],
|
||||
apdu_len - 2,
|
||||
data);
|
||||
if (!apdu)
|
||||
return -1;
|
||||
/* optional checking - most likely was already done prior to this call */
|
||||
if (apdu[0] != PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST)
|
||||
return -1;
|
||||
if (apdu[1] != SERVICE_UNCONFIRMED_I_HAVE)
|
||||
return -1;
|
||||
len = ihave_decode_service_request(&apdu[2], apdu_len - 2, data);
|
||||
|
||||
return len;
|
||||
return len;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
@@ -146,62 +130,48 @@ int ihave_decode_apdu(
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
void testIHaveData(Test * pTest, BACNET_I_HAVE_DATA *data)
|
||||
void testIHaveData(Test * pTest, BACNET_I_HAVE_DATA * data)
|
||||
{
|
||||
uint8_t apdu[480] = {0};
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
BACNET_I_HAVE_DATA test_data;
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
BACNET_I_HAVE_DATA test_data;
|
||||
|
||||
len = ihave_encode_apdu(
|
||||
&apdu[0],
|
||||
data);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
len = ihave_encode_apdu(&apdu[0], data);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
|
||||
len = ihave_decode_apdu(
|
||||
&apdu[0],
|
||||
apdu_len,
|
||||
&test_data);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_data.device_id.type ==
|
||||
data->device_id.type);
|
||||
ct_test(pTest, test_data.device_id.instance ==
|
||||
data->device_id.instance);
|
||||
ct_test(pTest, test_data.object_id.type ==
|
||||
data->object_id.type);
|
||||
ct_test(pTest, test_data.object_id.instance ==
|
||||
data->object_id.instance);
|
||||
ct_test(pTest, characterstring_same(
|
||||
&test_data.object_name,&data->object_name));
|
||||
len = ihave_decode_apdu(&apdu[0], apdu_len, &test_data);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_data.device_id.type == data->device_id.type);
|
||||
ct_test(pTest, test_data.device_id.instance ==
|
||||
data->device_id.instance);
|
||||
ct_test(pTest, test_data.object_id.type == data->object_id.type);
|
||||
ct_test(pTest, test_data.object_id.instance ==
|
||||
data->object_id.instance);
|
||||
ct_test(pTest, characterstring_same(&test_data.object_name,
|
||||
&data->object_name));
|
||||
}
|
||||
|
||||
void testIHave(Test * pTest)
|
||||
{
|
||||
BACNET_I_HAVE_DATA data;
|
||||
BACNET_I_HAVE_DATA data;
|
||||
|
||||
characterstring_init_ansi(
|
||||
&data.object_name,"patricia");
|
||||
data.device_id.type = OBJECT_DEVICE;
|
||||
for (
|
||||
data.device_id.instance = 1;
|
||||
data.device_id.instance <= BACNET_MAX_INSTANCE;
|
||||
data.device_id.instance <<= 1)
|
||||
{
|
||||
for (
|
||||
data.object_id.type = OBJECT_ANALOG_INPUT;
|
||||
data.object_id.type <= MAX_BACNET_OBJECT_TYPE;
|
||||
data.object_id.type++)
|
||||
{
|
||||
for (
|
||||
data.object_id.instance = 1;
|
||||
data.object_id.instance <= BACNET_MAX_INSTANCE;
|
||||
data.object_id.instance <<= 1)
|
||||
{
|
||||
testIHaveData(pTest,&data);
|
||||
}
|
||||
characterstring_init_ansi(&data.object_name, "patricia");
|
||||
data.device_id.type = OBJECT_DEVICE;
|
||||
for (data.device_id.instance = 1;
|
||||
data.device_id.instance <= BACNET_MAX_INSTANCE;
|
||||
data.device_id.instance <<= 1) {
|
||||
for (data.object_id.type = OBJECT_ANALOG_INPUT;
|
||||
data.object_id.type <= MAX_BACNET_OBJECT_TYPE;
|
||||
data.object_id.type++) {
|
||||
for (data.object_id.instance = 1;
|
||||
data.object_id.instance <= BACNET_MAX_INSTANCE;
|
||||
data.object_id.instance <<= 1) {
|
||||
testIHaveData(pTest, &data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST_I_HAVE
|
||||
|
||||
+12
-21
@@ -38,39 +38,30 @@
|
||||
#include <stdbool.h>
|
||||
#include "bacstr.h"
|
||||
|
||||
typedef struct BACnet_I_Have_Data
|
||||
{
|
||||
BACNET_OBJECT_ID device_id;
|
||||
BACNET_OBJECT_ID object_id;
|
||||
BACNET_CHARACTER_STRING object_name;
|
||||
typedef struct BACnet_I_Have_Data {
|
||||
BACNET_OBJECT_ID device_id;
|
||||
BACNET_OBJECT_ID object_id;
|
||||
BACNET_CHARACTER_STRING object_name;
|
||||
} BACNET_I_HAVE_DATA;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int ihave_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
BACNET_I_HAVE_DATA *data);
|
||||
int ihave_encode_apdu(uint8_t * apdu, BACNET_I_HAVE_DATA * data);
|
||||
|
||||
int ihave_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_I_HAVE_DATA *data);
|
||||
int ihave_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_I_HAVE_DATA * data);
|
||||
|
||||
int ihave_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_I_HAVE_DATA *data);
|
||||
int ihave_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_I_HAVE_DATA * data);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testIHave(Test * pTest);
|
||||
void testIHave(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
|
||||
+123
-152
@@ -39,219 +39,190 @@
|
||||
#define strcasecmp stricmp
|
||||
#endif
|
||||
|
||||
bool indtext_by_string(
|
||||
INDTEXT_DATA *data_list,
|
||||
const char *search_name,
|
||||
unsigned *found_index)
|
||||
bool indtext_by_string(INDTEXT_DATA * data_list,
|
||||
const char *search_name, unsigned *found_index)
|
||||
{
|
||||
bool found = false;
|
||||
unsigned index = 0;
|
||||
bool found = false;
|
||||
unsigned index = 0;
|
||||
|
||||
if (data_list && search_name)
|
||||
{
|
||||
while (data_list->pString)
|
||||
{
|
||||
if (strcmp(data_list->pString,search_name) == 0)
|
||||
{
|
||||
index = data_list->index;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
data_list++;
|
||||
if (data_list && search_name) {
|
||||
while (data_list->pString) {
|
||||
if (strcmp(data_list->pString, search_name) == 0) {
|
||||
index = data_list->index;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
data_list++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found && found_index)
|
||||
*found_index = index;
|
||||
if (found && found_index)
|
||||
*found_index = index;
|
||||
|
||||
return found;
|
||||
return found;
|
||||
}
|
||||
|
||||
/* case insensitive version */
|
||||
bool indtext_by_istring(
|
||||
INDTEXT_DATA *data_list,
|
||||
const char *search_name,
|
||||
unsigned *found_index)
|
||||
bool indtext_by_istring(INDTEXT_DATA * data_list,
|
||||
const char *search_name, unsigned *found_index)
|
||||
{
|
||||
bool found = false;
|
||||
unsigned index = 0;
|
||||
bool found = false;
|
||||
unsigned index = 0;
|
||||
|
||||
if (data_list && search_name)
|
||||
{
|
||||
while (data_list->pString)
|
||||
{
|
||||
if (strcasecmp(data_list->pString,search_name) == 0)
|
||||
{
|
||||
index = data_list->index;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
data_list++;
|
||||
if (data_list && search_name) {
|
||||
while (data_list->pString) {
|
||||
if (strcasecmp(data_list->pString, search_name) == 0) {
|
||||
index = data_list->index;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
data_list++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found && found_index)
|
||||
*found_index = index;
|
||||
if (found && found_index)
|
||||
*found_index = index;
|
||||
|
||||
return found;
|
||||
return found;
|
||||
}
|
||||
|
||||
unsigned indtext_by_string_default(
|
||||
INDTEXT_DATA *data_list,
|
||||
const char *search_name,
|
||||
unsigned default_index)
|
||||
unsigned indtext_by_string_default(INDTEXT_DATA * data_list,
|
||||
const char *search_name, unsigned default_index)
|
||||
{
|
||||
unsigned index = 0;
|
||||
unsigned index = 0;
|
||||
|
||||
if (!indtext_by_string(data_list,search_name,&index))
|
||||
index = default_index;
|
||||
if (!indtext_by_string(data_list, search_name, &index))
|
||||
index = default_index;
|
||||
|
||||
return index;
|
||||
return index;
|
||||
}
|
||||
|
||||
unsigned indtext_by_istring_default(
|
||||
INDTEXT_DATA *data_list,
|
||||
const char *search_name,
|
||||
unsigned default_index)
|
||||
unsigned indtext_by_istring_default(INDTEXT_DATA * data_list,
|
||||
const char *search_name, unsigned default_index)
|
||||
{
|
||||
unsigned index = 0;
|
||||
unsigned index = 0;
|
||||
|
||||
if (!indtext_by_istring(data_list,search_name,&index))
|
||||
index = default_index;
|
||||
if (!indtext_by_istring(data_list, search_name, &index))
|
||||
index = default_index;
|
||||
|
||||
return index;
|
||||
return index;
|
||||
}
|
||||
|
||||
const char *indtext_by_index_default(
|
||||
INDTEXT_DATA *data_list,
|
||||
unsigned index,
|
||||
const char *default_string)
|
||||
const char *indtext_by_index_default(INDTEXT_DATA * data_list,
|
||||
unsigned index, const char *default_string)
|
||||
{
|
||||
const char *pString = NULL;
|
||||
const char *pString = NULL;
|
||||
|
||||
if (data_list)
|
||||
{
|
||||
while (data_list->pString)
|
||||
{
|
||||
if (data_list->index == index)
|
||||
{
|
||||
pString = data_list->pString;
|
||||
break;
|
||||
}
|
||||
data_list++;
|
||||
if (data_list) {
|
||||
while (data_list->pString) {
|
||||
if (data_list->index == index) {
|
||||
pString = data_list->pString;
|
||||
break;
|
||||
}
|
||||
data_list++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pString?pString:default_string;
|
||||
return pString ? pString : default_string;
|
||||
}
|
||||
|
||||
const char *indtext_by_index_split_default(
|
||||
INDTEXT_DATA *data_list,
|
||||
int index,
|
||||
int split_index,
|
||||
const char *before_split_default_name,
|
||||
const char *default_name)
|
||||
const char *indtext_by_index_split_default(INDTEXT_DATA * data_list,
|
||||
int index,
|
||||
int split_index,
|
||||
const char *before_split_default_name, const char *default_name)
|
||||
{
|
||||
if (index < split_index)
|
||||
return indtext_by_index_default(data_list, index, before_split_default_name);
|
||||
else
|
||||
return indtext_by_index_default(data_list, index, default_name);
|
||||
if (index < split_index)
|
||||
return indtext_by_index_default(data_list, index,
|
||||
before_split_default_name);
|
||||
else
|
||||
return indtext_by_index_default(data_list, index, default_name);
|
||||
};
|
||||
|
||||
|
||||
const char *indtext_by_index(
|
||||
INDTEXT_DATA *data_list,
|
||||
unsigned index)
|
||||
const char *indtext_by_index(INDTEXT_DATA * data_list, unsigned index)
|
||||
{
|
||||
return indtext_by_index_default(
|
||||
data_list,
|
||||
index,
|
||||
NULL);
|
||||
return indtext_by_index_default(data_list, index, NULL);
|
||||
}
|
||||
|
||||
unsigned indtext_count(
|
||||
INDTEXT_DATA *data_list)
|
||||
unsigned indtext_count(INDTEXT_DATA * data_list)
|
||||
{
|
||||
unsigned count = 0; /* return value */
|
||||
unsigned count = 0; /* return value */
|
||||
|
||||
if (data_list)
|
||||
{
|
||||
while (data_list->pString)
|
||||
{
|
||||
count++;
|
||||
data_list++;
|
||||
if (data_list) {
|
||||
while (data_list->pString) {
|
||||
count++;
|
||||
data_list++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
return count;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include "ctest.h"
|
||||
|
||||
static INDTEXT_DATA data_list[] =
|
||||
{
|
||||
{1, "Joshua"},
|
||||
{2, "Mary"},
|
||||
{3, "Anna"},
|
||||
{4, "Christopher"},
|
||||
{5, "Patricia"},
|
||||
{0, NULL}
|
||||
static INDTEXT_DATA data_list[] = {
|
||||
{1, "Joshua"},
|
||||
{2, "Mary"},
|
||||
{3, "Anna"},
|
||||
{4, "Christopher"},
|
||||
{5, "Patricia"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
void testIndexText(Test* pTest)
|
||||
void testIndexText(Test * pTest)
|
||||
{
|
||||
unsigned i; /*counter */
|
||||
const char *pString;
|
||||
unsigned index;
|
||||
bool valid;
|
||||
unsigned count = 0;
|
||||
unsigned i; /*counter */
|
||||
const char *pString;
|
||||
unsigned index;
|
||||
bool valid;
|
||||
unsigned count = 0;
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
pString = indtext_by_index(data_list,i);
|
||||
if (pString)
|
||||
{
|
||||
count++;
|
||||
valid = indtext_by_string(data_list,pString,&index);
|
||||
ct_test(pTest,valid == true);
|
||||
ct_test(pTest,index == i);
|
||||
ct_test(pTest,index == indtext_by_string_default(data_list,pString,index));
|
||||
for (i = 0; i < 10; i++) {
|
||||
pString = indtext_by_index(data_list, i);
|
||||
if (pString) {
|
||||
count++;
|
||||
valid = indtext_by_string(data_list, pString, &index);
|
||||
ct_test(pTest, valid == true);
|
||||
ct_test(pTest, index == i);
|
||||
ct_test(pTest, index == indtext_by_string_default(data_list,
|
||||
pString, index));
|
||||
}
|
||||
}
|
||||
}
|
||||
ct_test(pTest,indtext_count(data_list) == count);
|
||||
ct_test(pTest,indtext_by_string(data_list,"Harry",NULL) == false);
|
||||
ct_test(pTest,indtext_by_string(data_list,NULL,NULL) == false);
|
||||
ct_test(pTest,indtext_by_string(NULL,NULL,NULL) == false);
|
||||
ct_test(pTest,indtext_by_index(data_list,0) == NULL);
|
||||
ct_test(pTest,indtext_by_index(data_list,10) == NULL);
|
||||
ct_test(pTest,indtext_by_index(NULL,10) == NULL);
|
||||
/* case insensitive versions */
|
||||
ct_test(pTest,indtext_by_istring(data_list,"JOSHUA",NULL) == true);
|
||||
ct_test(pTest,indtext_by_istring(data_list,"joshua",NULL) == true);
|
||||
valid = indtext_by_istring(data_list,"ANNA",&index);
|
||||
ct_test(pTest,index == indtext_by_istring_default(data_list,"ANNA",index));
|
||||
ct_test(pTest, indtext_count(data_list) == count);
|
||||
ct_test(pTest, indtext_by_string(data_list, "Harry", NULL) == false);
|
||||
ct_test(pTest, indtext_by_string(data_list, NULL, NULL) == false);
|
||||
ct_test(pTest, indtext_by_string(NULL, NULL, NULL) == false);
|
||||
ct_test(pTest, indtext_by_index(data_list, 0) == NULL);
|
||||
ct_test(pTest, indtext_by_index(data_list, 10) == NULL);
|
||||
ct_test(pTest, indtext_by_index(NULL, 10) == NULL);
|
||||
/* case insensitive versions */
|
||||
ct_test(pTest, indtext_by_istring(data_list, "JOSHUA", NULL) == true);
|
||||
ct_test(pTest, indtext_by_istring(data_list, "joshua", NULL) == true);
|
||||
valid = indtext_by_istring(data_list, "ANNA", &index);
|
||||
ct_test(pTest, index == indtext_by_istring_default(data_list, "ANNA",
|
||||
index));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TEST_INDEX_TEXT
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("index text", NULL);
|
||||
pTest = ct_create("index text", NULL);
|
||||
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testIndexText);
|
||||
assert(rc);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testIndexText);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void)ct_report(pTest);
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
|
||||
ct_destroy(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_INDEX_TEXT */
|
||||
#endif /* TEST_INDEX_TEXT */
|
||||
|
||||
+23
-40
@@ -39,74 +39,57 @@
|
||||
#include <string.h>
|
||||
|
||||
/* index and text pairs */
|
||||
typedef struct
|
||||
{
|
||||
unsigned index; /* index number that matches the text */
|
||||
const char *pString; /* text pair - use NULL to end the list */
|
||||
typedef struct {
|
||||
unsigned index; /* index number that matches the text */
|
||||
const char *pString; /* text pair - use NULL to end the list */
|
||||
} INDTEXT_DATA;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* Searches for a matching string and returns the index to the string
|
||||
in the parameter found_index.
|
||||
If the string is not found, false is returned
|
||||
If the string is found, true is returned and the found_index contains
|
||||
the first index where the string was found. */
|
||||
bool indtext_by_string(
|
||||
INDTEXT_DATA *data_list,
|
||||
const char *search_name,
|
||||
unsigned *found_index);
|
||||
bool indtext_by_string(INDTEXT_DATA * data_list,
|
||||
const char *search_name, unsigned *found_index);
|
||||
/* case insensitive version */
|
||||
bool indtext_by_istring(
|
||||
INDTEXT_DATA *data_list,
|
||||
const char *search_name,
|
||||
unsigned *found_index);
|
||||
bool indtext_by_istring(INDTEXT_DATA * data_list,
|
||||
const char *search_name, unsigned *found_index);
|
||||
/* Searches for a matching string and returns the index to the string
|
||||
or the default_index if the string is not found. */
|
||||
unsigned indtext_by_string_default(
|
||||
INDTEXT_DATA *data_list,
|
||||
const char *search_name,
|
||||
unsigned default_index);
|
||||
unsigned indtext_by_string_default(INDTEXT_DATA * data_list,
|
||||
const char *search_name, unsigned default_index);
|
||||
/* case insensitive version */
|
||||
unsigned indtext_by_istring_default(
|
||||
INDTEXT_DATA *data_list,
|
||||
const char *search_name,
|
||||
unsigned default_index);
|
||||
unsigned indtext_by_istring_default(INDTEXT_DATA * data_list,
|
||||
const char *search_name, unsigned default_index);
|
||||
/* for a given index, return the matching string,
|
||||
or NULL if not found */
|
||||
const char *indtext_by_index(
|
||||
INDTEXT_DATA *data_list,
|
||||
unsigned index);
|
||||
const char *indtext_by_index(INDTEXT_DATA * data_list, unsigned index);
|
||||
/* for a given index, return the matching string,
|
||||
or default_name if not found */
|
||||
const char *indtext_by_index_default(
|
||||
INDTEXT_DATA *data_list,
|
||||
unsigned index,
|
||||
const char *default_name);
|
||||
const char *indtext_by_index_default(INDTEXT_DATA * data_list,
|
||||
unsigned index, const char *default_name);
|
||||
/* for a given index, return the matching string,
|
||||
or default_name if not found.
|
||||
if the index is before the split,
|
||||
the before_split_default_name is used */
|
||||
const char *indtext_by_index_split_default(
|
||||
INDTEXT_DATA *data_list,
|
||||
int index,
|
||||
int split_index,
|
||||
const char *before_split_default_name,
|
||||
const char *default_name);
|
||||
const char *indtext_by_index_split_default(INDTEXT_DATA * data_list,
|
||||
int index,
|
||||
int split_index,
|
||||
const char *before_split_default_name, const char *default_name);
|
||||
|
||||
/* returns the number of elements in the list */
|
||||
unsigned indtext_count(
|
||||
INDTEXT_DATA *data_list);
|
||||
unsigned indtext_count(INDTEXT_DATA * data_list);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testIndexText(Test* pTest);
|
||||
#include "ctest.h"
|
||||
void testIndexText(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
+15
-16
@@ -43,23 +43,22 @@
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct mstp_port_struct_t mstp_port; // port data
|
||||
uint8_t my_mac = 0x05; // local MAC address
|
||||
struct mstp_port_struct_t mstp_port; // port data
|
||||
uint8_t my_mac = 0x05; // local MAC address
|
||||
|
||||
MSTP_Init(&mstp_port,my_mac);
|
||||
MSTP_Init(&mstp_port, my_mac);
|
||||
|
||||
// loop forever
|
||||
for (;;)
|
||||
{
|
||||
// input
|
||||
RS485_Check_UART_Data(&mstp_port);
|
||||
MSTP_Receive_Frame_FSM(&mstp_port);
|
||||
// process
|
||||
// loop forever
|
||||
for (;;) {
|
||||
// input
|
||||
RS485_Check_UART_Data(&mstp_port);
|
||||
MSTP_Receive_Frame_FSM(&mstp_port);
|
||||
// process
|
||||
|
||||
// output
|
||||
MSTP_Master_Node_FSM(&mstp_port);
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
// output
|
||||
MSTP_Master_Node_FSM(&mstp_port);
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+1317
-1435
File diff suppressed because it is too large
Load Diff
+124
-126
@@ -66,134 +66,131 @@
|
||||
#define FRAME_TYPE_PROPRIETARY_MAX 255
|
||||
|
||||
// receive FSM states
|
||||
typedef enum
|
||||
{
|
||||
MSTP_RECEIVE_STATE_IDLE,
|
||||
MSTP_RECEIVE_STATE_PREAMBLE,
|
||||
MSTP_RECEIVE_STATE_HEADER,
|
||||
MSTP_RECEIVE_STATE_HEADER_CRC,
|
||||
MSTP_RECEIVE_STATE_DATA,
|
||||
MSTP_RECEIVE_STATE_DATA_CRC
|
||||
typedef enum {
|
||||
MSTP_RECEIVE_STATE_IDLE,
|
||||
MSTP_RECEIVE_STATE_PREAMBLE,
|
||||
MSTP_RECEIVE_STATE_HEADER,
|
||||
MSTP_RECEIVE_STATE_HEADER_CRC,
|
||||
MSTP_RECEIVE_STATE_DATA,
|
||||
MSTP_RECEIVE_STATE_DATA_CRC
|
||||
} MSTP_RECEIVE_STATE;
|
||||
|
||||
// master node FSM states
|
||||
typedef enum
|
||||
{
|
||||
MSTP_MASTER_STATE_INITIALIZE,
|
||||
MSTP_MASTER_STATE_IDLE,
|
||||
MSTP_MASTER_STATE_USE_TOKEN,
|
||||
MSTP_MASTER_STATE_WAIT_FOR_REPLY,
|
||||
MSTP_MASTER_STATE_DONE_WITH_TOKEN,
|
||||
MSTP_MASTER_STATE_PASS_TOKEN,
|
||||
MSTP_MASTER_STATE_NO_TOKEN,
|
||||
MSTP_MASTER_STATE_POLL_FOR_MASTER,
|
||||
MSTP_MASTER_STATE_ANSWER_DATA_REQUEST
|
||||
typedef enum {
|
||||
MSTP_MASTER_STATE_INITIALIZE,
|
||||
MSTP_MASTER_STATE_IDLE,
|
||||
MSTP_MASTER_STATE_USE_TOKEN,
|
||||
MSTP_MASTER_STATE_WAIT_FOR_REPLY,
|
||||
MSTP_MASTER_STATE_DONE_WITH_TOKEN,
|
||||
MSTP_MASTER_STATE_PASS_TOKEN,
|
||||
MSTP_MASTER_STATE_NO_TOKEN,
|
||||
MSTP_MASTER_STATE_POLL_FOR_MASTER,
|
||||
MSTP_MASTER_STATE_ANSWER_DATA_REQUEST
|
||||
} MSTP_MASTER_STATE;
|
||||
|
||||
struct mstp_port_struct_t
|
||||
{
|
||||
MSTP_RECEIVE_STATE receive_state;
|
||||
// When a master node is powered up or reset,
|
||||
// it shall unconditionally enter the INITIALIZE state.
|
||||
MSTP_MASTER_STATE master_state;
|
||||
// A Boolean flag set to TRUE by the Receive State Machine
|
||||
// if an error is detected during the reception of a frame.
|
||||
// Set to FALSE by the main state machine.
|
||||
unsigned ReceiveError:1;
|
||||
// There is data in the buffer
|
||||
unsigned DataAvailable:1;
|
||||
unsigned FramingError:1; // TRUE if we got a framing error
|
||||
unsigned ReceivedInvalidFrame:1;
|
||||
// A Boolean flag set to TRUE by the Receive State Machine
|
||||
// if a valid frame is received.
|
||||
// Set to FALSE by the main state machine.
|
||||
unsigned ReceivedValidFrame:1;
|
||||
// A Boolean flag set to TRUE by the master machine if this node is the
|
||||
// only known master node.
|
||||
unsigned SoleMaster:1;
|
||||
// After receiving a frame this value will be TRUE until Tturnaround
|
||||
// has expired
|
||||
unsigned Turn_Around_Waiting:1;
|
||||
// stores the latest received data
|
||||
uint8_t DataRegister;
|
||||
// Used to accumulate the CRC on the data field of a frame.
|
||||
uint16_t DataCRC;
|
||||
// Used to store the data length of a received frame.
|
||||
unsigned DataLength;
|
||||
// Used to store the destination address of a received frame.
|
||||
uint8_t DestinationAddress;
|
||||
// Used to count the number of received octets or errors.
|
||||
// This is used in the detection of link activity.
|
||||
unsigned EventCount;
|
||||
// Used to store the frame type of a received frame.
|
||||
uint8_t FrameType;
|
||||
// The number of frames sent by this node during a single token hold.
|
||||
// When this counter reaches the value Nmax_info_frames, the node must
|
||||
// pass the token.
|
||||
unsigned FrameCount;
|
||||
// Used to accumulate the CRC on the header of a frame.
|
||||
uint8_t HeaderCRC;
|
||||
// Used as an index by the Receive State Machine, up to a maximum value of
|
||||
// InputBufferSize.
|
||||
unsigned Index;
|
||||
// An array of octets, used to store octets as they are received.
|
||||
// InputBuffer is indexed from 0 to InputBufferSize-1.
|
||||
// The maximum size of a frame is 501 octets.
|
||||
uint8_t InputBuffer[MAX_MPDU];
|
||||
// "Next Station," the MAC address of the node to which This Station passes
|
||||
// the token. If the Next_Station is unknown, Next_Station shall be equal to
|
||||
// This_Station.
|
||||
uint8_t Next_Station;
|
||||
// "Poll Station," the MAC address of the node to which This Station last
|
||||
// sent a Poll For Master. This is used during token maintenance.
|
||||
uint8_t Poll_Station;
|
||||
// A counter of transmission retries used for Token and Poll For Master
|
||||
// transmission.
|
||||
unsigned RetryCount;
|
||||
// A timer with nominal 5 millisecond resolution used to measure and
|
||||
// generate silence on the medium between octets. It is incremented by a
|
||||
// timer process and is cleared by the Receive State Machine when activity
|
||||
// is detected and by the SendFrame procedure as each octet is transmitted.
|
||||
// Since the timer resolution is limited and the timer is not necessarily
|
||||
// synchronized to other machine events, a timer value of N will actually
|
||||
// denote intervals between N-1 and N
|
||||
unsigned SilenceTimer;
|
||||
struct mstp_port_struct_t {
|
||||
MSTP_RECEIVE_STATE receive_state;
|
||||
// When a master node is powered up or reset,
|
||||
// it shall unconditionally enter the INITIALIZE state.
|
||||
MSTP_MASTER_STATE master_state;
|
||||
// A Boolean flag set to TRUE by the Receive State Machine
|
||||
// if an error is detected during the reception of a frame.
|
||||
// Set to FALSE by the main state machine.
|
||||
unsigned ReceiveError:1;
|
||||
// There is data in the buffer
|
||||
unsigned DataAvailable:1;
|
||||
unsigned FramingError:1; // TRUE if we got a framing error
|
||||
unsigned ReceivedInvalidFrame:1;
|
||||
// A Boolean flag set to TRUE by the Receive State Machine
|
||||
// if a valid frame is received.
|
||||
// Set to FALSE by the main state machine.
|
||||
unsigned ReceivedValidFrame:1;
|
||||
// A Boolean flag set to TRUE by the master machine if this node is the
|
||||
// only known master node.
|
||||
unsigned SoleMaster:1;
|
||||
// After receiving a frame this value will be TRUE until Tturnaround
|
||||
// has expired
|
||||
unsigned Turn_Around_Waiting:1;
|
||||
// stores the latest received data
|
||||
uint8_t DataRegister;
|
||||
// Used to accumulate the CRC on the data field of a frame.
|
||||
uint16_t DataCRC;
|
||||
// Used to store the data length of a received frame.
|
||||
unsigned DataLength;
|
||||
// Used to store the destination address of a received frame.
|
||||
uint8_t DestinationAddress;
|
||||
// Used to count the number of received octets or errors.
|
||||
// This is used in the detection of link activity.
|
||||
unsigned EventCount;
|
||||
// Used to store the frame type of a received frame.
|
||||
uint8_t FrameType;
|
||||
// The number of frames sent by this node during a single token hold.
|
||||
// When this counter reaches the value Nmax_info_frames, the node must
|
||||
// pass the token.
|
||||
unsigned FrameCount;
|
||||
// Used to accumulate the CRC on the header of a frame.
|
||||
uint8_t HeaderCRC;
|
||||
// Used as an index by the Receive State Machine, up to a maximum value of
|
||||
// InputBufferSize.
|
||||
unsigned Index;
|
||||
// An array of octets, used to store octets as they are received.
|
||||
// InputBuffer is indexed from 0 to InputBufferSize-1.
|
||||
// The maximum size of a frame is 501 octets.
|
||||
uint8_t InputBuffer[MAX_MPDU];
|
||||
// "Next Station," the MAC address of the node to which This Station passes
|
||||
// the token. If the Next_Station is unknown, Next_Station shall be equal to
|
||||
// This_Station.
|
||||
uint8_t Next_Station;
|
||||
// "Poll Station," the MAC address of the node to which This Station last
|
||||
// sent a Poll For Master. This is used during token maintenance.
|
||||
uint8_t Poll_Station;
|
||||
// A counter of transmission retries used for Token and Poll For Master
|
||||
// transmission.
|
||||
unsigned RetryCount;
|
||||
// A timer with nominal 5 millisecond resolution used to measure and
|
||||
// generate silence on the medium between octets. It is incremented by a
|
||||
// timer process and is cleared by the Receive State Machine when activity
|
||||
// is detected and by the SendFrame procedure as each octet is transmitted.
|
||||
// Since the timer resolution is limited and the timer is not necessarily
|
||||
// synchronized to other machine events, a timer value of N will actually
|
||||
// denote intervals between N-1 and N
|
||||
unsigned SilenceTimer;
|
||||
|
||||
// A timer used to measure and generate Reply Postponed frames. It is
|
||||
// incremented by a timer process and is cleared by the Master Node State
|
||||
// Machine when a Data Expecting Reply Answer activity is completed.
|
||||
unsigned ReplyPostponedTimer;
|
||||
// A timer used to measure and generate Reply Postponed frames. It is
|
||||
// incremented by a timer process and is cleared by the Master Node State
|
||||
// Machine when a Data Expecting Reply Answer activity is completed.
|
||||
unsigned ReplyPostponedTimer;
|
||||
|
||||
// Used to store the Source Address of a received frame.
|
||||
uint8_t SourceAddress;
|
||||
// Used to store the Source Address of a received frame.
|
||||
uint8_t SourceAddress;
|
||||
|
||||
// The number of tokens received by this node. When this counter reaches the
|
||||
// value Npoll, the node polls the address range between TS and NS for
|
||||
// additional master nodes. TokenCount is set to zero at the end of the
|
||||
// polling process.
|
||||
unsigned TokenCount;
|
||||
// The number of tokens received by this node. When this counter reaches the
|
||||
// value Npoll, the node polls the address range between TS and NS for
|
||||
// additional master nodes. TokenCount is set to zero at the end of the
|
||||
// polling process.
|
||||
unsigned TokenCount;
|
||||
|
||||
// "This Station," the MAC address of this node. TS is generally read from a
|
||||
// hardware DIP switch, or from nonvolatile memory. Valid values for TS are
|
||||
// 0 to 254. The value 255 is used to denote broadcast when used as a
|
||||
// destination address but is not allowed as a value for TS.
|
||||
uint8_t This_Station;
|
||||
// "This Station," the MAC address of this node. TS is generally read from a
|
||||
// hardware DIP switch, or from nonvolatile memory. Valid values for TS are
|
||||
// 0 to 254. The value 255 is used to denote broadcast when used as a
|
||||
// destination address but is not allowed as a value for TS.
|
||||
uint8_t This_Station;
|
||||
|
||||
// This parameter represents the value of the Max_Info_Frames property of
|
||||
// the node's Device object. The value of Max_Info_Frames specifies the
|
||||
// maximum number of information frames the node may send before it must
|
||||
// pass the token. Max_Info_Frames may have different values on different
|
||||
// nodes. This may be used to allocate more or less of the available link
|
||||
// bandwidth to particular nodes. If Max_Info_Frames is not writable in a
|
||||
// node, its value shall be 1.
|
||||
unsigned Nmax_info_frames;
|
||||
// This parameter represents the value of the Max_Info_Frames property of
|
||||
// the node's Device object. The value of Max_Info_Frames specifies the
|
||||
// maximum number of information frames the node may send before it must
|
||||
// pass the token. Max_Info_Frames may have different values on different
|
||||
// nodes. This may be used to allocate more or less of the available link
|
||||
// bandwidth to particular nodes. If Max_Info_Frames is not writable in a
|
||||
// node, its value shall be 1.
|
||||
unsigned Nmax_info_frames;
|
||||
|
||||
// This parameter represents the value of the Max_Master property of the
|
||||
// node's Device object. The value of Max_Master specifies the highest
|
||||
// allowable address for master nodes. The value of Max_Master shall be
|
||||
// less than or equal to 127. If Max_Master is not writable in a node,
|
||||
// its value shall be 127.
|
||||
unsigned Nmax_master;
|
||||
// This parameter represents the value of the Max_Master property of the
|
||||
// node's Device object. The value of Max_Master specifies the highest
|
||||
// allowable address for master nodes. The value of Max_Master shall be
|
||||
// less than or equal to 127. If Max_Master is not writable in a node,
|
||||
// its value shall be 127.
|
||||
unsigned Nmax_master;
|
||||
};
|
||||
|
||||
#define DEFAULT_MAX_INFO_FRAMES 1
|
||||
@@ -206,17 +203,18 @@ struct mstp_port_struct_t
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void MSTP_Init(
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
uint8_t this_station_mac);
|
||||
void MSTP_Millisecond_Timer(volatile struct mstp_port_struct_t *mstp_port);
|
||||
void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port);
|
||||
void MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port);
|
||||
void MSTP_Init(volatile struct mstp_port_struct_t *mstp_port,
|
||||
uint8_t this_station_mac);
|
||||
void MSTP_Millisecond_Timer(volatile struct mstp_port_struct_t
|
||||
*mstp_port);
|
||||
void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t
|
||||
*mstp_port);
|
||||
void MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t
|
||||
*mstp_port);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
+340
-409
@@ -40,299 +40,256 @@
|
||||
#include "npdu.h"
|
||||
#include "apdu.h"
|
||||
|
||||
int npdu_encode_raw(
|
||||
uint8_t *npdu,
|
||||
BACNET_ADDRESS *dest,
|
||||
BACNET_ADDRESS *src,
|
||||
BACNET_NPDU_DATA *npdu_data)
|
||||
int npdu_encode_raw(uint8_t * npdu,
|
||||
BACNET_ADDRESS * dest,
|
||||
BACNET_ADDRESS * src, BACNET_NPDU_DATA * npdu_data)
|
||||
{
|
||||
int len = 0; // return value - number of octets loaded in this function
|
||||
int i = 0; // counter
|
||||
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
|
||||
npdu[1] = 0;
|
||||
// Bit 7: 1 indicates that the NSDU conveys a network layer message.
|
||||
// Message Type field is present.
|
||||
// 0 indicates that the NSDU contains a BACnet APDU.
|
||||
// Message Type field is absent.
|
||||
if (npdu_data->network_layer_message)
|
||||
npdu[1] |= BIT7;
|
||||
//Bit 6: Reserved. Shall be zero.
|
||||
//Bit 5: Destination specifier where:
|
||||
// 0 = DNET, DLEN, DADR, and Hop Count absent
|
||||
// 1 = DNET, DLEN, and Hop Count present
|
||||
// DLEN = 0 denotes broadcast MAC DADR and DADR field is absent
|
||||
// DLEN > 0 specifies length of DADR field
|
||||
if (dest && dest->net)
|
||||
npdu[1] |= BIT5;
|
||||
// Bit 4: Reserved. Shall be zero.
|
||||
// Bit 3: Source specifier where:
|
||||
// 0 = SNET, SLEN, and SADR absent
|
||||
// 1 = SNET, SLEN, and SADR present
|
||||
// SLEN = 0 Invalid
|
||||
// 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.
|
||||
// 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)
|
||||
npdu[1] |= BIT2;
|
||||
// Bits 1,0: Network priority where:
|
||||
// B'11' = Life Safety message
|
||||
// B'10' = Critical Equipment message
|
||||
// B'01' = Urgent message
|
||||
// B'00' = Normal message
|
||||
npdu[1] |= (npdu_data->priority & 0x03);
|
||||
len = 2;
|
||||
if (dest && dest->net)
|
||||
{
|
||||
len += encode_unsigned16(&npdu[len], dest->net);
|
||||
npdu[len++] = dest->len;
|
||||
// DLEN = 0 denotes broadcast MAC DADR and DADR field is absent
|
||||
// DLEN > 0 specifies length of DADR field
|
||||
if (dest->len)
|
||||
{
|
||||
for (i = 0; i < dest->len; i++)
|
||||
{
|
||||
npdu[len++] = dest->adr[i];
|
||||
if (npdu && npdu_data) {
|
||||
// Protocol Version
|
||||
npdu[0] = 1;
|
||||
// control octet
|
||||
npdu[1] = 0;
|
||||
// Bit 7: 1 indicates that the NSDU conveys a network layer message.
|
||||
// Message Type field is present.
|
||||
// 0 indicates that the NSDU contains a BACnet APDU.
|
||||
// Message Type field is absent.
|
||||
if (npdu_data->network_layer_message)
|
||||
npdu[1] |= BIT7;
|
||||
//Bit 6: Reserved. Shall be zero.
|
||||
//Bit 5: Destination specifier where:
|
||||
// 0 = DNET, DLEN, DADR, and Hop Count absent
|
||||
// 1 = DNET, DLEN, and Hop Count present
|
||||
// DLEN = 0 denotes broadcast MAC DADR and DADR field is absent
|
||||
// DLEN > 0 specifies length of DADR field
|
||||
if (dest && dest->net)
|
||||
npdu[1] |= BIT5;
|
||||
// Bit 4: Reserved. Shall be zero.
|
||||
// Bit 3: Source specifier where:
|
||||
// 0 = SNET, SLEN, and SADR absent
|
||||
// 1 = SNET, SLEN, and SADR present
|
||||
// SLEN = 0 Invalid
|
||||
// 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.
|
||||
// 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)
|
||||
npdu[1] |= BIT2;
|
||||
// Bits 1,0: Network priority where:
|
||||
// B'11' = Life Safety message
|
||||
// B'10' = Critical Equipment message
|
||||
// B'01' = Urgent message
|
||||
// B'00' = Normal message
|
||||
npdu[1] |= (npdu_data->priority & 0x03);
|
||||
len = 2;
|
||||
if (dest && dest->net) {
|
||||
len += encode_unsigned16(&npdu[len], dest->net);
|
||||
npdu[len++] = dest->len;
|
||||
// DLEN = 0 denotes broadcast MAC DADR and DADR field is absent
|
||||
// DLEN > 0 specifies length of DADR field
|
||||
if (dest->len) {
|
||||
for (i = 0; i < dest->len; i++) {
|
||||
npdu[len++] = dest->adr[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (src && src->net)
|
||||
{
|
||||
len += encode_unsigned16(&npdu[len], src->net);
|
||||
npdu[len++] = src->len;
|
||||
// SLEN = 0 denotes broadcast MAC SADR and SADR field is absent
|
||||
// SLEN > 0 specifies length of SADR field
|
||||
if (src->len)
|
||||
{
|
||||
for (i = 0; i < src->len; i++)
|
||||
{
|
||||
npdu[len++] = src->adr[i];
|
||||
if (src && src->net) {
|
||||
len += encode_unsigned16(&npdu[len], src->net);
|
||||
npdu[len++] = src->len;
|
||||
// SLEN = 0 denotes broadcast MAC SADR and SADR field is absent
|
||||
// SLEN > 0 specifies length of SADR field
|
||||
if (src->len) {
|
||||
for (i = 0; i < src->len; i++) {
|
||||
npdu[len++] = src->adr[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
// The Hop Count field shall be present only if the message is
|
||||
// destined for a remote network, i.e., if DNET is present.
|
||||
// This is a one-octet field that is initialized to a value of 0xff.
|
||||
if (dest && dest->net) {
|
||||
npdu[len] = 0xFF;
|
||||
len++;
|
||||
}
|
||||
if (npdu_data->network_layer_message) {
|
||||
npdu[len] = npdu_data->network_message_type;
|
||||
len++;
|
||||
// Message Type field contains a value in the range 0x80 - 0xFF,
|
||||
// then a Vendor ID field shall be present
|
||||
if (npdu_data->network_message_type >= 0x80)
|
||||
len += encode_unsigned16(&npdu[len], npdu_data->vendor_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
// The Hop Count field shall be present only if the message is
|
||||
// destined for a remote network, i.e., if DNET is present.
|
||||
// This is a one-octet field that is initialized to a value of 0xff.
|
||||
if (dest && dest->net)
|
||||
{
|
||||
npdu[len] = 0xFF;
|
||||
len++;
|
||||
}
|
||||
if (npdu_data->network_layer_message)
|
||||
{
|
||||
npdu[len] = npdu_data->network_message_type;
|
||||
len++;
|
||||
// Message Type field contains a value in the range 0x80 - 0xFF,
|
||||
// then a Vendor ID field shall be present
|
||||
if (npdu_data->network_message_type >= 0x80)
|
||||
len += encode_unsigned16(&npdu[len], npdu_data->vendor_id);
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
return len;
|
||||
}
|
||||
|
||||
// encode 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
|
||||
BACNET_MESSAGE_PRIORITY priority)
|
||||
int npdu_encode_apdu(uint8_t * npdu, BACNET_ADDRESS * dest, BACNET_ADDRESS * src, bool data_expecting_reply, // true for confirmed messages
|
||||
BACNET_MESSAGE_PRIORITY priority)
|
||||
{
|
||||
BACNET_NPDU_DATA npdu_data = {0};
|
||||
BACNET_NPDU_DATA npdu_data = { 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);
|
||||
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);
|
||||
}
|
||||
|
||||
int npdu_decode(
|
||||
uint8_t *npdu,
|
||||
BACNET_ADDRESS *dest,
|
||||
BACNET_ADDRESS *src,
|
||||
BACNET_NPDU_DATA *npdu_data)
|
||||
int npdu_decode(uint8_t * npdu,
|
||||
BACNET_ADDRESS * dest,
|
||||
BACNET_ADDRESS * src, BACNET_NPDU_DATA * npdu_data)
|
||||
{
|
||||
int len = 0; // return value - number of octets loaded in this function
|
||||
int i = 0; // counter
|
||||
uint16_t src_net = 0;
|
||||
uint16_t dest_net = 0;
|
||||
uint8_t address_len = 0;
|
||||
uint8_t mac_octet = 0;
|
||||
int len = 0; // return value - number of octets loaded in this function
|
||||
int i = 0; // counter
|
||||
uint16_t src_net = 0;
|
||||
uint16_t dest_net = 0;
|
||||
uint8_t address_len = 0;
|
||||
uint8_t mac_octet = 0;
|
||||
|
||||
if (npdu && npdu_data)
|
||||
{
|
||||
// Protocol Version
|
||||
npdu_data->protocol_version = npdu[0];
|
||||
// control octet
|
||||
// Bit 7: 1 indicates that the NSDU conveys a network layer message.
|
||||
// Message Type field is present.
|
||||
// 0 indicates that the NSDU contains a BACnet APDU.
|
||||
// Message Type field is absent.
|
||||
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
|
||||
// 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.
|
||||
npdu_data->data_expecting_reply = (npdu[1] & BIT2) ? true : false;
|
||||
// Bits 1,0: Network priority where:
|
||||
// B'11' = Life Safety message
|
||||
// B'10' = Critical Equipment message
|
||||
// B'01' = Urgent message
|
||||
// B'00' = Normal message
|
||||
npdu_data->priority = npdu[1] & 0x03;
|
||||
// set the offset to where the optional stuff starts
|
||||
len = 2;
|
||||
//Bit 5: Destination specifier where:
|
||||
// 0 = DNET, DLEN, DADR, and Hop Count absent
|
||||
// 1 = DNET, DLEN, and Hop Count present
|
||||
// DLEN = 0 denotes broadcast MAC DADR and DADR field is absent
|
||||
// DLEN > 0 specifies length of DADR field
|
||||
if (npdu[1] & BIT5)
|
||||
{
|
||||
len += decode_unsigned16(&npdu[len], &dest_net);
|
||||
// DLEN = 0 denotes broadcast MAC DADR and DADR field is absent
|
||||
// DLEN > 0 specifies length of DADR field
|
||||
address_len = npdu[len++];
|
||||
if (dest)
|
||||
{
|
||||
dest->net = dest_net;
|
||||
dest->len = address_len;
|
||||
}
|
||||
if (address_len)
|
||||
{
|
||||
for (i = 0; i < address_len; i++)
|
||||
{
|
||||
mac_octet = npdu[len++];
|
||||
if (dest)
|
||||
dest->adr[i] = mac_octet;
|
||||
if (npdu && npdu_data) {
|
||||
// Protocol Version
|
||||
npdu_data->protocol_version = npdu[0];
|
||||
// control octet
|
||||
// Bit 7: 1 indicates that the NSDU conveys a network layer message.
|
||||
// Message Type field is present.
|
||||
// 0 indicates that the NSDU contains a BACnet APDU.
|
||||
// Message Type field is absent.
|
||||
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
|
||||
// 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.
|
||||
npdu_data->data_expecting_reply = (npdu[1] & BIT2) ? true : false;
|
||||
// Bits 1,0: Network priority where:
|
||||
// B'11' = Life Safety message
|
||||
// B'10' = Critical Equipment message
|
||||
// B'01' = Urgent message
|
||||
// B'00' = Normal message
|
||||
npdu_data->priority = npdu[1] & 0x03;
|
||||
// set the offset to where the optional stuff starts
|
||||
len = 2;
|
||||
//Bit 5: Destination specifier where:
|
||||
// 0 = DNET, DLEN, DADR, and Hop Count absent
|
||||
// 1 = DNET, DLEN, and Hop Count present
|
||||
// DLEN = 0 denotes broadcast MAC DADR and DADR field is absent
|
||||
// DLEN > 0 specifies length of DADR field
|
||||
if (npdu[1] & BIT5) {
|
||||
len += decode_unsigned16(&npdu[len], &dest_net);
|
||||
// DLEN = 0 denotes broadcast MAC DADR and DADR field is absent
|
||||
// DLEN > 0 specifies length of DADR field
|
||||
address_len = npdu[len++];
|
||||
if (dest) {
|
||||
dest->net = dest_net;
|
||||
dest->len = address_len;
|
||||
}
|
||||
if (address_len) {
|
||||
for (i = 0; i < address_len; i++) {
|
||||
mac_octet = npdu[len++];
|
||||
if (dest)
|
||||
dest->adr[i] = mac_octet;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// zero out the destination address
|
||||
else if (dest)
|
||||
{
|
||||
dest->net = 0;
|
||||
dest->len = 0;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++)
|
||||
{
|
||||
dest->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
// Bit 3: Source specifier where:
|
||||
// 0 = SNET, SLEN, and SADR absent
|
||||
// 1 = SNET, SLEN, and SADR present
|
||||
// SLEN = 0 Invalid
|
||||
// SLEN > 0 specifies length of SADR field
|
||||
if (npdu[1] & BIT3)
|
||||
{
|
||||
len += decode_unsigned16(&npdu[len], &src_net);
|
||||
// SLEN = 0 denotes broadcast MAC SADR and SADR field is absent
|
||||
// SLEN > 0 specifies length of SADR field
|
||||
address_len = npdu[len++];
|
||||
if (src)
|
||||
{
|
||||
src->net = src_net;
|
||||
src->len = address_len;
|
||||
}
|
||||
if (address_len)
|
||||
{
|
||||
for (i = 0; i < address_len; i++)
|
||||
{
|
||||
mac_octet = npdu[len++];
|
||||
if (src)
|
||||
src->adr[i] = mac_octet;
|
||||
// zero out the destination address
|
||||
else if (dest) {
|
||||
dest->net = 0;
|
||||
dest->len = 0;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
dest->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Bit 3: Source specifier where:
|
||||
// 0 = SNET, SLEN, and SADR absent
|
||||
// 1 = SNET, SLEN, and SADR present
|
||||
// SLEN = 0 Invalid
|
||||
// SLEN > 0 specifies length of SADR field
|
||||
if (npdu[1] & BIT3) {
|
||||
len += decode_unsigned16(&npdu[len], &src_net);
|
||||
// SLEN = 0 denotes broadcast MAC SADR and SADR field is absent
|
||||
// SLEN > 0 specifies length of SADR field
|
||||
address_len = npdu[len++];
|
||||
if (src) {
|
||||
src->net = src_net;
|
||||
src->len = address_len;
|
||||
}
|
||||
if (address_len) {
|
||||
for (i = 0; i < address_len; i++) {
|
||||
mac_octet = npdu[len++];
|
||||
if (src)
|
||||
src->adr[i] = mac_octet;
|
||||
}
|
||||
}
|
||||
} else if (src) {
|
||||
src->net = 0;
|
||||
src->len = 0;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
src->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
// The Hop Count field shall be present only if the message is
|
||||
// destined for a remote network, i.e., if DNET is present.
|
||||
// This is a one-octet field that is initialized to a value of 0xff.
|
||||
if (dest_net)
|
||||
npdu_data->hop_count = npdu[len++];
|
||||
else
|
||||
npdu_data->hop_count = 0;
|
||||
// Indicates that the NSDU conveys a network layer message.
|
||||
// Message Type field is present.
|
||||
if (npdu_data->network_layer_message) {
|
||||
npdu_data->network_message_type = npdu[len++];
|
||||
// Message Type field contains a value in the range 0x80 - 0xFF,
|
||||
// then a Vendor ID field shall be present
|
||||
if (npdu_data->network_message_type >= 0x80)
|
||||
len +=
|
||||
decode_unsigned16(&npdu[len], &npdu_data->vendor_id);
|
||||
} else
|
||||
npdu_data->network_message_type = 0;
|
||||
}
|
||||
else if (src)
|
||||
{
|
||||
src->net = 0;
|
||||
src->len = 0;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++)
|
||||
{
|
||||
src->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
// The Hop Count field shall be present only if the message is
|
||||
// destined for a remote network, i.e., if DNET is present.
|
||||
// This is a one-octet field that is initialized to a value of 0xff.
|
||||
if (dest_net)
|
||||
npdu_data->hop_count = npdu[len++];
|
||||
else
|
||||
npdu_data->hop_count = 0;
|
||||
// Indicates that the NSDU conveys a network layer message.
|
||||
// Message Type field is present.
|
||||
if (npdu_data->network_layer_message)
|
||||
{
|
||||
npdu_data->network_message_type = npdu[len++];
|
||||
// Message Type field contains a value in the range 0x80 - 0xFF,
|
||||
// then a Vendor ID field shall be present
|
||||
if (npdu_data->network_message_type >= 0x80)
|
||||
len += decode_unsigned16(&npdu[len], &npdu_data->vendor_id);
|
||||
}
|
||||
else
|
||||
npdu_data->network_message_type = 0;
|
||||
}
|
||||
|
||||
return len;
|
||||
return len;
|
||||
}
|
||||
|
||||
void npdu_handler(
|
||||
BACNET_ADDRESS *src, // source address
|
||||
uint8_t *pdu, // PDU data
|
||||
uint16_t pdu_len) // length PDU
|
||||
void npdu_handler(BACNET_ADDRESS * src, // source address
|
||||
uint8_t * pdu, // PDU data
|
||||
uint16_t pdu_len) // length PDU
|
||||
{
|
||||
int apdu_offset = 0;
|
||||
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
|
||||
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);
|
||||
}
|
||||
int apdu_offset = 0;
|
||||
BACNET_ADDRESS dest = { 0 };
|
||||
BACNET_NPDU_DATA npdu_data = { 0 };
|
||||
|
||||
return;
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -343,161 +300,135 @@ void npdu_handler(
|
||||
|
||||
void testNPDU2(Test * pTest)
|
||||
{
|
||||
uint8_t pdu[480] = {0};
|
||||
BACNET_ADDRESS dest = {0};
|
||||
BACNET_ADDRESS src = {0};
|
||||
BACNET_ADDRESS npdu_dest = {0};
|
||||
BACNET_ADDRESS npdu_src = {0};
|
||||
int len = 0;
|
||||
bool data_expecting_reply = false; // true for confirmed messages
|
||||
BACNET_MESSAGE_PRIORITY priority = MESSAGE_PRIORITY_NORMAL;
|
||||
BACNET_NPDU_DATA npdu_data = {0};
|
||||
int i = 0; // counter
|
||||
int npdu_len = 0;
|
||||
bool network_layer_message = false; // false if APDU
|
||||
BACNET_NETWORK_MESSAGE_TYPE network_message_type = 0;// optional
|
||||
uint16_t vendor_id = 0; // optional, if net message type is > 0x80
|
||||
uint8_t pdu[480] = { 0 };
|
||||
BACNET_ADDRESS dest = { 0 };
|
||||
BACNET_ADDRESS src = { 0 };
|
||||
BACNET_ADDRESS npdu_dest = { 0 };
|
||||
BACNET_ADDRESS npdu_src = { 0 };
|
||||
int len = 0;
|
||||
bool data_expecting_reply = false; // true for confirmed messages
|
||||
BACNET_MESSAGE_PRIORITY priority = MESSAGE_PRIORITY_NORMAL;
|
||||
BACNET_NPDU_DATA npdu_data = { 0 };
|
||||
int i = 0; // counter
|
||||
int npdu_len = 0;
|
||||
bool network_layer_message = false; // false if APDU
|
||||
BACNET_NETWORK_MESSAGE_TYPE network_message_type = 0; // optional
|
||||
uint16_t vendor_id = 0; // optional, if net message type is > 0x80
|
||||
|
||||
// mac_len = 0 if global address
|
||||
dest.mac_len = 6;
|
||||
for (i = 0; i < dest.mac_len; i++)
|
||||
{
|
||||
dest.mac[i] = i;
|
||||
}
|
||||
// DNET,DLEN,DADR
|
||||
dest.net = 1;
|
||||
dest.len = 6;
|
||||
for (i = 0; i < dest.len; i++)
|
||||
{
|
||||
dest.adr[i] = i * 10;
|
||||
}
|
||||
src.mac_len = 1;
|
||||
for (i = 0; i < src.mac_len; i++)
|
||||
{
|
||||
src.mac[i] = 0x80;
|
||||
}
|
||||
// SNET,SLEN,SADR
|
||||
src.net = 2;
|
||||
src.len = 1;
|
||||
for (i = 0; i < src.len; i++)
|
||||
{
|
||||
src.adr[i] = 0x40;
|
||||
}
|
||||
len = npdu_encode_apdu(
|
||||
&pdu[0],
|
||||
&dest,
|
||||
&src,
|
||||
data_expecting_reply,
|
||||
priority);
|
||||
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.network_layer_message == network_layer_message);
|
||||
ct_test(pTest, npdu_data.network_message_type == network_message_type);
|
||||
ct_test(pTest, npdu_data.vendor_id == vendor_id);
|
||||
ct_test(pTest, npdu_data.priority == priority);
|
||||
// DNET,DLEN,DADR
|
||||
ct_test(pTest, npdu_dest.net == dest.net);
|
||||
ct_test(pTest, npdu_dest.len == dest.len);
|
||||
for (i = 0; i < dest.len; i++)
|
||||
{
|
||||
ct_test(pTest, npdu_dest.adr[i] == dest.adr[i]);
|
||||
}
|
||||
// SNET,SLEN,SADR
|
||||
ct_test(pTest, npdu_src.net == src.net);
|
||||
ct_test(pTest, npdu_src.len == src.len);
|
||||
for (i = 0; i < src.len; i++)
|
||||
{
|
||||
ct_test(pTest, npdu_src.adr[i] == src.adr[i]);
|
||||
}
|
||||
// mac_len = 0 if global address
|
||||
dest.mac_len = 6;
|
||||
for (i = 0; i < dest.mac_len; i++) {
|
||||
dest.mac[i] = i;
|
||||
}
|
||||
// DNET,DLEN,DADR
|
||||
dest.net = 1;
|
||||
dest.len = 6;
|
||||
for (i = 0; i < dest.len; i++) {
|
||||
dest.adr[i] = i * 10;
|
||||
}
|
||||
src.mac_len = 1;
|
||||
for (i = 0; i < src.mac_len; i++) {
|
||||
src.mac[i] = 0x80;
|
||||
}
|
||||
// SNET,SLEN,SADR
|
||||
src.net = 2;
|
||||
src.len = 1;
|
||||
for (i = 0; i < src.len; i++) {
|
||||
src.adr[i] = 0x40;
|
||||
}
|
||||
len = npdu_encode_apdu(&pdu[0],
|
||||
&dest, &src, data_expecting_reply, priority);
|
||||
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.network_layer_message == network_layer_message);
|
||||
ct_test(pTest, npdu_data.network_message_type == network_message_type);
|
||||
ct_test(pTest, npdu_data.vendor_id == vendor_id);
|
||||
ct_test(pTest, npdu_data.priority == priority);
|
||||
// DNET,DLEN,DADR
|
||||
ct_test(pTest, npdu_dest.net == dest.net);
|
||||
ct_test(pTest, npdu_dest.len == dest.len);
|
||||
for (i = 0; i < dest.len; i++) {
|
||||
ct_test(pTest, npdu_dest.adr[i] == dest.adr[i]);
|
||||
}
|
||||
// SNET,SLEN,SADR
|
||||
ct_test(pTest, npdu_src.net == src.net);
|
||||
ct_test(pTest, npdu_src.len == src.len);
|
||||
for (i = 0; i < src.len; i++) {
|
||||
ct_test(pTest, npdu_src.adr[i] == src.adr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void testNPDU1(Test * pTest)
|
||||
{
|
||||
uint8_t pdu[480] = {0};
|
||||
BACNET_ADDRESS dest = {0};
|
||||
BACNET_ADDRESS src = {0};
|
||||
BACNET_ADDRESS npdu_dest = {0};
|
||||
BACNET_ADDRESS npdu_src = {0};
|
||||
int len = 0;
|
||||
bool data_expecting_reply = false; // true for confirmed messages
|
||||
BACNET_MESSAGE_PRIORITY priority = MESSAGE_PRIORITY_NORMAL;
|
||||
BACNET_NPDU_DATA npdu_data = {0};
|
||||
int i = 0; // counter
|
||||
int npdu_len = 0;
|
||||
bool network_layer_message = false; // false if APDU
|
||||
BACNET_NETWORK_MESSAGE_TYPE network_message_type = 0;// optional
|
||||
uint16_t vendor_id = 0; // optional, if net message type is > 0x80
|
||||
uint8_t pdu[480] = { 0 };
|
||||
BACNET_ADDRESS dest = { 0 };
|
||||
BACNET_ADDRESS src = { 0 };
|
||||
BACNET_ADDRESS npdu_dest = { 0 };
|
||||
BACNET_ADDRESS npdu_src = { 0 };
|
||||
int len = 0;
|
||||
bool data_expecting_reply = false; // true for confirmed messages
|
||||
BACNET_MESSAGE_PRIORITY priority = MESSAGE_PRIORITY_NORMAL;
|
||||
BACNET_NPDU_DATA npdu_data = { 0 };
|
||||
int i = 0; // counter
|
||||
int npdu_len = 0;
|
||||
bool network_layer_message = false; // false if APDU
|
||||
BACNET_NETWORK_MESSAGE_TYPE network_message_type = 0; // optional
|
||||
uint16_t vendor_id = 0; // optional, if net message type is > 0x80
|
||||
|
||||
// mac_len = 0 if global address
|
||||
dest.mac_len = 0;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++)
|
||||
{
|
||||
dest.mac[i] = 0;
|
||||
}
|
||||
// DNET,DLEN,DADR
|
||||
dest.net = 0;
|
||||
dest.len = 0;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++)
|
||||
{
|
||||
dest.adr[i] = 0;
|
||||
}
|
||||
src.mac_len = 0;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++)
|
||||
{
|
||||
src.mac[i] = 0;
|
||||
}
|
||||
// SNET,SLEN,SADR
|
||||
src.net = 0;
|
||||
src.len = 0;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++)
|
||||
{
|
||||
src.adr[i] = 0;
|
||||
}
|
||||
len = npdu_encode_apdu(
|
||||
&pdu[0],
|
||||
&dest,
|
||||
&src,
|
||||
data_expecting_reply,
|
||||
priority);
|
||||
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.network_layer_message == network_layer_message);
|
||||
ct_test(pTest, npdu_data.network_message_type == network_message_type);
|
||||
ct_test(pTest, npdu_data.vendor_id == vendor_id);
|
||||
ct_test(pTest, npdu_data.priority == priority);
|
||||
ct_test(pTest, npdu_dest.mac_len == src.mac_len);
|
||||
ct_test(pTest, npdu_src.mac_len == dest.mac_len);
|
||||
// mac_len = 0 if global address
|
||||
dest.mac_len = 0;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
dest.mac[i] = 0;
|
||||
}
|
||||
// DNET,DLEN,DADR
|
||||
dest.net = 0;
|
||||
dest.len = 0;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
dest.adr[i] = 0;
|
||||
}
|
||||
src.mac_len = 0;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
src.mac[i] = 0;
|
||||
}
|
||||
// SNET,SLEN,SADR
|
||||
src.net = 0;
|
||||
src.len = 0;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
src.adr[i] = 0;
|
||||
}
|
||||
len = npdu_encode_apdu(&pdu[0],
|
||||
&dest, &src, data_expecting_reply, priority);
|
||||
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.network_layer_message == network_layer_message);
|
||||
ct_test(pTest, npdu_data.network_message_type == network_message_type);
|
||||
ct_test(pTest, npdu_data.vendor_id == vendor_id);
|
||||
ct_test(pTest, npdu_data.priority == priority);
|
||||
ct_test(pTest, npdu_dest.mac_len == src.mac_len);
|
||||
ct_test(pTest, npdu_src.mac_len == dest.mac_len);
|
||||
}
|
||||
|
||||
#ifdef TEST_NPDU
|
||||
// dummy stub for testing
|
||||
void tsm_free_invoke_id(uint8_t invokeID)
|
||||
{
|
||||
(void)invokeID;
|
||||
(void) invokeID;
|
||||
}
|
||||
|
||||
void iam_handler(
|
||||
uint8_t *service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS *src)
|
||||
void iam_handler(uint8_t * service_request,
|
||||
uint16_t service_len, BACNET_ADDRESS * src)
|
||||
{
|
||||
(void)service_request;
|
||||
(void)service_len;
|
||||
(void)src;
|
||||
(void) service_request;
|
||||
(void) service_len;
|
||||
(void) src;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
|
||||
+24
-35
@@ -40,50 +40,39 @@
|
||||
#include "bacenum.h"
|
||||
|
||||
// an NPDU structure keeps the parameter stack to a minimum
|
||||
typedef struct bacnet_npdu_data_t
|
||||
{
|
||||
uint8_t protocol_version;
|
||||
// parts of the control octet:
|
||||
bool data_expecting_reply; // true for confirmed messages
|
||||
bool network_layer_message; // false if APDU
|
||||
BACNET_MESSAGE_PRIORITY priority;
|
||||
// optional network message info
|
||||
BACNET_NETWORK_MESSAGE_TYPE network_message_type; // optional
|
||||
uint16_t vendor_id; // optional, if net message type is > 0x80
|
||||
uint8_t hop_count;
|
||||
typedef struct bacnet_npdu_data_t {
|
||||
uint8_t protocol_version;
|
||||
// parts of the control octet:
|
||||
bool data_expecting_reply; // true for confirmed messages
|
||||
bool network_layer_message; // false if APDU
|
||||
BACNET_MESSAGE_PRIORITY priority;
|
||||
// optional network message info
|
||||
BACNET_NETWORK_MESSAGE_TYPE network_message_type; // optional
|
||||
uint16_t vendor_id; // optional, if net message type is > 0x80
|
||||
uint8_t hop_count;
|
||||
} BACNET_NPDU_DATA;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
uint8_t npdu_encode_max_seg_max_apdu(int max_segs, int max_apdu);
|
||||
int npdu_encode_raw(
|
||||
uint8_t *npdu,
|
||||
BACNET_ADDRESS *dest,
|
||||
BACNET_ADDRESS *src,
|
||||
BACNET_NPDU_DATA *npdu_data);
|
||||
uint8_t npdu_encode_max_seg_max_apdu(int max_segs, int max_apdu);
|
||||
int npdu_encode_raw(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
|
||||
BACNET_MESSAGE_PRIORITY priority);
|
||||
int npdu_encode_apdu(uint8_t * npdu, BACNET_ADDRESS * dest, BACNET_ADDRESS * src, bool data_expecting_reply, // true for confirmed messages
|
||||
BACNET_MESSAGE_PRIORITY priority);
|
||||
|
||||
int npdu_decode(
|
||||
uint8_t *npdu,
|
||||
BACNET_ADDRESS *dest,
|
||||
BACNET_ADDRESS *src,
|
||||
BACNET_NPDU_DATA *npdu_data);
|
||||
int npdu_decode(uint8_t * npdu,
|
||||
BACNET_ADDRESS * dest,
|
||||
BACNET_ADDRESS * src, BACNET_NPDU_DATA * npdu_data);
|
||||
|
||||
void npdu_handler(
|
||||
BACNET_ADDRESS *src, // source address
|
||||
uint8_t *pdu, // PDU data
|
||||
uint16_t pdu_len); // length PDU
|
||||
void npdu_handler(BACNET_ADDRESS * src, // source address
|
||||
uint8_t * pdu, // PDU data
|
||||
uint16_t pdu_len); // length PDU
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
+91
-112
@@ -38,106 +38,93 @@
|
||||
#include "rd.h"
|
||||
|
||||
/* encode service */
|
||||
int rd_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint8_t invoke_id,
|
||||
BACNET_REINITIALIZED_STATE state,
|
||||
BACNET_CHARACTER_STRING *password)
|
||||
int rd_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id,
|
||||
BACNET_REINITIALIZED_STATE state, BACNET_CHARACTER_STRING * password)
|
||||
{
|
||||
int len = 0; /* length of each encoding */
|
||||
int apdu_len = 0; /* total length of the apdu, return value */
|
||||
int len = 0; /* length of each encoding */
|
||||
int apdu_len = 0; /* total length of the apdu, return value */
|
||||
|
||||
if (apdu)
|
||||
{
|
||||
apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
|
||||
apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU);
|
||||
apdu[2] = invoke_id;
|
||||
apdu[3] = SERVICE_CONFIRMED_REINITIALIZE_DEVICE;
|
||||
apdu_len = 4;
|
||||
len = encode_context_enumerated(&apdu[apdu_len], 0,
|
||||
state);
|
||||
apdu_len += len;
|
||||
/* optional password */
|
||||
if (password)
|
||||
{
|
||||
/* FIXME: must be at least 1 character, limited to 20 characters */
|
||||
len = encode_context_character_string(&apdu[apdu_len], 1,
|
||||
password);
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
|
||||
apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU);
|
||||
apdu[2] = invoke_id;
|
||||
apdu[3] = SERVICE_CONFIRMED_REINITIALIZE_DEVICE;
|
||||
apdu_len = 4;
|
||||
len = encode_context_enumerated(&apdu[apdu_len], 0, state);
|
||||
apdu_len += len;
|
||||
/* optional password */
|
||||
if (password) {
|
||||
/* FIXME: must be at least 1 character, limited to 20 characters */
|
||||
len = encode_context_character_string(&apdu[apdu_len], 1,
|
||||
password);
|
||||
apdu_len += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* decode the service request only */
|
||||
int rd_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_REINITIALIZED_STATE *state,
|
||||
BACNET_CHARACTER_STRING *password)
|
||||
int rd_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_REINITIALIZED_STATE * state, BACNET_CHARACTER_STRING * password)
|
||||
{
|
||||
unsigned len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value_type = 0;
|
||||
int value = 0;
|
||||
unsigned len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value_type = 0;
|
||||
int value = 0;
|
||||
|
||||
/* check for value pointers */
|
||||
if (apdu_len)
|
||||
{
|
||||
/* Tag 0: reinitializedStateOfDevice */
|
||||
if (!decode_is_context_tag(&apdu[len], 0))
|
||||
return -1;
|
||||
len += decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += decode_enumerated(&apdu[len], len_value_type, &value);
|
||||
if (state)
|
||||
*state = value;
|
||||
/* Tag 1: password - optional */
|
||||
if (len < apdu_len)
|
||||
{
|
||||
if (!decode_is_context_tag(&apdu[len], 1))
|
||||
return -1;
|
||||
len += decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += decode_character_string(&apdu[len], len_value_type, password);
|
||||
/* check for value pointers */
|
||||
if (apdu_len) {
|
||||
/* Tag 0: reinitializedStateOfDevice */
|
||||
if (!decode_is_context_tag(&apdu[len], 0))
|
||||
return -1;
|
||||
len += decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len += decode_enumerated(&apdu[len], len_value_type, &value);
|
||||
if (state)
|
||||
*state = value;
|
||||
/* Tag 1: password - optional */
|
||||
if (len < apdu_len) {
|
||||
if (!decode_is_context_tag(&apdu[len], 1))
|
||||
return -1;
|
||||
len += decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
len +=
|
||||
decode_character_string(&apdu[len], len_value_type,
|
||||
password);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (int)len;
|
||||
return (int) len;
|
||||
}
|
||||
|
||||
int rd_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
BACNET_REINITIALIZED_STATE *state,
|
||||
BACNET_CHARACTER_STRING *password)
|
||||
int rd_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id,
|
||||
BACNET_REINITIALIZED_STATE * state, BACNET_CHARACTER_STRING * password)
|
||||
{
|
||||
int len = 0;
|
||||
unsigned offset = 0;
|
||||
int len = 0;
|
||||
unsigned offset = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
|
||||
return -1;
|
||||
// apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted());
|
||||
*invoke_id = apdu[2]; /* invoke id - filled in by net layer */
|
||||
if (apdu[3] != SERVICE_CONFIRMED_REINITIALIZE_DEVICE)
|
||||
return -1;
|
||||
offset = 4;
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
|
||||
return -1;
|
||||
// apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted());
|
||||
*invoke_id = apdu[2]; /* invoke id - filled in by net layer */
|
||||
if (apdu[3] != SERVICE_CONFIRMED_REINITIALIZE_DEVICE)
|
||||
return -1;
|
||||
offset = 4;
|
||||
|
||||
if (apdu_len > offset)
|
||||
{
|
||||
len = rd_decode_service_request(
|
||||
&apdu[offset],
|
||||
apdu_len - offset,
|
||||
state,
|
||||
password);
|
||||
}
|
||||
if (apdu_len > offset) {
|
||||
len = rd_decode_service_request(&apdu[offset],
|
||||
apdu_len - offset, state, password);
|
||||
}
|
||||
|
||||
return len;
|
||||
return len;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
@@ -147,38 +134,30 @@ int rd_decode_apdu(
|
||||
|
||||
void test_ReinitializeDevice(Test * pTest)
|
||||
{
|
||||
uint8_t apdu[480] = {0};
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 128;
|
||||
uint8_t test_invoke_id = 0;
|
||||
BACNET_REINITIALIZED_STATE state;
|
||||
BACNET_REINITIALIZED_STATE test_state;
|
||||
BACNET_CHARACTER_STRING password;
|
||||
BACNET_CHARACTER_STRING test_password;
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 128;
|
||||
uint8_t test_invoke_id = 0;
|
||||
BACNET_REINITIALIZED_STATE state;
|
||||
BACNET_REINITIALIZED_STATE test_state;
|
||||
BACNET_CHARACTER_STRING password;
|
||||
BACNET_CHARACTER_STRING test_password;
|
||||
|
||||
state = BACNET_REINIT_WARMSTART;
|
||||
characterstring_init_ansi(&password,"John 3:16");
|
||||
len = rd_encode_apdu(
|
||||
&apdu[0],
|
||||
invoke_id,
|
||||
state,
|
||||
&password);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
state = BACNET_REINIT_WARMSTART;
|
||||
characterstring_init_ansi(&password, "John 3:16");
|
||||
len = rd_encode_apdu(&apdu[0], invoke_id, state, &password);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
|
||||
len = rd_decode_apdu(
|
||||
&apdu[0],
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_state,
|
||||
&test_password);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
ct_test(pTest, test_state == state);
|
||||
ct_test(pTest, characterstring_same(&test_password,&password));
|
||||
len = rd_decode_apdu(&apdu[0],
|
||||
apdu_len, &test_invoke_id, &test_state, &test_password);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
ct_test(pTest, test_state == state);
|
||||
ct_test(pTest, characterstring_same(&test_password, &password));
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_REINITIALIZE_DEVICE
|
||||
|
||||
+17
-22
@@ -39,37 +39,32 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
// encode service
|
||||
int rd_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint8_t invoke_id,
|
||||
BACNET_REINITIALIZED_STATE state,
|
||||
BACNET_CHARACTER_STRING *password);
|
||||
int rd_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id,
|
||||
BACNET_REINITIALIZED_STATE state,
|
||||
BACNET_CHARACTER_STRING * password);
|
||||
|
||||
// decode the service request only
|
||||
int rd_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_REINITIALIZED_STATE *state,
|
||||
BACNET_CHARACTER_STRING *password);
|
||||
|
||||
int rd_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
BACNET_REINITIALIZED_STATE *state,
|
||||
BACNET_CHARACTER_STRING *password);
|
||||
int rd_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_REINITIALIZED_STATE * state,
|
||||
BACNET_CHARACTER_STRING * password);
|
||||
|
||||
int rd_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id,
|
||||
BACNET_REINITIALIZED_STATE * state,
|
||||
BACNET_CHARACTER_STRING * password);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void test_ReinitializeDevice(Test * pTest);
|
||||
void test_ReinitializeDevice(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
|
||||
+80
-124
@@ -37,71 +37,56 @@
|
||||
#include "bacdef.h"
|
||||
|
||||
// encode service
|
||||
int reject_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint8_t invoke_id,
|
||||
uint8_t reject_reason)
|
||||
int reject_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, uint8_t reject_reason)
|
||||
{
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
|
||||
if (apdu)
|
||||
{
|
||||
apdu[0] = PDU_TYPE_REJECT;
|
||||
apdu[1] = invoke_id;
|
||||
apdu[2] = reject_reason;
|
||||
apdu_len = 3;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
if (apdu) {
|
||||
apdu[0] = PDU_TYPE_REJECT;
|
||||
apdu[1] = invoke_id;
|
||||
apdu[2] = reject_reason;
|
||||
apdu_len = 3;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
// decode the service request only
|
||||
int reject_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
uint8_t *reject_reason)
|
||||
int reject_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, uint8_t * invoke_id, uint8_t * reject_reason)
|
||||
{
|
||||
int len = 0;
|
||||
int len = 0;
|
||||
|
||||
if (apdu_len)
|
||||
{
|
||||
if (invoke_id)
|
||||
*invoke_id = apdu[0];
|
||||
if (reject_reason)
|
||||
*reject_reason = apdu[1];
|
||||
}
|
||||
|
||||
return len;
|
||||
if (apdu_len) {
|
||||
if (invoke_id)
|
||||
*invoke_id = apdu[0];
|
||||
if (reject_reason)
|
||||
*reject_reason = apdu[1];
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
// decode the whole APDU - mainly used for unit testing
|
||||
int reject_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
uint8_t *reject_reason)
|
||||
int reject_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len, uint8_t * invoke_id, uint8_t * reject_reason)
|
||||
{
|
||||
int len = 0;
|
||||
int len = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu_len)
|
||||
{
|
||||
if (apdu[0] != PDU_TYPE_REJECT)
|
||||
return -1;
|
||||
if (apdu_len > 1)
|
||||
{
|
||||
len = reject_decode_service_request(
|
||||
&apdu[1],
|
||||
apdu_len - 1,
|
||||
invoke_id,
|
||||
reject_reason);
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu_len) {
|
||||
if (apdu[0] != PDU_TYPE_REJECT)
|
||||
return -1;
|
||||
if (apdu_len > 1) {
|
||||
len = reject_decode_service_request(&apdu[1],
|
||||
apdu_len - 1, invoke_id, reject_reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
@@ -111,83 +96,54 @@ int reject_decode_apdu(
|
||||
|
||||
void testReject(Test * pTest)
|
||||
{
|
||||
uint8_t apdu[480] = {0};
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 0;
|
||||
uint8_t reject_reason = 0;
|
||||
uint8_t test_invoke_id = 0;
|
||||
uint8_t test_reject_reason = 0;
|
||||
|
||||
len = reject_encode_apdu(
|
||||
&apdu[0],
|
||||
invoke_id,
|
||||
reject_reason);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 0;
|
||||
uint8_t reject_reason = 0;
|
||||
uint8_t test_invoke_id = 0;
|
||||
uint8_t test_reject_reason = 0;
|
||||
|
||||
len = reject_decode_apdu(
|
||||
&apdu[0],
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_reject_reason);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
ct_test(pTest, test_reject_reason == reject_reason);
|
||||
len = reject_encode_apdu(&apdu[0], invoke_id, reject_reason);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
|
||||
// change type to get negative response
|
||||
apdu[0] = PDU_TYPE_ABORT;
|
||||
len = reject_decode_apdu(
|
||||
&apdu[0],
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_reject_reason);
|
||||
ct_test(pTest, len == -1);
|
||||
len = reject_decode_apdu(&apdu[0],
|
||||
apdu_len, &test_invoke_id, &test_reject_reason);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
ct_test(pTest, test_reject_reason == reject_reason);
|
||||
|
||||
// test NULL APDU
|
||||
len = reject_decode_apdu(
|
||||
NULL,
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_reject_reason);
|
||||
ct_test(pTest, len == -1);
|
||||
// change type to get negative response
|
||||
apdu[0] = PDU_TYPE_ABORT;
|
||||
len = reject_decode_apdu(&apdu[0],
|
||||
apdu_len, &test_invoke_id, &test_reject_reason);
|
||||
ct_test(pTest, len == -1);
|
||||
|
||||
// force a zero length
|
||||
len = reject_decode_apdu(
|
||||
&apdu[0],
|
||||
0,
|
||||
&test_invoke_id,
|
||||
&test_reject_reason);
|
||||
ct_test(pTest, len == 0);
|
||||
|
||||
|
||||
// check them all...
|
||||
for (
|
||||
invoke_id = 0;
|
||||
invoke_id < 255;
|
||||
invoke_id++)
|
||||
{
|
||||
for (
|
||||
reject_reason = 0;
|
||||
reject_reason < 255;
|
||||
reject_reason++)
|
||||
{
|
||||
len = reject_encode_apdu(
|
||||
&apdu[0],
|
||||
invoke_id,
|
||||
reject_reason);
|
||||
apdu_len = len;
|
||||
ct_test(pTest, len != 0);
|
||||
len = reject_decode_apdu(
|
||||
&apdu[0],
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_reject_reason);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
ct_test(pTest, test_reject_reason == reject_reason);
|
||||
// test NULL APDU
|
||||
len = reject_decode_apdu(NULL,
|
||||
apdu_len, &test_invoke_id, &test_reject_reason);
|
||||
ct_test(pTest, len == -1);
|
||||
|
||||
// force a zero length
|
||||
len = reject_decode_apdu(&apdu[0],
|
||||
0, &test_invoke_id, &test_reject_reason);
|
||||
ct_test(pTest, len == 0);
|
||||
|
||||
|
||||
// check them all...
|
||||
for (invoke_id = 0; invoke_id < 255; invoke_id++) {
|
||||
for (reject_reason = 0; reject_reason < 255; reject_reason++) {
|
||||
len = reject_encode_apdu(&apdu[0], invoke_id, reject_reason);
|
||||
apdu_len = len;
|
||||
ct_test(pTest, len != 0);
|
||||
len = reject_decode_apdu(&apdu[0],
|
||||
apdu_len, &test_invoke_id, &test_reject_reason);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
ct_test(pTest, test_reject_reason == reject_reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST_REJECT
|
||||
|
||||
+10
-20
@@ -39,32 +39,22 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int reject_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint8_t invoke_id,
|
||||
uint8_t reject_reason);
|
||||
int reject_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, uint8_t reject_reason);
|
||||
|
||||
int reject_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
uint8_t *reject_reason);
|
||||
|
||||
int reject_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
uint8_t *reject_reason);
|
||||
int reject_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, uint8_t * invoke_id, uint8_t * reject_reason);
|
||||
|
||||
int reject_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len, uint8_t * invoke_id, uint8_t * reject_reason);
|
||||
|
||||
#ifdef TEST
|
||||
void testReject(Test * pTest);
|
||||
void testReject(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
|
||||
+138
-153
@@ -48,7 +48,7 @@
|
||||
*****************************************************************************/
|
||||
bool Ringbuf_Empty(RING_BUFFER const *b)
|
||||
{
|
||||
return (b->count == 0);
|
||||
return (b->count == 0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@@ -59,7 +59,7 @@ bool Ringbuf_Empty(RING_BUFFER const *b)
|
||||
*****************************************************************************/
|
||||
char *Ringbuf_Get_Front(RING_BUFFER const *b)
|
||||
{
|
||||
return (b->count ? &(b->data[b->head * b->element_size]) : NULL);
|
||||
return (b->count ? &(b->data[b->head * b->element_size]) : NULL);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@@ -68,20 +68,19 @@ char *Ringbuf_Get_Front(RING_BUFFER const *b)
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
char *Ringbuf_Pop_Front(RING_BUFFER *b)
|
||||
char *Ringbuf_Pop_Front(RING_BUFFER * b)
|
||||
{
|
||||
char *data = NULL; // return value
|
||||
char *data = NULL; // return value
|
||||
|
||||
if (b->count)
|
||||
{
|
||||
data = &(b->data[b->head * b->element_size]);
|
||||
b->head++;
|
||||
if (b->head >= b->element_count)
|
||||
b->head = 0;
|
||||
b->count--;
|
||||
}
|
||||
if (b->count) {
|
||||
data = &(b->data[b->head * b->element_size]);
|
||||
b->head++;
|
||||
if (b->head >= b->element_count)
|
||||
b->head = 0;
|
||||
b->count--;
|
||||
}
|
||||
|
||||
return data;
|
||||
return data;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@@ -90,34 +89,30 @@ char *Ringbuf_Pop_Front(RING_BUFFER *b)
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
bool Ringbuf_Put(
|
||||
RING_BUFFER *b, // ring buffer structure
|
||||
char *data_element) // one element to add to the ring
|
||||
bool Ringbuf_Put(RING_BUFFER * b, // ring buffer structure
|
||||
char *data_element) // one element to add to the ring
|
||||
{
|
||||
bool status = false; // return value
|
||||
unsigned offset = 0; // offset into array of data
|
||||
char *ring_data = NULL; // used to help point ring data
|
||||
unsigned i; // loop counter
|
||||
bool status = false; // return value
|
||||
unsigned offset = 0; // offset into array of data
|
||||
char *ring_data = NULL; // used to help point ring data
|
||||
unsigned i; // loop counter
|
||||
|
||||
if (b && data_element)
|
||||
{
|
||||
// limit the amount of data that we accept
|
||||
if (b->count < b->element_count)
|
||||
{
|
||||
offset = b->head + b->count;
|
||||
if (offset >= b->element_count)
|
||||
offset -= b->element_count;
|
||||
ring_data = b->data + offset * b->element_size;
|
||||
for(i = 0; i < b->element_size; i++)
|
||||
{
|
||||
ring_data[i] = data_element[i];
|
||||
}
|
||||
b->count++;
|
||||
status = true;
|
||||
if (b && data_element) {
|
||||
// limit the amount of data that we accept
|
||||
if (b->count < b->element_count) {
|
||||
offset = b->head + b->count;
|
||||
if (offset >= b->element_count)
|
||||
offset -= b->element_count;
|
||||
ring_data = b->data + offset * b->element_size;
|
||||
for (i = 0; i < b->element_size; i++) {
|
||||
ring_data[i] = data_element[i];
|
||||
}
|
||||
b->count++;
|
||||
status = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
return status;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@@ -126,19 +121,18 @@ bool Ringbuf_Put(
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void Ringbuf_Init(
|
||||
RING_BUFFER *b, // ring buffer structure
|
||||
char *data, // data block or array of data
|
||||
unsigned element_size, // size of one element in the data block
|
||||
unsigned element_count) // number of elements in the data block
|
||||
void Ringbuf_Init(RING_BUFFER * b, // ring buffer structure
|
||||
char *data, // data block or array of data
|
||||
unsigned element_size, // size of one element in the data block
|
||||
unsigned element_count) // number of elements in the data block
|
||||
{
|
||||
b->head = 0;
|
||||
b->count = 0;
|
||||
b->data = data;
|
||||
b->element_size = element_size;
|
||||
b->element_count = element_count;
|
||||
b->head = 0;
|
||||
b->count = 0;
|
||||
b->data = data;
|
||||
b->element_size = element_size;
|
||||
b->element_count = element_count;
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
@@ -150,139 +144,130 @@ void Ringbuf_Init(
|
||||
// test the FIFO
|
||||
#define RING_BUFFER_DATA_SIZE 5
|
||||
#define RING_BUFFER_SIZE 16
|
||||
void testRingBuf(Test* pTest)
|
||||
void testRingBuf(Test * pTest)
|
||||
{
|
||||
RING_BUFFER test_buffer;
|
||||
char data_store[RING_BUFFER_DATA_SIZE * RING_BUFFER_SIZE];
|
||||
char data[RING_BUFFER_DATA_SIZE];
|
||||
char *test_data;
|
||||
unsigned index;
|
||||
unsigned data_index;
|
||||
unsigned count;
|
||||
unsigned dummy;
|
||||
bool status;
|
||||
RING_BUFFER test_buffer;
|
||||
char data_store[RING_BUFFER_DATA_SIZE * RING_BUFFER_SIZE];
|
||||
char data[RING_BUFFER_DATA_SIZE];
|
||||
char *test_data;
|
||||
unsigned index;
|
||||
unsigned data_index;
|
||||
unsigned count;
|
||||
unsigned dummy;
|
||||
bool status;
|
||||
|
||||
Ringbuf_Init(&test_buffer,data_store,RING_BUFFER_DATA_SIZE,RING_BUFFER_SIZE);
|
||||
ct_test(pTest,Ringbuf_Empty(&test_buffer));
|
||||
Ringbuf_Init(&test_buffer, data_store, RING_BUFFER_DATA_SIZE,
|
||||
RING_BUFFER_SIZE);
|
||||
ct_test(pTest, Ringbuf_Empty(&test_buffer));
|
||||
|
||||
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
|
||||
{
|
||||
data[data_index] = data_index;
|
||||
}
|
||||
status = Ringbuf_Put(&test_buffer, data);
|
||||
ct_test(pTest,status == true);
|
||||
ct_test(pTest,!Ringbuf_Empty(&test_buffer));
|
||||
|
||||
test_data = Ringbuf_Get_Front(&test_buffer);
|
||||
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
|
||||
{
|
||||
ct_test(pTest,test_data[data_index] == data[data_index]);
|
||||
}
|
||||
ct_test(pTest,!Ringbuf_Empty(&test_buffer));
|
||||
|
||||
test_data = Ringbuf_Pop_Front(&test_buffer);
|
||||
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
|
||||
{
|
||||
ct_test(pTest,test_data[data_index] == data[data_index]);
|
||||
}
|
||||
ct_test(pTest,Ringbuf_Empty(&test_buffer));
|
||||
|
||||
// fill to max
|
||||
for (index = 0; index < RING_BUFFER_SIZE; index++)
|
||||
{
|
||||
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
|
||||
{
|
||||
data[data_index] = index;
|
||||
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++) {
|
||||
data[data_index] = data_index;
|
||||
}
|
||||
status = Ringbuf_Put(&test_buffer, data);
|
||||
ct_test(pTest,status == true);
|
||||
ct_test(pTest,!Ringbuf_Empty(&test_buffer));
|
||||
}
|
||||
// verify actions on full buffer
|
||||
for (index = 0; index < RING_BUFFER_SIZE; index++)
|
||||
{
|
||||
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
|
||||
{
|
||||
data[data_index] = index;
|
||||
}
|
||||
status = Ringbuf_Put(&test_buffer, data);
|
||||
ct_test(pTest,status == false);
|
||||
ct_test(pTest,!Ringbuf_Empty(&test_buffer));
|
||||
}
|
||||
ct_test(pTest, status == true);
|
||||
ct_test(pTest, !Ringbuf_Empty(&test_buffer));
|
||||
|
||||
// check buffer full
|
||||
for (index = 0; index < RING_BUFFER_SIZE; index++)
|
||||
{
|
||||
test_data = Ringbuf_Get_Front(&test_buffer);
|
||||
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
|
||||
{
|
||||
ct_test(pTest,test_data[data_index] == index);
|
||||
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++) {
|
||||
ct_test(pTest, test_data[data_index] == data[data_index]);
|
||||
}
|
||||
ct_test(pTest, !Ringbuf_Empty(&test_buffer));
|
||||
|
||||
test_data = Ringbuf_Pop_Front(&test_buffer);
|
||||
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
|
||||
{
|
||||
ct_test(pTest,test_data[data_index] == index);
|
||||
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++) {
|
||||
ct_test(pTest, test_data[data_index] == data[data_index]);
|
||||
}
|
||||
}
|
||||
ct_test(pTest,Ringbuf_Empty(&test_buffer));
|
||||
ct_test(pTest, Ringbuf_Empty(&test_buffer));
|
||||
|
||||
// test the ring around the buffer
|
||||
for (index = 0; index < RING_BUFFER_SIZE; index++)
|
||||
{
|
||||
for (count = 1; count < 4; count++)
|
||||
{
|
||||
dummy = index * count;
|
||||
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
|
||||
{
|
||||
data[data_index] = dummy;
|
||||
}
|
||||
status = Ringbuf_Put(&test_buffer, data);
|
||||
ct_test(pTest,status == true);
|
||||
// fill to max
|
||||
for (index = 0; index < RING_BUFFER_SIZE; index++) {
|
||||
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE;
|
||||
data_index++) {
|
||||
data[data_index] = index;
|
||||
}
|
||||
status = Ringbuf_Put(&test_buffer, data);
|
||||
ct_test(pTest, status == true);
|
||||
ct_test(pTest, !Ringbuf_Empty(&test_buffer));
|
||||
}
|
||||
// verify actions on full buffer
|
||||
for (index = 0; index < RING_BUFFER_SIZE; index++) {
|
||||
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE;
|
||||
data_index++) {
|
||||
data[data_index] = index;
|
||||
}
|
||||
status = Ringbuf_Put(&test_buffer, data);
|
||||
ct_test(pTest, status == false);
|
||||
ct_test(pTest, !Ringbuf_Empty(&test_buffer));
|
||||
}
|
||||
|
||||
for (count = 1; count < 4; count++)
|
||||
{
|
||||
dummy = index * count;
|
||||
test_data = Ringbuf_Get_Front(&test_buffer);
|
||||
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
|
||||
{
|
||||
ct_test(pTest,test_data[data_index] == dummy);
|
||||
}
|
||||
// check buffer full
|
||||
for (index = 0; index < RING_BUFFER_SIZE; index++) {
|
||||
test_data = Ringbuf_Get_Front(&test_buffer);
|
||||
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE;
|
||||
data_index++) {
|
||||
ct_test(pTest, test_data[data_index] == index);
|
||||
}
|
||||
|
||||
test_data = Ringbuf_Pop_Front(&test_buffer);
|
||||
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
|
||||
{
|
||||
ct_test(pTest,test_data[data_index] == dummy);
|
||||
}
|
||||
test_data = Ringbuf_Pop_Front(&test_buffer);
|
||||
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE;
|
||||
data_index++) {
|
||||
ct_test(pTest, test_data[data_index] == index);
|
||||
}
|
||||
}
|
||||
}
|
||||
ct_test(pTest,Ringbuf_Empty(&test_buffer));
|
||||
ct_test(pTest, Ringbuf_Empty(&test_buffer));
|
||||
|
||||
// test the ring around the buffer
|
||||
for (index = 0; index < RING_BUFFER_SIZE; index++) {
|
||||
for (count = 1; count < 4; count++) {
|
||||
dummy = index * count;
|
||||
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE;
|
||||
data_index++) {
|
||||
data[data_index] = dummy;
|
||||
}
|
||||
status = Ringbuf_Put(&test_buffer, data);
|
||||
ct_test(pTest, status == true);
|
||||
}
|
||||
|
||||
for (count = 1; count < 4; count++) {
|
||||
dummy = index * count;
|
||||
test_data = Ringbuf_Get_Front(&test_buffer);
|
||||
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE;
|
||||
data_index++) {
|
||||
ct_test(pTest, test_data[data_index] == dummy);
|
||||
}
|
||||
|
||||
test_data = Ringbuf_Pop_Front(&test_buffer);
|
||||
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE;
|
||||
data_index++) {
|
||||
ct_test(pTest, test_data[data_index] == dummy);
|
||||
}
|
||||
}
|
||||
}
|
||||
ct_test(pTest, Ringbuf_Empty(&test_buffer));
|
||||
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_RINGBUF
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("ringbuf", NULL);
|
||||
pTest = ct_create("ringbuf", NULL);
|
||||
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testRingBuf);
|
||||
assert(rc);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testRingBuf);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void)ct_report(pTest);
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
|
||||
ct_destroy(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
+17
-21
@@ -42,34 +42,30 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
struct ring_buffer_t
|
||||
{
|
||||
char *data; // block of memory or array of data
|
||||
unsigned element_size; // how many bytes for each chunk
|
||||
unsigned element_count; // number of chunks of data
|
||||
unsigned head; // first chunk of data
|
||||
unsigned count; // number of chunks in use
|
||||
struct ring_buffer_t {
|
||||
char *data; // block of memory or array of data
|
||||
unsigned element_size; // how many bytes for each chunk
|
||||
unsigned element_count; // number of chunks of data
|
||||
unsigned head; // first chunk of data
|
||||
unsigned count; // number of chunks in use
|
||||
};
|
||||
typedef struct ring_buffer_t RING_BUFFER;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
bool Ringbuf_Empty(RING_BUFFER const *b);
|
||||
char *Ringbuf_Get_Front(RING_BUFFER const *b);
|
||||
char *Ringbuf_Pop_Front(RING_BUFFER *b);
|
||||
bool Ringbuf_Put(
|
||||
RING_BUFFER *b, // ring buffer structure
|
||||
char *data_element); // one element to add to the ring
|
||||
void Ringbuf_Init(
|
||||
RING_BUFFER *b, // ring buffer structure
|
||||
char *data, // data block or array of data
|
||||
unsigned element_size, // size of one element in the data block
|
||||
unsigned element_count); // number of elements in the data block
|
||||
bool Ringbuf_Empty(RING_BUFFER const *b);
|
||||
char *Ringbuf_Get_Front(RING_BUFFER const *b);
|
||||
char *Ringbuf_Pop_Front(RING_BUFFER * b);
|
||||
bool Ringbuf_Put(RING_BUFFER * b, // ring buffer structure
|
||||
char *data_element); // one element to add to the ring
|
||||
void Ringbuf_Init(RING_BUFFER * b, // ring buffer structure
|
||||
char *data, // data block or array of data
|
||||
unsigned element_size, // size of one element in the data block
|
||||
unsigned element_count); // number of elements in the data block
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
+239
-291
@@ -38,240 +38,203 @@
|
||||
#include "rp.h"
|
||||
|
||||
// encode service
|
||||
int rp_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint8_t invoke_id,
|
||||
BACNET_READ_PROPERTY_DATA *data)
|
||||
int rp_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, BACNET_READ_PROPERTY_DATA * data)
|
||||
{
|
||||
int len = 0; // length of each encoding
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
int len = 0; // length of each encoding
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
|
||||
if (apdu)
|
||||
{
|
||||
apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
|
||||
apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU);
|
||||
apdu[2] = invoke_id;
|
||||
apdu[3] = SERVICE_CONFIRMED_READ_PROPERTY; // service choice
|
||||
apdu_len = 4;
|
||||
len = encode_context_object_id(&apdu[apdu_len], 0,
|
||||
data->object_type, data->object_instance);
|
||||
apdu_len += len;
|
||||
len = encode_context_enumerated(&apdu[apdu_len], 1,
|
||||
data->object_property);
|
||||
apdu_len += len;
|
||||
/* optional array index */
|
||||
if (data->array_index != BACNET_ARRAY_ALL)
|
||||
{
|
||||
len = encode_context_unsigned(&apdu[apdu_len], 2,
|
||||
data->array_index);
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
|
||||
apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU);
|
||||
apdu[2] = invoke_id;
|
||||
apdu[3] = SERVICE_CONFIRMED_READ_PROPERTY; // service choice
|
||||
apdu_len = 4;
|
||||
len = encode_context_object_id(&apdu[apdu_len], 0,
|
||||
data->object_type, data->object_instance);
|
||||
apdu_len += len;
|
||||
len = encode_context_enumerated(&apdu[apdu_len], 1,
|
||||
data->object_property);
|
||||
apdu_len += len;
|
||||
/* optional array index */
|
||||
if (data->array_index != BACNET_ARRAY_ALL) {
|
||||
len = encode_context_unsigned(&apdu[apdu_len], 2,
|
||||
data->array_index);
|
||||
apdu_len += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
// decode the service request only
|
||||
int rp_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_READ_PROPERTY_DATA *data)
|
||||
int rp_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_READ_PROPERTY_DATA * data)
|
||||
{
|
||||
unsigned len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value_type = 0;
|
||||
int type = 0; // for decoding
|
||||
int property = 0; // for decoding
|
||||
uint32_t array_value = 0; // for decoding
|
||||
unsigned len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value_type = 0;
|
||||
int type = 0; // for decoding
|
||||
int property = 0; // for decoding
|
||||
uint32_t array_value = 0; // for decoding
|
||||
|
||||
// check for value pointers
|
||||
if (apdu_len && data)
|
||||
{
|
||||
// Tag 0: Object ID
|
||||
if (!decode_is_context_tag(&apdu[len++], 0))
|
||||
return -1;
|
||||
len += decode_object_id(&apdu[len], &type, &data->object_instance);
|
||||
data->object_type = type;
|
||||
// check for value pointers
|
||||
if (apdu_len && data) {
|
||||
// Tag 0: Object ID
|
||||
if (!decode_is_context_tag(&apdu[len++], 0))
|
||||
return -1;
|
||||
len += decode_object_id(&apdu[len], &type, &data->object_instance);
|
||||
data->object_type = type;
|
||||
// Tag 1: Property ID
|
||||
len += decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
if (tag_number != 1)
|
||||
return -1;
|
||||
len += decode_enumerated(&apdu[len], len_value_type, &property);
|
||||
data->object_property = property;
|
||||
// Tag 2: Optional Array Index
|
||||
if (len < apdu_len) {
|
||||
len += decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value_type);
|
||||
if (tag_number == 2) {
|
||||
len += decode_unsigned(&apdu[len], len_value_type,
|
||||
&array_value);
|
||||
data->array_index = array_value;
|
||||
} else
|
||||
data->array_index = BACNET_ARRAY_ALL;
|
||||
} else
|
||||
data->array_index = BACNET_ARRAY_ALL;
|
||||
}
|
||||
|
||||
return (int) len;
|
||||
}
|
||||
|
||||
int rp_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id, BACNET_READ_PROPERTY_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
unsigned offset = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
|
||||
return -1;
|
||||
// apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted());
|
||||
*invoke_id = apdu[2]; /* invoke id - filled in by net layer */
|
||||
if (apdu[3] != SERVICE_CONFIRMED_READ_PROPERTY)
|
||||
return -1;
|
||||
offset = 4;
|
||||
|
||||
if (apdu_len > offset) {
|
||||
len = rp_decode_service_request(&apdu[offset],
|
||||
apdu_len - offset, data);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int rp_ack_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, BACNET_READ_PROPERTY_DATA * data)
|
||||
{
|
||||
int len = 0; // length of each encoding
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
|
||||
if (apdu) {
|
||||
apdu[0] = PDU_TYPE_COMPLEX_ACK; /* complex ACK service */
|
||||
apdu[1] = invoke_id; /* original invoke id from request */
|
||||
apdu[2] = SERVICE_CONFIRMED_READ_PROPERTY; // service choice
|
||||
apdu_len = 3;
|
||||
// service ack follows
|
||||
apdu_len += encode_context_object_id(&apdu[apdu_len], 0,
|
||||
data->object_type, data->object_instance);
|
||||
apdu_len += encode_context_enumerated(&apdu[apdu_len], 1,
|
||||
data->object_property);
|
||||
// context 2 array index is optional
|
||||
if (data->array_index != BACNET_ARRAY_ALL) {
|
||||
apdu_len += encode_context_unsigned(&apdu[apdu_len], 2,
|
||||
data->array_index);
|
||||
}
|
||||
// propertyValue
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 3);
|
||||
for (len = 0; len < data->application_data_len; len++) {
|
||||
apdu[apdu_len++] = data->application_data[len];
|
||||
}
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 3);
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
int rp_ack_decode_service_request(uint8_t * apdu, int apdu_len, // total length of the apdu
|
||||
BACNET_READ_PROPERTY_DATA * data)
|
||||
{
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value_type = 0;
|
||||
int tag_len = 0; // length of tag decode
|
||||
int len = 0; // total length of decodes
|
||||
int object = 0, property = 0; // for decoding
|
||||
uint32_t array_value = 0; // for decoding
|
||||
|
||||
// FIXME: check apdu_len against the len during decode
|
||||
// Tag 0: Object ID
|
||||
if (!decode_is_context_tag(&apdu[0], 0))
|
||||
return -1;
|
||||
len = 1;
|
||||
len += decode_object_id(&apdu[len], &object, &data->object_instance);
|
||||
data->object_type = object;
|
||||
// Tag 1: Property ID
|
||||
len += decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
if (tag_number != 1)
|
||||
return -1;
|
||||
return -1;
|
||||
len += decode_enumerated(&apdu[len], len_value_type, &property);
|
||||
data->object_property = property;
|
||||
// Tag 2: Optional Array Index
|
||||
if (len < apdu_len)
|
||||
{
|
||||
len += decode_tag_number_and_value(&apdu[len],&tag_number,
|
||||
&len_value_type);
|
||||
if (tag_number == 2)
|
||||
{
|
||||
len += decode_unsigned(&apdu[len], len_value_type,
|
||||
&array_value);
|
||||
data->array_index = array_value;
|
||||
}
|
||||
else
|
||||
data->array_index = BACNET_ARRAY_ALL;
|
||||
}
|
||||
else
|
||||
data->array_index = BACNET_ARRAY_ALL;
|
||||
}
|
||||
|
||||
return (int)len;
|
||||
}
|
||||
|
||||
int rp_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
BACNET_READ_PROPERTY_DATA *data)
|
||||
{
|
||||
int len = 0;
|
||||
unsigned offset = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
|
||||
return -1;
|
||||
// apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted());
|
||||
*invoke_id = apdu[2]; /* invoke id - filled in by net layer */
|
||||
if (apdu[3] != SERVICE_CONFIRMED_READ_PROPERTY)
|
||||
return -1;
|
||||
offset = 4;
|
||||
|
||||
if (apdu_len > offset)
|
||||
{
|
||||
len = rp_decode_service_request(
|
||||
&apdu[offset],
|
||||
apdu_len - offset,
|
||||
data);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int rp_ack_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint8_t invoke_id,
|
||||
BACNET_READ_PROPERTY_DATA *data)
|
||||
{
|
||||
int len = 0; // length of each encoding
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
|
||||
if (apdu)
|
||||
{
|
||||
apdu[0] = PDU_TYPE_COMPLEX_ACK; /* complex ACK service */
|
||||
apdu[1] = invoke_id; /* original invoke id from request */
|
||||
apdu[2] = SERVICE_CONFIRMED_READ_PROPERTY; // service choice
|
||||
apdu_len = 3;
|
||||
// service ack follows
|
||||
apdu_len += encode_context_object_id(&apdu[apdu_len], 0,
|
||||
data->object_type, data->object_instance);
|
||||
apdu_len += encode_context_enumerated(&apdu[apdu_len], 1,
|
||||
data->object_property);
|
||||
// context 2 array index is optional
|
||||
if (data->array_index != BACNET_ARRAY_ALL)
|
||||
{
|
||||
apdu_len += encode_context_unsigned(&apdu[apdu_len], 2,
|
||||
data->array_index);
|
||||
}
|
||||
// propertyValue
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 3);
|
||||
for (len = 0; len < data->application_data_len; len++)
|
||||
{
|
||||
apdu[apdu_len++] = data->application_data[len];
|
||||
}
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 3);
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
int rp_ack_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
int apdu_len, // total length of the apdu
|
||||
BACNET_READ_PROPERTY_DATA *data)
|
||||
{
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value_type = 0;
|
||||
int tag_len = 0; // length of tag decode
|
||||
int len = 0; // total length of decodes
|
||||
int object = 0, property = 0; // for decoding
|
||||
uint32_t array_value = 0; // for decoding
|
||||
|
||||
// FIXME: check apdu_len against the len during decode
|
||||
// Tag 0: Object ID
|
||||
if (!decode_is_context_tag(&apdu[0], 0))
|
||||
return -1;
|
||||
len = 1;
|
||||
len += decode_object_id(&apdu[len],
|
||||
&object, &data->object_instance);
|
||||
data->object_type = object;
|
||||
// Tag 1: Property ID
|
||||
len += decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
if (tag_number != 1)
|
||||
return -1;
|
||||
len += decode_enumerated(&apdu[len],
|
||||
len_value_type,
|
||||
&property);
|
||||
data->object_property = property;
|
||||
// Tag 2: Optional Array Index
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
if (tag_number == 2)
|
||||
{
|
||||
len += tag_len;
|
||||
len += decode_unsigned(&apdu[len],
|
||||
len_value_type, &array_value);
|
||||
data->array_index = array_value;
|
||||
}
|
||||
else
|
||||
data->array_index = BACNET_ARRAY_ALL;
|
||||
|
||||
// Tag 3: opening context tag */
|
||||
if (decode_is_opening_tag_number(&apdu[len], 3))
|
||||
{
|
||||
// a tag number of 3 is not extended so only one octet
|
||||
len++;
|
||||
// don't decode the application tag number or its data here
|
||||
data->application_data = &apdu[len];
|
||||
data->application_data_len = apdu_len - len - 1 /*closing tag*/;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
|
||||
return len;
|
||||
if (tag_number == 2) {
|
||||
len += tag_len;
|
||||
len += decode_unsigned(&apdu[len], len_value_type, &array_value);
|
||||
data->array_index = array_value;
|
||||
} else
|
||||
data->array_index = BACNET_ARRAY_ALL;
|
||||
|
||||
// Tag 3: opening context tag */
|
||||
if (decode_is_opening_tag_number(&apdu[len], 3)) {
|
||||
// a tag number of 3 is not extended so only one octet
|
||||
len++;
|
||||
// don't decode the application tag number or its data here
|
||||
data->application_data = &apdu[len];
|
||||
data->application_data_len = apdu_len - len - 1 /*closing tag */ ;
|
||||
} else
|
||||
return -1;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int rp_ack_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
int apdu_len, // total length of the apdu
|
||||
uint8_t *invoke_id,
|
||||
BACNET_READ_PROPERTY_DATA *data)
|
||||
int rp_ack_decode_apdu(uint8_t * apdu, int apdu_len, // total length of the apdu
|
||||
uint8_t * invoke_id, BACNET_READ_PROPERTY_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
int offset = 0;
|
||||
int len = 0;
|
||||
int offset = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu[0] != PDU_TYPE_COMPLEX_ACK)
|
||||
return -1;
|
||||
*invoke_id = apdu[1];
|
||||
if (apdu[2] != SERVICE_CONFIRMED_READ_PROPERTY)
|
||||
return -1;
|
||||
offset = 3;
|
||||
if (apdu_len > offset)
|
||||
{
|
||||
len = rp_ack_decode_service_request(
|
||||
&apdu[offset],
|
||||
apdu_len - offset,
|
||||
data);
|
||||
}
|
||||
|
||||
return len;
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu[0] != PDU_TYPE_COMPLEX_ACK)
|
||||
return -1;
|
||||
*invoke_id = apdu[1];
|
||||
if (apdu[2] != SERVICE_CONFIRMED_READ_PROPERTY)
|
||||
return -1;
|
||||
offset = 3;
|
||||
if (apdu_len > offset) {
|
||||
len = rp_ack_decode_service_request(&apdu[offset],
|
||||
apdu_len - offset, data);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
@@ -281,93 +244,78 @@ int rp_ack_decode_apdu(
|
||||
|
||||
void testReadPropertyAck(Test * pTest)
|
||||
{
|
||||
uint8_t apdu[480] = {0};
|
||||
uint8_t apdu2[480] = {0};
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 1;
|
||||
uint8_t test_invoke_id = 0;
|
||||
BACNET_READ_PROPERTY_DATA data;
|
||||
BACNET_READ_PROPERTY_DATA test_data;
|
||||
BACNET_OBJECT_TYPE object_type = OBJECT_DEVICE;
|
||||
uint32_t object_instance = 0;
|
||||
int object = 0;
|
||||
uint8_t apdu[480] = { 0 };
|
||||
uint8_t apdu2[480] = { 0 };
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 1;
|
||||
uint8_t test_invoke_id = 0;
|
||||
BACNET_READ_PROPERTY_DATA data;
|
||||
BACNET_READ_PROPERTY_DATA test_data;
|
||||
BACNET_OBJECT_TYPE object_type = OBJECT_DEVICE;
|
||||
uint32_t object_instance = 0;
|
||||
int object = 0;
|
||||
|
||||
data.object_type = OBJECT_DEVICE;
|
||||
data.object_instance = 1;
|
||||
data.object_property = PROP_OBJECT_IDENTIFIER;
|
||||
data.array_index = BACNET_ARRAY_ALL;
|
||||
data.object_type = OBJECT_DEVICE;
|
||||
data.object_instance = 1;
|
||||
data.object_property = PROP_OBJECT_IDENTIFIER;
|
||||
data.array_index = BACNET_ARRAY_ALL;
|
||||
|
||||
data.application_data_len = encode_bacnet_object_id(&apdu2[0],
|
||||
data.object_type,
|
||||
data.object_instance);
|
||||
data.application_data = &apdu2[0];
|
||||
|
||||
len = rp_ack_encode_apdu(
|
||||
&apdu[0],
|
||||
invoke_id,
|
||||
&data);
|
||||
ct_test(pTest, len != 0);
|
||||
ct_test(pTest, len != -1);
|
||||
apdu_len = len;
|
||||
len = rp_ack_decode_apdu(
|
||||
&apdu[0],
|
||||
apdu_len, // total length of the apdu
|
||||
&test_invoke_id,
|
||||
&test_data);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
data.application_data_len = encode_bacnet_object_id(&apdu2[0],
|
||||
data.object_type, data.object_instance);
|
||||
data.application_data = &apdu2[0];
|
||||
|
||||
ct_test(pTest, test_data.object_type == data.object_type);
|
||||
ct_test(pTest, test_data.object_instance == data.object_instance);
|
||||
ct_test(pTest, test_data.object_property == data.object_property);
|
||||
ct_test(pTest, test_data.array_index == data.array_index);
|
||||
ct_test(pTest, test_data.application_data_len == data.application_data_len);
|
||||
len = rp_ack_encode_apdu(&apdu[0], invoke_id, &data);
|
||||
ct_test(pTest, len != 0);
|
||||
ct_test(pTest, len != -1);
|
||||
apdu_len = len;
|
||||
len = rp_ack_decode_apdu(&apdu[0], apdu_len, // total length of the apdu
|
||||
&test_invoke_id, &test_data);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
|
||||
/* since object property == object_id, decode the application data using
|
||||
the appropriate decode function */
|
||||
len = decode_object_id(
|
||||
test_data.application_data,
|
||||
&object,
|
||||
&object_instance);
|
||||
object_type = object;
|
||||
ct_test(pTest, object_type == data.object_type);
|
||||
ct_test(pTest, object_instance == data.object_instance);
|
||||
ct_test(pTest, test_data.object_type == data.object_type);
|
||||
ct_test(pTest, test_data.object_instance == data.object_instance);
|
||||
ct_test(pTest, test_data.object_property == data.object_property);
|
||||
ct_test(pTest, test_data.array_index == data.array_index);
|
||||
ct_test(pTest,
|
||||
test_data.application_data_len == data.application_data_len);
|
||||
|
||||
/* since object property == object_id, decode the application data using
|
||||
the appropriate decode function */
|
||||
len = decode_object_id(test_data.application_data,
|
||||
&object, &object_instance);
|
||||
object_type = object;
|
||||
ct_test(pTest, object_type == data.object_type);
|
||||
ct_test(pTest, object_instance == data.object_instance);
|
||||
}
|
||||
|
||||
void testReadProperty(Test * pTest)
|
||||
{
|
||||
uint8_t apdu[480] = {0};
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 128;
|
||||
uint8_t test_invoke_id = 0;
|
||||
BACNET_READ_PROPERTY_DATA data;
|
||||
BACNET_READ_PROPERTY_DATA test_data;
|
||||
|
||||
data.object_type = OBJECT_DEVICE;
|
||||
data.object_instance = 1;
|
||||
data.object_property = PROP_OBJECT_IDENTIFIER;
|
||||
data.array_index = BACNET_ARRAY_ALL;
|
||||
len = rp_encode_apdu(
|
||||
&apdu[0],
|
||||
invoke_id,
|
||||
&data);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 128;
|
||||
uint8_t test_invoke_id = 0;
|
||||
BACNET_READ_PROPERTY_DATA data;
|
||||
BACNET_READ_PROPERTY_DATA test_data;
|
||||
|
||||
len = rp_decode_apdu(
|
||||
&apdu[0],
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_data);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_data.object_type == data.object_type);
|
||||
ct_test(pTest, test_data.object_instance == data.object_instance);
|
||||
ct_test(pTest, test_data.object_property == data.object_property);
|
||||
ct_test(pTest, test_data.array_index == data.array_index);
|
||||
data.object_type = OBJECT_DEVICE;
|
||||
data.object_instance = 1;
|
||||
data.object_property = PROP_OBJECT_IDENTIFIER;
|
||||
data.array_index = BACNET_ARRAY_ALL;
|
||||
len = rp_encode_apdu(&apdu[0], invoke_id, &data);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
|
||||
return;
|
||||
len = rp_decode_apdu(&apdu[0], apdu_len, &test_invoke_id, &test_data);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_data.object_type == data.object_type);
|
||||
ct_test(pTest, test_data.object_instance == data.object_instance);
|
||||
ct_test(pTest, test_data.object_property == data.object_property);
|
||||
ct_test(pTest, test_data.array_index == data.array_index);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_READ_PROPERTY
|
||||
|
||||
+26
-42
@@ -37,65 +37,49 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct BACnet_Read_Property_Data
|
||||
{
|
||||
BACNET_OBJECT_TYPE object_type;
|
||||
uint32_t object_instance;
|
||||
BACNET_PROPERTY_ID object_property;
|
||||
int32_t array_index;
|
||||
uint8_t *application_data;
|
||||
int application_data_len;
|
||||
typedef struct BACnet_Read_Property_Data {
|
||||
BACNET_OBJECT_TYPE object_type;
|
||||
uint32_t object_instance;
|
||||
BACNET_PROPERTY_ID object_property;
|
||||
int32_t array_index;
|
||||
uint8_t *application_data;
|
||||
int application_data_len;
|
||||
} BACNET_READ_PROPERTY_DATA;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
// encode service
|
||||
int rp_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint8_t invoke_id,
|
||||
BACNET_READ_PROPERTY_DATA *data);
|
||||
int rp_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, BACNET_READ_PROPERTY_DATA * data);
|
||||
|
||||
// decode the service request only
|
||||
int rp_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_READ_PROPERTY_DATA *data);
|
||||
|
||||
int rp_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
BACNET_READ_PROPERTY_DATA *data);
|
||||
int rp_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_READ_PROPERTY_DATA * data);
|
||||
|
||||
int rp_ack_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint8_t invoke_id,
|
||||
BACNET_READ_PROPERTY_DATA *data);
|
||||
int rp_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id, BACNET_READ_PROPERTY_DATA * data);
|
||||
|
||||
int rp_ack_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
int apdu_len, // total length of the apdu
|
||||
BACNET_READ_PROPERTY_DATA *data);
|
||||
int rp_ack_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, BACNET_READ_PROPERTY_DATA * data);
|
||||
|
||||
int rp_ack_decode_service_request(uint8_t * apdu, int apdu_len, // total length of the apdu
|
||||
BACNET_READ_PROPERTY_DATA * data);
|
||||
|
||||
int rp_ack_decode_apdu(uint8_t * apdu, int apdu_len, // total length of the apdu
|
||||
uint8_t * invoke_id, BACNET_READ_PROPERTY_DATA * data);
|
||||
|
||||
int rp_ack_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
int apdu_len, // total length of the apdu
|
||||
uint8_t *invoke_id,
|
||||
BACNET_READ_PROPERTY_DATA *data);
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
|
||||
void test_ReadProperty(Test * pTest);
|
||||
void test_ReadPropertyAck(Test * pTest);
|
||||
void test_ReadProperty(Test * pTest);
|
||||
void test_ReadPropertyAck(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
|
||||
+594
-725
File diff suppressed because it is too large
Load Diff
+41
-76
@@ -42,7 +42,7 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* encode functions */
|
||||
/* Start with the Init function, and then add an object,
|
||||
@@ -51,104 +51,69 @@ extern "C" {
|
||||
until the APDU is full.*/
|
||||
|
||||
/* RPM */
|
||||
int rpm_encode_apdu_init(
|
||||
uint8_t *apdu,
|
||||
uint8_t invoke_id);
|
||||
int rpm_encode_apdu_init(uint8_t * apdu, uint8_t invoke_id);
|
||||
|
||||
int rpm_encode_apdu_object_begin(
|
||||
uint8_t *apdu,
|
||||
BACNET_OBJECT_TYPE object_type,
|
||||
uint32_t object_instance);
|
||||
int rpm_encode_apdu_object_begin(uint8_t * apdu,
|
||||
BACNET_OBJECT_TYPE object_type, uint32_t object_instance);
|
||||
|
||||
int rpm_encode_apdu_object_property(
|
||||
uint8_t *apdu,
|
||||
BACNET_PROPERTY_ID object_property,
|
||||
int32_t array_index);
|
||||
int rpm_encode_apdu_object_property(uint8_t * apdu,
|
||||
BACNET_PROPERTY_ID object_property, int32_t array_index);
|
||||
|
||||
int rpm_encode_apdu_object_end(
|
||||
uint8_t *apdu);
|
||||
int rpm_encode_apdu_object_end(uint8_t * apdu);
|
||||
|
||||
int rpm_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
uint8_t **service_request,
|
||||
unsigned *service_request_len);
|
||||
int rpm_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id,
|
||||
uint8_t ** service_request, unsigned *service_request_len);
|
||||
|
||||
/* decode the object portion of the service request only */
|
||||
int rpm_decode_object_id(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_OBJECT_TYPE *object_type,
|
||||
uint32_t *object_instance);
|
||||
int rpm_decode_object_id(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_OBJECT_TYPE * object_type, uint32_t * object_instance);
|
||||
|
||||
/* is this the end of this object property list? */
|
||||
int rpm_decode_object_end(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len);
|
||||
int rpm_decode_object_end(uint8_t * apdu, unsigned apdu_len);
|
||||
|
||||
/* decode the object property portion of the service request only */
|
||||
int rpm_decode_object_property(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_PROPERTY_ID *object_property,
|
||||
int32_t *array_index);
|
||||
int rpm_decode_object_property(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_PROPERTY_ID * object_property, int32_t * array_index);
|
||||
|
||||
/* RPM Ack */
|
||||
int rpm_ack_encode_apdu_object_begin(
|
||||
uint8_t *apdu,
|
||||
BACNET_OBJECT_TYPE object_type,
|
||||
uint32_t object_instance);
|
||||
int rpm_ack_encode_apdu_object_begin(uint8_t * apdu,
|
||||
BACNET_OBJECT_TYPE object_type, uint32_t object_instance);
|
||||
|
||||
int rpm_ack_encode_apdu_object_property_value(
|
||||
uint8_t *apdu,
|
||||
uint8_t *application_data,
|
||||
unsigned application_data_len);
|
||||
int rpm_ack_encode_apdu_object_property_value(uint8_t * apdu,
|
||||
uint8_t * application_data, unsigned application_data_len);
|
||||
|
||||
int rpm_ack_encode_apdu_object_property_error(
|
||||
uint8_t *apdu,
|
||||
BACNET_ERROR_CLASS error_class,
|
||||
BACNET_ERROR_CODE error_code);
|
||||
int rpm_ack_encode_apdu_object_property_error(uint8_t * apdu,
|
||||
BACNET_ERROR_CLASS error_class, BACNET_ERROR_CODE error_code);
|
||||
|
||||
int rpm_ack_encode_apdu_object_end(
|
||||
uint8_t *apdu);
|
||||
int rpm_ack_encode_apdu_object_end(uint8_t * apdu);
|
||||
|
||||
int rpm_ack_decode_object_id(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_OBJECT_TYPE *object_type,
|
||||
uint32_t *object_instance);
|
||||
int rpm_ack_decode_object_id(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_OBJECT_TYPE * object_type, uint32_t * object_instance);
|
||||
/* is this the end of the list of this objects properties values? */
|
||||
int rpm_ack_decode_object_end(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len);
|
||||
int rpm_ack_decode_object_property(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_PROPERTY_ID *object_property,
|
||||
int32_t *array_index);
|
||||
int rpm_ack_decode_object_end(uint8_t * apdu, unsigned apdu_len);
|
||||
int rpm_ack_decode_object_property(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_PROPERTY_ID * object_property, int32_t * array_index);
|
||||
/* decode the object property value portion of the service request only */
|
||||
int rpm_ack_decode_object_property_value(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t **application_data,
|
||||
unsigned *application_data_len);
|
||||
int rpm_ack_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
int apdu_len, /* total length of the apdu */
|
||||
uint8_t *invoke_id,
|
||||
uint8_t **service_request,
|
||||
unsigned *service_request_len);
|
||||
int rpm_ack_decode_object_property_value(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t ** application_data, unsigned *application_data_len);
|
||||
int rpm_ack_decode_apdu(uint8_t * apdu, int apdu_len, /* total length of the apdu */
|
||||
uint8_t * invoke_id,
|
||||
uint8_t ** service_request, unsigned *service_request_len);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testReadPropertyMultiple(Test * pTest);
|
||||
void testReadPropertyMultipleAck(Test * pTest);
|
||||
void testReadPropertyMultiple(Test * pTest);
|
||||
void testReadPropertyMultipleAck(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
|
||||
+8
-11
@@ -41,22 +41,19 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void RS485_Initialize(void);
|
||||
void RS485_Initialize(void);
|
||||
|
||||
void RS485_Send_Frame(
|
||||
volatile struct mstp_port_struct_t *mstp_port, // port specific data
|
||||
uint8_t *buffer, // frame to send (up to 501 bytes of data)
|
||||
uint16_t nbytes); // number of bytes of data (up to 501)
|
||||
void RS485_Send_Frame(volatile struct mstp_port_struct_t *mstp_port, // port specific data
|
||||
uint8_t * buffer, // frame to send (up to 501 bytes of data)
|
||||
uint16_t nbytes); // number of bytes of data (up to 501)
|
||||
|
||||
void RS485_Check_UART_Data(
|
||||
volatile struct mstp_port_struct_t *mstp_port); // port specific data
|
||||
void RS485_Check_UART_Data(volatile struct mstp_port_struct_t *mstp_port); // port specific data
|
||||
|
||||
void RS485_Process_Tx_Message(void);
|
||||
void RS485_Process_Tx_Message(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
+114
-125
@@ -40,181 +40,170 @@
|
||||
#include <stddef.h>
|
||||
#include "sbuf.h"
|
||||
|
||||
void sbuf_init(
|
||||
STATIC_BUFFER *b, /* static buffer structure */
|
||||
char *data, /* actual size, in bytes, of the data block or array of data */
|
||||
unsigned size) /* number of bytes used */
|
||||
{
|
||||
if (b)
|
||||
{
|
||||
b->data = data;
|
||||
b->size = size;
|
||||
b->count = 0;
|
||||
}
|
||||
void sbuf_init(STATIC_BUFFER * b, /* static buffer structure */
|
||||
char *data, /* actual size, in bytes, of the data block or array of data */
|
||||
unsigned size)
|
||||
{ /* number of bytes used */
|
||||
if (b) {
|
||||
b->data = data;
|
||||
b->size = size;
|
||||
b->count = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
/* returns true if count==0, false if count > 0 */
|
||||
bool sbuf_empty(STATIC_BUFFER const *b)
|
||||
{
|
||||
return (b?(b->count == 0):false);
|
||||
return (b ? (b->count == 0) : false);
|
||||
}
|
||||
|
||||
char *sbuf_data(STATIC_BUFFER const *b)
|
||||
{
|
||||
return (b?b->data:NULL);
|
||||
return (b ? b->data : NULL);
|
||||
}
|
||||
|
||||
unsigned sbuf_size(STATIC_BUFFER *b)
|
||||
unsigned sbuf_size(STATIC_BUFFER * b)
|
||||
{
|
||||
return (b?b->size:0);
|
||||
return (b ? b->size : 0);
|
||||
}
|
||||
|
||||
unsigned sbuf_count(STATIC_BUFFER *b)
|
||||
unsigned sbuf_count(STATIC_BUFFER * b)
|
||||
{
|
||||
return (b?b->count:0);
|
||||
return (b ? b->count : 0);
|
||||
}
|
||||
|
||||
/* returns true if successful, false if not enough room to append data */
|
||||
bool sbuf_put(
|
||||
STATIC_BUFFER *b, /* static buffer structure */
|
||||
unsigned offset, /* where to start */
|
||||
char *data, /* number of bytes used */
|
||||
unsigned data_size) /* how many to add */
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
bool sbuf_put(STATIC_BUFFER * b, /* static buffer structure */
|
||||
unsigned offset, /* where to start */
|
||||
char *data, /* number of bytes used */
|
||||
unsigned data_size)
|
||||
{ /* how many to add */
|
||||
bool status = false; /* return value */
|
||||
|
||||
if (b && b->data)
|
||||
{
|
||||
if (((offset + data_size) < b->size))
|
||||
{
|
||||
b->count = offset + data_size;
|
||||
while (data_size)
|
||||
{
|
||||
b->data[offset] = *data;
|
||||
offset++;
|
||||
data++;
|
||||
data_size--;
|
||||
}
|
||||
status = true;
|
||||
if (b && b->data) {
|
||||
if (((offset + data_size) < b->size)) {
|
||||
b->count = offset + data_size;
|
||||
while (data_size) {
|
||||
b->data[offset] = *data;
|
||||
offset++;
|
||||
data++;
|
||||
data_size--;
|
||||
}
|
||||
status = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* returns true if successful, false if not enough room to append data */
|
||||
bool sbuf_append(
|
||||
STATIC_BUFFER *b, /* static buffer structure */
|
||||
char *data, /* number of bytes used */
|
||||
unsigned data_size) /* how many to add */
|
||||
{
|
||||
unsigned count = 0;
|
||||
|
||||
if (b)
|
||||
count = b->count;
|
||||
|
||||
return sbuf_put(b, count, data, data_size);
|
||||
bool sbuf_append(STATIC_BUFFER * b, /* static buffer structure */
|
||||
char *data, /* number of bytes used */
|
||||
unsigned data_size)
|
||||
{ /* how many to add */
|
||||
unsigned count = 0;
|
||||
|
||||
if (b)
|
||||
count = b->count;
|
||||
|
||||
return sbuf_put(b, count, data, data_size);
|
||||
}
|
||||
|
||||
/* returns true if successful, false if not enough room to append data */
|
||||
bool sbuf_truncate(
|
||||
STATIC_BUFFER *b, /* static buffer structure */
|
||||
unsigned count) /* total number of bytes in use */
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
bool sbuf_truncate(STATIC_BUFFER * b, /* static buffer structure */
|
||||
unsigned count)
|
||||
{ /* total number of bytes in use */
|
||||
bool status = false; /* return value */
|
||||
|
||||
if (b)
|
||||
{
|
||||
if (count < b->size)
|
||||
{
|
||||
b->count = count;
|
||||
status = true;
|
||||
if (b) {
|
||||
if (count < b->size) {
|
||||
b->count = count;
|
||||
status = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ctest.h"
|
||||
|
||||
void testStaticBuffer(Test* pTest)
|
||||
void testStaticBuffer(Test * pTest)
|
||||
{
|
||||
STATIC_BUFFER sbuffer;
|
||||
char *data1 = "Joshua";
|
||||
char *data2 = "Anna";
|
||||
char *data3 = "Christopher";
|
||||
char *data4 = "Mary";
|
||||
char data_buffer[480] = "";
|
||||
char test_data_buffer[480] = "";
|
||||
char *data;
|
||||
unsigned count;
|
||||
STATIC_BUFFER sbuffer;
|
||||
char *data1 = "Joshua";
|
||||
char *data2 = "Anna";
|
||||
char *data3 = "Christopher";
|
||||
char *data4 = "Mary";
|
||||
char data_buffer[480] = "";
|
||||
char test_data_buffer[480] = "";
|
||||
char *data;
|
||||
unsigned count;
|
||||
|
||||
sbuf_init(&sbuffer,NULL,0);
|
||||
ct_test(pTest,sbuf_empty(&sbuffer) == true);
|
||||
ct_test(pTest,sbuf_data(&sbuffer) == NULL);
|
||||
ct_test(pTest,sbuf_size(&sbuffer) == 0);
|
||||
ct_test(pTest,sbuf_count(&sbuffer) == 0);
|
||||
ct_test(pTest,sbuf_append(&sbuffer,data1,strlen(data1)) == false);
|
||||
sbuf_init(&sbuffer, NULL, 0);
|
||||
ct_test(pTest, sbuf_empty(&sbuffer) == true);
|
||||
ct_test(pTest, sbuf_data(&sbuffer) == NULL);
|
||||
ct_test(pTest, sbuf_size(&sbuffer) == 0);
|
||||
ct_test(pTest, sbuf_count(&sbuffer) == 0);
|
||||
ct_test(pTest, sbuf_append(&sbuffer, data1, strlen(data1)) == false);
|
||||
|
||||
sbuf_init(&sbuffer,data_buffer,sizeof(data_buffer));
|
||||
ct_test(pTest,sbuf_empty(&sbuffer) == true);
|
||||
ct_test(pTest,sbuf_data(&sbuffer) == data_buffer);
|
||||
ct_test(pTest,sbuf_size(&sbuffer) == sizeof(data_buffer));
|
||||
ct_test(pTest,sbuf_count(&sbuffer) == 0);
|
||||
|
||||
ct_test(pTest,sbuf_append(&sbuffer,data1,strlen(data1)) == true);
|
||||
ct_test(pTest,sbuf_append(&sbuffer,data2,strlen(data2)) == true);
|
||||
ct_test(pTest,sbuf_append(&sbuffer,data3,strlen(data3)) == true);
|
||||
ct_test(pTest,sbuf_append(&sbuffer,data4,strlen(data4)) == true);
|
||||
strcat(test_data_buffer,data1);
|
||||
strcat(test_data_buffer,data2);
|
||||
strcat(test_data_buffer,data3);
|
||||
strcat(test_data_buffer,data4);
|
||||
ct_test(pTest,sbuf_count(&sbuffer) == strlen(test_data_buffer));
|
||||
sbuf_init(&sbuffer, data_buffer, sizeof(data_buffer));
|
||||
ct_test(pTest, sbuf_empty(&sbuffer) == true);
|
||||
ct_test(pTest, sbuf_data(&sbuffer) == data_buffer);
|
||||
ct_test(pTest, sbuf_size(&sbuffer) == sizeof(data_buffer));
|
||||
ct_test(pTest, sbuf_count(&sbuffer) == 0);
|
||||
|
||||
data = sbuf_data(&sbuffer);
|
||||
count = sbuf_count(&sbuffer);
|
||||
ct_test(pTest,memcmp(data,test_data_buffer,count) == 0);
|
||||
ct_test(pTest,count == strlen(test_data_buffer));
|
||||
|
||||
ct_test(pTest,sbuf_truncate(&sbuffer,0) == true);
|
||||
ct_test(pTest,sbuf_count(&sbuffer) == 0);
|
||||
ct_test(pTest,sbuf_size(&sbuffer) == sizeof(data_buffer));
|
||||
ct_test(pTest,sbuf_append(&sbuffer,data4,strlen(data4)) == true);
|
||||
data = sbuf_data(&sbuffer);
|
||||
count = sbuf_count(&sbuffer);
|
||||
ct_test(pTest,memcmp(data,data4,count) == 0);
|
||||
ct_test(pTest,count == strlen(data4));
|
||||
ct_test(pTest, sbuf_append(&sbuffer, data1, strlen(data1)) == true);
|
||||
ct_test(pTest, sbuf_append(&sbuffer, data2, strlen(data2)) == true);
|
||||
ct_test(pTest, sbuf_append(&sbuffer, data3, strlen(data3)) == true);
|
||||
ct_test(pTest, sbuf_append(&sbuffer, data4, strlen(data4)) == true);
|
||||
strcat(test_data_buffer, data1);
|
||||
strcat(test_data_buffer, data2);
|
||||
strcat(test_data_buffer, data3);
|
||||
strcat(test_data_buffer, data4);
|
||||
ct_test(pTest, sbuf_count(&sbuffer) == strlen(test_data_buffer));
|
||||
|
||||
return;
|
||||
data = sbuf_data(&sbuffer);
|
||||
count = sbuf_count(&sbuffer);
|
||||
ct_test(pTest, memcmp(data, test_data_buffer, count) == 0);
|
||||
ct_test(pTest, count == strlen(test_data_buffer));
|
||||
|
||||
ct_test(pTest, sbuf_truncate(&sbuffer, 0) == true);
|
||||
ct_test(pTest, sbuf_count(&sbuffer) == 0);
|
||||
ct_test(pTest, sbuf_size(&sbuffer) == sizeof(data_buffer));
|
||||
ct_test(pTest, sbuf_append(&sbuffer, data4, strlen(data4)) == true);
|
||||
data = sbuf_data(&sbuffer);
|
||||
count = sbuf_count(&sbuffer);
|
||||
ct_test(pTest, memcmp(data, data4, count) == 0);
|
||||
ct_test(pTest, count == strlen(data4));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_STATIC_BUFFER
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("static buffer", NULL);
|
||||
pTest = ct_create("static buffer", NULL);
|
||||
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testStaticBuffer);
|
||||
assert(rc);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testStaticBuffer);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void)ct_report(pTest);
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
|
||||
ct_destroy(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_STATIC_BUFFER */
|
||||
#endif /* TEST */
|
||||
|
||||
#endif /* TEST_STATIC_BUFFER */
|
||||
#endif /* TEST */
|
||||
|
||||
+23
-29
@@ -42,45 +42,39 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
struct static_buffer_t
|
||||
{
|
||||
char *data; /* block of memory or array of data */
|
||||
unsigned size; /* actual size, in bytes, of the block of data */
|
||||
unsigned count; /* number of bytes in use */
|
||||
struct static_buffer_t {
|
||||
char *data; /* block of memory or array of data */
|
||||
unsigned size; /* actual size, in bytes, of the block of data */
|
||||
unsigned count; /* number of bytes in use */
|
||||
};
|
||||
typedef struct static_buffer_t STATIC_BUFFER;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void sbuf_init(
|
||||
STATIC_BUFFER *b, /* static buffer structure */
|
||||
char *data, /* actual size, in bytes, of the data block or array of data */
|
||||
unsigned size); /* number of bytes used */
|
||||
void sbuf_init(STATIC_BUFFER * b, /* static buffer structure */
|
||||
char *data, /* actual size, in bytes, of the data block or array of data */
|
||||
unsigned size); /* number of bytes used */
|
||||
/* returns true if size==0, false if size > 0 */
|
||||
bool sbuf_empty(STATIC_BUFFER const *b);
|
||||
char *sbuf_data(STATIC_BUFFER const *b);
|
||||
unsigned sbuf_size(STATIC_BUFFER *b);
|
||||
unsigned sbuf_count(STATIC_BUFFER *b);
|
||||
bool sbuf_empty(STATIC_BUFFER const *b);
|
||||
char *sbuf_data(STATIC_BUFFER const *b);
|
||||
unsigned sbuf_size(STATIC_BUFFER * b);
|
||||
unsigned sbuf_count(STATIC_BUFFER * b);
|
||||
/* returns true if successful, false if not enough room to append data */
|
||||
bool sbuf_put(
|
||||
STATIC_BUFFER *b, /* static buffer structure */
|
||||
unsigned offset, /* where to start */
|
||||
char *data, /* number of bytes used */
|
||||
unsigned data_size); /* how many to add */
|
||||
bool sbuf_put(STATIC_BUFFER * b, /* static buffer structure */
|
||||
unsigned offset, /* where to start */
|
||||
char *data, /* number of bytes used */
|
||||
unsigned data_size); /* how many to add */
|
||||
/* returns true if successful, false if not enough room to append data */
|
||||
bool sbuf_append(
|
||||
STATIC_BUFFER *b, /* static buffer structure */
|
||||
char *data, /* number of bytes used */
|
||||
unsigned data_size); /* how many to add */
|
||||
bool sbuf_append(STATIC_BUFFER * b, /* static buffer structure */
|
||||
char *data, /* number of bytes used */
|
||||
unsigned data_size); /* how many to add */
|
||||
/* returns true if successful, false if not enough room to append data */
|
||||
bool sbuf_truncate(
|
||||
STATIC_BUFFER *b, /* static buffer structure */
|
||||
unsigned count); /* total number of bytes in use */
|
||||
|
||||
bool sbuf_truncate(STATIC_BUFFER * b, /* static buffer structure */
|
||||
unsigned count); /* total number of bytes in use */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
+133
-166
@@ -34,7 +34,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h> // memmove()
|
||||
#include <string.h> // memmove()
|
||||
#include "bits.h"
|
||||
#include "apdu.h"
|
||||
#include "bacdef.h"
|
||||
@@ -57,77 +57,69 @@
|
||||
|
||||
// declare space for the TSM transactions, and set it up in the init.
|
||||
/* table rules: an Invoke ID = 0 is an unused spot in the table */
|
||||
static BACNET_TSM_DATA TSM_List[MAX_TSM_TRANSACTIONS] = {{0}};
|
||||
static BACNET_TSM_DATA TSM_List[MAX_TSM_TRANSACTIONS] = { {0} };
|
||||
|
||||
// returns MAX_TSM_TRANSACTIONS if not found
|
||||
static uint8_t tsm_find_invokeID_index(uint8_t invokeID)
|
||||
{
|
||||
unsigned i = 0; // counter
|
||||
uint8_t index = MAX_TSM_TRANSACTIONS; // return value
|
||||
unsigned i = 0; // counter
|
||||
uint8_t index = MAX_TSM_TRANSACTIONS; // return value
|
||||
|
||||
for (i = 0; i < MAX_TSM_TRANSACTIONS; i++)
|
||||
{
|
||||
if (TSM_List[i].InvokeID == invokeID)
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
for (i = 0; i < MAX_TSM_TRANSACTIONS; i++) {
|
||||
if (TSM_List[i].InvokeID == invokeID) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
return index;
|
||||
}
|
||||
|
||||
static uint8_t tsm_find_first_free_index(void)
|
||||
{
|
||||
unsigned i = 0; // counter
|
||||
uint8_t index = MAX_TSM_TRANSACTIONS; // return value
|
||||
unsigned i = 0; // counter
|
||||
uint8_t index = MAX_TSM_TRANSACTIONS; // return value
|
||||
|
||||
for (i = 0; i < MAX_TSM_TRANSACTIONS; i++)
|
||||
{
|
||||
if (TSM_List[i].InvokeID == 0)
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
for (i = 0; i < MAX_TSM_TRANSACTIONS; i++) {
|
||||
if (TSM_List[i].InvokeID == 0) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
return index;
|
||||
}
|
||||
|
||||
bool tsm_transaction_available(void)
|
||||
{
|
||||
bool status = false; // return value
|
||||
unsigned i = 0; // counter
|
||||
bool status = false; // return value
|
||||
unsigned i = 0; // counter
|
||||
|
||||
for (i = 0; i < MAX_TSM_TRANSACTIONS; i++)
|
||||
{
|
||||
if (TSM_List[i].InvokeID == 0)
|
||||
{
|
||||
// one is available!
|
||||
status = true;
|
||||
break;
|
||||
for (i = 0; i < MAX_TSM_TRANSACTIONS; i++) {
|
||||
if (TSM_List[i].InvokeID == 0) {
|
||||
// one is available!
|
||||
status = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
return status;
|
||||
}
|
||||
|
||||
uint8_t tsm_transaction_idle_count(void)
|
||||
{
|
||||
uint8_t count = 0; // return value
|
||||
unsigned i = 0; // counter
|
||||
uint8_t count = 0; // return value
|
||||
unsigned i = 0; // counter
|
||||
|
||||
for (i = 0; i < MAX_TSM_TRANSACTIONS; i++)
|
||||
{
|
||||
if ((TSM_List[i].InvokeID == 0) &&
|
||||
(TSM_List[i].state == TSM_STATE_IDLE))
|
||||
{
|
||||
// one is available!
|
||||
count++;
|
||||
for (i = 0; i < MAX_TSM_TRANSACTIONS; i++) {
|
||||
if ((TSM_List[i].InvokeID == 0) &&
|
||||
(TSM_List[i].state == TSM_STATE_IDLE)) {
|
||||
// one is available!
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
return count;
|
||||
}
|
||||
|
||||
/* gets the next free invokeID,
|
||||
@@ -135,162 +127,138 @@ uint8_t tsm_transaction_idle_count(void)
|
||||
returns 0 if none are available */
|
||||
uint8_t tsm_next_free_invokeID(void)
|
||||
{
|
||||
static uint8_t current_invokeID = 1; // incremented...
|
||||
uint8_t index = 0;
|
||||
uint8_t invokeID = 0;
|
||||
bool found = false;
|
||||
static uint8_t current_invokeID = 1; // incremented...
|
||||
uint8_t index = 0;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return invokeID;
|
||||
return invokeID;
|
||||
}
|
||||
|
||||
void tsm_set_confirmed_unsegmented_transaction(
|
||||
uint8_t invokeID,
|
||||
BACNET_ADDRESS *dest,
|
||||
uint8_t *pdu,
|
||||
uint16_t pdu_len)
|
||||
void tsm_set_confirmed_unsegmented_transaction(uint8_t invokeID,
|
||||
BACNET_ADDRESS * dest, uint8_t * pdu, uint16_t pdu_len)
|
||||
{
|
||||
uint16_t j = 0;
|
||||
uint8_t index;
|
||||
uint16_t j = 0;
|
||||
uint8_t index;
|
||||
|
||||
if (invokeID)
|
||||
{
|
||||
index = tsm_find_invokeID_index(invokeID);
|
||||
if (index < MAX_TSM_TRANSACTIONS)
|
||||
{
|
||||
// assign the transaction
|
||||
TSM_List[index].state = TSM_STATE_AWAIT_CONFIRMATION;
|
||||
TSM_List[index].RetryCount = Device_Number_Of_APDU_Retries();
|
||||
// start the timer
|
||||
TSM_List[index].RequestTimer = Device_APDU_Timeout();
|
||||
// copy the data
|
||||
for (j = 0; j < pdu_len; j++)
|
||||
{
|
||||
TSM_List[index].pdu[j] = pdu[j];
|
||||
}
|
||||
TSM_List[index].pdu_len = pdu_len;
|
||||
address_copy(&TSM_List[index].dest,dest);
|
||||
if (invokeID) {
|
||||
index = tsm_find_invokeID_index(invokeID);
|
||||
if (index < MAX_TSM_TRANSACTIONS) {
|
||||
// assign the transaction
|
||||
TSM_List[index].state = TSM_STATE_AWAIT_CONFIRMATION;
|
||||
TSM_List[index].RetryCount = Device_Number_Of_APDU_Retries();
|
||||
// start the timer
|
||||
TSM_List[index].RequestTimer = Device_APDU_Timeout();
|
||||
// copy the data
|
||||
for (j = 0; j < pdu_len; j++) {
|
||||
TSM_List[index].pdu[j] = pdu[j];
|
||||
}
|
||||
TSM_List[index].pdu_len = pdu_len;
|
||||
address_copy(&TSM_List[index].dest, dest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
// used to retrieve the transaction payload
|
||||
// if we wanted to find out what we sent (i.e. when we get an ack)
|
||||
bool tsm_get_transaction_pdu(
|
||||
uint8_t invokeID,
|
||||
BACNET_ADDRESS *dest,
|
||||
uint8_t *pdu,
|
||||
uint16_t *pdu_len)
|
||||
bool tsm_get_transaction_pdu(uint8_t invokeID,
|
||||
BACNET_ADDRESS * dest, uint8_t * pdu, uint16_t * pdu_len)
|
||||
{
|
||||
uint16_t j = 0;
|
||||
uint8_t index;
|
||||
bool found = false;
|
||||
uint16_t j = 0;
|
||||
uint8_t index;
|
||||
bool found = false;
|
||||
|
||||
if (invokeID)
|
||||
{
|
||||
index = tsm_find_invokeID_index(invokeID);
|
||||
// how much checking is needed? state? dest match? just invokeID?
|
||||
if (index < MAX_TSM_TRANSACTIONS)
|
||||
{
|
||||
// FIXME: we may want to free the transaction so it doesn't timeout
|
||||
// retrieve the transaction
|
||||
// FIXME: bounds check the pdu_len?
|
||||
*pdu_len = TSM_List[index].pdu_len;
|
||||
for (j = 0; j < *pdu_len; j++)
|
||||
{
|
||||
pdu[j] = TSM_List[index].pdu[j];
|
||||
}
|
||||
address_copy(dest,&TSM_List[index].dest);
|
||||
found = true;
|
||||
if (invokeID) {
|
||||
index = tsm_find_invokeID_index(invokeID);
|
||||
// how much checking is needed? state? dest match? just invokeID?
|
||||
if (index < MAX_TSM_TRANSACTIONS) {
|
||||
// FIXME: we may want to free the transaction so it doesn't timeout
|
||||
// retrieve the transaction
|
||||
// FIXME: bounds check the pdu_len?
|
||||
*pdu_len = TSM_List[index].pdu_len;
|
||||
for (j = 0; j < *pdu_len; j++) {
|
||||
pdu[j] = TSM_List[index].pdu[j];
|
||||
}
|
||||
address_copy(dest, &TSM_List[index].dest);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
return found;
|
||||
}
|
||||
|
||||
/* called once a millisecond or slower */
|
||||
void tsm_timer_milliseconds(uint16_t milliseconds)
|
||||
{
|
||||
unsigned i = 0; // counter
|
||||
int bytes_sent = 0;
|
||||
unsigned i = 0; // counter
|
||||
int bytes_sent = 0;
|
||||
|
||||
for (i = 0; i < MAX_TSM_TRANSACTIONS; i++)
|
||||
{
|
||||
if (TSM_List[i].state == TSM_STATE_AWAIT_CONFIRMATION)
|
||||
{
|
||||
if (TSM_List[i].RequestTimer > milliseconds)
|
||||
TSM_List[i].RequestTimer -= milliseconds;
|
||||
else
|
||||
TSM_List[i].RequestTimer = 0;
|
||||
/* timeout. retry? */
|
||||
if (TSM_List[i].RequestTimer == 0)
|
||||
{
|
||||
TSM_List[i].RetryCount--;
|
||||
TSM_List[i].RequestTimer = Device_APDU_Timeout();
|
||||
if (TSM_List[i].RetryCount)
|
||||
{
|
||||
bytes_sent = datalink_send_pdu(
|
||||
&TSM_List[i].dest, /* destination address */
|
||||
&TSM_List[i].pdu[0],
|
||||
TSM_List[i].pdu_len); /* number of bytes of data */
|
||||
for (i = 0; i < MAX_TSM_TRANSACTIONS; i++) {
|
||||
if (TSM_List[i].state == TSM_STATE_AWAIT_CONFIRMATION) {
|
||||
if (TSM_List[i].RequestTimer > milliseconds)
|
||||
TSM_List[i].RequestTimer -= milliseconds;
|
||||
else
|
||||
TSM_List[i].RequestTimer = 0;
|
||||
/* timeout. retry? */
|
||||
if (TSM_List[i].RequestTimer == 0) {
|
||||
TSM_List[i].RetryCount--;
|
||||
TSM_List[i].RequestTimer = Device_APDU_Timeout();
|
||||
if (TSM_List[i].RetryCount) {
|
||||
bytes_sent = datalink_send_pdu(&TSM_List[i].dest, /* destination address */
|
||||
&TSM_List[i].pdu[0], TSM_List[i].pdu_len); /* number of bytes of data */
|
||||
} else {
|
||||
TSM_List[i].InvokeID = 0;
|
||||
TSM_List[i].state = TSM_STATE_IDLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TSM_List[i].InvokeID = 0;
|
||||
TSM_List[i].state = TSM_STATE_IDLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tsm_free_invoke_id(uint8_t invokeID)
|
||||
{
|
||||
uint8_t index;
|
||||
uint8_t index;
|
||||
|
||||
index = tsm_find_invokeID_index(invokeID);
|
||||
if (index < MAX_TSM_TRANSACTIONS)
|
||||
{
|
||||
TSM_List[index].state = TSM_STATE_IDLE;
|
||||
TSM_List[index].InvokeID = 0;
|
||||
}
|
||||
index = tsm_find_invokeID_index(invokeID);
|
||||
if (index < MAX_TSM_TRANSACTIONS) {
|
||||
TSM_List[index].state = TSM_STATE_IDLE;
|
||||
TSM_List[index].InvokeID = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* see if the invoke ID has been made free */
|
||||
bool tsm_invoke_id_free(uint8_t invokeID)
|
||||
{
|
||||
bool status = true;
|
||||
uint8_t index;
|
||||
bool status = true;
|
||||
uint8_t index;
|
||||
|
||||
index = tsm_find_invokeID_index(invokeID);
|
||||
if (index < MAX_TSM_TRANSACTIONS)
|
||||
status = false;
|
||||
index = tsm_find_invokeID_index(invokeID);
|
||||
if (index < MAX_TSM_TRANSACTIONS)
|
||||
status = false;
|
||||
|
||||
return status;
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
@@ -303,8 +271,8 @@ bool I_Am_Request = true;
|
||||
|
||||
void testTSM(Test * pTest)
|
||||
{
|
||||
/* FIXME: add some unit testing...*/
|
||||
return;
|
||||
/* FIXME: add some unit testing... */
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_TSM
|
||||
@@ -327,4 +295,3 @@ int main(void)
|
||||
}
|
||||
#endif /* TEST_TSM */
|
||||
#endif /* TEST */
|
||||
|
||||
|
||||
+48
-58
@@ -42,81 +42,72 @@
|
||||
/* note: TSM functionality is optional - only needed if we are
|
||||
doing client requests */
|
||||
#if TSM_ENABLED
|
||||
typedef enum
|
||||
{
|
||||
TSM_STATE_IDLE,
|
||||
TSM_STATE_AWAIT_CONFIRMATION,
|
||||
TSM_STATE_AWAIT_RESPONSE,
|
||||
TSM_STATE_SEGMENTED_REQUEST,
|
||||
TSM_STATE_SEGMENTED_CONFIRMATION
|
||||
typedef enum {
|
||||
TSM_STATE_IDLE,
|
||||
TSM_STATE_AWAIT_CONFIRMATION,
|
||||
TSM_STATE_AWAIT_RESPONSE,
|
||||
TSM_STATE_SEGMENTED_REQUEST,
|
||||
TSM_STATE_SEGMENTED_CONFIRMATION
|
||||
} BACNET_TSM_STATE;
|
||||
|
||||
// 5.4.1 Variables And Parameters
|
||||
// The following variables are defined for each instance of
|
||||
// Transaction State Machine:
|
||||
typedef struct BACnet_TSM_Data
|
||||
{
|
||||
// used to count APDU retries
|
||||
uint8_t RetryCount;
|
||||
// used to count segment retries
|
||||
//uint8_t SegmentRetryCount;
|
||||
// used to control APDU retries and the acceptance of server replies
|
||||
//bool SentAllSegments;
|
||||
// stores the sequence number of the last segment received in order
|
||||
//uint8_t LastSequenceNumber;
|
||||
// stores the sequence number of the first segment of
|
||||
// a sequence of segments that fill a window
|
||||
//uint8_t InitialSequenceNumber;
|
||||
// stores the current window size
|
||||
//uint8_t ActualWindowSize;
|
||||
// stores the window size proposed by the segment sender
|
||||
//uint8_t ProposedWindowSize;
|
||||
// used to perform timeout on PDU segments
|
||||
//uint8_t SegmentTimer;
|
||||
// used to perform timeout on Confirmed Requests
|
||||
// in milliseconds
|
||||
uint16_t RequestTimer;
|
||||
// unique id
|
||||
uint8_t InvokeID;
|
||||
// state that the TSM is in
|
||||
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;
|
||||
typedef struct BACnet_TSM_Data {
|
||||
// used to count APDU retries
|
||||
uint8_t RetryCount;
|
||||
// used to count segment retries
|
||||
//uint8_t SegmentRetryCount;
|
||||
// used to control APDU retries and the acceptance of server replies
|
||||
//bool SentAllSegments;
|
||||
// stores the sequence number of the last segment received in order
|
||||
//uint8_t LastSequenceNumber;
|
||||
// stores the sequence number of the first segment of
|
||||
// a sequence of segments that fill a window
|
||||
//uint8_t InitialSequenceNumber;
|
||||
// stores the current window size
|
||||
//uint8_t ActualWindowSize;
|
||||
// stores the window size proposed by the segment sender
|
||||
//uint8_t ProposedWindowSize;
|
||||
// used to perform timeout on PDU segments
|
||||
//uint8_t SegmentTimer;
|
||||
// used to perform timeout on Confirmed Requests
|
||||
// in milliseconds
|
||||
uint16_t RequestTimer;
|
||||
// unique id
|
||||
uint8_t InvokeID;
|
||||
// state that the TSM is in
|
||||
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;
|
||||
} BACNET_TSM_DATA;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
bool tsm_transaction_available(void);
|
||||
uint8_t tsm_transaction_idle_count(void);
|
||||
void tsm_timer_milliseconds(uint16_t milliseconds);
|
||||
bool tsm_transaction_available(void);
|
||||
uint8_t tsm_transaction_idle_count(void);
|
||||
void tsm_timer_milliseconds(uint16_t milliseconds);
|
||||
// free the invoke ID when the reply comes back
|
||||
void tsm_free_invoke_id(uint8_t invokeID);
|
||||
void tsm_free_invoke_id(uint8_t invokeID);
|
||||
// use these in tandem
|
||||
uint8_t tsm_next_free_invokeID(void);
|
||||
uint8_t tsm_next_free_invokeID(void);
|
||||
// returns the same invoke ID that was given
|
||||
void tsm_set_confirmed_unsegmented_transaction(
|
||||
uint8_t invokeID,
|
||||
BACNET_ADDRESS *dest,
|
||||
uint8_t *pdu,
|
||||
uint16_t pdu_len);
|
||||
void tsm_set_confirmed_unsegmented_transaction(uint8_t invokeID,
|
||||
BACNET_ADDRESS * dest, uint8_t * pdu, uint16_t pdu_len);
|
||||
// returns true if transaction is found
|
||||
bool tsm_get_transaction_pdu(
|
||||
uint8_t invokeID,
|
||||
BACNET_ADDRESS *dest,
|
||||
uint8_t *pdu,
|
||||
uint16_t *pdu_len);
|
||||
bool tsm_get_transaction_pdu(uint8_t invokeID,
|
||||
BACNET_ADDRESS * dest, uint8_t * pdu, uint16_t * pdu_len);
|
||||
|
||||
bool tsm_invoke_id_free(uint8_t invokeID);
|
||||
bool tsm_invoke_id_free(uint8_t invokeID);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
/* define out any functions necessary for compile */
|
||||
#else
|
||||
|
||||
@@ -125,4 +116,3 @@ bool tsm_invoke_id_free(uint8_t invokeID);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+151
-182
@@ -39,137 +39,122 @@
|
||||
|
||||
/* encode service - use -1 for limit for unlimited */
|
||||
|
||||
int whohas_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
BACNET_WHO_HAS_DATA *data)
|
||||
int whohas_encode_apdu(uint8_t * apdu, BACNET_WHO_HAS_DATA * data)
|
||||
{
|
||||
int len = 0; // length of each encoding
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
int len = 0; // length of each encoding
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
|
||||
if (apdu && data) {
|
||||
apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST;
|
||||
apdu[1] = SERVICE_UNCONFIRMED_WHO_HAS; // service choice
|
||||
apdu_len = 2;
|
||||
// optional limits - must be used as a pair
|
||||
if ((data->low_limit >= 0) && (data->low_limit <= BACNET_MAX_INSTANCE) &&
|
||||
(data->high_limit >= 0) && (data->high_limit <= BACNET_MAX_INSTANCE))
|
||||
{
|
||||
len = encode_context_unsigned(
|
||||
&apdu[apdu_len],
|
||||
0,
|
||||
data->low_limit);
|
||||
apdu_len += len;
|
||||
len = encode_context_unsigned(
|
||||
&apdu[apdu_len],
|
||||
1,
|
||||
data->high_limit);
|
||||
apdu_len += len;
|
||||
if (apdu && data) {
|
||||
apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST;
|
||||
apdu[1] = SERVICE_UNCONFIRMED_WHO_HAS; // service choice
|
||||
apdu_len = 2;
|
||||
// optional limits - must be used as a pair
|
||||
if ((data->low_limit >= 0)
|
||||
&& (data->low_limit <= BACNET_MAX_INSTANCE)
|
||||
&& (data->high_limit >= 0)
|
||||
&& (data->high_limit <= BACNET_MAX_INSTANCE)) {
|
||||
len =
|
||||
encode_context_unsigned(&apdu[apdu_len], 0,
|
||||
data->low_limit);
|
||||
apdu_len += len;
|
||||
len = encode_context_unsigned(&apdu[apdu_len],
|
||||
1, data->high_limit);
|
||||
apdu_len += len;
|
||||
}
|
||||
if (data->object_name) {
|
||||
len = encode_context_character_string(&apdu[apdu_len],
|
||||
3, &data->object.name);
|
||||
apdu_len += len;
|
||||
} else {
|
||||
len = encode_context_object_id(&apdu[apdu_len],
|
||||
2,
|
||||
data->object.identifier.type,
|
||||
data->object.identifier.instance);
|
||||
apdu_len += len;
|
||||
}
|
||||
}
|
||||
if (data->object_name)
|
||||
{
|
||||
len = encode_context_character_string(
|
||||
&apdu[apdu_len],
|
||||
3,
|
||||
&data->object.name);
|
||||
apdu_len += len;
|
||||
}
|
||||
else
|
||||
{
|
||||
len = encode_context_object_id(
|
||||
&apdu[apdu_len],
|
||||
2,
|
||||
data->object.identifier.type,
|
||||
data->object.identifier.instance);
|
||||
apdu_len += len;
|
||||
}
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
// decode the service request only
|
||||
int whohas_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_WHO_HAS_DATA *data)
|
||||
int whohas_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_WHO_HAS_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint32_t decoded_value = 0; /* for decoding */
|
||||
int decoded_type = 0; /* for decoding */
|
||||
int len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint32_t decoded_value = 0; /* for decoding */
|
||||
int decoded_type = 0; /* for decoding */
|
||||
|
||||
if (apdu_len && data)
|
||||
{
|
||||
/* optional limits - must be used as a pair */
|
||||
if (decode_is_context_tag(&apdu[len], 0))
|
||||
{
|
||||
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value);
|
||||
len += decode_unsigned(&apdu[len], len_value, &decoded_value);
|
||||
if (decoded_value <= BACNET_MAX_INSTANCE)
|
||||
data->low_limit = decoded_value;
|
||||
if (!decode_is_context_tag(&apdu[len], 1))
|
||||
return -1;
|
||||
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value);
|
||||
len += decode_unsigned(&apdu[len],
|
||||
len_value, &decoded_value);
|
||||
if (decoded_value <= BACNET_MAX_INSTANCE)
|
||||
data->high_limit = decoded_value;
|
||||
if (apdu_len && data) {
|
||||
/* optional limits - must be used as a pair */
|
||||
if (decode_is_context_tag(&apdu[len], 0)) {
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
len += decode_unsigned(&apdu[len], len_value, &decoded_value);
|
||||
if (decoded_value <= BACNET_MAX_INSTANCE)
|
||||
data->low_limit = decoded_value;
|
||||
if (!decode_is_context_tag(&apdu[len], 1))
|
||||
return -1;
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
len += decode_unsigned(&apdu[len], len_value, &decoded_value);
|
||||
if (decoded_value <= BACNET_MAX_INSTANCE)
|
||||
data->high_limit = decoded_value;
|
||||
} else {
|
||||
data->low_limit = -1;
|
||||
data->high_limit = -1;
|
||||
}
|
||||
/* object id */
|
||||
if (decode_is_context_tag(&apdu[len], 2)) {
|
||||
data->object_name = false;
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
len +=
|
||||
decode_object_id(&apdu[len], &decoded_type,
|
||||
&data->object.identifier.instance);
|
||||
data->object.identifier.type = decoded_type;
|
||||
}
|
||||
/* object name */
|
||||
else if (decode_is_context_tag(&apdu[len], 3)) {
|
||||
data->object_name = true;
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
len +=
|
||||
decode_character_string(&apdu[len], len_value,
|
||||
&data->object.name);
|
||||
}
|
||||
/* missing required parameters */
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
data->low_limit = -1;
|
||||
data->high_limit = -1;
|
||||
}
|
||||
/* object id */
|
||||
if (decode_is_context_tag(&apdu[len], 2))
|
||||
{
|
||||
data->object_name = false;
|
||||
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value);
|
||||
len += decode_object_id(&apdu[len], &decoded_type,
|
||||
&data->object.identifier.instance);
|
||||
data->object.identifier.type = decoded_type;
|
||||
}
|
||||
/* object name */
|
||||
else if (decode_is_context_tag(&apdu[len], 3))
|
||||
{
|
||||
data->object_name = true;
|
||||
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value);
|
||||
len += decode_character_string(&apdu[len], len_value,
|
||||
&data->object.name);
|
||||
}
|
||||
/* missing required parameters */
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
return len;
|
||||
return len;
|
||||
}
|
||||
|
||||
int whohas_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_WHO_HAS_DATA *data)
|
||||
int whohas_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_WHO_HAS_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
int len = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu[0] != PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST)
|
||||
return -1;
|
||||
if (apdu[1] != SERVICE_UNCONFIRMED_WHO_IS)
|
||||
return -1;
|
||||
// optional limits - must be used as a pair
|
||||
if (apdu_len > 2)
|
||||
{
|
||||
len = whohas_decode_service_request(
|
||||
&apdu[2],
|
||||
apdu_len - 2,
|
||||
data);
|
||||
}
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu[0] != PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST)
|
||||
return -1;
|
||||
if (apdu[1] != SERVICE_UNCONFIRMED_WHO_IS)
|
||||
return -1;
|
||||
// optional limits - must be used as a pair
|
||||
if (apdu_len > 2) {
|
||||
len = whohas_decode_service_request(&apdu[2], apdu_len - 2, data);
|
||||
}
|
||||
|
||||
return len;
|
||||
return len;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
@@ -177,84 +162,68 @@ int whohas_decode_apdu(
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
void testWhoHasData(Test * pTest, BACNET_WHO_HAS_DATA *data)
|
||||
void testWhoHasData(Test * pTest, BACNET_WHO_HAS_DATA * data)
|
||||
{
|
||||
uint8_t apdu[480] = {0};
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
BACNET_WHO_HAS_DATA test_data;
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
BACNET_WHO_HAS_DATA test_data;
|
||||
|
||||
len = whohas_encode_apdu(
|
||||
&apdu[0],
|
||||
data);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
len = whohas_encode_apdu(&apdu[0], data);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
|
||||
len = whohas_decode_apdu(
|
||||
&apdu[0],
|
||||
apdu_len,
|
||||
&test_data);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_data.low_limit == data->low_limit);
|
||||
ct_test(pTest, test_data.high_limit == data->high_limit);
|
||||
ct_test(pTest, test_data.object_name == data->object_name);
|
||||
/* Object ID */
|
||||
if (data->object_name == false)
|
||||
{
|
||||
ct_test(pTest, test_data.object.identifier.type ==
|
||||
data->object.identifier.type);
|
||||
ct_test(pTest, test_data.object.identifier.instance ==
|
||||
data->object.identifier.instance);
|
||||
}
|
||||
/* Object Name */
|
||||
else
|
||||
{
|
||||
ct_test(pTest, characterstring_same(
|
||||
&test_data.object.name,&data->object.name));
|
||||
}
|
||||
len = whohas_decode_apdu(&apdu[0], apdu_len, &test_data);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_data.low_limit == data->low_limit);
|
||||
ct_test(pTest, test_data.high_limit == data->high_limit);
|
||||
ct_test(pTest, test_data.object_name == data->object_name);
|
||||
/* Object ID */
|
||||
if (data->object_name == false) {
|
||||
ct_test(pTest, test_data.object.identifier.type ==
|
||||
data->object.identifier.type);
|
||||
ct_test(pTest, test_data.object.identifier.instance ==
|
||||
data->object.identifier.instance);
|
||||
}
|
||||
/* Object Name */
|
||||
else {
|
||||
ct_test(pTest, characterstring_same(&test_data.object.name,
|
||||
&data->object.name));
|
||||
}
|
||||
}
|
||||
|
||||
void testWhoHas(Test * pTest)
|
||||
{
|
||||
BACNET_WHO_HAS_DATA data;
|
||||
BACNET_WHO_HAS_DATA data;
|
||||
|
||||
data.low_limit = -1;
|
||||
data.high_limit = -1;
|
||||
data.object_name = false;
|
||||
data.object.identifier.type = OBJECT_ANALOG_INPUT;
|
||||
data.object.identifier.instance = 1;
|
||||
testWhoHasData(pTest,&data);
|
||||
data.low_limit = -1;
|
||||
data.high_limit = -1;
|
||||
data.object_name = false;
|
||||
data.object.identifier.type = OBJECT_ANALOG_INPUT;
|
||||
data.object.identifier.instance = 1;
|
||||
testWhoHasData(pTest, &data);
|
||||
|
||||
for (
|
||||
data.low_limit = 0;
|
||||
data.low_limit <= BACNET_MAX_INSTANCE;
|
||||
data.low_limit += (BACNET_MAX_INSTANCE/4))
|
||||
{
|
||||
for (
|
||||
data.high_limit = 0;
|
||||
data.high_limit <= BACNET_MAX_INSTANCE;
|
||||
data.high_limit += (BACNET_MAX_INSTANCE/4))
|
||||
{
|
||||
data.object_name = false;
|
||||
for (
|
||||
data.object.identifier.type = OBJECT_ANALOG_INPUT;
|
||||
data.object.identifier.type <= MAX_BACNET_OBJECT_TYPE;
|
||||
data.object.identifier.type++)
|
||||
{
|
||||
for (
|
||||
data.object.identifier.instance = 1;
|
||||
data.object.identifier.instance <= BACNET_MAX_INSTANCE;
|
||||
data.object.identifier.instance <<= 1)
|
||||
{
|
||||
testWhoHasData(pTest,&data);
|
||||
for (data.low_limit = 0;
|
||||
data.low_limit <= BACNET_MAX_INSTANCE;
|
||||
data.low_limit += (BACNET_MAX_INSTANCE / 4)) {
|
||||
for (data.high_limit = 0;
|
||||
data.high_limit <= BACNET_MAX_INSTANCE;
|
||||
data.high_limit += (BACNET_MAX_INSTANCE / 4)) {
|
||||
data.object_name = false;
|
||||
for (data.object.identifier.type = OBJECT_ANALOG_INPUT;
|
||||
data.object.identifier.type <= MAX_BACNET_OBJECT_TYPE;
|
||||
data.object.identifier.type++) {
|
||||
for (data.object.identifier.instance = 1;
|
||||
data.object.identifier.instance <= BACNET_MAX_INSTANCE;
|
||||
data.object.identifier.instance <<= 1) {
|
||||
testWhoHasData(pTest, &data);
|
||||
}
|
||||
}
|
||||
data.object_name = true;
|
||||
characterstring_init_ansi(&data.object.name, "patricia");
|
||||
testWhoHasData(pTest, &data);
|
||||
}
|
||||
}
|
||||
data.object_name = true;
|
||||
characterstring_init_ansi(
|
||||
&data.object.name,"patricia");
|
||||
testWhoHasData(pTest,&data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST_WHOHAS
|
||||
|
||||
+16
-26
@@ -38,45 +38,35 @@
|
||||
#include <stdbool.h>
|
||||
#include "bacstr.h"
|
||||
|
||||
typedef struct BACnet_Who_Has_Data
|
||||
{
|
||||
int32_t low_limit; /* deviceInstanceRange */
|
||||
int32_t high_limit;
|
||||
bool object_name; /* true if a string */
|
||||
union
|
||||
{
|
||||
BACNET_OBJECT_ID identifier;
|
||||
BACNET_CHARACTER_STRING name;
|
||||
} object;
|
||||
typedef struct BACnet_Who_Has_Data {
|
||||
int32_t low_limit; /* deviceInstanceRange */
|
||||
int32_t high_limit;
|
||||
bool object_name; /* true if a string */
|
||||
union {
|
||||
BACNET_OBJECT_ID identifier;
|
||||
BACNET_CHARACTER_STRING name;
|
||||
} object;
|
||||
} BACNET_WHO_HAS_DATA;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
// encode service - use -1 for limit if you want unlimited
|
||||
int whohas_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
BACNET_WHO_HAS_DATA *data);
|
||||
int whohas_encode_apdu(uint8_t * apdu, BACNET_WHO_HAS_DATA * data);
|
||||
|
||||
int whohas_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_WHO_HAS_DATA *data);
|
||||
int whohas_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_WHO_HAS_DATA * data);
|
||||
|
||||
int whohas_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_WHO_HAS_DATA *data);
|
||||
int whohas_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_WHO_HAS_DATA * data);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testWhoHas(Test * pTest);
|
||||
void testWhoHas(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
|
||||
+96
-131
@@ -37,103 +37,84 @@
|
||||
#include "bacdef.h"
|
||||
|
||||
// encode I-Am service - use -1 for limit if you want unlimited
|
||||
int whois_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
int32_t low_limit,
|
||||
int32_t high_limit)
|
||||
int whois_encode_apdu(uint8_t * apdu,
|
||||
int32_t low_limit, int32_t high_limit)
|
||||
{
|
||||
int len = 0; // length of each encoding
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
int len = 0; // length of each encoding
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
|
||||
if (apdu) {
|
||||
apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST;
|
||||
apdu[1] = SERVICE_UNCONFIRMED_WHO_IS; // service choice
|
||||
apdu_len = 2;
|
||||
// optional limits - must be used as a pair
|
||||
if ((low_limit >= 0) && (low_limit <= BACNET_MAX_INSTANCE) &&
|
||||
(high_limit >= 0) && (high_limit <= BACNET_MAX_INSTANCE))
|
||||
{
|
||||
len = encode_context_unsigned(
|
||||
&apdu[apdu_len],
|
||||
0,
|
||||
low_limit);
|
||||
apdu_len += len;
|
||||
len = encode_context_unsigned(
|
||||
&apdu[apdu_len],
|
||||
1,
|
||||
high_limit);
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST;
|
||||
apdu[1] = SERVICE_UNCONFIRMED_WHO_IS; // service choice
|
||||
apdu_len = 2;
|
||||
// optional limits - must be used as a pair
|
||||
if ((low_limit >= 0) && (low_limit <= BACNET_MAX_INSTANCE) &&
|
||||
(high_limit >= 0) && (high_limit <= BACNET_MAX_INSTANCE)) {
|
||||
len = encode_context_unsigned(&apdu[apdu_len], 0, low_limit);
|
||||
apdu_len += len;
|
||||
len = encode_context_unsigned(&apdu[apdu_len], 1, high_limit);
|
||||
apdu_len += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
// decode the service request only
|
||||
int whois_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
int32_t *pLow_limit,
|
||||
int32_t *pHigh_limit)
|
||||
int whois_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, int32_t * pLow_limit, int32_t * pHigh_limit)
|
||||
{
|
||||
int len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint32_t decoded_value = 0;
|
||||
int len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint32_t decoded_value = 0;
|
||||
|
||||
// optional limits - must be used as a pair
|
||||
if (apdu_len)
|
||||
{
|
||||
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value);
|
||||
if (tag_number != 0)
|
||||
return -1;
|
||||
len += decode_unsigned(&apdu[len], len_value, &decoded_value);
|
||||
if (decoded_value <= BACNET_MAX_INSTANCE)
|
||||
{
|
||||
if (pLow_limit)
|
||||
*pLow_limit = decoded_value;
|
||||
// optional limits - must be used as a pair
|
||||
if (apdu_len) {
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
if (tag_number != 0)
|
||||
return -1;
|
||||
len += decode_unsigned(&apdu[len], len_value, &decoded_value);
|
||||
if (decoded_value <= BACNET_MAX_INSTANCE) {
|
||||
if (pLow_limit)
|
||||
*pLow_limit = decoded_value;
|
||||
}
|
||||
len +=
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value);
|
||||
if (tag_number != 1)
|
||||
return -1;
|
||||
len += decode_unsigned(&apdu[len], len_value, &decoded_value);
|
||||
if (decoded_value <= BACNET_MAX_INSTANCE) {
|
||||
if (pHigh_limit)
|
||||
*pHigh_limit = decoded_value;
|
||||
}
|
||||
}
|
||||
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value);
|
||||
if (tag_number != 1)
|
||||
return -1;
|
||||
len += decode_unsigned(&apdu[len],
|
||||
len_value, &decoded_value);
|
||||
if (decoded_value <= BACNET_MAX_INSTANCE)
|
||||
{
|
||||
if (pHigh_limit)
|
||||
*pHigh_limit = decoded_value;
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int whois_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
int32_t *pLow_limit,
|
||||
int32_t *pHigh_limit)
|
||||
int whois_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len, int32_t * pLow_limit, int32_t * pHigh_limit)
|
||||
{
|
||||
int len = 0;
|
||||
int len = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu[0] != PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST)
|
||||
return -1;
|
||||
if (apdu[1] != SERVICE_UNCONFIRMED_WHO_IS)
|
||||
return -1;
|
||||
// optional limits - must be used as a pair
|
||||
if (apdu_len > 2)
|
||||
{
|
||||
len = whois_decode_service_request(
|
||||
&apdu[2],
|
||||
apdu_len - 2,
|
||||
pLow_limit,
|
||||
pHigh_limit);
|
||||
}
|
||||
|
||||
return len;
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu[0] != PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST)
|
||||
return -1;
|
||||
if (apdu[1] != SERVICE_UNCONFIRMED_WHO_IS)
|
||||
return -1;
|
||||
// optional limits - must be used as a pair
|
||||
if (apdu_len > 2) {
|
||||
len = whois_decode_service_request(&apdu[2],
|
||||
apdu_len - 2, pLow_limit, pHigh_limit);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
@@ -143,56 +124,40 @@ int whois_decode_apdu(
|
||||
|
||||
void testWhoIs(Test * pTest)
|
||||
{
|
||||
uint8_t apdu[480] = {0};
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
int32_t low_limit = -1;
|
||||
int32_t high_limit = -1;
|
||||
int32_t test_low_limit = -1;
|
||||
int32_t test_high_limit = -1;
|
||||
|
||||
len = whois_encode_apdu(
|
||||
&apdu[0],
|
||||
low_limit,
|
||||
high_limit);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
int32_t low_limit = -1;
|
||||
int32_t high_limit = -1;
|
||||
int32_t test_low_limit = -1;
|
||||
int32_t test_high_limit = -1;
|
||||
|
||||
len = whois_decode_apdu(
|
||||
&apdu[0],
|
||||
apdu_len,
|
||||
&test_low_limit,
|
||||
&test_high_limit);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_low_limit == low_limit);
|
||||
ct_test(pTest, test_high_limit == high_limit);
|
||||
len = whois_encode_apdu(&apdu[0], low_limit, high_limit);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
|
||||
for (
|
||||
low_limit = 0;
|
||||
low_limit <= BACNET_MAX_INSTANCE;
|
||||
low_limit += (BACNET_MAX_INSTANCE/4))
|
||||
{
|
||||
for (
|
||||
high_limit = 0;
|
||||
high_limit <= BACNET_MAX_INSTANCE;
|
||||
high_limit += (BACNET_MAX_INSTANCE/4))
|
||||
{
|
||||
len = whois_encode_apdu(
|
||||
&apdu[0],
|
||||
low_limit,
|
||||
high_limit);
|
||||
apdu_len = len;
|
||||
ct_test(pTest, len != 0);
|
||||
len = whois_decode_apdu(
|
||||
&apdu[0],
|
||||
apdu_len,
|
||||
&test_low_limit,
|
||||
&test_high_limit);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_low_limit == low_limit);
|
||||
ct_test(pTest, test_high_limit == high_limit);
|
||||
len = whois_decode_apdu(&apdu[0],
|
||||
apdu_len, &test_low_limit, &test_high_limit);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_low_limit == low_limit);
|
||||
ct_test(pTest, test_high_limit == high_limit);
|
||||
|
||||
for (low_limit = 0;
|
||||
low_limit <= BACNET_MAX_INSTANCE;
|
||||
low_limit += (BACNET_MAX_INSTANCE / 4)) {
|
||||
for (high_limit = 0;
|
||||
high_limit <= BACNET_MAX_INSTANCE;
|
||||
high_limit += (BACNET_MAX_INSTANCE / 4)) {
|
||||
len = whois_encode_apdu(&apdu[0], low_limit, high_limit);
|
||||
apdu_len = len;
|
||||
ct_test(pTest, len != 0);
|
||||
len = whois_decode_apdu(&apdu[0],
|
||||
apdu_len, &test_low_limit, &test_high_limit);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_low_limit == low_limit);
|
||||
ct_test(pTest, test_high_limit == high_limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST_WHOIS
|
||||
|
||||
+10
-20
@@ -39,33 +39,23 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
// encode service - use -1 for limit if you want unlimited
|
||||
int whois_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
int32_t low_limit,
|
||||
int32_t high_limit);
|
||||
int whois_encode_apdu(uint8_t * apdu,
|
||||
int32_t low_limit, int32_t high_limit);
|
||||
|
||||
int whois_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
int32_t *pLow_limit,
|
||||
int32_t *pHigh_limit);
|
||||
|
||||
int whois_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
int32_t *pLow_limit,
|
||||
int32_t *pHigh_limit);
|
||||
int whois_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, int32_t * pLow_limit, int32_t * pHigh_limit);
|
||||
|
||||
int whois_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len, int32_t * pLow_limit, int32_t * pHigh_limit);
|
||||
|
||||
#ifdef TEST
|
||||
void testWhoIs(Test * pTest);
|
||||
void testWhoIs(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
|
||||
+240
-265
@@ -39,153 +39,138 @@
|
||||
#include "wp.h"
|
||||
|
||||
// encode service
|
||||
int wp_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint8_t invoke_id,
|
||||
BACNET_WRITE_PROPERTY_DATA *data)
|
||||
int wp_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, BACNET_WRITE_PROPERTY_DATA * data)
|
||||
{
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
int apdu_len = 0; // total length of the apdu, return value
|
||||
|
||||
if (apdu)
|
||||
{
|
||||
apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
|
||||
apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted());
|
||||
apdu[2] = invoke_id;
|
||||
apdu[3] = SERVICE_CONFIRMED_WRITE_PROPERTY; // service choice
|
||||
apdu_len = 4;
|
||||
apdu_len += encode_context_object_id(&apdu[apdu_len], 0,
|
||||
data->object_type, data->object_instance);
|
||||
apdu_len += encode_context_enumerated(&apdu[apdu_len], 1,
|
||||
data->object_property);
|
||||
/* optional array index; ALL is -1 which is assumed when missing */
|
||||
if (data->array_index != BACNET_ARRAY_ALL)
|
||||
apdu_len += encode_context_unsigned(&apdu[apdu_len], 2,
|
||||
data->array_index);
|
||||
// propertyValue
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 3);
|
||||
apdu_len += bacapp_encode_application_data(&apdu[apdu_len], &data->value);
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 3);
|
||||
// optional priority - 0 if not set, 1..16 if set
|
||||
if (data->priority != BACNET_NO_PRIORITY)
|
||||
apdu_len += encode_context_unsigned(&apdu[apdu_len], 4,
|
||||
data->priority);
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
if (apdu) {
|
||||
apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
|
||||
apdu[1] =
|
||||
encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted());
|
||||
apdu[2] = invoke_id;
|
||||
apdu[3] = SERVICE_CONFIRMED_WRITE_PROPERTY; // service choice
|
||||
apdu_len = 4;
|
||||
apdu_len += encode_context_object_id(&apdu[apdu_len], 0,
|
||||
data->object_type, data->object_instance);
|
||||
apdu_len += encode_context_enumerated(&apdu[apdu_len], 1,
|
||||
data->object_property);
|
||||
/* optional array index; ALL is -1 which is assumed when missing */
|
||||
if (data->array_index != BACNET_ARRAY_ALL)
|
||||
apdu_len += encode_context_unsigned(&apdu[apdu_len], 2,
|
||||
data->array_index);
|
||||
// propertyValue
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 3);
|
||||
apdu_len +=
|
||||
bacapp_encode_application_data(&apdu[apdu_len], &data->value);
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 3);
|
||||
// optional priority - 0 if not set, 1..16 if set
|
||||
if (data->priority != BACNET_NO_PRIORITY)
|
||||
apdu_len += encode_context_unsigned(&apdu[apdu_len], 4,
|
||||
data->priority);
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* decode the service request only */
|
||||
/* FIXME: there could be various error messages returned
|
||||
using unique values less than zero */
|
||||
int wp_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_WRITE_PROPERTY_DATA *data)
|
||||
int wp_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_WRITE_PROPERTY_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
int tag_len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value_type = 0;
|
||||
int type = 0; // for decoding
|
||||
int property = 0; // for decoding
|
||||
uint32_t unsigned_value = 0;
|
||||
int len = 0;
|
||||
int tag_len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value_type = 0;
|
||||
int type = 0; // for decoding
|
||||
int property = 0; // for decoding
|
||||
uint32_t unsigned_value = 0;
|
||||
|
||||
// check for value pointers
|
||||
if (apdu_len && data)
|
||||
{
|
||||
// Tag 0: Object ID
|
||||
if (!decode_is_context_tag(&apdu[len++], 0))
|
||||
return -1;
|
||||
len += decode_object_id(&apdu[len], &type, &data->object_instance);
|
||||
data->object_type = type;
|
||||
// Tag 1: Property ID
|
||||
len += decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
if (tag_number != 1)
|
||||
return -1;
|
||||
len += decode_enumerated(&apdu[len], len_value_type, &property);
|
||||
data->object_property = property;
|
||||
// Tag 2: Optional Array Index
|
||||
// note: decode without incrementing len so we can check for opening tag
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
if (tag_number == 2)
|
||||
{
|
||||
len += tag_len;
|
||||
len += decode_unsigned(&apdu[len], len_value_type,
|
||||
&unsigned_value);
|
||||
data->array_index = unsigned_value;
|
||||
}
|
||||
else
|
||||
data->array_index = BACNET_ARRAY_ALL;
|
||||
// Tag 3: opening context tag */
|
||||
if (!decode_is_opening_tag_number(&apdu[len], 3))
|
||||
return -1;
|
||||
// a tag number of 3 is not extended so only one octet
|
||||
len++;
|
||||
len += bacapp_decode_application_data(
|
||||
&apdu[len],
|
||||
apdu_len - len,
|
||||
&data->value);
|
||||
/* FIXME: check the return value; abort if no valid data? */
|
||||
/* FIXME: there might be more than one data element in here! */
|
||||
if (!decode_is_closing_tag_number(&apdu[len], 3))
|
||||
return -1;
|
||||
// a tag number of 3 is not extended so only one octet
|
||||
len++;
|
||||
// Tag 4: optional Priority - assumed MAX if not explicitly set
|
||||
data->priority = BACNET_MAX_PRIORITY;
|
||||
if ((unsigned)len < apdu_len)
|
||||
{
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
if (tag_number == 4)
|
||||
{
|
||||
len += tag_len;
|
||||
len = decode_unsigned(&apdu[len], len_value_type, &unsigned_value);
|
||||
if ((unsigned_value >= BACNET_MIN_PRIORITY) &&
|
||||
(unsigned_value <= BACNET_MAX_PRIORITY))
|
||||
{
|
||||
data->priority = (uint8_t)unsigned_value;
|
||||
// check for value pointers
|
||||
if (apdu_len && data) {
|
||||
// Tag 0: Object ID
|
||||
if (!decode_is_context_tag(&apdu[len++], 0))
|
||||
return -1;
|
||||
len += decode_object_id(&apdu[len], &type, &data->object_instance);
|
||||
data->object_type = type;
|
||||
// Tag 1: Property ID
|
||||
len += decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
if (tag_number != 1)
|
||||
return -1;
|
||||
len += decode_enumerated(&apdu[len], len_value_type, &property);
|
||||
data->object_property = property;
|
||||
// Tag 2: Optional Array Index
|
||||
// note: decode without incrementing len so we can check for opening tag
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
if (tag_number == 2) {
|
||||
len += tag_len;
|
||||
len += decode_unsigned(&apdu[len], len_value_type,
|
||||
&unsigned_value);
|
||||
data->array_index = unsigned_value;
|
||||
} else
|
||||
data->array_index = BACNET_ARRAY_ALL;
|
||||
// Tag 3: opening context tag */
|
||||
if (!decode_is_opening_tag_number(&apdu[len], 3))
|
||||
return -1;
|
||||
// a tag number of 3 is not extended so only one octet
|
||||
len++;
|
||||
len += bacapp_decode_application_data(&apdu[len],
|
||||
apdu_len - len, &data->value);
|
||||
/* FIXME: check the return value; abort if no valid data? */
|
||||
/* FIXME: there might be more than one data element in here! */
|
||||
if (!decode_is_closing_tag_number(&apdu[len], 3))
|
||||
return -1;
|
||||
// a tag number of 3 is not extended so only one octet
|
||||
len++;
|
||||
// Tag 4: optional Priority - assumed MAX if not explicitly set
|
||||
data->priority = BACNET_MAX_PRIORITY;
|
||||
if ((unsigned) len < apdu_len) {
|
||||
tag_len = decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
if (tag_number == 4) {
|
||||
len += tag_len;
|
||||
len =
|
||||
decode_unsigned(&apdu[len], len_value_type,
|
||||
&unsigned_value);
|
||||
if ((unsigned_value >= BACNET_MIN_PRIORITY)
|
||||
&& (unsigned_value <= BACNET_MAX_PRIORITY)) {
|
||||
data->priority = (uint8_t) unsigned_value;
|
||||
} else
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
return len;
|
||||
}
|
||||
|
||||
int wp_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
BACNET_WRITE_PROPERTY_DATA *data)
|
||||
int wp_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id, BACNET_WRITE_PROPERTY_DATA * data)
|
||||
{
|
||||
int len = 0;
|
||||
unsigned offset = 0;
|
||||
int len = 0;
|
||||
unsigned offset = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
|
||||
return -1;
|
||||
// apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted());
|
||||
*invoke_id = apdu[2]; /* invoke id - filled in by net layer */
|
||||
if (apdu[3] != SERVICE_CONFIRMED_WRITE_PROPERTY)
|
||||
return -1;
|
||||
offset = 4;
|
||||
if (!apdu)
|
||||
return -1;
|
||||
// optional checking - most likely was already done prior to this call
|
||||
if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
|
||||
return -1;
|
||||
// apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted());
|
||||
*invoke_id = apdu[2]; /* invoke id - filled in by net layer */
|
||||
if (apdu[3] != SERVICE_CONFIRMED_WRITE_PROPERTY)
|
||||
return -1;
|
||||
offset = 4;
|
||||
|
||||
if (apdu_len > offset)
|
||||
{
|
||||
len = wp_decode_service_request(
|
||||
&apdu[offset],
|
||||
apdu_len - offset,
|
||||
data);
|
||||
}
|
||||
|
||||
return len;
|
||||
if (apdu_len > offset) {
|
||||
len = wp_decode_service_request(&apdu[offset],
|
||||
apdu_len - offset, data);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
@@ -197,169 +182,159 @@ int wp_decode_apdu(
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
void testWritePropertyTag(Test * pTest,
|
||||
BACNET_WRITE_PROPERTY_DATA *data)
|
||||
void testWritePropertyTag(Test * pTest, BACNET_WRITE_PROPERTY_DATA * data)
|
||||
{
|
||||
BACNET_WRITE_PROPERTY_DATA test_data = {0};
|
||||
uint8_t apdu[480] = {0};
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 128;
|
||||
uint8_t test_invoke_id = 0;
|
||||
|
||||
len = wp_encode_apdu(
|
||||
&apdu[0],
|
||||
invoke_id,
|
||||
data);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
BACNET_WRITE_PROPERTY_DATA test_data = { 0 };
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 128;
|
||||
uint8_t test_invoke_id = 0;
|
||||
|
||||
len = wp_decode_apdu(
|
||||
&apdu[0],
|
||||
apdu_len,
|
||||
&test_invoke_id,
|
||||
&test_data);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_data.object_type == data->object_type);
|
||||
ct_test(pTest, test_data.object_instance == data->object_instance);
|
||||
ct_test(pTest, test_data.object_property == data->object_property);
|
||||
ct_test(pTest, test_data.array_index == data->array_index);
|
||||
ct_test(pTest, test_data.value.tag == data->value.tag);
|
||||
switch (test_data.value.tag)
|
||||
{
|
||||
len = wp_encode_apdu(&apdu[0], invoke_id, data);
|
||||
ct_test(pTest, len != 0);
|
||||
apdu_len = len;
|
||||
|
||||
len = wp_decode_apdu(&apdu[0], apdu_len, &test_invoke_id, &test_data);
|
||||
ct_test(pTest, len != -1);
|
||||
ct_test(pTest, test_data.object_type == data->object_type);
|
||||
ct_test(pTest, test_data.object_instance == data->object_instance);
|
||||
ct_test(pTest, test_data.object_property == data->object_property);
|
||||
ct_test(pTest, test_data.array_index == data->array_index);
|
||||
ct_test(pTest, test_data.value.tag == data->value.tag);
|
||||
switch (test_data.value.tag) {
|
||||
case BACNET_APPLICATION_TAG_NULL:
|
||||
break;
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_BOOLEAN:
|
||||
ct_test(pTest, test_data.value.type.Boolean ==
|
||||
data->value.type.Boolean);
|
||||
break;
|
||||
ct_test(pTest, test_data.value.type.Boolean ==
|
||||
data->value.type.Boolean);
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_UNSIGNED_INT:
|
||||
ct_test(pTest, test_data.value.type.Unsigned_Int ==
|
||||
data->value.type.Unsigned_Int);
|
||||
break;
|
||||
ct_test(pTest, test_data.value.type.Unsigned_Int ==
|
||||
data->value.type.Unsigned_Int);
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_SIGNED_INT:
|
||||
ct_test(pTest, test_data.value.type.Signed_Int ==
|
||||
data->value.type.Signed_Int);
|
||||
break;
|
||||
ct_test(pTest, test_data.value.type.Signed_Int ==
|
||||
data->value.type.Signed_Int);
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_REAL:
|
||||
ct_test(pTest, test_data.value.type.Real ==
|
||||
data->value.type.Real);
|
||||
break;
|
||||
ct_test(pTest, test_data.value.type.Real == data->value.type.Real);
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_ENUMERATED:
|
||||
ct_test(pTest, test_data.value.type.Enumerated ==
|
||||
data->value.type.Enumerated);
|
||||
break;
|
||||
ct_test(pTest, test_data.value.type.Enumerated ==
|
||||
data->value.type.Enumerated);
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_DATE:
|
||||
ct_test(pTest, test_data.value.type.Date.year ==
|
||||
data->value.type.Date.year);
|
||||
ct_test(pTest, test_data.value.type.Date.month ==
|
||||
data->value.type.Date.month);
|
||||
ct_test(pTest, test_data.value.type.Date.day ==
|
||||
data->value.type.Date.day);
|
||||
ct_test(pTest, test_data.value.type.Date.wday ==
|
||||
data->value.type.Date.wday);
|
||||
break;
|
||||
ct_test(pTest, test_data.value.type.Date.year ==
|
||||
data->value.type.Date.year);
|
||||
ct_test(pTest, test_data.value.type.Date.month ==
|
||||
data->value.type.Date.month);
|
||||
ct_test(pTest, test_data.value.type.Date.day ==
|
||||
data->value.type.Date.day);
|
||||
ct_test(pTest, test_data.value.type.Date.wday ==
|
||||
data->value.type.Date.wday);
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_TIME:
|
||||
ct_test(pTest, test_data.value.type.Time.hour ==
|
||||
data->value.type.Time.hour);
|
||||
ct_test(pTest, test_data.value.type.Time.min ==
|
||||
data->value.type.Time.min);
|
||||
ct_test(pTest, test_data.value.type.Time.sec ==
|
||||
data->value.type.Time.sec);
|
||||
ct_test(pTest, test_data.value.type.Time.hundredths ==
|
||||
data->value.type.Time.hundredths);
|
||||
break;
|
||||
ct_test(pTest, test_data.value.type.Time.hour ==
|
||||
data->value.type.Time.hour);
|
||||
ct_test(pTest, test_data.value.type.Time.min ==
|
||||
data->value.type.Time.min);
|
||||
ct_test(pTest, test_data.value.type.Time.sec ==
|
||||
data->value.type.Time.sec);
|
||||
ct_test(pTest, test_data.value.type.Time.hundredths ==
|
||||
data->value.type.Time.hundredths);
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_OBJECT_ID:
|
||||
ct_test(pTest, test_data.value.type.Object_Id.type ==
|
||||
data->value.type.Object_Id.type);
|
||||
ct_test(pTest, test_data.value.type.Object_Id.instance ==
|
||||
data->value.type.Object_Id.instance);
|
||||
break;
|
||||
ct_test(pTest, test_data.value.type.Object_Id.type ==
|
||||
data->value.type.Object_Id.type);
|
||||
ct_test(pTest, test_data.value.type.Object_Id.instance ==
|
||||
data->value.type.Object_Id.instance);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void testWriteProperty(Test * pTest)
|
||||
{
|
||||
BACNET_WRITE_PROPERTY_DATA data = {0};
|
||||
BACNET_WRITE_PROPERTY_DATA data = { 0 };
|
||||
|
||||
data.value.tag = BACNET_APPLICATION_TAG_NULL;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.tag = BACNET_APPLICATION_TAG_NULL;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
|
||||
data.value.tag = BACNET_APPLICATION_TAG_BOOLEAN;
|
||||
data.value.type.Boolean = true;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.type.Boolean = false;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.tag = BACNET_APPLICATION_TAG_BOOLEAN;
|
||||
data.value.type.Boolean = true;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.type.Boolean = false;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
|
||||
data.value.tag = BACNET_APPLICATION_TAG_UNSIGNED_INT;
|
||||
data.value.type.Unsigned_Int = 0;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.type.Unsigned_Int = 0xFFFF;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.type.Unsigned_Int = 0xFFFFFFFF;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.tag = BACNET_APPLICATION_TAG_UNSIGNED_INT;
|
||||
data.value.type.Unsigned_Int = 0;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.type.Unsigned_Int = 0xFFFF;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.type.Unsigned_Int = 0xFFFFFFFF;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
|
||||
data.value.tag = BACNET_APPLICATION_TAG_SIGNED_INT;
|
||||
data.value.type.Signed_Int = 0;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.type.Signed_Int = -1;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.type.Signed_Int = 32768;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.type.Signed_Int = -32768;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
|
||||
data.value.tag = BACNET_APPLICATION_TAG_REAL;
|
||||
data.value.type.Real = 0.0;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.type.Real = -1.0;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.type.Real = 1.0;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.type.Real = 3.14159;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.type.Real = -3.14159;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
|
||||
data.value.tag = BACNET_APPLICATION_TAG_ENUMERATED;
|
||||
data.value.type.Enumerated = 0;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.type.Enumerated = 0xFFFF;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.type.Enumerated = 0xFFFFFFFF;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
|
||||
data.value.tag = BACNET_APPLICATION_TAG_DATE;
|
||||
data.value.type.Date.year = 2005;
|
||||
data.value.type.Date.month = 5;
|
||||
data.value.type.Date.day = 22;
|
||||
data.value.type.Date.wday = 1;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.tag = BACNET_APPLICATION_TAG_SIGNED_INT;
|
||||
data.value.type.Signed_Int = 0;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.type.Signed_Int = -1;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.type.Signed_Int = 32768;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.type.Signed_Int = -32768;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
|
||||
data.value.tag = BACNET_APPLICATION_TAG_TIME;
|
||||
data.value.type.Time.hour = 23;
|
||||
data.value.type.Time.min = 59;
|
||||
data.value.type.Time.sec = 59;
|
||||
data.value.type.Time.hundredths = 12;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.tag = BACNET_APPLICATION_TAG_REAL;
|
||||
data.value.type.Real = 0.0;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.type.Real = -1.0;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.type.Real = 1.0;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.type.Real = 3.14159;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.type.Real = -3.14159;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
|
||||
data.value.tag = BACNET_APPLICATION_TAG_OBJECT_ID;
|
||||
data.value.type.Object_Id.type = OBJECT_ANALOG_INPUT;
|
||||
data.value.type.Object_Id.instance = 0;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.type.Object_Id.type = OBJECT_LIFE_SAFETY_ZONE;
|
||||
data.value.type.Object_Id.instance = BACNET_MAX_INSTANCE;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.tag = BACNET_APPLICATION_TAG_ENUMERATED;
|
||||
data.value.type.Enumerated = 0;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.type.Enumerated = 0xFFFF;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.type.Enumerated = 0xFFFFFFFF;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
|
||||
return;
|
||||
data.value.tag = BACNET_APPLICATION_TAG_DATE;
|
||||
data.value.type.Date.year = 2005;
|
||||
data.value.type.Date.month = 5;
|
||||
data.value.type.Date.day = 22;
|
||||
data.value.type.Date.wday = 1;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
|
||||
data.value.tag = BACNET_APPLICATION_TAG_TIME;
|
||||
data.value.type.Time.hour = 23;
|
||||
data.value.type.Time.min = 59;
|
||||
data.value.type.Time.sec = 59;
|
||||
data.value.type.Time.hundredths = 12;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
|
||||
data.value.tag = BACNET_APPLICATION_TAG_OBJECT_ID;
|
||||
data.value.type.Object_Id.type = OBJECT_ANALOG_INPUT;
|
||||
data.value.type.Object_Id.instance = 0;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
data.value.type.Object_Id.type = OBJECT_LIFE_SAFETY_ZONE;
|
||||
data.value.type.Object_Id.instance = BACNET_MAX_INSTANCE;
|
||||
testWritePropertyTag(pTest, &data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_WRITE_PROPERTY
|
||||
uint16_t Device_Max_APDU_Length_Accepted(void)
|
||||
{
|
||||
return MAX_APDU;
|
||||
return MAX_APDU;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
|
||||
+20
-29
@@ -39,49 +39,40 @@
|
||||
#include "bacdcode.h"
|
||||
#include "bacapp.h"
|
||||
|
||||
typedef struct BACnet_Write_Property_Data
|
||||
{
|
||||
BACNET_OBJECT_TYPE object_type;
|
||||
uint32_t object_instance;
|
||||
BACNET_PROPERTY_ID object_property;
|
||||
int32_t array_index; // use BACNET_ARRAY_ALL when not setting
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
uint8_t priority; // use 0 if not setting the priority
|
||||
typedef struct BACnet_Write_Property_Data {
|
||||
BACNET_OBJECT_TYPE object_type;
|
||||
uint32_t object_instance;
|
||||
BACNET_PROPERTY_ID object_property;
|
||||
int32_t array_index; // use BACNET_ARRAY_ALL when not setting
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
uint8_t priority; // use 0 if not setting the priority
|
||||
} BACNET_WRITE_PROPERTY_DATA;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
// encode service
|
||||
int wp_encode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint8_t invoke_id,
|
||||
BACNET_WRITE_PROPERTY_DATA *data);
|
||||
int wp_encode_apdu(uint8_t * apdu,
|
||||
uint8_t invoke_id, BACNET_WRITE_PROPERTY_DATA * data);
|
||||
|
||||
// decode the service request only
|
||||
int wp_decode_service_request(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_WRITE_PROPERTY_DATA *data);
|
||||
|
||||
int wp_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
BACNET_WRITE_PROPERTY_DATA *data);
|
||||
int wp_decode_service_request(uint8_t * apdu,
|
||||
unsigned apdu_len, BACNET_WRITE_PROPERTY_DATA * data);
|
||||
|
||||
int wp_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id, BACNET_WRITE_PROPERTY_DATA * data);
|
||||
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
|
||||
void test_ReadProperty(Test * pTest);
|
||||
void test_ReadPropertyAck(Test * pTest);
|
||||
void test_ReadProperty(Test * pTest);
|
||||
void test_ReadPropertyAck(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user