ran the indent program on the source files to make them consistent.

This commit is contained in:
skarg
2006-02-18 22:34:36 +00:00
parent 21b373c75c
commit b1d46ffa8c
72 changed files with 10446 additions and 11551 deletions
+80 -124
View File
@@ -37,71 +37,56 @@
#include "bacdef.h" #include "bacdef.h"
// encode service // encode service
int abort_encode_apdu( int abort_encode_apdu(uint8_t * apdu,
uint8_t *apdu, uint8_t invoke_id, uint8_t abort_reason)
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) if (apdu) {
{ apdu[0] = PDU_TYPE_ABORT;
apdu[0] = PDU_TYPE_ABORT; apdu[1] = invoke_id;
apdu[1] = invoke_id; apdu[2] = abort_reason;
apdu[2] = abort_reason; apdu_len = 3;
apdu_len = 3; }
}
return apdu_len;
return apdu_len;
} }
// decode the service request only // decode the service request only
int abort_decode_service_request( int abort_decode_service_request(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, uint8_t * invoke_id, uint8_t * abort_reason)
unsigned apdu_len,
uint8_t *invoke_id,
uint8_t *abort_reason)
{ {
int len = 0; int len = 0;
if (apdu_len) if (apdu_len) {
{ if (invoke_id)
if (invoke_id) *invoke_id = apdu[0];
*invoke_id = apdu[0]; if (abort_reason)
if (abort_reason) *abort_reason = apdu[1];
*abort_reason = apdu[1]; }
}
return len;
return len;
} }
// decode the whole APDU - mainly used for unit testing // decode the whole APDU - mainly used for unit testing
int abort_decode_apdu( int abort_decode_apdu(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, uint8_t * invoke_id, uint8_t * abort_reason)
unsigned apdu_len,
uint8_t *invoke_id,
uint8_t *abort_reason)
{ {
int len = 0; int len = 0;
if (!apdu) if (!apdu)
return -1; return -1;
// optional checking - most likely was already done prior to this call // optional checking - most likely was already done prior to this call
if (apdu_len) if (apdu_len) {
{ if (apdu[0] != PDU_TYPE_ABORT)
if (apdu[0] != PDU_TYPE_ABORT) return -1;
return -1; if (apdu_len > 1) {
if (apdu_len > 1) len = abort_decode_service_request(&apdu[1],
{ apdu_len - 1, invoke_id, abort_reason);
len = abort_decode_service_request( }
&apdu[1],
apdu_len - 1,
invoke_id,
abort_reason);
} }
}
return len;
return len;
} }
#ifdef TEST #ifdef TEST
@@ -111,83 +96,54 @@ int abort_decode_apdu(
void testAbort(Test * pTest) void testAbort(Test * pTest)
{ {
uint8_t apdu[480] = {0}; uint8_t apdu[480] = { 0 };
int len = 0; int len = 0;
int apdu_len = 0; int apdu_len = 0;
uint8_t invoke_id = 0; uint8_t invoke_id = 0;
uint8_t abort_reason = 0; uint8_t abort_reason = 0;
uint8_t test_invoke_id = 0; uint8_t test_invoke_id = 0;
uint8_t test_abort_reason = 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;
len = abort_decode_apdu( len = abort_encode_apdu(&apdu[0], invoke_id, abort_reason);
&apdu[0], ct_test(pTest, len != 0);
apdu_len, apdu_len = 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);
// change type to get negative response len = abort_decode_apdu(&apdu[0],
apdu[0] = PDU_TYPE_REJECT; apdu_len, &test_invoke_id, &test_abort_reason);
len = abort_decode_apdu( ct_test(pTest, len != -1);
&apdu[0], ct_test(pTest, test_invoke_id == invoke_id);
apdu_len, ct_test(pTest, test_abort_reason == abort_reason);
&test_invoke_id,
&test_abort_reason);
ct_test(pTest, len == -1);
// test NULL APDU // change type to get negative response
len = abort_decode_apdu( apdu[0] = PDU_TYPE_REJECT;
NULL, len = abort_decode_apdu(&apdu[0],
apdu_len, apdu_len, &test_invoke_id, &test_abort_reason);
&test_invoke_id, ct_test(pTest, len == -1);
&test_abort_reason);
ct_test(pTest, len == -1);
// force a zero length // test NULL APDU
len = abort_decode_apdu( len = abort_decode_apdu(NULL,
&apdu[0], apdu_len, &test_invoke_id, &test_abort_reason);
0, ct_test(pTest, len == -1);
&test_invoke_id,
&test_abort_reason); // force a zero length
ct_test(pTest, len == 0); 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; // check them all...
invoke_id < 255; for (invoke_id = 0; invoke_id < 255; invoke_id++) {
invoke_id++) for (abort_reason = 0; abort_reason < 255; abort_reason++) {
{ len = abort_encode_apdu(&apdu[0], invoke_id, abort_reason);
for ( apdu_len = len;
abort_reason = 0; ct_test(pTest, len != 0);
abort_reason < 255; len = abort_decode_apdu(&apdu[0],
abort_reason++) apdu_len, &test_invoke_id, &test_abort_reason);
{ ct_test(pTest, len != -1);
len = abort_encode_apdu( ct_test(pTest, test_invoke_id == invoke_id);
&apdu[0], ct_test(pTest, test_abort_reason == abort_reason);
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 #ifdef TEST_ABORT
+10 -20
View File
@@ -39,33 +39,23 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
int abort_encode_apdu( int abort_encode_apdu(uint8_t * apdu,
uint8_t *apdu, uint8_t invoke_id, uint8_t abort_reason);
uint8_t invoke_id,
uint8_t abort_reason);
int abort_decode_service_request( int abort_decode_service_request(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, uint8_t * invoke_id, uint8_t * abort_reason);
unsigned apdu_len,
uint8_t *invoke_id, int abort_decode_apdu(uint8_t * apdu,
uint8_t *abort_reason); 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 #ifdef TEST
#include "ctest.h" #include "ctest.h"
void testAbort(Test * pTest); void testAbort(Test * pTest);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+223 -279
View File
@@ -44,287 +44,241 @@
// occurs in BACnet. A device id is bound to a MAC address. // 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 // The normal method is using Who-Is, and using the data from I-Am
static struct Address_Cache_Entry static struct Address_Cache_Entry {
{ bool valid;
bool valid; bool bind_request;
bool bind_request; uint32_t device_id;
uint32_t device_id; unsigned max_apdu;
unsigned max_apdu; BACNET_ADDRESS address;
BACNET_ADDRESS address;
} Address_Cache[MAX_ADDRESS_CACHE]; } Address_Cache[MAX_ADDRESS_CACHE];
void address_copy( void address_copy(BACNET_ADDRESS * dest, BACNET_ADDRESS * src)
BACNET_ADDRESS *dest,
BACNET_ADDRESS *src)
{ {
unsigned i = 0; // counter 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];
}
}
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( void address_remove_device(uint32_t device_id)
uint32_t device_id)
{ {
unsigned i; unsigned i;
for (i = 0; i < MAX_ADDRESS_CACHE; i++) for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
{ if ((Address_Cache[i].valid ||
if ((Address_Cache[i].valid || Address_Cache[i].bind_request) &&
Address_Cache[i].bind_request) && (Address_Cache[i].device_id == device_id)) {
(Address_Cache[i].device_id == device_id)) Address_Cache[i].valid = false;
{ break;
Address_Cache[i].valid = false; }
break;
} }
}
return; return;
} }
void address_init(void) void address_init(void)
{ {
unsigned i; unsigned i;
for (i = 0; i < MAX_ADDRESS_CACHE; i++) for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
{ Address_Cache[i].valid = false;
Address_Cache[i].valid = false; Address_Cache[i].bind_request = false;
Address_Cache[i].bind_request = false; }
}
return; return;
} }
bool address_get_by_device( bool address_get_by_device(uint32_t device_id,
uint32_t device_id, unsigned *max_apdu, BACNET_ADDRESS * src)
unsigned *max_apdu,
BACNET_ADDRESS *src)
{ {
unsigned i; unsigned i;
bool found = false; // return value bool found = false; // return value
for (i = 0; i < MAX_ADDRESS_CACHE; i++) for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
{ if (Address_Cache[i].valid &&
if (Address_Cache[i].valid && (Address_Cache[i].device_id == device_id)) {
(Address_Cache[i].device_id == device_id)) address_copy(src, &Address_Cache[i].address);
{ *max_apdu = Address_Cache[i].max_apdu;
address_copy(src, &Address_Cache[i].address); found = true;
*max_apdu = Address_Cache[i].max_apdu; break;
found = true; }
break;
} }
}
return found; return found;
} }
void address_add( void address_add(uint32_t device_id,
uint32_t device_id, unsigned max_apdu, BACNET_ADDRESS * src)
unsigned max_apdu,
BACNET_ADDRESS *src)
{ {
unsigned i; unsigned i;
bool found = false; // return value bool found = false; // return value
// existing device - update address // existing device - update address
for (i = 0; i < MAX_ADDRESS_CACHE; i++) for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
{ if (Address_Cache[i].valid &&
if (Address_Cache[i].valid && (Address_Cache[i].device_id == device_id)) {
(Address_Cache[i].device_id == device_id)) address_copy(&Address_Cache[i].address, src);
{ Address_Cache[i].max_apdu = max_apdu;
address_copy(&Address_Cache[i].address,src); found = true;
Address_Cache[i].max_apdu = max_apdu; break;
found = true; }
break;
} }
} // new device
// new device if (!found) {
if (!found) for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
{ if (!Address_Cache[i].valid) {
for (i = 0; i < MAX_ADDRESS_CACHE; i++) Address_Cache[i].valid = true;
{ Address_Cache[i].device_id = device_id;
if (!Address_Cache[i].valid) Address_Cache[i].max_apdu = max_apdu;
{ address_copy(&Address_Cache[i].address, src);
Address_Cache[i].valid = true; break;
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 // returns true if device is already bound
// also returns the address and max apdu if already bound // also returns the address and max apdu if already bound
bool address_bind_request( bool address_bind_request(uint32_t device_id,
uint32_t device_id, unsigned *max_apdu, BACNET_ADDRESS * src)
unsigned *max_apdu,
BACNET_ADDRESS *src)
{ {
unsigned i; unsigned i;
bool found = false; // return value bool found = false; // return value
// existing device - update address // existing device - update address
for (i = 0; i < MAX_ADDRESS_CACHE; i++) for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
{ if (Address_Cache[i].valid &&
if (Address_Cache[i].valid && (Address_Cache[i].device_id == device_id)) {
(Address_Cache[i].device_id == device_id)) found = true;
{ address_copy(src, &Address_Cache[i].address);
found = true; *max_apdu = Address_Cache[i].max_apdu;
address_copy(src, &Address_Cache[i].address); break;
*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 && if (!found) {
(Address_Cache[i].device_id == device_id)) for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
{ if (!(Address_Cache[i].bind_request || Address_Cache[i].valid)) {
return found; 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;
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;
} }
void address_add_binding( void address_add_binding(uint32_t device_id,
uint32_t device_id, unsigned max_apdu, BACNET_ADDRESS * src)
unsigned max_apdu,
BACNET_ADDRESS *src)
{ {
unsigned i; unsigned i;
bool found = false; // return value bool found = false; // return value
// existing device - update address // existing device - update address
for (i = 0; i < MAX_ADDRESS_CACHE; i++) for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
{ if (Address_Cache[i].valid &&
if (Address_Cache[i].valid && (Address_Cache[i].device_id == device_id)) {
(Address_Cache[i].device_id == device_id)) address_copy(&Address_Cache[i].address, src);
{ Address_Cache[i].max_apdu = max_apdu;
address_copy(&Address_Cache[i].address,src); found = true;
Address_Cache[i].max_apdu = max_apdu; break;
found = true; }
break;
} }
} // add new device - but only if bind requested
// add new device - but only if bind requested if (!found) {
if (!found) for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
{ if (!Address_Cache[i].valid && Address_Cache[i].bind_request) {
for (i = 0; i < MAX_ADDRESS_CACHE; i++) Address_Cache[i].valid = true;
{ Address_Cache[i].bind_request = false;
if (!Address_Cache[i].valid && Address_Cache[i].bind_request) Address_Cache[i].device_id = device_id;
{ Address_Cache[i].max_apdu = max_apdu;
Address_Cache[i].valid = true; address_copy(&Address_Cache[i].address, src);
Address_Cache[i].bind_request = false; break;
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( bool address_get_by_index(unsigned index,
unsigned index, uint32_t * device_id, unsigned *max_apdu, BACNET_ADDRESS * src)
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 (index < MAX_ADDRESS_CACHE) {
{ if (Address_Cache[index].valid) {
if (Address_Cache[index].valid) address_copy(src, &Address_Cache[index].address);
{ *device_id = Address_Cache[index].device_id;
address_copy(src, &Address_Cache[index].address); *max_apdu = Address_Cache[index].max_apdu;
*device_id = Address_Cache[index].device_id; found = true;
*max_apdu = Address_Cache[index].max_apdu; }
found = true;
} }
}
return found; return found;
} }
unsigned address_count(void) unsigned address_count(void)
{ {
unsigned i; unsigned i;
unsigned count = 0; // return value unsigned count = 0; // return value
for (i = 0; i < MAX_ADDRESS_CACHE; i++) for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
{ if (Address_Cache[i].valid)
if (Address_Cache[i].valid) count++;
count++; }
}
return count; return count;
} }
bool address_match( bool address_match(BACNET_ADDRESS * dest, BACNET_ADDRESS * src)
BACNET_ADDRESS *dest,
BACNET_ADDRESS *src)
{ {
unsigned i; unsigned i;
unsigned max_len; unsigned max_len;
bool match = true; // return value bool match = true; // return value
if (dest->mac_len != src->mac_len) if (dest->mac_len != src->mac_len)
match = false; match = false;
max_len = dest->mac_len; max_len = dest->mac_len;
if (max_len > MAX_MAC_LEN) if (max_len > MAX_MAC_LEN)
max_len = MAX_MAC_LEN; max_len = MAX_MAC_LEN;
for (i = 0; i < max_len; i++) for (i = 0; i < max_len; i++) {
{ if (dest->mac[i] != src->mac[i])
if (dest->mac[i] != src->mac[i]) match = false;
match = false; }
} if (dest->net != src->net)
if (dest->net != src->net) match = false;
match = false; if (dest->len != src->len)
if (dest->len != src->len) match = false;
match = false; max_len = dest->len;
max_len = dest->len; if (max_len > MAX_MAC_LEN)
if (max_len > MAX_MAC_LEN) max_len = MAX_MAC_LEN;
max_len = MAX_MAC_LEN; for (i = 0; i < max_len; i++) {
for (i = 0; i < max_len; i++) if (dest->adr[i] != src->adr[i])
{ match = false;
if (dest->adr[i] != src->adr[i]) }
match = false;
} return match;
return match;
} }
#ifdef TEST #ifdef TEST
@@ -332,72 +286,62 @@ bool address_match(
#include <string.h> #include <string.h>
#include "ctest.h" #include "ctest.h"
static void set_address( static void set_address(unsigned index, BACNET_ADDRESS * dest)
unsigned index,
BACNET_ADDRESS *dest)
{ {
unsigned i; unsigned i;
for (i = 0; i < MAX_MAC_LEN; i++) for (i = 0; i < MAX_MAC_LEN; i++) {
{ dest->mac[i] = index;
dest->mac[i] = index; }
} dest->mac_len = MAX_MAC_LEN;
dest->mac_len = MAX_MAC_LEN; dest->net = 7;
dest->net = 7; dest->len = MAX_MAC_LEN;
dest->len = MAX_MAC_LEN; for (i = 0; i < MAX_MAC_LEN; i++) {
for (i = 0; i < MAX_MAC_LEN; i++) dest->adr[i] = index;
{ }
dest->adr[i] = index;
}
} }
void testAddress(Test * pTest) void testAddress(Test * pTest)
{ {
unsigned i, count; unsigned i, count;
BACNET_ADDRESS src; BACNET_ADDRESS src;
uint32_t device_id = 0; uint32_t device_id = 0;
unsigned max_apdu = 480; unsigned max_apdu = 480;
BACNET_ADDRESS test_address; BACNET_ADDRESS test_address;
uint32_t test_device_id = 0; uint32_t test_device_id = 0;
unsigned test_max_apdu = 0; unsigned test_max_apdu = 0;
for (i = 0; i < MAX_ADDRESS_CACHE; i++) for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
{ set_address(i, &src);
set_address(i,&src); device_id = i * 255;
device_id = i * 255; address_add(device_id, max_apdu, &src);
address_add( count = address_count();
device_id, ct_test(pTest, count == (i + 1));
max_apdu, }
&src);
count = address_count();
ct_test(pTest, count == (i + 1));
}
for (i = 0; i < MAX_ADDRESS_CACHE; i++) for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
{ device_id = i * 255;
device_id = i * 255; ct_test(pTest, address_get_by_device(device_id, &test_max_apdu,
ct_test(pTest, address_get_by_device(device_id, &test_max_apdu, &test_address));
&test_address)); set_address(i, &src);
set_address(i,&src); ct_test(pTest, test_max_apdu == max_apdu);
ct_test(pTest, test_max_apdu == max_apdu); ct_test(pTest, address_match(&test_address, &src));
ct_test(pTest, address_match(&test_address,&src)); ct_test(pTest, address_get_by_index(i, &test_device_id,
ct_test(pTest, address_get_by_index(i, &test_device_id, &test_max_apdu, &test_address));
&test_max_apdu,&test_address)); ct_test(pTest, test_device_id == device_id);
ct_test(pTest, test_device_id == device_id); ct_test(pTest, test_max_apdu == max_apdu);
ct_test(pTest, test_max_apdu == max_apdu); ct_test(pTest, address_match(&test_address, &src));
ct_test(pTest, address_match(&test_address,&src)); ct_test(pTest, address_count() == MAX_ADDRESS_CACHE);
ct_test(pTest, address_count() == MAX_ADDRESS_CACHE); }
}
for (i = 0; i < MAX_ADDRESS_CACHE; i++) for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
{ device_id = i * 255;
device_id = i * 255; address_remove_device(device_id);
address_remove_device(device_id); ct_test(pTest, !address_get_by_device(device_id, &test_max_apdu,
ct_test(pTest, !address_get_by_device(device_id, &test_max_apdu, &test_address));
&test_address)); count = address_count();
count = address_count(); ct_test(pTest, count == (MAX_ADDRESS_CACHE - i - 1));
ct_test(pTest, count == (MAX_ADDRESS_CACHE-i-1)); }
}
} }
#ifdef TEST_ADDRESS #ifdef TEST_ADDRESS
+19 -36
View File
@@ -41,51 +41,34 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
void address_init(void); void address_init(void);
void address_copy( void address_copy(BACNET_ADDRESS * dest, BACNET_ADDRESS * src);
BACNET_ADDRESS *dest,
BACNET_ADDRESS *src);
void address_add( void address_add(uint32_t device_id,
uint32_t device_id, unsigned max_apdu, BACNET_ADDRESS * src);
unsigned max_apdu,
BACNET_ADDRESS *src);
void address_remove_device( void address_remove_device(uint32_t device_id);
uint32_t device_id);
bool address_get_by_device( bool address_get_by_device(uint32_t device_id,
uint32_t device_id, unsigned *max_apdu, BACNET_ADDRESS * src);
unsigned *max_apdu,
BACNET_ADDRESS *src);
bool address_get_by_index( bool address_get_by_index(unsigned index,
unsigned index, uint32_t * device_id, unsigned *max_apdu, BACNET_ADDRESS * src);
uint32_t *device_id,
unsigned *max_apdu,
BACNET_ADDRESS *src);
unsigned address_count(void); unsigned address_count(void);
bool address_match( bool address_match(BACNET_ADDRESS * dest, BACNET_ADDRESS * src);
BACNET_ADDRESS *dest,
BACNET_ADDRESS *src); bool address_bind_request(uint32_t device_id,
unsigned *max_apdu, BACNET_ADDRESS * src);
bool address_bind_request(
uint32_t device_id, void address_add_binding(uint32_t device_id,
unsigned *max_apdu, unsigned max_apdu, BACNET_ADDRESS * src);
BACNET_ADDRESS *src);
void address_add_binding(
uint32_t device_id,
unsigned max_apdu,
BACNET_ADDRESS *src);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+330 -378
View File
@@ -44,482 +44,434 @@
#include "iam.h" #include "iam.h"
/* a simple table for crossing the services supported */ /* a simple table for crossing the services supported */
static BACNET_SERVICES_SUPPORTED confirmed_service_supported[MAX_BACNET_CONFIRMED_SERVICE] = static BACNET_SERVICES_SUPPORTED
{ confirmed_service_supported[MAX_BACNET_CONFIRMED_SERVICE] = {
SERVICE_SUPPORTED_ACKNOWLEDGE_ALARM, SERVICE_SUPPORTED_ACKNOWLEDGE_ALARM,
SERVICE_SUPPORTED_CONFIRMED_COV_NOTIFICATION, SERVICE_SUPPORTED_CONFIRMED_COV_NOTIFICATION,
SERVICE_SUPPORTED_CONFIRMED_EVENT_NOTIFICATION, SERVICE_SUPPORTED_CONFIRMED_EVENT_NOTIFICATION,
SERVICE_SUPPORTED_GET_ALARM_SUMMARY, SERVICE_SUPPORTED_GET_ALARM_SUMMARY,
SERVICE_SUPPORTED_GET_ENROLLMENT_SUMMARY, SERVICE_SUPPORTED_GET_ENROLLMENT_SUMMARY,
SERVICE_SUPPORTED_SUBSCRIBE_COV, SERVICE_SUPPORTED_SUBSCRIBE_COV,
SERVICE_SUPPORTED_ATOMIC_READ_FILE, SERVICE_SUPPORTED_ATOMIC_READ_FILE,
SERVICE_SUPPORTED_ATOMIC_WRITE_FILE, SERVICE_SUPPORTED_ATOMIC_WRITE_FILE,
SERVICE_SUPPORTED_ADD_LIST_ELEMENT, SERVICE_SUPPORTED_ADD_LIST_ELEMENT,
SERVICE_SUPPORTED_REMOVE_LIST_ELEMENT, SERVICE_SUPPORTED_REMOVE_LIST_ELEMENT,
SERVICE_SUPPORTED_CREATE_OBJECT, SERVICE_SUPPORTED_CREATE_OBJECT,
SERVICE_SUPPORTED_DELETE_OBJECT, SERVICE_SUPPORTED_DELETE_OBJECT,
SERVICE_SUPPORTED_READ_PROPERTY, SERVICE_SUPPORTED_READ_PROPERTY,
SERVICE_SUPPORTED_READ_PROPERTY_CONDITIONAL, SERVICE_SUPPORTED_READ_PROPERTY_CONDITIONAL,
SERVICE_SUPPORTED_READ_PROPERTY_MULTIPLE, SERVICE_SUPPORTED_READ_PROPERTY_MULTIPLE,
SERVICE_SUPPORTED_WRITE_PROPERTY, SERVICE_SUPPORTED_WRITE_PROPERTY,
SERVICE_SUPPORTED_WRITE_PROPERTY_MULTIPLE, SERVICE_SUPPORTED_WRITE_PROPERTY_MULTIPLE,
SERVICE_SUPPORTED_DEVICE_COMMUNICATION_CONTROL, SERVICE_SUPPORTED_DEVICE_COMMUNICATION_CONTROL,
SERVICE_SUPPORTED_PRIVATE_TRANSFER, SERVICE_SUPPORTED_PRIVATE_TRANSFER,
SERVICE_SUPPORTED_TEXT_MESSAGE, SERVICE_SUPPORTED_TEXT_MESSAGE,
SERVICE_SUPPORTED_REINITIALIZE_DEVICE, SERVICE_SUPPORTED_REINITIALIZE_DEVICE,
SERVICE_SUPPORTED_VT_OPEN, SERVICE_SUPPORTED_VT_OPEN,
SERVICE_SUPPORTED_VT_CLOSE, SERVICE_SUPPORTED_VT_CLOSE,
SERVICE_SUPPORTED_VT_DATA, SERVICE_SUPPORTED_VT_DATA,
SERVICE_SUPPORTED_AUTHENTICATE, SERVICE_SUPPORTED_AUTHENTICATE,
SERVICE_SUPPORTED_REQUEST_KEY, SERVICE_SUPPORTED_REQUEST_KEY,
SERVICE_SUPPORTED_READ_RANGE, SERVICE_SUPPORTED_READ_RANGE,
SERVICE_SUPPORTED_LIFE_SAFETY_OPERATION, SERVICE_SUPPORTED_LIFE_SAFETY_OPERATION,
SERVICE_SUPPORTED_SUBSCRIBE_COV_PROPERTY, SERVICE_SUPPORTED_SUBSCRIBE_COV_PROPERTY,
SERVICE_SUPPORTED_GET_EVENT_INFORMATION SERVICE_SUPPORTED_GET_EVENT_INFORMATION
}; };
/* a simple table for crossing the services supported */ /* a simple table for crossing the services supported */
static BACNET_SERVICES_SUPPORTED unconfirmed_service_supported[MAX_BACNET_UNCONFIRMED_SERVICE] = static BACNET_SERVICES_SUPPORTED
{ unconfirmed_service_supported[MAX_BACNET_UNCONFIRMED_SERVICE] = {
SERVICE_SUPPORTED_I_AM, SERVICE_SUPPORTED_I_AM,
SERVICE_SUPPORTED_I_HAVE, SERVICE_SUPPORTED_I_HAVE,
SERVICE_SUPPORTED_UNCONFIRMED_COV_NOTIFICATION, SERVICE_SUPPORTED_UNCONFIRMED_COV_NOTIFICATION,
SERVICE_SUPPORTED_UNCONFIRMED_EVENT_NOTIFICATION, SERVICE_SUPPORTED_UNCONFIRMED_EVENT_NOTIFICATION,
SERVICE_SUPPORTED_UNCONFIRMED_PRIVATE_TRANSFER, SERVICE_SUPPORTED_UNCONFIRMED_PRIVATE_TRANSFER,
SERVICE_SUPPORTED_UNCONFIRMED_TEXT_MESSAGE, SERVICE_SUPPORTED_UNCONFIRMED_TEXT_MESSAGE,
SERVICE_SUPPORTED_TIME_SYNCHRONIZATION, SERVICE_SUPPORTED_TIME_SYNCHRONIZATION,
SERVICE_SUPPORTED_WHO_HAS, SERVICE_SUPPORTED_WHO_HAS,
SERVICE_SUPPORTED_WHO_IS, SERVICE_SUPPORTED_WHO_IS,
SERVICE_SUPPORTED_UTC_TIME_SYNCHRONIZATION SERVICE_SUPPORTED_UTC_TIME_SYNCHRONIZATION
}; };
// Confirmed Function Handlers // Confirmed Function Handlers
// If they are not set, they are handled by a reject message // If they are not set, they are handled by a reject message
static confirmed_function static confirmed_function Confirmed_Function[MAX_BACNET_CONFIRMED_SERVICE];
Confirmed_Function[MAX_BACNET_CONFIRMED_SERVICE];
void apdu_set_confirmed_handler( void apdu_set_confirmed_handler(BACNET_CONFIRMED_SERVICE service_choice,
BACNET_CONFIRMED_SERVICE service_choice, confirmed_function pFunction)
confirmed_function pFunction)
{ {
if (service_choice < MAX_BACNET_CONFIRMED_SERVICE) if (service_choice < MAX_BACNET_CONFIRMED_SERVICE)
Confirmed_Function[service_choice] = pFunction; Confirmed_Function[service_choice] = pFunction;
} }
/* returns true if the handler is set */ /* returns true if the handler is set */
bool apdu_confirmed_handler( bool apdu_confirmed_handler(BACNET_CONFIRMED_SERVICE service_choice)
BACNET_CONFIRMED_SERVICE service_choice)
{ {
bool status = false; bool status = false;
if ((service_choice < MAX_BACNET_CONFIRMED_SERVICE) && if ((service_choice < MAX_BACNET_CONFIRMED_SERVICE) &&
(Confirmed_Function[service_choice] != NULL)) (Confirmed_Function[service_choice] != NULL))
status = true; status = true;
return status; return status;
} }
bool apdu_service_supported(BACNET_SERVICES_SUPPORTED service_supported) bool apdu_service_supported(BACNET_SERVICES_SUPPORTED service_supported)
{ {
int i = 0; int i = 0;
bool status = false; bool status = false;
bool found = false; bool found = false;
if (service_supported < MAX_BACNET_SERVICES_SUPPORTED) if (service_supported < MAX_BACNET_SERVICES_SUPPORTED) {
{ /* is it a confirmed service? */
/* is it a confirmed service? */ for (i = 0; i < MAX_BACNET_CONFIRMED_SERVICE; i++) {
for (i = 0; i < MAX_BACNET_CONFIRMED_SERVICE; i++) if (confirmed_service_supported[i] == service_supported) {
{ if (apdu_confirmed_handler(i))
if (confirmed_service_supported[i] == service_supported) status = true;
{ found = true;
if (apdu_confirmed_handler(i)) break;
status = true; }
found = true; }
break;
} if (!found) {
} /* is it an unconfirmed service? */
for (i = 0; i < MAX_BACNET_UNCONFIRMED_SERVICE; i++) {
if (!found) if (unconfirmed_service_supported[i] == service_supported) {
{ if (apdu_unconfirmed_handler(i))
/* is it an unconfirmed service? */ status = true;
for (i = 0; i < MAX_BACNET_UNCONFIRMED_SERVICE; i++) break;
{ }
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 // Allow the APDU handler to automatically reject
static confirmed_function Unrecognized_Service_Handler; static confirmed_function Unrecognized_Service_Handler;
void apdu_set_unrecognized_service_handler_handler( void apdu_set_unrecognized_service_handler_handler(confirmed_function
confirmed_function pFunction) pFunction)
{ {
Unrecognized_Service_Handler = pFunction; Unrecognized_Service_Handler = pFunction;
} }
// Unconfirmed Function Handlers // Unconfirmed Function Handlers
// If they are not set, they are not handled // If they are not set, they are not handled
static unconfirmed_function static unconfirmed_function
Unconfirmed_Function[MAX_BACNET_UNCONFIRMED_SERVICE] = Unconfirmed_Function[MAX_BACNET_UNCONFIRMED_SERVICE] = {
{
NULL NULL
}; };
void apdu_set_unconfirmed_handler( void apdu_set_unconfirmed_handler(BACNET_UNCONFIRMED_SERVICE
BACNET_UNCONFIRMED_SERVICE service_choice, service_choice, unconfirmed_function pFunction)
unconfirmed_function pFunction)
{ {
if (service_choice < MAX_BACNET_UNCONFIRMED_SERVICE) if (service_choice < MAX_BACNET_UNCONFIRMED_SERVICE)
Unconfirmed_Function[service_choice] = pFunction; Unconfirmed_Function[service_choice] = pFunction;
} }
bool apdu_unconfirmed_handler( bool apdu_unconfirmed_handler(BACNET_UNCONFIRMED_SERVICE service_choice)
BACNET_UNCONFIRMED_SERVICE service_choice)
{ {
bool status = false; bool status = false;
if ((service_choice < MAX_BACNET_UNCONFIRMED_SERVICE) &&
(Unconfirmed_Function[service_choice] != NULL))
status = true;
return status; if ((service_choice < MAX_BACNET_UNCONFIRMED_SERVICE) &&
(Unconfirmed_Function[service_choice] != NULL))
status = true;
return status;
} }
// Confirmed ACK Function Handlers // Confirmed ACK Function Handlers
static void *Confirmed_ACK_Function[MAX_BACNET_CONFIRMED_SERVICE]; static void *Confirmed_ACK_Function[MAX_BACNET_CONFIRMED_SERVICE];
void apdu_set_confirmed_simple_ack_handler( void apdu_set_confirmed_simple_ack_handler(BACNET_CONFIRMED_SERVICE
BACNET_CONFIRMED_SERVICE service_choice, service_choice, confirmed_simple_ack_function pFunction)
confirmed_simple_ack_function pFunction)
{ {
switch (service_choice) switch (service_choice) {
{
case SERVICE_CONFIRMED_ACKNOWLEDGE_ALARM: case SERVICE_CONFIRMED_ACKNOWLEDGE_ALARM:
case SERVICE_CONFIRMED_COV_NOTIFICATION: case SERVICE_CONFIRMED_COV_NOTIFICATION:
case SERVICE_CONFIRMED_EVENT_NOTIFICATION: case SERVICE_CONFIRMED_EVENT_NOTIFICATION:
case SERVICE_CONFIRMED_SUBSCRIBE_COV: case SERVICE_CONFIRMED_SUBSCRIBE_COV:
case SERVICE_CONFIRMED_SUBSCRIBE_COV_PROPERTY: case SERVICE_CONFIRMED_SUBSCRIBE_COV_PROPERTY:
case SERVICE_CONFIRMED_LIFE_SAFETY_OPERATION: case SERVICE_CONFIRMED_LIFE_SAFETY_OPERATION:
// Object Access Services // Object Access Services
case SERVICE_CONFIRMED_ADD_LIST_ELEMENT: case SERVICE_CONFIRMED_ADD_LIST_ELEMENT:
case SERVICE_CONFIRMED_REMOVE_LIST_ELEMENT: case SERVICE_CONFIRMED_REMOVE_LIST_ELEMENT:
case SERVICE_CONFIRMED_DELETE_OBJECT: case SERVICE_CONFIRMED_DELETE_OBJECT:
case SERVICE_CONFIRMED_WRITE_PROPERTY: case SERVICE_CONFIRMED_WRITE_PROPERTY:
case SERVICE_CONFIRMED_WRITE_PROPERTY_MULTIPLE: case SERVICE_CONFIRMED_WRITE_PROPERTY_MULTIPLE:
// Remote Device Management Services // Remote Device Management Services
case SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL: case SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL:
case SERVICE_CONFIRMED_TEXT_MESSAGE: case SERVICE_CONFIRMED_TEXT_MESSAGE:
case SERVICE_CONFIRMED_REINITIALIZE_DEVICE: case SERVICE_CONFIRMED_REINITIALIZE_DEVICE:
// Virtual Terminal Services // Virtual Terminal Services
case SERVICE_CONFIRMED_VT_CLOSE: case SERVICE_CONFIRMED_VT_CLOSE:
// Security Services // Security Services
case SERVICE_CONFIRMED_REQUEST_KEY: case SERVICE_CONFIRMED_REQUEST_KEY:
Confirmed_ACK_Function[service_choice] = (void *)pFunction; Confirmed_ACK_Function[service_choice] = (void *) pFunction;
break; break;
default: default:
break; break;
} }
} }
void apdu_set_confirmed_ack_handler( void apdu_set_confirmed_ack_handler(BACNET_CONFIRMED_SERVICE
BACNET_CONFIRMED_SERVICE service_choice, service_choice, confirmed_ack_function pFunction)
confirmed_ack_function pFunction)
{ {
switch (service_choice) switch (service_choice) {
{
case SERVICE_CONFIRMED_GET_ALARM_SUMMARY: case SERVICE_CONFIRMED_GET_ALARM_SUMMARY:
case SERVICE_CONFIRMED_GET_ENROLLMENT_SUMMARY: case SERVICE_CONFIRMED_GET_ENROLLMENT_SUMMARY:
case SERVICE_CONFIRMED_GET_EVENT_INFORMATION: case SERVICE_CONFIRMED_GET_EVENT_INFORMATION:
// File Access Services // File Access Services
case SERVICE_CONFIRMED_ATOMIC_READ_FILE: case SERVICE_CONFIRMED_ATOMIC_READ_FILE:
case SERVICE_CONFIRMED_ATOMIC_WRITE_FILE: case SERVICE_CONFIRMED_ATOMIC_WRITE_FILE:
// Object Access Services // Object Access Services
case SERVICE_CONFIRMED_CREATE_OBJECT: case SERVICE_CONFIRMED_CREATE_OBJECT:
case SERVICE_CONFIRMED_READ_PROPERTY: case SERVICE_CONFIRMED_READ_PROPERTY:
case SERVICE_CONFIRMED_READ_PROPERTY_CONDITIONAL: case SERVICE_CONFIRMED_READ_PROPERTY_CONDITIONAL:
case SERVICE_CONFIRMED_READ_PROPERTY_MULTIPLE: case SERVICE_CONFIRMED_READ_PROPERTY_MULTIPLE:
case SERVICE_CONFIRMED_READ_RANGE: case SERVICE_CONFIRMED_READ_RANGE:
// Remote Device Management Services // Remote Device Management Services
case SERVICE_CONFIRMED_PRIVATE_TRANSFER: case SERVICE_CONFIRMED_PRIVATE_TRANSFER:
// Virtual Terminal Services // Virtual Terminal Services
case SERVICE_CONFIRMED_VT_OPEN: case SERVICE_CONFIRMED_VT_OPEN:
case SERVICE_CONFIRMED_VT_DATA: case SERVICE_CONFIRMED_VT_DATA:
// Security Services // Security Services
case SERVICE_CONFIRMED_AUTHENTICATE: case SERVICE_CONFIRMED_AUTHENTICATE:
Confirmed_ACK_Function[service_choice] = (void *)pFunction; Confirmed_ACK_Function[service_choice] = (void *) pFunction;
break; break;
default: default:
break; break;
} }
} }
static error_function static error_function Error_Function[MAX_BACNET_CONFIRMED_SERVICE];
Error_Function[MAX_BACNET_CONFIRMED_SERVICE];
void apdu_set_error_handler( void apdu_set_error_handler(BACNET_CONFIRMED_SERVICE service_choice,
BACNET_CONFIRMED_SERVICE service_choice, error_function pFunction)
error_function pFunction)
{ {
if (service_choice < MAX_BACNET_CONFIRMED_SERVICE) if (service_choice < MAX_BACNET_CONFIRMED_SERVICE)
Error_Function[service_choice] = pFunction; Error_Function[service_choice] = pFunction;
} }
static abort_function Abort_Function; static abort_function Abort_Function;
void apdu_set_abort_handler( void apdu_set_abort_handler(abort_function pFunction)
abort_function pFunction)
{ {
Abort_Function = pFunction; Abort_Function = pFunction;
} }
static reject_function Reject_Function; static reject_function Reject_Function;
void apdu_set_reject_handler( void apdu_set_reject_handler(reject_function pFunction)
reject_function pFunction)
{ {
Reject_Function = pFunction; Reject_Function = pFunction;
} }
uint16_t apdu_decode_confirmed_service_request( uint16_t apdu_decode_confirmed_service_request(uint8_t * apdu, // APDU data
uint8_t *apdu, // APDU data uint16_t apdu_len,
uint16_t apdu_len, BACNET_CONFIRMED_SERVICE_DATA * service_data,
BACNET_CONFIRMED_SERVICE_DATA *service_data, uint8_t * service_choice,
uint8_t *service_choice, uint8_t ** service_request, uint16_t * service_request_len)
uint8_t **service_request,
uint16_t *service_request_len)
{ {
uint16_t len = 0; // counts where we are in PDU uint16_t len = 0; // counts where we are in PDU
service_data->segmented_message = (apdu[0] & BIT3) ? true : false;
service_data->more_follows = (apdu[0] & BIT2) ? true : false;
service_data->segmented_response_accepted = (apdu[0] & BIT1) ? true : false;
service_data->max_segs = decode_max_segs(apdu[1]);
service_data->max_resp = decode_max_apdu(apdu[1]);
service_data->invoke_id = apdu[2];
len = 3;
if (service_data->segmented_message)
{
service_data->sequence_number = apdu[len++];
service_data->proposed_window_number = apdu[len++];
}
*service_choice = apdu[len++];
*service_request = &apdu[len];
*service_request_len = apdu_len - len;
return len; service_data->segmented_message = (apdu[0] & BIT3) ? true : false;
} service_data->more_follows = (apdu[0] & BIT2) ? true : false;
service_data->segmented_response_accepted =
void apdu_handler( (apdu[0] & BIT1) ? true : false;
BACNET_ADDRESS *src, // source address service_data->max_segs = decode_max_segs(apdu[1]);
bool data_expecting_reply, service_data->max_resp = decode_max_apdu(apdu[1]);
uint8_t *apdu, // APDU data service_data->invoke_id = apdu[2];
uint16_t apdu_len) len = 3;
{ if (service_data->segmented_message) {
BACNET_CONFIRMED_SERVICE_DATA service_data = {0}; service_data->sequence_number = apdu[len++];
BACNET_CONFIRMED_SERVICE_ACK_DATA service_ack_data = {0}; service_data->proposed_window_number = apdu[len++];
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_choice = apdu[len++];
return; *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
View File
@@ -41,28 +41,26 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
typedef struct _confirmed_service_data typedef struct _confirmed_service_data {
{ bool segmented_message;
bool segmented_message; bool more_follows;
bool more_follows; bool segmented_response_accepted;
bool segmented_response_accepted; int max_segs;
int max_segs; int max_resp;
int max_resp; uint8_t invoke_id;
uint8_t invoke_id; uint8_t sequence_number;
uint8_t sequence_number; uint8_t proposed_window_number;
uint8_t proposed_window_number; } BACNET_CONFIRMED_SERVICE_DATA;
} BACNET_CONFIRMED_SERVICE_DATA;
typedef struct _confirmed_service_ack_data typedef struct _confirmed_service_ack_data {
{ bool segmented_message;
bool segmented_message; bool more_follows;
bool more_follows; uint8_t invoke_id;
uint8_t invoke_id; uint8_t sequence_number;
uint8_t sequence_number; uint8_t proposed_window_number;
uint8_t proposed_window_number; } BACNET_CONFIRMED_SERVICE_ACK_DATA;
} BACNET_CONFIRMED_SERVICE_ACK_DATA;
// generic unconfirmed function handler // generic unconfirmed function handler
// Suitable to handle the following services: // Suitable to handle the following services:
@@ -70,10 +68,8 @@ typedef struct _confirmed_service_ack_data
// Unconfirmed_Event_Notification, Unconfirmed_Private_Transfer, // Unconfirmed_Event_Notification, Unconfirmed_Private_Transfer,
// Unconfirmed_Text_Message, Time_Synchronization, Who_Has, // Unconfirmed_Text_Message, Time_Synchronization, Who_Has,
// UTC_Time_Synchronization // UTC_Time_Synchronization
typedef void (*unconfirmed_function)( typedef void (*unconfirmed_function) (uint8_t * service_request,
uint8_t *service_request, uint16_t len, BACNET_ADDRESS * src);
uint16_t len,
BACNET_ADDRESS *src);
// generic confirmed function handler // generic confirmed function handler
// Suitable to handle the following services: // Suitable to handle the following services:
@@ -91,100 +87,79 @@ typedef void (*unconfirmed_function)(
// Confirmed_Text_Message, Reinitialize_Device, // Confirmed_Text_Message, Reinitialize_Device,
// VT_Open, VT_Close, VT_Data_Handler, // VT_Open, VT_Close, VT_Data_Handler,
// Authenticate, Request_Key // Authenticate, Request_Key
typedef void (*confirmed_function)( typedef void (*confirmed_function) (uint8_t * service_request,
uint8_t *service_request, uint16_t service_len,
uint16_t service_len, BACNET_ADDRESS * src,
BACNET_ADDRESS *src, BACNET_CONFIRMED_SERVICE_DATA * service_data);
BACNET_CONFIRMED_SERVICE_DATA *service_data);
// generic confirmed simple ack function handler // generic confirmed simple ack function handler
typedef void (*confirmed_simple_ack_function)( typedef void (*confirmed_simple_ack_function) (BACNET_ADDRESS * src,
BACNET_ADDRESS *src, uint8_t invoke_id);
uint8_t invoke_id);
// generic confirmed ack function handler // generic confirmed ack function handler
typedef void (*confirmed_ack_function)( typedef void (*confirmed_ack_function) (uint8_t * service_request,
uint8_t *service_request, uint16_t service_len,
uint16_t service_len, BACNET_ADDRESS * src,
BACNET_ADDRESS *src, BACNET_CONFIRMED_SERVICE_ACK_DATA * service_data);
BACNET_CONFIRMED_SERVICE_ACK_DATA *service_data);
// generic error reply function // generic error reply function
typedef void (*error_function)( typedef void (*error_function) (BACNET_ADDRESS * src,
BACNET_ADDRESS *src, uint8_t invoke_id,
uint8_t invoke_id, BACNET_ERROR_CLASS error_class, BACNET_ERROR_CODE error_code);
BACNET_ERROR_CLASS error_class,
BACNET_ERROR_CODE error_code);
// generic abort reply function // generic abort reply function
typedef void (*abort_function)( typedef void (*abort_function) (BACNET_ADDRESS * src,
BACNET_ADDRESS *src, uint8_t invoke_id, uint8_t abort_reason);
uint8_t invoke_id,
uint8_t abort_reason);
// generic reject reply function // generic reject reply function
typedef void (*reject_function)( typedef void (*reject_function) (BACNET_ADDRESS * src,
BACNET_ADDRESS *src, uint8_t invoke_id, uint8_t reject_reason);
uint8_t invoke_id,
uint8_t reject_reason);
void apdu_set_confirmed_ack_handler( void apdu_set_confirmed_ack_handler(BACNET_CONFIRMED_SERVICE
BACNET_CONFIRMED_SERVICE service_choice, service_choice, confirmed_ack_function pFunction);
confirmed_ack_function pFunction);
void apdu_set_confirmed_simple_ack_handler( void apdu_set_confirmed_simple_ack_handler(BACNET_CONFIRMED_SERVICE
BACNET_CONFIRMED_SERVICE service_choice, service_choice, confirmed_simple_ack_function pFunction);
confirmed_simple_ack_function pFunction);
// configure reject for confirmed services that are not supported // configure reject for confirmed services that are not supported
void apdu_set_unrecognized_service_handler_handler( void apdu_set_unrecognized_service_handler_handler(confirmed_function
confirmed_function pFunction); pFunction);
void apdu_set_confirmed_handler( void apdu_set_confirmed_handler(BACNET_CONFIRMED_SERVICE
BACNET_CONFIRMED_SERVICE service_choice, service_choice, confirmed_function pFunction);
confirmed_function pFunction);
/* returns true if the handler is set */ /* returns true if the handler is set */
bool apdu_confirmed_handler( bool apdu_confirmed_handler(BACNET_CONFIRMED_SERVICE service_choice);
BACNET_CONFIRMED_SERVICE service_choice);
void apdu_set_unconfirmed_handler( void apdu_set_unconfirmed_handler(BACNET_UNCONFIRMED_SERVICE
BACNET_UNCONFIRMED_SERVICE service_choice, service_choice, unconfirmed_function pFunction);
unconfirmed_function pFunction);
/* returns true if the handler is set */ /* returns true if the handler is set */
bool apdu_unconfirmed_handler( bool apdu_unconfirmed_handler(BACNET_UNCONFIRMED_SERVICE
BACNET_UNCONFIRMED_SERVICE service_choice); service_choice);
/* returns true if the service is supported by a handler */ /* 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( void apdu_set_error_handler(BACNET_CONFIRMED_SERVICE service_choice,
BACNET_CONFIRMED_SERVICE service_choice, error_function pFunction);
error_function pFunction);
void apdu_set_abort_handler( void apdu_set_abort_handler(abort_function pFunction);
abort_function pFunction);
void apdu_set_reject_handler( void apdu_set_reject_handler(reject_function pFunction);
reject_function pFunction);
uint16_t apdu_decode_confirmed_service_request( uint16_t apdu_decode_confirmed_service_request(uint8_t * apdu, // APDU data
uint8_t *apdu, // APDU data uint16_t apdu_len,
uint16_t apdu_len, BACNET_CONFIRMED_SERVICE_DATA * service_data,
BACNET_CONFIRMED_SERVICE_DATA *service_data, uint8_t * service_choice,
uint8_t *service_choice, uint8_t ** service_request, uint16_t * service_request_len);
uint8_t **service_request,
uint16_t *service_request_len);
void apdu_handler( void apdu_handler(BACNET_ADDRESS * src, // source address
BACNET_ADDRESS *src, // source address bool data_expecting_reply, uint8_t * apdu, // APDU data
bool data_expecting_reply, uint16_t pdu_len); // for confirmed messages
uint8_t *apdu, // APDU data
uint16_t pdu_len); // for confirmed messages
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+18 -23
View File
@@ -45,41 +45,36 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
bool arcnet_valid(void); bool arcnet_valid(void);
void arcnet_cleanup(void); void arcnet_cleanup(void);
bool arcnet_init(char *interface_name); bool arcnet_init(char *interface_name);
/* function to send a packet out the 802.2 socket */ /* function to send a packet out the 802.2 socket */
/* returns 0 on success, non-zero on failure */ /* returns 0 on success, non-zero on failure */
int arcnet_send( int arcnet_send(BACNET_ADDRESS * dest, // destination address
BACNET_ADDRESS *dest, // destination address BACNET_ADDRESS * src, // source address
BACNET_ADDRESS *src, // source address uint8_t * pdu, // any data to be sent - may be null
uint8_t *pdu, // any data to be sent - may be null unsigned pdu_len); // number of bytes of data
unsigned pdu_len); // number of bytes of data
/* function to send a packet out the 802.2 socket */ /* function to send a packet out the 802.2 socket */
/* returns zero on success, non-zero on failure */ /* returns zero on success, non-zero on failure */
int arcnet_send_pdu( int arcnet_send_pdu(BACNET_ADDRESS * dest, // destination address
BACNET_ADDRESS *dest, // destination address uint8_t * pdu, // any data to be sent - may be null
uint8_t *pdu, // any data to be sent - may be null unsigned pdu_len); // number of bytes of data
unsigned pdu_len); // number of bytes of data
// receives an framed packet // receives an framed packet
// returns the number of octets in the PDU, or zero on failure // returns the number of octets in the PDU, or zero on failure
uint16_t arcnet_receive( uint16_t arcnet_receive(BACNET_ADDRESS * src, // source address
BACNET_ADDRESS *src, // source address uint8_t * pdu, // PDU data
uint8_t *pdu, // PDU data uint16_t max_pdu, // amount of space available in the PDU
uint16_t max_pdu, // amount of space available in the PDU unsigned timeout); // milliseconds to wait for a packet
unsigned timeout); // milliseconds to wait for a packet
void arcnet_get_my_address(BACNET_ADDRESS *my_address); void arcnet_get_my_address(BACNET_ADDRESS * my_address);
void arcnet_get_broadcast_address( void arcnet_get_broadcast_address(BACNET_ADDRESS * dest); // destination address
BACNET_ADDRESS *dest); // destination address
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+341 -398
View File
@@ -41,324 +41,289 @@
// Atomic Read File // Atomic Read File
// encode service // encode service
int arf_encode_apdu( int arf_encode_apdu(uint8_t * apdu,
uint8_t *apdu, uint8_t invoke_id, BACNET_ATOMIC_READ_FILE_DATA * data)
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) if (apdu) {
{ apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST; apdu[1] =
apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted()); encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted());
apdu[2] = invoke_id; apdu[2] = invoke_id;
apdu[3] = SERVICE_CONFIRMED_ATOMIC_READ_FILE; // service choice apdu[3] = SERVICE_CONFIRMED_ATOMIC_READ_FILE; // service choice
apdu_len = 4; apdu_len = 4;
apdu_len += encode_tagged_object_id(&apdu[apdu_len], apdu_len += encode_tagged_object_id(&apdu[apdu_len],
data->object_type, data->object_instance); data->object_type, data->object_instance);
switch (data->access) switch (data->access) {
{ case FILE_STREAM_ACCESS:
case FILE_STREAM_ACCESS: apdu_len += encode_opening_tag(&apdu[apdu_len], 0);
apdu_len += encode_opening_tag(&apdu[apdu_len], 0); apdu_len += encode_tagged_signed(&apdu[apdu_len],
apdu_len += encode_tagged_signed(&apdu[apdu_len], data->type.stream.fileStartPosition);
data->type.stream.fileStartPosition); apdu_len += encode_tagged_unsigned(&apdu[apdu_len],
apdu_len += encode_tagged_unsigned(&apdu[apdu_len], data->type.stream.requestedOctetCount);
data->type.stream.requestedOctetCount); apdu_len += encode_closing_tag(&apdu[apdu_len], 0);
apdu_len += encode_closing_tag(&apdu[apdu_len], 0); break;
break; case FILE_RECORD_ACCESS:
case FILE_RECORD_ACCESS: apdu_len += encode_opening_tag(&apdu[apdu_len], 1);
apdu_len += encode_opening_tag(&apdu[apdu_len], 1); apdu_len += encode_tagged_signed(&apdu[apdu_len],
apdu_len += encode_tagged_signed(&apdu[apdu_len], data->type.record.fileStartRecord);
data->type.record.fileStartRecord); apdu_len += encode_tagged_unsigned(&apdu[apdu_len],
apdu_len += encode_tagged_unsigned(&apdu[apdu_len], data->type.record.RecordCount);
data->type.record.RecordCount); apdu_len += encode_closing_tag(&apdu[apdu_len], 1);
apdu_len += encode_closing_tag(&apdu[apdu_len], 1); break;
break; default:
default: break;
break; }
} }
}
return apdu_len;
return apdu_len;
} }
// decode the service request only // decode the service request only
int arf_decode_service_request( int arf_decode_service_request(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, BACNET_ATOMIC_READ_FILE_DATA * data)
unsigned apdu_len,
BACNET_ATOMIC_READ_FILE_DATA *data)
{ {
int len = 0; int len = 0;
int tag_len = 0; int tag_len = 0;
uint8_t tag_number = 0; uint8_t tag_number = 0;
uint32_t len_value_type = 0; uint32_t len_value_type = 0;
int type = 0; // for decoding int type = 0; // for decoding
// check for value pointers // check for value pointers
if (apdu_len && data) if (apdu_len && data) {
{ len =
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value_type); decode_tag_number_and_value(&apdu[0], &tag_number,
if (tag_number != BACNET_APPLICATION_TAG_OBJECT_ID) &len_value_type);
return -1; if (tag_number != BACNET_APPLICATION_TAG_OBJECT_ID)
len += decode_object_id(&apdu[len], &type, &data->object_instance); return -1;
data->object_type = type; len += decode_object_id(&apdu[len], &type, &data->object_instance);
if (decode_is_opening_tag_number(&apdu[len], 0)) data->object_type = type;
{ if (decode_is_opening_tag_number(&apdu[len], 0)) {
data->access = FILE_STREAM_ACCESS; data->access = FILE_STREAM_ACCESS;
// a tag number is not extended so only one octet // a tag number is not extended so only one octet
len++; len++;
// fileStartPosition // fileStartPosition
tag_len = decode_tag_number_and_value(&apdu[len], tag_len = decode_tag_number_and_value(&apdu[len],
&tag_number, &len_value_type); &tag_number, &len_value_type);
len += tag_len; len += tag_len;
if (tag_number != BACNET_APPLICATION_TAG_SIGNED_INT) if (tag_number != BACNET_APPLICATION_TAG_SIGNED_INT)
return -1; return -1;
len += decode_signed(&apdu[len], len += decode_signed(&apdu[len],
len_value_type, len_value_type, &data->type.stream.fileStartPosition);
&data->type.stream.fileStartPosition); // requestedOctetCount
// requestedOctetCount tag_len = decode_tag_number_and_value(&apdu[len],
tag_len = decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type);
&tag_number, &len_value_type); len += tag_len;
len += tag_len; if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT)
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT) return -1;
return -1; len += decode_unsigned(&apdu[len],
len += decode_unsigned(&apdu[len], len_value_type, &data->type.stream.requestedOctetCount);
len_value_type, if (!decode_is_closing_tag_number(&apdu[len], 0))
&data->type.stream.requestedOctetCount); return -1;
if (!decode_is_closing_tag_number(&apdu[len], 0)) // a tag number is not extended so only one octet
return -1; len++;
// a tag number is not extended so only one octet } else if (decode_is_opening_tag_number(&apdu[len], 1)) {
len++; 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( int arf_decode_apdu(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len,
unsigned apdu_len, uint8_t * invoke_id, BACNET_ATOMIC_READ_FILE_DATA * data)
uint8_t *invoke_id,
BACNET_ATOMIC_READ_FILE_DATA *data)
{ {
int len = 0; int len = 0;
unsigned offset = 0; unsigned offset = 0;
if (!apdu) if (!apdu)
return -1; return -1;
// optional checking - most likely was already done prior to this call // optional checking - most likely was already done prior to this call
if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST) if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
return -1; return -1;
// apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted()); // apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted());
*invoke_id = apdu[2]; /* invoke id - filled in by net layer */ *invoke_id = apdu[2]; /* invoke id - filled in by net layer */
if (apdu[3] != SERVICE_CONFIRMED_ATOMIC_READ_FILE) if (apdu[3] != SERVICE_CONFIRMED_ATOMIC_READ_FILE)
return -1; return -1;
offset = 4; offset = 4;
if (apdu_len > offset) if (apdu_len > offset) {
{ len = arf_decode_service_request(&apdu[offset],
len = arf_decode_service_request( apdu_len - offset, data);
&apdu[offset], }
apdu_len - offset,
data); return len;
}
return len;
} }
// encode service // encode service
int arf_ack_encode_apdu( int arf_ack_encode_apdu(uint8_t * apdu,
uint8_t *apdu, uint8_t invoke_id, BACNET_ATOMIC_READ_FILE_DATA * data)
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) if (apdu) {
{ apdu[0] = PDU_TYPE_COMPLEX_ACK;
apdu[0] = PDU_TYPE_COMPLEX_ACK; apdu[1] = invoke_id;
apdu[1] = invoke_id; apdu[2] = SERVICE_CONFIRMED_ATOMIC_READ_FILE; // service choice
apdu[2] = SERVICE_CONFIRMED_ATOMIC_READ_FILE; // service choice apdu_len = 3;
apdu_len = 3; // endOfFile
// endOfFile apdu_len +=
apdu_len += encode_tagged_boolean(&apdu[apdu_len], data->endOfFile); encode_tagged_boolean(&apdu[apdu_len], data->endOfFile);
switch (data->access) switch (data->access) {
{ case FILE_STREAM_ACCESS:
case FILE_STREAM_ACCESS: apdu_len += encode_opening_tag(&apdu[apdu_len], 0);
apdu_len += encode_opening_tag(&apdu[apdu_len], 0); apdu_len += encode_tagged_signed(&apdu[apdu_len],
apdu_len += encode_tagged_signed(&apdu[apdu_len], data->type.stream.fileStartPosition);
data->type.stream.fileStartPosition); apdu_len += encode_tagged_octet_string(&apdu[apdu_len],
apdu_len += encode_tagged_octet_string(&apdu[apdu_len], &data->fileData);
&data->fileData); apdu_len += encode_closing_tag(&apdu[apdu_len], 0);
apdu_len += encode_closing_tag(&apdu[apdu_len], 0); break;
break; case FILE_RECORD_ACCESS:
case FILE_RECORD_ACCESS: apdu_len += encode_opening_tag(&apdu[apdu_len], 1);
apdu_len += encode_opening_tag(&apdu[apdu_len], 1); apdu_len += encode_tagged_signed(&apdu[apdu_len],
apdu_len += encode_tagged_signed(&apdu[apdu_len], data->type.record.fileStartRecord);
data->type.record.fileStartRecord); apdu_len += encode_tagged_unsigned(&apdu[apdu_len],
apdu_len += encode_tagged_unsigned(&apdu[apdu_len], data->type.record.RecordCount);
data->type.record.RecordCount); apdu_len += encode_tagged_octet_string(&apdu[apdu_len],
apdu_len += encode_tagged_octet_string(&apdu[apdu_len], &data->fileData);
&data->fileData); apdu_len += encode_closing_tag(&apdu[apdu_len], 1);
apdu_len += encode_closing_tag(&apdu[apdu_len], 1); break;
break; default:
default: break;
break; }
} }
}
return apdu_len;
return apdu_len;
} }
// decode the service request only // decode the service request only
int arf_ack_decode_service_request( int arf_ack_decode_service_request(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, BACNET_ATOMIC_READ_FILE_DATA * data)
unsigned apdu_len,
BACNET_ATOMIC_READ_FILE_DATA *data)
{ {
int len = 0; int len = 0;
int tag_len = 0; int tag_len = 0;
uint8_t tag_number = 0; uint8_t tag_number = 0;
uint32_t len_value_type = 0; uint32_t len_value_type = 0;
// check for value pointers // check for value pointers
if (apdu_len && data) if (apdu_len && data) {
{ len =
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value_type); decode_tag_number_and_value(&apdu[0], &tag_number,
if (tag_number != BACNET_APPLICATION_TAG_BOOLEAN) &len_value_type);
return -1; if (tag_number != BACNET_APPLICATION_TAG_BOOLEAN)
data->endOfFile = decode_boolean(len_value_type); return -1;
if (decode_is_opening_tag_number(&apdu[len], 0)) data->endOfFile = decode_boolean(len_value_type);
{ if (decode_is_opening_tag_number(&apdu[len], 0)) {
data->access = FILE_STREAM_ACCESS; data->access = FILE_STREAM_ACCESS;
// a tag number is not extended so only one octet // a tag number is not extended so only one octet
len++; len++;
// fileStartPosition // fileStartPosition
tag_len = decode_tag_number_and_value(&apdu[len], tag_len = decode_tag_number_and_value(&apdu[len],
&tag_number, &len_value_type); &tag_number, &len_value_type);
len += tag_len; len += tag_len;
if (tag_number != BACNET_APPLICATION_TAG_SIGNED_INT) if (tag_number != BACNET_APPLICATION_TAG_SIGNED_INT)
return -1; return -1;
len += decode_signed(&apdu[len], len += decode_signed(&apdu[len],
len_value_type, len_value_type, &data->type.stream.fileStartPosition);
&data->type.stream.fileStartPosition); // fileData
// fileData tag_len = decode_tag_number_and_value(&apdu[len],
tag_len = decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type);
&tag_number, &len_value_type); len += tag_len;
len += tag_len; if (tag_number != BACNET_APPLICATION_TAG_OCTET_STRING)
if (tag_number != BACNET_APPLICATION_TAG_OCTET_STRING) return -1;
return -1; len += decode_octet_string(&apdu[len],
len += decode_octet_string(&apdu[len], len_value_type, &data->fileData);
len_value_type, if (!decode_is_closing_tag_number(&apdu[len], 0))
&data->fileData); return -1;
if (!decode_is_closing_tag_number(&apdu[len], 0)) // a tag number is not extended so only one octet
return -1; len++;
// a tag number is not extended so only one octet } else if (decode_is_opening_tag_number(&apdu[len], 1)) {
len++; 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( int arf_ack_decode_apdu(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len,
unsigned apdu_len, uint8_t * invoke_id, BACNET_ATOMIC_READ_FILE_DATA * data)
uint8_t *invoke_id,
BACNET_ATOMIC_READ_FILE_DATA *data)
{ {
int len = 0; int len = 0;
unsigned offset = 0; unsigned offset = 0;
if (!apdu) if (!apdu)
return -1; return -1;
// optional checking - most likely was already done prior to this call // optional checking - most likely was already done prior to this call
if (apdu[0] != PDU_TYPE_COMPLEX_ACK) if (apdu[0] != PDU_TYPE_COMPLEX_ACK)
return -1; return -1;
*invoke_id = apdu[1]; /* invoke id - filled in by net layer */ *invoke_id = apdu[1]; /* invoke id - filled in by net layer */
if (apdu[2] != SERVICE_CONFIRMED_ATOMIC_READ_FILE) if (apdu[2] != SERVICE_CONFIRMED_ATOMIC_READ_FILE)
return -1; return -1;
offset = 3; offset = 3;
if (apdu_len > offset) if (apdu_len > offset) {
{ len = arf_ack_decode_service_request(&apdu[offset],
len = arf_ack_decode_service_request( apdu_len - offset, data);
&apdu[offset], }
apdu_len - offset,
data); return len;
}
return len;
} }
@@ -368,143 +333,121 @@ int arf_ack_decode_apdu(
#include "ctest.h" #include "ctest.h"
void testAtomicReadFileAckAccess(Test * pTest, void testAtomicReadFileAckAccess(Test * pTest,
BACNET_ATOMIC_READ_FILE_DATA *data) BACNET_ATOMIC_READ_FILE_DATA * data)
{ {
BACNET_ATOMIC_READ_FILE_DATA test_data = {0}; BACNET_ATOMIC_READ_FILE_DATA test_data = { 0 };
uint8_t apdu[480] = {0}; uint8_t apdu[480] = { 0 };
int len = 0; int len = 0;
int apdu_len = 0; int apdu_len = 0;
uint8_t invoke_id = 128; uint8_t invoke_id = 128;
uint8_t test_invoke_id = 0; uint8_t test_invoke_id = 0;
len = arf_ack_encode_apdu( len = arf_ack_encode_apdu(&apdu[0], invoke_id, data);
&apdu[0], ct_test(pTest, len != 0);
invoke_id, apdu_len = len;
data);
ct_test(pTest, len != 0);
apdu_len = len;
len = arf_ack_decode_apdu( len = arf_ack_decode_apdu(&apdu[0],
&apdu[0], apdu_len, &test_invoke_id, &test_data);
apdu_len, ct_test(pTest, len != -1);
&test_invoke_id, ct_test(pTest, test_data.endOfFile == data->endOfFile);
&test_data); ct_test(pTest, test_data.access == data->access);
ct_test(pTest, len != -1); if (test_data.access == FILE_STREAM_ACCESS) {
ct_test(pTest, test_data.endOfFile == data->endOfFile); ct_test(pTest, test_data.type.stream.fileStartPosition ==
ct_test(pTest, test_data.access == data->access); data->type.stream.fileStartPosition);
if (test_data.access == FILE_STREAM_ACCESS) } else if (test_data.access == FILE_RECORD_ACCESS) {
{ ct_test(pTest, test_data.type.record.fileStartRecord ==
ct_test(pTest, test_data.type.stream.fileStartPosition == data->type.record.fileStartRecord);
data->type.stream.fileStartPosition); ct_test(pTest, test_data.type.record.RecordCount ==
} data->type.record.RecordCount);
else if (test_data.access == FILE_RECORD_ACCESS) }
{ ct_test(pTest, octetstring_length(&test_data.fileData) ==
ct_test(pTest, test_data.type.record.fileStartRecord == octetstring_length(&data->fileData));
data->type.record.fileStartRecord); ct_test(pTest, memcmp(octetstring_value(&test_data.fileData),
ct_test(pTest, test_data.type.record.RecordCount == octetstring_value(&data->fileData),
data->type.record.RecordCount); octetstring_length(&test_data.fileData)) == 0);
}
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) void testAtomicReadFileAck(Test * pTest)
{ {
BACNET_ATOMIC_READ_FILE_DATA data = {0}; BACNET_ATOMIC_READ_FILE_DATA data = { 0 };
uint8_t test_octet_string[32] = "Joshua-Mary-Anna-Christopher"; 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);
data.endOfFile = false;
data.access = FILE_RECORD_ACCESS; data.endOfFile = true;
data.type.record.fileStartRecord = 1; data.access = FILE_STREAM_ACCESS;
data.type.record.RecordCount = 2; data.type.stream.fileStartPosition = 0;
octetstring_init(&data.fileData, octetstring_init(&data.fileData,
test_octet_string, test_octet_string, sizeof(test_octet_string));
sizeof(test_octet_string)); testAtomicReadFileAckAccess(pTest, &data);
testAtomicReadFileAckAccess(pTest, &data);
data.endOfFile = false;
return; 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, void testAtomicReadFileAccess(Test * pTest,
BACNET_ATOMIC_READ_FILE_DATA *data) BACNET_ATOMIC_READ_FILE_DATA * data)
{ {
BACNET_ATOMIC_READ_FILE_DATA test_data = {0}; BACNET_ATOMIC_READ_FILE_DATA test_data = { 0 };
uint8_t apdu[480] = {0}; uint8_t apdu[480] = { 0 };
int len = 0; int len = 0;
int apdu_len = 0; int apdu_len = 0;
uint8_t invoke_id = 128; uint8_t invoke_id = 128;
uint8_t test_invoke_id = 0; uint8_t test_invoke_id = 0;
len = arf_encode_apdu( len = arf_encode_apdu(&apdu[0], invoke_id, data);
&apdu[0], ct_test(pTest, len != 0);
invoke_id, apdu_len = len;
data);
ct_test(pTest, len != 0);
apdu_len = len;
len = arf_decode_apdu( len = arf_decode_apdu(&apdu[0], apdu_len, &test_invoke_id, &test_data);
&apdu[0], ct_test(pTest, len != -1);
apdu_len, ct_test(pTest, test_data.object_type == data->object_type);
&test_invoke_id, ct_test(pTest, test_data.object_instance == data->object_instance);
&test_data); ct_test(pTest, test_data.access == data->access);
ct_test(pTest, len != -1); if (test_data.access == FILE_STREAM_ACCESS) {
ct_test(pTest, test_data.object_type == data->object_type); ct_test(pTest, test_data.type.stream.fileStartPosition ==
ct_test(pTest, test_data.object_instance == data->object_instance); data->type.stream.fileStartPosition);
ct_test(pTest, test_data.access == data->access); ct_test(pTest, test_data.type.stream.requestedOctetCount ==
if (test_data.access == FILE_STREAM_ACCESS) data->type.stream.requestedOctetCount);
{ } else if (test_data.access == FILE_RECORD_ACCESS) {
ct_test(pTest, test_data.type.stream.fileStartPosition == ct_test(pTest, test_data.type.record.fileStartRecord ==
data->type.stream.fileStartPosition); data->type.record.fileStartRecord);
ct_test(pTest, test_data.type.stream.requestedOctetCount == ct_test(pTest, test_data.type.record.RecordCount ==
data->type.stream.requestedOctetCount); data->type.record.RecordCount);
} }
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) void testAtomicReadFile(Test * pTest)
{ {
BACNET_ATOMIC_READ_FILE_DATA data = {0}; 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);
data.object_type = OBJECT_FILE; data.object_type = OBJECT_FILE;
data.object_instance = 2; data.object_instance = 1;
data.access = FILE_RECORD_ACCESS; data.access = FILE_STREAM_ACCESS;
data.type.record.fileStartRecord = 1; data.type.stream.fileStartPosition = 0;
data.type.record.RecordCount = 2; data.type.stream.requestedOctetCount = 128;
testAtomicReadFileAccess(pTest, &data); testAtomicReadFileAccess(pTest, &data);
return; 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 #ifdef TEST_ATOMIC_READ_FILE
uint16_t Device_Max_APDU_Length_Accepted(void) uint16_t Device_Max_APDU_Length_Accepted(void)
{ {
return MAX_APDU; return MAX_APDU;
} }
int main(void) int main(void)
+36 -54
View File
@@ -39,82 +39,64 @@
#include "bacdcode.h" #include "bacdcode.h"
#include "bacstr.h" #include "bacstr.h"
typedef struct BACnet_Atomic_Read_File_Data typedef struct BACnet_Atomic_Read_File_Data {
{ BACNET_OBJECT_TYPE object_type;
BACNET_OBJECT_TYPE object_type; uint32_t object_instance;
uint32_t object_instance; BACNET_FILE_ACCESS_METHOD access;
BACNET_FILE_ACCESS_METHOD access; union {
union struct {
{ int32_t fileStartPosition;
struct uint32_t requestedOctetCount;
{ } stream;
int32_t fileStartPosition; struct {
uint32_t requestedOctetCount; int32_t fileStartRecord;
} stream; // requested or returned record count
struct uint32_t RecordCount;
{ } record;
int32_t fileStartRecord; } type;
// requested or returned record count BACNET_OCTET_STRING fileData;
uint32_t RecordCount; bool endOfFile;
} record;
} type;
BACNET_OCTET_STRING fileData;
bool endOfFile;
} BACNET_ATOMIC_READ_FILE_DATA; } BACNET_ATOMIC_READ_FILE_DATA;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
// Atomic Read File // Atomic Read File
// encode service // encode service
int arf_encode_apdu( int arf_encode_apdu(uint8_t * apdu,
uint8_t *apdu, uint8_t invoke_id, BACNET_ATOMIC_READ_FILE_DATA * data);
uint8_t invoke_id,
BACNET_ATOMIC_READ_FILE_DATA *data);
// decode the service request only // decode the service request only
int arf_decode_service_request( int arf_decode_service_request(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, BACNET_ATOMIC_READ_FILE_DATA * data);
unsigned apdu_len,
BACNET_ATOMIC_READ_FILE_DATA *data); int arf_decode_apdu(uint8_t * apdu,
unsigned apdu_len,
int arf_decode_apdu( uint8_t * invoke_id, BACNET_ATOMIC_READ_FILE_DATA * data);
uint8_t *apdu,
unsigned apdu_len,
uint8_t *invoke_id,
BACNET_ATOMIC_READ_FILE_DATA *data);
// Atomic Read File Ack // Atomic Read File Ack
// encode service // encode service
int arf_ack_encode_apdu( int arf_ack_encode_apdu(uint8_t * apdu,
uint8_t *apdu, uint8_t invoke_id, BACNET_ATOMIC_READ_FILE_DATA * data);
uint8_t invoke_id,
BACNET_ATOMIC_READ_FILE_DATA *data);
// decode the service request only // decode the service request only
int arf_ack_decode_service_request( int arf_ack_decode_service_request(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, BACNET_ATOMIC_READ_FILE_DATA * data);
unsigned apdu_len,
BACNET_ATOMIC_READ_FILE_DATA *data);
int arf_ack_decode_apdu( int arf_ack_decode_apdu(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len,
unsigned apdu_len, uint8_t * invoke_id, BACNET_ATOMIC_READ_FILE_DATA * data);
uint8_t *invoke_id,
BACNET_ATOMIC_READ_FILE_DATA *data);
#ifdef TEST #ifdef TEST
#include "ctest.h" #include "ctest.h"
void test_AtomicReadFile(Test * pTest); void test_AtomicReadFile(Test * pTest);
void test_AtomicReadFileAck(Test * pTest); void test_AtomicReadFileAck(Test * pTest);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+274 -331
View File
@@ -41,267 +41,233 @@
// Atomic Write File // Atomic Write File
// encode service // encode service
int awf_encode_apdu( int awf_encode_apdu(uint8_t * apdu,
uint8_t *apdu, uint8_t invoke_id, BACNET_ATOMIC_WRITE_FILE_DATA * data)
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) if (apdu) {
{ apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST; apdu[1] =
apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted()); encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted());
apdu[2] = invoke_id; apdu[2] = invoke_id;
apdu[3] = SERVICE_CONFIRMED_ATOMIC_WRITE_FILE; // service choice apdu[3] = SERVICE_CONFIRMED_ATOMIC_WRITE_FILE; // service choice
apdu_len = 4; apdu_len = 4;
apdu_len += encode_tagged_object_id(&apdu[apdu_len], apdu_len += encode_tagged_object_id(&apdu[apdu_len],
data->object_type, data->object_instance); data->object_type, data->object_instance);
switch (data->access) switch (data->access) {
{ case FILE_STREAM_ACCESS:
case FILE_STREAM_ACCESS: apdu_len += encode_opening_tag(&apdu[apdu_len], 0);
apdu_len += encode_opening_tag(&apdu[apdu_len], 0); apdu_len += encode_tagged_signed(&apdu[apdu_len],
apdu_len += encode_tagged_signed(&apdu[apdu_len], data->type.stream.fileStartPosition);
data->type.stream.fileStartPosition); apdu_len += encode_tagged_octet_string(&apdu[apdu_len],
apdu_len += encode_tagged_octet_string(&apdu[apdu_len], &data->fileData);
&data->fileData); apdu_len += encode_closing_tag(&apdu[apdu_len], 0);
apdu_len += encode_closing_tag(&apdu[apdu_len], 0); break;
break; case FILE_RECORD_ACCESS:
case FILE_RECORD_ACCESS: apdu_len += encode_opening_tag(&apdu[apdu_len], 1);
apdu_len += encode_opening_tag(&apdu[apdu_len], 1); apdu_len += encode_tagged_signed(&apdu[apdu_len],
apdu_len += encode_tagged_signed(&apdu[apdu_len], data->type.record.fileStartRecord);
data->type.record.fileStartRecord); apdu_len += encode_tagged_unsigned(&apdu[apdu_len],
apdu_len += encode_tagged_unsigned(&apdu[apdu_len], data->type.record.returnedRecordCount);
data->type.record.returnedRecordCount); apdu_len += encode_tagged_octet_string(&apdu[apdu_len],
apdu_len += encode_tagged_octet_string(&apdu[apdu_len], &data->fileData);
&data->fileData); apdu_len += encode_closing_tag(&apdu[apdu_len], 1);
apdu_len += encode_closing_tag(&apdu[apdu_len], 1); break;
break; default:
default: break;
break; }
} }
}
return apdu_len;
return apdu_len;
} }
// decode the service request only // decode the service request only
int awf_decode_service_request( int awf_decode_service_request(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, BACNET_ATOMIC_WRITE_FILE_DATA * data)
unsigned apdu_len,
BACNET_ATOMIC_WRITE_FILE_DATA *data)
{ {
int len = 0; int len = 0;
int tag_len = 0; int tag_len = 0;
uint8_t tag_number = 0; uint8_t tag_number = 0;
uint32_t len_value_type = 0; uint32_t len_value_type = 0;
int type = 0; // for decoding int type = 0; // for decoding
// check for value pointers // check for value pointers
if (apdu_len && data) if (apdu_len && data) {
{ len =
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value_type); decode_tag_number_and_value(&apdu[0], &tag_number,
if (tag_number != BACNET_APPLICATION_TAG_OBJECT_ID) &len_value_type);
return -1; if (tag_number != BACNET_APPLICATION_TAG_OBJECT_ID)
len += decode_object_id(&apdu[len], &type, &data->object_instance); return -1;
data->object_type = type; len += decode_object_id(&apdu[len], &type, &data->object_instance);
if (decode_is_opening_tag_number(&apdu[len], 0)) data->object_type = type;
{ if (decode_is_opening_tag_number(&apdu[len], 0)) {
data->access = FILE_STREAM_ACCESS; data->access = FILE_STREAM_ACCESS;
// a tag number of 2 is not extended so only one octet // a tag number of 2 is not extended so only one octet
len++; len++;
// fileStartPosition // fileStartPosition
tag_len = decode_tag_number_and_value(&apdu[len], tag_len = decode_tag_number_and_value(&apdu[len],
&tag_number, &len_value_type); &tag_number, &len_value_type);
len += tag_len; len += tag_len;
if (tag_number != BACNET_APPLICATION_TAG_SIGNED_INT) if (tag_number != BACNET_APPLICATION_TAG_SIGNED_INT)
return -1; return -1;
len += decode_signed(&apdu[len], len += decode_signed(&apdu[len],
len_value_type, len_value_type, &data->type.stream.fileStartPosition);
&data->type.stream.fileStartPosition); // fileData
// fileData tag_len = decode_tag_number_and_value(&apdu[len],
tag_len = decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type);
&tag_number, &len_value_type); len += tag_len;
len += tag_len; if (tag_number != BACNET_APPLICATION_TAG_OCTET_STRING)
if (tag_number != BACNET_APPLICATION_TAG_OCTET_STRING) return -1;
return -1; len += decode_octet_string(&apdu[len],
len += decode_octet_string(&apdu[len], len_value_type, &data->fileData);
len_value_type, if (!decode_is_closing_tag_number(&apdu[len], 0))
&data->fileData); return -1;
if (!decode_is_closing_tag_number(&apdu[len], 0)) // a tag number is not extended so only one octet
return -1; len++;
// a tag number is not extended so only one octet } else if (decode_is_opening_tag_number(&apdu[len], 1)) {
len++; 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( int awf_decode_apdu(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len,
unsigned apdu_len, uint8_t * invoke_id, BACNET_ATOMIC_WRITE_FILE_DATA * data)
uint8_t *invoke_id,
BACNET_ATOMIC_WRITE_FILE_DATA *data)
{ {
int len = 0; int len = 0;
unsigned offset = 0; unsigned offset = 0;
if (!apdu) if (!apdu)
return -1; return -1;
// optional checking - most likely was already done prior to this call // optional checking - most likely was already done prior to this call
if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST) if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
return -1; return -1;
// apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted()); // apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted());
*invoke_id = apdu[2]; /* invoke id - filled in by net layer */ *invoke_id = apdu[2]; /* invoke id - filled in by net layer */
if (apdu[3] != SERVICE_CONFIRMED_ATOMIC_WRITE_FILE) if (apdu[3] != SERVICE_CONFIRMED_ATOMIC_WRITE_FILE)
return -1; return -1;
offset = 4; offset = 4;
if (apdu_len > offset) if (apdu_len > offset) {
{ len = awf_decode_service_request(&apdu[offset],
len = awf_decode_service_request( apdu_len - offset, data);
&apdu[offset], }
apdu_len - offset,
data); return len;
}
return len;
} }
int awf_ack_encode_apdu( int awf_ack_encode_apdu(uint8_t * apdu,
uint8_t *apdu, uint8_t invoke_id, BACNET_ATOMIC_WRITE_FILE_DATA * data)
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) if (apdu) {
{ apdu[0] = PDU_TYPE_COMPLEX_ACK;
apdu[0] = PDU_TYPE_COMPLEX_ACK; apdu[1] = invoke_id;
apdu[1] = invoke_id; apdu[2] = SERVICE_CONFIRMED_ATOMIC_WRITE_FILE; // service choice
apdu[2] = SERVICE_CONFIRMED_ATOMIC_WRITE_FILE; // service choice apdu_len = 3;
apdu_len = 3; switch (data->access) {
switch (data->access) case FILE_STREAM_ACCESS:
{ apdu_len += encode_context_signed(&apdu[apdu_len], 0,
case FILE_STREAM_ACCESS: data->type.stream.fileStartPosition);
apdu_len += encode_context_signed(&apdu[apdu_len], 0, break;
data->type.stream.fileStartPosition); case FILE_RECORD_ACCESS:
break; apdu_len += encode_context_signed(&apdu[apdu_len], 1,
case FILE_RECORD_ACCESS: data->type.record.fileStartRecord);
apdu_len += encode_context_signed(&apdu[apdu_len], 1, break;
data->type.record.fileStartRecord); default:
break; break;
default: }
break;
} }
}
return apdu_len;
return apdu_len;
} }
// decode the service request only // decode the service request only
int awf_ack_decode_service_request( int awf_ack_decode_service_request(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, BACNET_ATOMIC_WRITE_FILE_DATA * data)
unsigned apdu_len,
BACNET_ATOMIC_WRITE_FILE_DATA *data)
{ {
int len = 0; int len = 0;
uint8_t tag_number = 0; uint8_t tag_number = 0;
uint32_t len_value_type = 0; uint32_t len_value_type = 0;
// check for value pointers // check for value pointers
if (apdu_len && data) if (apdu_len && data) {
{ len =
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value_type); decode_tag_number_and_value(&apdu[0], &tag_number,
if (tag_number == 0) &len_value_type);
{ if (tag_number == 0) {
data->access = FILE_STREAM_ACCESS; data->access = FILE_STREAM_ACCESS;
len += decode_signed(&apdu[len], len += decode_signed(&apdu[len],
len_value_type, len_value_type, &data->type.stream.fileStartPosition);
&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( int awf_ack_decode_apdu(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len,
unsigned apdu_len, uint8_t * invoke_id, BACNET_ATOMIC_WRITE_FILE_DATA * data)
uint8_t *invoke_id,
BACNET_ATOMIC_WRITE_FILE_DATA *data)
{ {
int len = 0; int len = 0;
unsigned offset = 0; unsigned offset = 0;
if (!apdu) if (!apdu)
return -1; return -1;
// optional checking - most likely was already done prior to this call // optional checking - most likely was already done prior to this call
if (apdu[0] != PDU_TYPE_COMPLEX_ACK) if (apdu[0] != PDU_TYPE_COMPLEX_ACK)
return -1; return -1;
*invoke_id = apdu[1]; /* invoke id - filled in by net layer */ *invoke_id = apdu[1]; /* invoke id - filled in by net layer */
if (apdu[2] != SERVICE_CONFIRMED_ATOMIC_WRITE_FILE) if (apdu[2] != SERVICE_CONFIRMED_ATOMIC_WRITE_FILE)
return -1; return -1;
offset = 3; offset = 3;
if (apdu_len > offset) if (apdu_len > offset) {
{ len = awf_decode_service_request(&apdu[offset],
len = awf_decode_service_request( apdu_len - offset, data);
&apdu[offset], }
apdu_len - offset,
data); return len;
}
return len;
} }
#ifdef TEST #ifdef TEST
@@ -310,133 +276,110 @@ int awf_ack_decode_apdu(
#include "ctest.h" #include "ctest.h"
void testAtomicWriteFileAccess(Test * pTest, void testAtomicWriteFileAccess(Test * pTest,
BACNET_ATOMIC_WRITE_FILE_DATA *data) BACNET_ATOMIC_WRITE_FILE_DATA * data)
{ {
BACNET_ATOMIC_WRITE_FILE_DATA test_data = {0}; BACNET_ATOMIC_WRITE_FILE_DATA test_data = { 0 };
uint8_t apdu[480] = {0}; uint8_t apdu[480] = { 0 };
int len = 0; int len = 0;
int apdu_len = 0; int apdu_len = 0;
uint8_t invoke_id = 128; uint8_t invoke_id = 128;
uint8_t test_invoke_id = 0; uint8_t test_invoke_id = 0;
len = awf_encode_apdu( len = awf_encode_apdu(&apdu[0], invoke_id, data);
&apdu[0], ct_test(pTest, len != 0);
invoke_id, apdu_len = len;
data);
ct_test(pTest, len != 0);
apdu_len = len;
len = awf_decode_apdu( len = awf_decode_apdu(&apdu[0], apdu_len, &test_invoke_id, &test_data);
&apdu[0], ct_test(pTest, len != -1);
apdu_len, ct_test(pTest, test_data.object_type == data->object_type);
&test_invoke_id, ct_test(pTest, test_data.object_instance == data->object_instance);
&test_data); ct_test(pTest, test_data.access == data->access);
ct_test(pTest, len != -1); if (test_data.access == FILE_STREAM_ACCESS) {
ct_test(pTest, test_data.object_type == data->object_type); ct_test(pTest, test_data.type.stream.fileStartPosition ==
ct_test(pTest, test_data.object_instance == data->object_instance); data->type.stream.fileStartPosition);
ct_test(pTest, test_data.access == data->access); } else if (test_data.access == FILE_RECORD_ACCESS) {
if (test_data.access == FILE_STREAM_ACCESS) ct_test(pTest, test_data.type.record.fileStartRecord ==
{ data->type.record.fileStartRecord);
ct_test(pTest, test_data.type.stream.fileStartPosition == ct_test(pTest, test_data.type.record.returnedRecordCount ==
data->type.stream.fileStartPosition); data->type.record.returnedRecordCount);
} }
else if (test_data.access == FILE_RECORD_ACCESS) ct_test(pTest, octetstring_length(&test_data.fileData) ==
{ octetstring_length(&data->fileData));
ct_test(pTest, test_data.type.record.fileStartRecord == ct_test(pTest, memcmp(octetstring_value(&test_data.fileData),
data->type.record.fileStartRecord); octetstring_value(&data->fileData),
ct_test(pTest, test_data.type.record.returnedRecordCount == octetstring_length(&test_data.fileData)) == 0);
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) void testAtomicWriteFile(Test * pTest)
{ {
BACNET_ATOMIC_WRITE_FILE_DATA data = {0}; BACNET_ATOMIC_WRITE_FILE_DATA data = { 0 };
uint8_t test_octet_string[32] = "Joshua-Mary-Anna-Christopher"; uint8_t test_octet_string[32] = "Joshua-Mary-Anna-Christopher";
data.object_type = OBJECT_FILE; data.object_type = OBJECT_FILE;
data.object_instance = 1; data.object_instance = 1;
data.access = FILE_STREAM_ACCESS; data.access = FILE_STREAM_ACCESS;
data.type.stream.fileStartPosition = 0; data.type.stream.fileStartPosition = 0;
octetstring_init(&data.fileData, octetstring_init(&data.fileData,
test_octet_string, test_octet_string, sizeof(test_octet_string));
sizeof(test_octet_string)); testAtomicWriteFileAccess(pTest, &data);
testAtomicWriteFileAccess(pTest, &data);
data.object_type = OBJECT_FILE; data.object_type = OBJECT_FILE;
data.object_instance = 1; data.object_instance = 1;
data.access = FILE_RECORD_ACCESS; data.access = FILE_RECORD_ACCESS;
data.type.record.fileStartRecord = 1; data.type.record.fileStartRecord = 1;
data.type.record.returnedRecordCount = 2; data.type.record.returnedRecordCount = 2;
octetstring_init(&data.fileData, octetstring_init(&data.fileData,
test_octet_string, test_octet_string, sizeof(test_octet_string));
sizeof(test_octet_string)); testAtomicWriteFileAccess(pTest, &data);
testAtomicWriteFileAccess(pTest, &data);
return;
return;
} }
void testAtomicWriteFileAckAccess(Test * pTest, void testAtomicWriteFileAckAccess(Test * pTest,
BACNET_ATOMIC_WRITE_FILE_DATA *data) BACNET_ATOMIC_WRITE_FILE_DATA * data)
{ {
BACNET_ATOMIC_WRITE_FILE_DATA test_data = {0}; BACNET_ATOMIC_WRITE_FILE_DATA test_data = { 0 };
uint8_t apdu[480] = {0}; uint8_t apdu[480] = { 0 };
int len = 0; int len = 0;
int apdu_len = 0; int apdu_len = 0;
uint8_t invoke_id = 128; uint8_t invoke_id = 128;
uint8_t test_invoke_id = 0; uint8_t test_invoke_id = 0;
len = awf_encode_apdu( len = awf_encode_apdu(&apdu[0], invoke_id, data);
&apdu[0], ct_test(pTest, len != 0);
invoke_id, apdu_len = len;
data);
ct_test(pTest, len != 0);
apdu_len = len;
len = awf_decode_apdu( len = awf_decode_apdu(&apdu[0], apdu_len, &test_invoke_id, &test_data);
&apdu[0], ct_test(pTest, len != -1);
apdu_len, ct_test(pTest, test_data.access == data->access);
&test_invoke_id, if (test_data.access == FILE_STREAM_ACCESS) {
&test_data); ct_test(pTest, test_data.type.stream.fileStartPosition ==
ct_test(pTest, len != -1); data->type.stream.fileStartPosition);
ct_test(pTest, test_data.access == data->access); } else if (test_data.access == FILE_RECORD_ACCESS) {
if (test_data.access == FILE_STREAM_ACCESS) ct_test(pTest, test_data.type.record.fileStartRecord ==
{ data->type.record.fileStartRecord);
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) void testAtomicWriteFileAck(Test * pTest)
{ {
BACNET_ATOMIC_WRITE_FILE_DATA data = {0}; BACNET_ATOMIC_WRITE_FILE_DATA data = { 0 };
data.access = FILE_STREAM_ACCESS;
data.type.stream.fileStartPosition = 42;
testAtomicWriteFileAckAccess(pTest, &data);
data.access = FILE_RECORD_ACCESS; data.access = FILE_STREAM_ACCESS;
data.type.record.fileStartRecord = 54; data.type.stream.fileStartPosition = 42;
testAtomicWriteFileAckAccess(pTest, &data); testAtomicWriteFileAckAccess(pTest, &data);
return; data.access = FILE_RECORD_ACCESS;
data.type.record.fileStartRecord = 54;
testAtomicWriteFileAckAccess(pTest, &data);
return;
} }
#ifdef TEST_ATOMIC_WRITE_FILE #ifdef TEST_ATOMIC_WRITE_FILE
uint16_t Device_Max_APDU_Length_Accepted(void) uint16_t Device_Max_APDU_Length_Accepted(void)
{ {
return MAX_APDU; return MAX_APDU;
} }
int main(void) int main(void)
+33 -51
View File
@@ -38,78 +38,60 @@
#include <stdbool.h> #include <stdbool.h>
#include "bacdcode.h" #include "bacdcode.h"
typedef struct BACnet_Atomic_Write_File_Data typedef struct BACnet_Atomic_Write_File_Data {
{ BACNET_OBJECT_TYPE object_type;
BACNET_OBJECT_TYPE object_type; uint32_t object_instance;
uint32_t object_instance; BACNET_FILE_ACCESS_METHOD access;
BACNET_FILE_ACCESS_METHOD access; union {
union struct {
{ int32_t fileStartPosition;
struct } stream;
{ struct {
int32_t fileStartPosition; int32_t fileStartRecord;
} stream; uint32_t returnedRecordCount;
struct } record;
{ } type;
int32_t fileStartRecord; BACNET_OCTET_STRING fileData;
uint32_t returnedRecordCount;
} record;
} type;
BACNET_OCTET_STRING fileData;
} BACNET_ATOMIC_WRITE_FILE_DATA; } BACNET_ATOMIC_WRITE_FILE_DATA;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
// Atomic Write File // Atomic Write File
// encode service // encode service
int awf_encode_apdu( int awf_encode_apdu(uint8_t * apdu,
uint8_t *apdu, uint8_t invoke_id, BACNET_ATOMIC_WRITE_FILE_DATA * data);
uint8_t invoke_id,
BACNET_ATOMIC_WRITE_FILE_DATA *data);
// decode the service request only // decode the service request only
int awf_decode_service_request( int awf_decode_service_request(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, BACNET_ATOMIC_WRITE_FILE_DATA * data);
unsigned apdu_len,
BACNET_ATOMIC_WRITE_FILE_DATA *data); int awf_decode_apdu(uint8_t * apdu,
unsigned apdu_len,
int awf_decode_apdu( uint8_t * invoke_id, BACNET_ATOMIC_WRITE_FILE_DATA * data);
uint8_t *apdu,
unsigned apdu_len,
uint8_t *invoke_id,
BACNET_ATOMIC_WRITE_FILE_DATA *data);
// Atomic Write File Ack // Atomic Write File Ack
// encode service // encode service
int awf_ack_encode_apdu( int awf_ack_encode_apdu(uint8_t * apdu,
uint8_t *apdu, uint8_t invoke_id, BACNET_ATOMIC_WRITE_FILE_DATA * data);
uint8_t invoke_id,
BACNET_ATOMIC_WRITE_FILE_DATA *data);
// decode the service request only // decode the service request only
int awf_ack_decode_service_request( int awf_ack_decode_service_request(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, BACNET_ATOMIC_WRITE_FILE_DATA * data);
unsigned apdu_len,
BACNET_ATOMIC_WRITE_FILE_DATA *data);
int awf_ack_decode_apdu( int awf_ack_decode_apdu(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len,
unsigned apdu_len, uint8_t * invoke_id, BACNET_ATOMIC_WRITE_FILE_DATA * data);
uint8_t *invoke_id,
BACNET_ATOMIC_WRITE_FILE_DATA *data);
#ifdef TEST #ifdef TEST
#include "ctest.h" #include "ctest.h"
void test_AtomicWriteFile(Test * pTest); void test_AtomicWriteFile(Test * pTest);
void test_AtomicWriteFileAck(Test * pTest); void test_AtomicWriteFileAck(Test * pTest);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+567 -659
View File
File diff suppressed because it is too large Load Diff
+33 -45
View File
@@ -40,66 +40,54 @@
#include "bacdef.h" #include "bacdef.h"
#include "bacstr.h" #include "bacstr.h"
typedef struct BACnet_Application_Data_Value typedef struct BACnet_Application_Data_Value {
{ uint8_t tag;
uint8_t tag; union {
union /* NULL - not needed as it is encoded in the tag alone */
{ bool Boolean;
/* NULL - not needed as it is encoded in the tag alone */ uint32_t Unsigned_Int;
bool Boolean; int32_t Signed_Int;
uint32_t Unsigned_Int; float Real;
int32_t Signed_Int; double Double;
float Real; BACNET_OCTET_STRING Octet_String;
double Double; BACNET_CHARACTER_STRING Character_String;
BACNET_OCTET_STRING Octet_String; BACNET_BIT_STRING Bit_String;
BACNET_CHARACTER_STRING Character_String; int Enumerated;
BACNET_BIT_STRING Bit_String; BACNET_DATE Date;
int Enumerated; BACNET_TIME Time;
BACNET_DATE Date; BACNET_OBJECT_ID Object_Id;
BACNET_TIME Time; } type;
BACNET_OBJECT_ID Object_Id;
} type;
} BACNET_APPLICATION_DATA_VALUE; } BACNET_APPLICATION_DATA_VALUE;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
int bacapp_decode_application_data( int bacapp_decode_application_data(uint8_t * apdu,
uint8_t *apdu, uint8_t apdu_len, BACNET_APPLICATION_DATA_VALUE * value);
uint8_t apdu_len,
BACNET_APPLICATION_DATA_VALUE *value);
int bacapp_encode_application_data( int bacapp_encode_application_data(uint8_t * apdu,
uint8_t *apdu, BACNET_APPLICATION_DATA_VALUE * value);
BACNET_APPLICATION_DATA_VALUE *value);
bool bacapp_copy( bool bacapp_copy(BACNET_APPLICATION_DATA_VALUE * dest_value,
BACNET_APPLICATION_DATA_VALUE *dest_value, BACNET_APPLICATION_DATA_VALUE * src_value);
BACNET_APPLICATION_DATA_VALUE *src_value);
bool bacapp_compare( bool bacapp_compare(BACNET_APPLICATION_DATA_VALUE * value,
BACNET_APPLICATION_DATA_VALUE *value, BACNET_APPLICATION_DATA_VALUE * test_value);
BACNET_APPLICATION_DATA_VALUE *test_value);
bool bacapp_parse_application_data( bool bacapp_parse_application_data(BACNET_APPLICATION_TAG tag_number,
BACNET_APPLICATION_TAG tag_number, const char *argv, BACNET_APPLICATION_DATA_VALUE * value);
const char *argv,
BACNET_APPLICATION_DATA_VALUE *value);
bool bacapp_print_value( bool bacapp_print_value(FILE * stream,
FILE *stream, BACNET_APPLICATION_DATA_VALUE * value,
BACNET_APPLICATION_DATA_VALUE *value, BACNET_PROPERTY_ID property);
BACNET_PROPERTY_ID property);
#ifdef TEST #ifdef TEST
#include "ctest.h" #include "ctest.h"
void testBACnetApplicationData(Test * pTest); void testBACnetApplicationData(Test * pTest);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+554 -553
View File
File diff suppressed because it is too large Load Diff
+84 -77
View File
@@ -42,117 +42,125 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
// from clause 20.2.1 General Rules for Encoding BACnet Tags // from clause 20.2.1 General Rules for Encoding BACnet Tags
// returns the number of apdu bytes consumed // returns the number of apdu bytes consumed
int encode_tag(uint8_t * apdu, uint8_t tag_number, bool context_specific, int encode_tag(uint8_t * apdu, uint8_t tag_number,
uint32_t len_value_type); bool context_specific, uint32_t len_value_type);
// from clause 20.2.1.3.2 Constructed Data // from clause 20.2.1.3.2 Constructed Data
// returns the number of apdu bytes consumed // returns the number of apdu bytes consumed
int encode_opening_tag(uint8_t * apdu, uint8_t tag_number); int encode_opening_tag(uint8_t * apdu, uint8_t tag_number);
int encode_closing_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, int decode_tag_number_and_value(uint8_t * apdu, uint8_t * tag_number,
uint32_t * value); uint32_t * value);
// returns true if the tag is context specific // 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 // 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 // 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 // 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 // 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 // from clause 20.2.3 Encoding of a Boolean Value
int encode_tagged_boolean(uint8_t * apdu, bool boolean_value); int encode_tagged_boolean(uint8_t * apdu, bool boolean_value);
bool decode_boolean(uint32_t len_value); bool decode_boolean(uint32_t len_value);
int encode_context_boolean(uint8_t * apdu, bool boolean_value); int encode_context_boolean(uint8_t * apdu, bool boolean_value);
bool decode_context_boolean(uint8_t * apdu); bool decode_context_boolean(uint8_t * apdu);
// from clause 20.2.10 Encoding of a Bit String Value // from clause 20.2.10 Encoding of a Bit String Value
// returns the number of apdu bytes consumed // returns the number of apdu bytes consumed
int decode_bitstring(uint8_t * apdu, uint32_t len_value, int decode_bitstring(uint8_t * apdu, uint32_t len_value,
BACNET_BIT_STRING *bit_string); BACNET_BIT_STRING * bit_string);
// returns the number of apdu bytes consumed // returns the number of apdu bytes consumed
int encode_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); int encode_tagged_bitstring(uint8_t * apdu,
BACNET_BIT_STRING * bit_string);
// from clause 20.2.6 Encoding of a Real Number Value // from clause 20.2.6 Encoding of a Real Number Value
// and 20.2.1 General Rules for Encoding BACnet Tags // and 20.2.1 General Rules for Encoding BACnet Tags
// returns the number of apdu bytes consumed // returns the number of apdu bytes consumed
int decode_real(uint8_t * apdu, float *real_value); int decode_real(uint8_t * apdu, float *real_value);
int encode_bacnet_real(float value, uint8_t * apdu); int encode_bacnet_real(float value, uint8_t * apdu);
int encode_tagged_real(uint8_t * apdu, float value); int encode_tagged_real(uint8_t * apdu, float value);
// from clause 20.2.14 Encoding of an Object Identifier Value // from clause 20.2.14 Encoding of an Object Identifier Value
// and 20.2.1 General Rules for Encoding BACnet Tags // and 20.2.1 General Rules for Encoding BACnet Tags
// returns the number of apdu bytes consumed // returns the number of apdu bytes consumed
int decode_object_id(uint8_t * apdu, int *object_type, uint32_t *instance); int decode_object_id(uint8_t * apdu, int *object_type,
int encode_bacnet_object_id(uint8_t * apdu, int object_type, uint32_t instance); uint32_t * instance);
int encode_context_object_id(uint8_t * apdu, int tag_number, int encode_bacnet_object_id(uint8_t * apdu, int object_type,
int object_type, uint32_t instance); uint32_t instance);
int encode_tagged_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 // from clause 20.2.8 Encoding of an Octet String Value
// and 20.2.1 General Rules for Encoding BACnet Tags // and 20.2.1 General Rules for Encoding BACnet Tags
// returns the number of apdu bytes consumed // returns the number of apdu bytes consumed
int encode_octet_string(uint8_t * apdu, int encode_octet_string(uint8_t * apdu,
BACNET_OCTET_STRING *octet_string); BACNET_OCTET_STRING * octet_string);
int encode_tagged_octet_string(uint8_t * apdu, int encode_tagged_octet_string(uint8_t * apdu,
BACNET_OCTET_STRING *octet_string); BACNET_OCTET_STRING * octet_string);
int decode_octet_string(uint8_t * apdu, uint32_t len_value, int decode_octet_string(uint8_t * apdu, uint32_t len_value,
BACNET_OCTET_STRING *octet_string); BACNET_OCTET_STRING * octet_string);
// from clause 20.2.9 Encoding of a Character String Value // from clause 20.2.9 Encoding of a Character String Value
// and 20.2.1 General Rules for Encoding BACnet Tags // and 20.2.1 General Rules for Encoding BACnet Tags
// returns the number of apdu bytes consumed // returns the number of apdu bytes consumed
int encode_bacnet_character_string(uint8_t * apdu, int encode_bacnet_character_string(uint8_t * apdu,
BACNET_CHARACTER_STRING *char_string); BACNET_CHARACTER_STRING * char_string);
int encode_tagged_character_string(uint8_t * apdu, int encode_tagged_character_string(uint8_t * apdu,
BACNET_CHARACTER_STRING *char_string); BACNET_CHARACTER_STRING * char_string);
int encode_context_character_string(uint8_t * apdu, int tag_number, int encode_context_character_string(uint8_t * apdu, int tag_number,
BACNET_CHARACTER_STRING *char_string); BACNET_CHARACTER_STRING * char_string);
int decode_character_string(uint8_t * apdu, uint32_t len_value, int decode_character_string(uint8_t * apdu, uint32_t len_value,
BACNET_CHARACTER_STRING *char_string); BACNET_CHARACTER_STRING * char_string);
// from clause 20.2.4 Encoding of an Unsigned Integer Value // from clause 20.2.4 Encoding of an Unsigned Integer Value
// and 20.2.1 General Rules for Encoding BACnet Tags // and 20.2.1 General Rules for Encoding BACnet Tags
// returns the number of apdu bytes consumed // returns the number of apdu bytes consumed
int encode_bacnet_unsigned(uint8_t * apdu, 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_context_unsigned(uint8_t * apdu, int tag_number,
int encode_tagged_unsigned(uint8_t * apdu, uint32_t value); uint32_t value);
int decode_unsigned(uint8_t * apdu, uint32_t len_value, 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 // from clause 20.2.5 Encoding of a Signed Integer Value
// and 20.2.1 General Rules for Encoding BACnet Tags // and 20.2.1 General Rules for Encoding BACnet Tags
// returns the number of apdu bytes consumed // returns the number of apdu bytes consumed
int encode_bacnet_signed(uint8_t * apdu, 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_tagged_signed(uint8_t * apdu, int32_t value);
int encode_context_signed(uint8_t * apdu, int tag_number, int32_t value); int encode_context_signed(uint8_t * apdu, int tag_number,
int decode_signed(uint8_t * apdu, uint32_t len_value, int32_t *value); 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 // from clause 20.2.11 Encoding of an Enumerated Value
// and 20.2.1 General Rules for Encoding BACnet Tags // and 20.2.1 General Rules for Encoding BACnet Tags
// returns the number of apdu bytes consumed // returns the number of apdu bytes consumed
int decode_enumerated(uint8_t * apdu, uint32_t len_value, 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_bacnet_enumerated(uint8_t * apdu, int value);
int encode_tagged_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 encode_context_enumerated(uint8_t * apdu, int tag_number,
int value);
// from clause 20.2.13 Encoding of a Time Value // from clause 20.2.13 Encoding of a Time Value
// and 20.2.1 General Rules for Encoding BACnet Tags // and 20.2.1 General Rules for Encoding BACnet Tags
// returns the number of apdu bytes consumed // returns the number of apdu bytes consumed
int encode_bacnet_time(uint8_t * apdu, int hour, int min, int sec, int encode_bacnet_time(uint8_t * apdu, int hour, int min, int sec,
int hundredths); int hundredths);
int encode_tagged_time(uint8_t * apdu, int hour, int min, int sec, int encode_tagged_time(uint8_t * apdu, int hour, int min, int sec,
int hundredths); int hundredths);
int decode_bacnet_time(uint8_t * apdu, int *hour, int *min, int *sec, int decode_bacnet_time(uint8_t * apdu, int *hour, int *min, int *sec,
int *hundredths); int *hundredths);
// BACnet Date // BACnet Date
// year = years since 1900 // 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 // from clause 20.2.12 Encoding of a Date Value
// and 20.2.1 General Rules for Encoding BACnet Tags // and 20.2.1 General Rules for Encoding BACnet Tags
// returns the number of apdu bytes consumed // returns the number of apdu bytes consumed
int encode_bacnet_date(uint8_t * apdu, int year, int month, int day, int encode_bacnet_date(uint8_t * apdu, int year, int month, int day,
int wday); int wday);
int encode_tagged_date(uint8_t * apdu, int year, int month, int day, int encode_tagged_date(uint8_t * apdu, int year, int month, int day,
int wday); int wday);
int decode_date(uint8_t * apdu, int *year, int *month, int *day, int decode_date(uint8_t * apdu, int *year, int *month, int *day,
int *wday); int *wday);
// two octet unsigned16 // two octet unsigned16
int encode_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); int decode_unsigned16(uint8_t * apdu, uint16_t * value);
// four octet unsigned32 // four octet unsigned32
int encode_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); int decode_unsigned32(uint8_t * apdu, uint32_t * value);
// from clause 20.1.2.4 max-segments-accepted // from clause 20.1.2.4 max-segments-accepted
// and clause 20.1.2.5 max-APDU-length-accepted // and clause 20.1.2.5 max-APDU-length-accepted
// returns the encoded octet // returns the encoded octet
uint8_t encode_max_segs_max_apdu(int max_segs, int max_apdu); uint8_t encode_max_segs_max_apdu(int max_segs, int max_apdu);
int decode_max_segs(uint8_t octet); int decode_max_segs(uint8_t octet);
int decode_max_apdu(uint8_t octet); int decode_max_apdu(uint8_t octet);
// returns the number of apdu bytes consumed // returns the number of apdu bytes consumed
int encode_simple_ack(uint8_t * apdu, uint8_t invoke_id, int encode_simple_ack(uint8_t * apdu, uint8_t invoke_id,
uint8_t service_choice); uint8_t service_choice);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+20 -24
View File
@@ -56,11 +56,10 @@
// embedded systems need fixed name sizes // embedded systems need fixed name sizes
#define MAX_OBJECT_NAME 10 #define MAX_OBJECT_NAME 10
// common object properties // common object properties
typedef struct BACnet_Object_Data typedef struct BACnet_Object_Data {
{ uint32_t Object_Identifier;
uint32_t Object_Identifier; char Object_Name[MAX_OBJECT_NAME];
char Object_Name[MAX_OBJECT_NAME]; BACNET_OBJECT_TYPE Object_Type;
BACNET_OBJECT_TYPE Object_Type;
} BACNET_OBJECT_DATA; } BACNET_OBJECT_DATA;
#define BACNET_BROADCAST_NETWORK 0xFFFF #define BACNET_BROADCAST_NETWORK 0xFFFF
@@ -75,39 +74,36 @@ struct BACnet_Device_Address {
// DNET,DLEN,DADR or SNET,SLEN,SADR // DNET,DLEN,DADR or SNET,SLEN,SADR
// the following are used if the device is behind a router // the following are used if the device is behind a router
// net = 0 indicates local // 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 denotes broadcast MAC ADR and ADR field is absent
// LEN > 0 specifies length of ADR field // LEN > 0 specifies length of ADR field
int len; /* length of MAC address */ int len; /* length of MAC address */
uint8_t adr[MAX_MAC_LEN]; /* hwaddr (MAC) address */ uint8_t adr[MAX_MAC_LEN]; /* hwaddr (MAC) address */
}; };
typedef struct BACnet_Device_Address BACNET_ADDRESS; typedef struct BACnet_Device_Address BACNET_ADDRESS;
/* date */ /* date */
typedef struct BACnet_Date typedef struct BACnet_Date {
{ uint16_t year; /* AD */
uint16_t year; /* AD */ uint8_t month; /* 1=Jan */
uint8_t month; /* 1=Jan */ uint8_t day; /* 1..31 */
uint8_t day; /* 1..31 */ uint8_t wday; /* 1=Monday */
uint8_t wday; /* 1=Monday */
} BACNET_DATE; } BACNET_DATE;
/* time */ /* time */
typedef struct BACnet_Time typedef struct BACnet_Time {
{ uint8_t hour;
uint8_t hour; uint8_t min;
uint8_t min; uint8_t sec;
uint8_t sec; uint8_t hundredths;
uint8_t hundredths;
} BACNET_TIME; } BACNET_TIME;
/* note: with microprocessors having lots more code space than memory, /* note: with microprocessors having lots more code space than memory,
it might be better to have a packed encoding with a library to it might be better to have a packed encoding with a library to
easily access the data. */ easily access the data. */
typedef struct BACnet_Object_Id typedef struct BACnet_Object_Id {
{ uint16_t type;
uint16_t type; uint32_t instance;
uint32_t instance;
} BACNET_OBJECT_ID; } BACNET_OBJECT_ID;
#define MAX_NPDU (1+1+2+1+MAX_MAC_LEN+2+1+MAX_MAC_LEN+1+1+2) #define MAX_NPDU (1+1+2+1+MAX_MAC_LEN+2+1+MAX_MAC_LEN+1+1+2)
+901 -928
View File
File diff suppressed because it is too large Load Diff
+165 -226
View File
@@ -37,125 +37,104 @@
#include "bacdef.h" #include "bacdef.h"
// encode service // encode service
int bacerror_encode_apdu( int bacerror_encode_apdu(uint8_t * apdu,
uint8_t *apdu, uint8_t invoke_id,
uint8_t invoke_id, BACNET_CONFIRMED_SERVICE service,
BACNET_CONFIRMED_SERVICE service, BACNET_ERROR_CLASS error_class, BACNET_ERROR_CODE error_code)
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) if (apdu) {
{ apdu[0] = PDU_TYPE_ERROR;
apdu[0] = PDU_TYPE_ERROR; apdu[1] = invoke_id;
apdu[1] = invoke_id; apdu[2] = service;
apdu[2] = service; apdu_len = 3;
apdu_len = 3; // service parameters
// service parameters apdu_len += encode_tagged_enumerated(&apdu[apdu_len], error_class);
apdu_len += encode_tagged_enumerated(&apdu[apdu_len], apdu_len += encode_tagged_enumerated(&apdu[apdu_len], error_code);
error_class); }
apdu_len += encode_tagged_enumerated(&apdu[apdu_len],
error_code); return apdu_len;
}
return apdu_len;
} }
// decode the application class and code // decode the application class and code
int bacerror_decode_error_class_and_code( int bacerror_decode_error_class_and_code(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len,
unsigned apdu_len, BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
BACNET_ERROR_CLASS *error_class,
BACNET_ERROR_CODE *error_code)
{ {
int len = 0; int len = 0;
uint8_t tag_number = 0; uint8_t tag_number = 0;
uint32_t len_value_type = 0; uint32_t len_value_type = 0;
int decoded_value = 0; int decoded_value = 0;
if (apdu_len) if (apdu_len) {
{ // error class
// error class len += decode_tag_number_and_value(&apdu[len],
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type);
&tag_number, &len_value_type); if (tag_number != BACNET_APPLICATION_TAG_ENUMERATED)
if (tag_number != BACNET_APPLICATION_TAG_ENUMERATED) return 0;
return 0; len +=
len += decode_enumerated(&apdu[len],len_value_type, &decoded_value); decode_enumerated(&apdu[len], len_value_type, &decoded_value);
if (error_class) if (error_class)
*error_class = decoded_value; *error_class = decoded_value;
// error code // error code
len += decode_tag_number_and_value(&apdu[len], len += decode_tag_number_and_value(&apdu[len],
&tag_number, &len_value_type); &tag_number, &len_value_type);
if (tag_number != BACNET_APPLICATION_TAG_ENUMERATED) if (tag_number != BACNET_APPLICATION_TAG_ENUMERATED)
return 0; return 0;
len += decode_enumerated(&apdu[len],len_value_type, &decoded_value); len +=
if (error_code) decode_enumerated(&apdu[len], len_value_type, &decoded_value);
*error_code = decoded_value; if (error_code)
} *error_code = decoded_value;
}
return len;
return len;
} }
// decode the service request only // decode the service request only
int bacerror_decode_service_request( int bacerror_decode_service_request(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len,
unsigned apdu_len, uint8_t * invoke_id,
uint8_t *invoke_id, BACNET_CONFIRMED_SERVICE * service,
BACNET_CONFIRMED_SERVICE *service, BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
BACNET_ERROR_CLASS *error_class,
BACNET_ERROR_CODE *error_code)
{ {
int len = 0; int len = 0;
if (apdu_len > 2) if (apdu_len > 2) {
{ if (invoke_id)
if (invoke_id) *invoke_id = apdu[0];
*invoke_id = apdu[0]; if (service)
if (service) *service = apdu[1];
*service = apdu[1]; // decode the application class and code
// decode the application class and code len = bacerror_decode_error_class_and_code(&apdu[2],
len = bacerror_decode_error_class_and_code( apdu_len - 2, error_class, error_code);
&apdu[2], }
apdu_len - 2,
error_class, return len;
error_code);
}
return len;
} }
// decode the whole APDU - mainly used for unit testing // decode the whole APDU - mainly used for unit testing
int bacerror_decode_apdu( int bacerror_decode_apdu(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len,
unsigned apdu_len, uint8_t * invoke_id,
uint8_t *invoke_id, BACNET_CONFIRMED_SERVICE * service,
BACNET_CONFIRMED_SERVICE *service, BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
BACNET_ERROR_CLASS *error_class,
BACNET_ERROR_CODE *error_code)
{ {
int len = 0; int len = 0;
if (!apdu) if (!apdu)
return -1; return -1;
// optional checking - most likely was already done prior to this call // optional checking - most likely was already done prior to this call
if (apdu_len) if (apdu_len) {
{ if (apdu[0] != PDU_TYPE_ERROR)
if (apdu[0] != PDU_TYPE_ERROR) return -1;
return -1; if (apdu_len > 1) {
if (apdu_len > 1) len = bacerror_decode_service_request(&apdu[1],
{ apdu_len - 1, invoke_id, service, error_class, error_code);
len = bacerror_decode_service_request( }
&apdu[1],
apdu_len - 1,
invoke_id,
service,
error_class,
error_code);
} }
}
return len;
return len;
} }
#ifdef TEST #ifdef TEST
@@ -165,137 +144,97 @@ int bacerror_decode_apdu(
void testBACError(Test * pTest) void testBACError(Test * pTest)
{ {
uint8_t apdu[480] = {0}; uint8_t apdu[480] = { 0 };
int len = 0; int len = 0;
int apdu_len = 0; int apdu_len = 0;
uint8_t invoke_id = 0; uint8_t invoke_id = 0;
BACNET_CONFIRMED_SERVICE service = 0; BACNET_CONFIRMED_SERVICE service = 0;
BACNET_ERROR_CLASS error_class = 0; BACNET_ERROR_CLASS error_class = 0;
BACNET_ERROR_CODE error_code = 0; BACNET_ERROR_CODE error_code = 0;
uint8_t test_invoke_id = 0; uint8_t test_invoke_id = 0;
BACNET_CONFIRMED_SERVICE test_service = 0; BACNET_CONFIRMED_SERVICE test_service = 0;
BACNET_ERROR_CLASS test_error_class = 0; BACNET_ERROR_CLASS test_error_class = 0;
BACNET_ERROR_CODE test_error_code = 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;
len = bacerror_decode_apdu( len = bacerror_encode_apdu(&apdu[0],
&apdu[0], invoke_id, service, error_class, error_code);
apdu_len, ct_test(pTest, len != 0);
&test_invoke_id, apdu_len = len;
&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);
// change type to get negative response len = bacerror_decode_apdu(&apdu[0],
apdu[0] = PDU_TYPE_ABORT; apdu_len,
len = bacerror_decode_apdu( &test_invoke_id,
&apdu[0], &test_service, &test_error_class, &test_error_code);
apdu_len, ct_test(pTest, len != -1);
&test_invoke_id, ct_test(pTest, test_invoke_id == invoke_id);
&test_service, ct_test(pTest, test_service == service);
&test_error_class, ct_test(pTest, test_error_class == error_class);
&test_error_code); ct_test(pTest, test_error_code == error_code);
ct_test(pTest, len == -1);
// test NULL APDU // change type to get negative response
len = bacerror_decode_apdu( apdu[0] = PDU_TYPE_ABORT;
NULL, len = bacerror_decode_apdu(&apdu[0],
apdu_len, apdu_len,
&test_invoke_id, &test_invoke_id,
&test_service, &test_service, &test_error_class, &test_error_code);
&test_error_class, ct_test(pTest, len == -1);
&test_error_code);
ct_test(pTest, len == -1);
// force a zero length // test NULL APDU
len = bacerror_decode_apdu( len = bacerror_decode_apdu(NULL,
&apdu[0], apdu_len,
0, &test_invoke_id,
&test_invoke_id, &test_service, &test_error_class, &test_error_code);
&test_service, ct_test(pTest, len == -1);
&test_error_class,
&test_error_code); // force a zero length
ct_test(pTest, len == 0); len = bacerror_decode_apdu(&apdu[0],
0,
&test_invoke_id,
// check them all... &test_service, &test_error_class, &test_error_code);
for ( ct_test(pTest, len == 0);
service = 0;
service < MAX_BACNET_CONFIRMED_SERVICE;
service++) // check them all...
{ for (service = 0; service < MAX_BACNET_CONFIRMED_SERVICE; service++) {
for ( for (error_class = 0;
error_class = 0; error_class < MAX_BACNET_ERROR_CLASS; error_class++) {
error_class < MAX_BACNET_ERROR_CLASS; for (error_code = 0;
error_class++) error_code < MAX_BACNET_ERROR_CODE; error_code++) {
{ len = bacerror_encode_apdu(&apdu[0],
for ( invoke_id, service, error_class, error_code);
error_code = 0; apdu_len = len;
error_code < MAX_BACNET_ERROR_CODE; ct_test(pTest, len != 0);
error_code++) len = bacerror_decode_apdu(&apdu[0],
{ apdu_len,
len = bacerror_encode_apdu( &test_invoke_id,
&apdu[0], &test_service, &test_error_class, &test_error_code);
invoke_id, ct_test(pTest, len != -1);
service, ct_test(pTest, test_invoke_id == invoke_id);
error_class, ct_test(pTest, test_service == service);
error_code); ct_test(pTest, test_error_class == error_class);
apdu_len = len; ct_test(pTest, test_error_code == error_code);
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 // max boundaries
service = 255; service = 255;
error_class = LAST_PROPRIETARY_ERROR_CLASS; error_class = LAST_PROPRIETARY_ERROR_CLASS;
error_code = LAST_PROPRIETARY_ERROR_CODE; error_code = LAST_PROPRIETARY_ERROR_CODE;
len = bacerror_encode_apdu( len = bacerror_encode_apdu(&apdu[0],
&apdu[0], invoke_id, service, error_class, error_code);
invoke_id, apdu_len = len;
service, ct_test(pTest, len != 0);
error_class, len = bacerror_decode_apdu(&apdu[0],
error_code); apdu_len,
apdu_len = len; &test_invoke_id,
ct_test(pTest, len != 0); &test_service, &test_error_class, &test_error_code);
len = bacerror_decode_apdu( ct_test(pTest, len != -1);
&apdu[0], ct_test(pTest, test_invoke_id == invoke_id);
apdu_len, ct_test(pTest, test_service == service);
&test_invoke_id, ct_test(pTest, test_error_class == error_class);
&test_service, ct_test(pTest, test_error_code == error_code);
&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 #ifdef TEST_BACERROR
+22 -32
View File
@@ -40,45 +40,35 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
int bacerror_encode_apdu( int bacerror_encode_apdu(uint8_t * apdu,
uint8_t *apdu, uint8_t invoke_id,
uint8_t invoke_id, BACNET_CONFIRMED_SERVICE service,
BACNET_CONFIRMED_SERVICE service, BACNET_ERROR_CLASS error_class, BACNET_ERROR_CODE error_code);
BACNET_ERROR_CLASS error_class,
BACNET_ERROR_CODE error_code);
int bacerror_decode_service_request( int bacerror_decode_service_request(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len,
unsigned apdu_len, uint8_t * invoke_id,
uint8_t *invoke_id, BACNET_CONFIRMED_SERVICE * service,
BACNET_CONFIRMED_SERVICE *service, BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code);
BACNET_ERROR_CLASS *error_class,
BACNET_ERROR_CODE *error_code); int bacerror_decode_apdu(uint8_t * apdu,
unsigned apdu_len,
int bacerror_decode_apdu( uint8_t * invoke_id,
uint8_t *apdu, BACNET_CONFIRMED_SERVICE * service,
unsigned apdu_len, BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code);
uint8_t *invoke_id,
BACNET_CONFIRMED_SERVICE *service, int bacerror_decode_error_class_and_code(uint8_t * apdu,
BACNET_ERROR_CLASS *error_class, unsigned apdu_len,
BACNET_ERROR_CODE *error_code); 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 #ifdef TEST
#include "ctest.h" #include "ctest.h"
void testBACError(Test * pTest); void testBACError(Test * pTest);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+58 -46
View File
@@ -37,63 +37,75 @@
#include "bacprop.h" #include "bacprop.h"
PROP_TAG_DATA bacnet_object_device_property_tag_map[] = { PROP_TAG_DATA bacnet_object_device_property_tag_map[] = {
{PROP_OBJECT_IDENTIFIER, BACNET_APPLICATION_TAG_OBJECT_ID}, {PROP_OBJECT_IDENTIFIER, BACNET_APPLICATION_TAG_OBJECT_ID}
{PROP_OBJECT_NAME, BACNET_APPLICATION_TAG_CHARACTER_STRING}, ,
{PROP_OBJECT_TYPE, BACNET_APPLICATION_TAG_ENUMERATED}, {PROP_OBJECT_NAME, BACNET_APPLICATION_TAG_CHARACTER_STRING}
{PROP_SYSTEM_STATUS, BACNET_APPLICATION_TAG_ENUMERATED}, ,
{PROP_VENDOR_NAME, BACNET_APPLICATION_TAG_CHARACTER_STRING}, {PROP_OBJECT_TYPE, BACNET_APPLICATION_TAG_ENUMERATED}
{PROP_VENDOR_IDENTIFIER, BACNET_APPLICATION_TAG_UNSIGNED_INT}, ,
{PROP_MODEL_NAME, BACNET_APPLICATION_TAG_CHARACTER_STRING}, {PROP_SYSTEM_STATUS, BACNET_APPLICATION_TAG_ENUMERATED}
{PROP_FIRMWARE_REVISION, BACNET_APPLICATION_TAG_CHARACTER_STRING}, ,
{PROP_APPLICATION_SOFTWARE_VERSION, BACNET_APPLICATION_TAG_CHARACTER_STRING}, {PROP_VENDOR_NAME, BACNET_APPLICATION_TAG_CHARACTER_STRING}
{PROP_PROTOCOL_VERSION, BACNET_APPLICATION_TAG_UNSIGNED_INT}, ,
{PROP_PROTOCOL_CONFORMANCE_CLASS, BACNET_APPLICATION_TAG_UNSIGNED_INT}, {PROP_VENDOR_IDENTIFIER, 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_MODEL_NAME, BACNET_APPLICATION_TAG_CHARACTER_STRING}
{PROP_MAX_APDU_LENGTH_ACCEPTED, BACNET_APPLICATION_TAG_UNSIGNED_INT}, ,
{PROP_SEGMENTATION_SUPPORTED, BACNET_APPLICATION_TAG_ENUMERATED}, {PROP_FIRMWARE_REVISION, BACNET_APPLICATION_TAG_CHARACTER_STRING}
{PROP_APDU_TIMEOUT, BACNET_APPLICATION_TAG_UNSIGNED_INT}, ,
{PROP_NUMBER_OF_APDU_RETRIES, BACNET_APPLICATION_TAG_UNSIGNED_INT}, {PROP_APPLICATION_SOFTWARE_VERSION,
{ -1, -1 } 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( signed bacprop_tag_by_index_default(PROP_TAG_DATA * data_list,
PROP_TAG_DATA *data_list, signed index, signed default_ret)
signed index,
signed default_ret)
{ {
signed pUnsigned = 0; signed pUnsigned = 0;
if (data_list) if (data_list) {
{ while (data_list->prop_id != -1) {
while (data_list->prop_id != -1) if (data_list->prop_id == index) {
{ pUnsigned = data_list->tag_id;
if (data_list->prop_id == index) break;
{ }
pUnsigned = data_list->tag_id; data_list++;
break; }
}
data_list++;
} }
}
return pUnsigned?pUnsigned:default_ret; return pUnsigned ? pUnsigned : default_ret;
} }
signed bacprop_property_tag(BACNET_OBJECT_TYPE type, signed prop) signed bacprop_property_tag(BACNET_OBJECT_TYPE type, signed prop)
{ {
switch (type) switch (type) {
{ case OBJECT_DEVICE:
case OBJECT_DEVICE: return
return bacprop_tag_by_index_default( bacprop_tag_by_index_default
bacnet_object_device_property_tag_map, (bacnet_object_device_property_tag_map, prop, -1);
prop,
-1);
default: default:
fprintf(stderr, "Unsupported object type"); fprintf(stderr, "Unsupported object type");
break; break;
} }
return -1; return -1;
} }
+8 -12
View File
@@ -38,25 +38,21 @@
#include <stdint.h> #include <stdint.h>
#include "bacenum.h" #include "bacenum.h"
typedef struct typedef struct {
{ signed prop_id; /* index number that matches the text */
signed prop_id; /* index number that matches the text */ signed tag_id; /* text pair - use NULL to end the list */
signed tag_id; /* text pair - use NULL to end the list */
} PROP_TAG_DATA; } PROP_TAG_DATA;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
signed bacprop_tag_by_index_default( signed bacprop_tag_by_index_default(PROP_TAG_DATA * data_list,
PROP_TAG_DATA *data_list, signed index, signed default_ret);
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 #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+413 -505
View File
File diff suppressed because it is too large Load Diff
+59 -81
View File
@@ -42,122 +42,100 @@
/* bit strings /* bit strings
They could be as large as 256/8=32 octets */ They could be as large as 256/8=32 octets */
#define MAX_BITSTRING_BYTES 15 #define MAX_BITSTRING_BYTES 15
typedef struct BACnet_Bit_String typedef struct BACnet_Bit_String {
{ uint8_t bits_used;
uint8_t bits_used; uint8_t value[MAX_BITSTRING_BYTES];
uint8_t value[MAX_BITSTRING_BYTES];
} BACNET_BIT_STRING; } BACNET_BIT_STRING;
#define MAX_CHARACTER_STRING_BYTES (MAX_APDU-6) #define MAX_CHARACTER_STRING_BYTES (MAX_APDU-6)
typedef struct BACnet_Character_String typedef struct BACnet_Character_String {
{ size_t length;
size_t length; uint8_t encoding;
uint8_t encoding; /* limit - 6 octets is the most our tag and type could be */
/* limit - 6 octets is the most our tag and type could be */ char value[MAX_CHARACTER_STRING_BYTES];
char value[MAX_CHARACTER_STRING_BYTES];
} BACNET_CHARACTER_STRING; } BACNET_CHARACTER_STRING;
/* FIXME: convert the bacdcode library to use BACNET_OCTET_STRING /* FIXME: convert the bacdcode library to use BACNET_OCTET_STRING
for APDU buffer to prevent buffer overflows */ for APDU buffer to prevent buffer overflows */
typedef struct BACnet_Octet_String typedef struct BACnet_Octet_String {
{ size_t length;
size_t length; /* limit - 6 octets is the most our tag and type could be */
/* limit - 6 octets is the most our tag and type could be */ uint8_t value[MAX_APDU - 6];
uint8_t value[MAX_APDU-6];
} BACNET_OCTET_STRING; } BACNET_OCTET_STRING;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
void bitstring_init(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); void bitstring_set_bit(BACNET_BIT_STRING * bit_string, uint8_t bit,
bool bitstring_bit(BACNET_BIT_STRING *bit_string, uint8_t bit); bool value);
uint8_t bitstring_bits_used(BACNET_BIT_STRING *bit_string); 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 // returns the number of bytes that a bit string is using
int bitstring_bytes_used(BACNET_BIT_STRING *bit_string); int bitstring_bytes_used(BACNET_BIT_STRING * bit_string);
uint8_t bitstring_bits_capacity(BACNET_BIT_STRING *bit_string); uint8_t bitstring_bits_capacity(BACNET_BIT_STRING * bit_string);
/* used for encoding and decoding from the APDU */ /* used for encoding and decoding from the APDU */
uint8_t bitstring_octet(BACNET_BIT_STRING *bit_string, uint8_t octet_index); uint8_t bitstring_octet(BACNET_BIT_STRING * bit_string,
bool bitstring_set_octet( uint8_t octet_index);
BACNET_BIT_STRING *bit_string, bool bitstring_set_octet(BACNET_BIT_STRING * bit_string, uint8_t index,
uint8_t index, uint8_t octet);
uint8_t octet); bool bitstring_set_bits_used(BACNET_BIT_STRING * bit_string,
bool bitstring_set_bits_used( uint8_t bytes_used, uint8_t unused_bits);
BACNET_BIT_STRING *bit_string,
uint8_t bytes_used,
uint8_t unused_bits);
/* returns false if the string exceeds capacity /* returns false if the string exceeds capacity
initialize by using length=0 */ initialize by using length=0 */
bool characterstring_init( bool characterstring_init(BACNET_CHARACTER_STRING * char_string,
BACNET_CHARACTER_STRING *char_string, uint8_t encoding, char *value, size_t length);
uint8_t encoding,
char *value,
size_t length);
/* used for ANSI C-Strings */ /* used for ANSI C-Strings */
bool characterstring_init_ansi( bool characterstring_init_ansi(BACNET_CHARACTER_STRING * char_string,
BACNET_CHARACTER_STRING *char_string, char *value);
char *value); bool characterstring_copy(BACNET_CHARACTER_STRING * dest,
bool characterstring_copy( BACNET_CHARACTER_STRING * src);
BACNET_CHARACTER_STRING *dest,
BACNET_CHARACTER_STRING *src);
/* returns true if the strings are the same length, encoding, value */ /* returns true if the strings are the same length, encoding, value */
bool characterstring_same( bool characterstring_same(BACNET_CHARACTER_STRING * dest,
BACNET_CHARACTER_STRING *dest, BACNET_CHARACTER_STRING * src);
BACNET_CHARACTER_STRING *src); bool characterstring_ansi_same(BACNET_CHARACTER_STRING * dest,
bool characterstring_ansi_same( const char *src);
BACNET_CHARACTER_STRING *dest,
const char *src);
/* returns false if the string exceeds capacity */ /* returns false if the string exceeds capacity */
bool characterstring_append( bool characterstring_append(BACNET_CHARACTER_STRING * char_string,
BACNET_CHARACTER_STRING *char_string, char *value, size_t length);
char *value,
size_t length);
/* This function sets a new length without changing the value. /* This function sets a new length without changing the value.
If length exceeds capacity, no modification happens and If length exceeds capacity, no modification happens and
function returns false. */ function returns false. */
bool characterstring_truncate( bool characterstring_truncate(BACNET_CHARACTER_STRING * char_string,
BACNET_CHARACTER_STRING *char_string, size_t length);
size_t length); bool characterstring_set_encoding(BACNET_CHARACTER_STRING *
bool characterstring_set_encoding( char_string, uint8_t encoding);
BACNET_CHARACTER_STRING *char_string,
uint8_t encoding);
/* Returns the value */ /* Returns the value */
char *characterstring_value(BACNET_CHARACTER_STRING *char_string); char *characterstring_value(BACNET_CHARACTER_STRING * char_string);
/* returns the length */ /* returns the length */
size_t characterstring_length(BACNET_CHARACTER_STRING *char_string); size_t characterstring_length(BACNET_CHARACTER_STRING * char_string);
uint8_t characterstring_encoding(BACNET_CHARACTER_STRING *char_string); uint8_t characterstring_encoding(BACNET_CHARACTER_STRING *
size_t characterstring_capacity(BACNET_CHARACTER_STRING *char_string); char_string);
size_t characterstring_capacity(BACNET_CHARACTER_STRING * char_string);
/* returns false if the string exceeds capacity /* returns false if the string exceeds capacity
initialize by using length=0 */ initialize by using length=0 */
bool octetstring_init( bool octetstring_init(BACNET_OCTET_STRING * octet_string,
BACNET_OCTET_STRING *octet_string, uint8_t * value, size_t length);
uint8_t *value, bool octetstring_copy(BACNET_OCTET_STRING * dest,
size_t length); BACNET_OCTET_STRING * src);
bool octetstring_copy(
BACNET_OCTET_STRING *dest,
BACNET_OCTET_STRING *src);
/* returns false if the string exceeds capacity */ /* returns false if the string exceeds capacity */
bool octetstring_append( bool octetstring_append(BACNET_OCTET_STRING * octet_string,
BACNET_OCTET_STRING *octet_string, uint8_t * value, size_t length);
uint8_t *value,
size_t length);
/* This function sets a new length without changing the value. /* This function sets a new length without changing the value.
If length exceeds capacity, no modification happens and If length exceeds capacity, no modification happens and
function returns false. */ function returns false. */
bool octetstring_truncate( bool octetstring_truncate(BACNET_OCTET_STRING * octet_string,
BACNET_OCTET_STRING *octet_string, size_t length);
size_t length);
/* Returns the value */ /* Returns the value */
uint8_t *octetstring_value(BACNET_OCTET_STRING *octet_string); uint8_t *octetstring_value(BACNET_OCTET_STRING * octet_string);
/* Returns the length.*/ /* Returns the length.*/
size_t octetstring_length(BACNET_OCTET_STRING *octet_string); size_t octetstring_length(BACNET_OCTET_STRING * octet_string);
size_t octetstring_capacity(BACNET_OCTET_STRING *octet_string); size_t octetstring_capacity(BACNET_OCTET_STRING * octet_string);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+1199 -678
View File
File diff suppressed because it is too large Load Diff
+21 -22
View File
@@ -40,31 +40,30 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
const char *bactext_confirmed_service_name(int index); const char *bactext_confirmed_service_name(int index);
const char *bactext_unconfirmed_service_name(int index); const char *bactext_unconfirmed_service_name(int index);
const char *bactext_application_tag_name(int index); const char *bactext_application_tag_name(int index);
const char *bactext_object_type_name(int index); const char *bactext_object_type_name(int index);
const char *bactext_property_name(int index); const char *bactext_property_name(int index);
const char *bactext_engineering_unit_name(int index); const char *bactext_engineering_unit_name(int index);
const char *bactext_reject_reason_name(int index); const char *bactext_reject_reason_name(int index);
const char *bactext_abort_reason_name(int index); const char *bactext_abort_reason_name(int index);
const char *bactext_error_class_name(int index); const char *bactext_error_class_name(int index);
const char *bactext_error_code_name(int index); const char *bactext_error_code_name(int index);
unsigned bactext_property_id(const char* name); unsigned bactext_property_id(const char *name);
const char *bactext_month_name(int index); const char *bactext_month_name(int index);
const char *bactext_week_of_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_day_of_week_name(int index);
const char *bactext_event_state_name(int index); const char *bactext_event_state_name(int index);
const char *bactext_binary_present_value_name(int index); const char *bactext_binary_present_value_name(int index);
const char *bactext_reliability_name(int index); const char *bactext_reliability_name(int index);
const char *bactext_device_status_name(int index); const char *bactext_device_status_name(int index);
const char *bactext_segmentation_name(int index); const char *bactext_segmentation_name(int index);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+3 -4
View File
@@ -3,7 +3,7 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
// Big-Endian systems save the most significant byte first. // Big-Endian systems save the most significant byte first.
// Sun and Motorola processors, IBM-370s and PDP-10s are big-endian. // Sun and Motorola processors, IBM-370s and PDP-10s are big-endian.
@@ -21,10 +21,9 @@ extern "C" {
// x[2] = 0x03 // x[2] = 0x03
// x[3] = 0x04 // x[3] = 0x04
int big_endian(void); int big_endian(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+96 -118
View File
@@ -36,7 +36,7 @@
#include <stdbool.h> // for the standard bool type. #include <stdbool.h> // for the standard bool type.
#include "bacdcode.h" #include "bacdcode.h"
#include "bip.h" #include "bip.h"
#include "net.h" // custom per port #include "net.h" // custom per port
static int BIP_Socket = -1; static int BIP_Socket = -1;
/* port to use - stored in host byte order */ /* 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) void bip_set_socket(int sock_fd)
{ {
BIP_Socket = sock_fd; BIP_Socket = sock_fd;
} }
bool bip_valid(void) bool bip_valid(void)
{ {
return (BIP_Socket != -1); return (BIP_Socket != -1);
} }
void bip_cleanup(void) void bip_cleanup(void)
{ {
if (bip_valid()) if (bip_valid())
close(BIP_Socket); close(BIP_Socket);
BIP_Socket = -1; BIP_Socket = -1;
return; return;
} }
static void set_network_address(struct in_addr *net_address, 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 { union {
uint8_t byte[4]; uint8_t byte[4];
uint32_t value; uint32_t value;
} long_data = {{0}}; } long_data = { {
0}};
long_data.byte[0] = octet1; long_data.byte[0] = octet1;
long_data.byte[1] = octet2; long_data.byte[1] = octet2;
long_data.byte[2] = octet3; long_data.byte[2] = octet3;
long_data.byte[3] = octet4; long_data.byte[3] = octet4;
net_address->s_addr = long_data.value; net_address->s_addr = long_data.value;
} }
void bip_set_address( void bip_set_address(uint8_t octet1,
uint8_t octet1, uint8_t octet2, uint8_t octet3, uint8_t octet4)
uint8_t octet2,
uint8_t octet3,
uint8_t octet4)
{ {
set_network_address(&BIP_Address, octet1, octet2, octet3, octet4); set_network_address(&BIP_Address, octet1, octet2, octet3, octet4);
} }
void bip_set_broadcast_address( void bip_set_broadcast_address(uint8_t octet1,
uint8_t octet1, uint8_t octet2, uint8_t octet3, uint8_t octet4)
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 // 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) */ /* function to send a packet out the BACnet/IP socket (Annex J) */
/* returns number of bytes sent on success, negative number on failure */ /* returns number of bytes sent on success, negative number on failure */
static int bip_send( static int bip_send(struct sockaddr_in *bip_dest, uint8_t * pdu, // any data to be sent - may be null
struct sockaddr_in *bip_dest, unsigned pdu_len) // number of bytes of data
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 }; uint8_t mtu[MAX_MPDU] = { 0 };
int mtu_len = 0; int mtu_len = 0;
int bytes_sent = 0; int bytes_sent = 0;
// assumes that the driver has already been initialized // assumes that the driver has already been initialized
if (BIP_Socket < 0) if (BIP_Socket < 0)
return BIP_Socket; 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)) 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 else
mtu[1] = 0x0A; /* Original-Unicast-NPDU */ mtu[1] = 0x0A; /* Original-Unicast-NPDU */
mtu_len = 2; 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); memcpy(&mtu[mtu_len], pdu, pdu_len);
mtu_len += pdu_len; mtu_len += pdu_len;
/* Send the packet */ /* Send the packet */
bytes_sent = sendto(BIP_Socket, (char *)mtu, mtu_len, 0, bytes_sent = sendto(BIP_Socket, (char *) mtu, mtu_len, 0,
(struct sockaddr *)bip_dest, (struct sockaddr *) bip_dest, sizeof(struct sockaddr));
sizeof(struct sockaddr));
return bytes_sent; return bytes_sent;
} }
/* function to send a packet out the BACnet/IP socket (Annex J) */ /* function to send a packet out the BACnet/IP socket (Annex J) */
/* returns number of bytes sent on success, negative number on failure */ /* returns number of bytes sent on success, negative number on failure */
int bip_send_pdu( int bip_send_pdu(BACNET_ADDRESS * dest, // destination address
BACNET_ADDRESS *dest, // destination address uint8_t * pdu, // any data to be sent - may be null
uint8_t *pdu, // any data to be sent - may be null unsigned pdu_len) // number of bytes of data
unsigned pdu_len) // number of bytes of data
{ {
struct sockaddr_in bip_dest; struct sockaddr_in bip_dest;
/* load destination IP address */ /* load destination IP address */
bip_dest.sin_family = AF_INET; bip_dest.sin_family = AF_INET;
if (dest->mac_len == 6) if (dest->mac_len == 6) {
{ (void) decode_unsigned32(&dest->mac[0],
(void)decode_unsigned32(&dest->mac[0], &(bip_dest.sin_addr.s_addr)); &(bip_dest.sin_addr.s_addr));
(void)decode_unsigned16(&dest->mac[4], &(bip_dest.sin_port)); (void) decode_unsigned16(&dest->mac[4], &(bip_dest.sin_port));
memset(&(bip_dest.sin_zero), '\0', 8); memset(&(bip_dest.sin_zero), '\0', 8);
} }
/* broadcast */ /* 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_addr.s_addr = htonl(BIP_Broadcast_Address.s_addr);
bip_dest.sin_port = htons(BIP_Port); bip_dest.sin_port = htons(BIP_Port);
memset(&(bip_dest.sin_zero), '\0', 8); memset(&(bip_dest.sin_zero), '\0', 8);
} } else
else
return -1; return -1;
/* function to send a packet out the BACnet/IP socket */ /* function to send a packet out the BACnet/IP socket */
/* returns 1 on success, 0 on failure */ /* returns 1 on success, 0 on failure */
return bip_send(&bip_dest, // destination address return bip_send(&bip_dest, // destination address
pdu, // any data to be sent - may be null pdu, // any data to be sent - may be null
pdu_len); // number of bytes of data pdu_len); // number of bytes of data
} }
// receives a BACnet/IP packet // receives a BACnet/IP packet
// returns the number of octets in the PDU, or zero on failure // returns the number of octets in the PDU, or zero on failure
uint16_t bip_receive( uint16_t bip_receive(BACNET_ADDRESS * src, // source address
BACNET_ADDRESS *src, // source address uint8_t * pdu, // PDU data
uint8_t *pdu, // PDU data uint16_t max_pdu, // amount of space available in the PDU
uint16_t max_pdu, // amount of space available in the PDU unsigned timeout) // number of milliseconds to wait for a packet
unsigned timeout) // number of milliseconds to wait for a packet
{ {
int received_bytes; int received_bytes;
uint8_t buf[MAX_MPDU] = {0}; // data uint8_t buf[MAX_MPDU] = { 0 }; // data
uint16_t pdu_len = 0; // return value uint16_t pdu_len = 0; // return value
fd_set read_fds; fd_set read_fds;
int max; int max;
struct timeval select_timeout; struct timeval select_timeout;
struct sockaddr_in sin = {-1}; struct sockaddr_in sin = { -1 };
socklen_t sin_len = sizeof(sin); socklen_t sin_len = sizeof(sin);
/* Make sure the socket is open */ /* 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 /* 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 the CPU time. We can use a timeout; it is only supported as
a select. */ a select. */
if (timeout >= 1000) if (timeout >= 1000) {
{
select_timeout.tv_sec = timeout / 1000; select_timeout.tv_sec = timeout / 1000;
select_timeout.tv_usec = select_timeout.tv_usec =
1000 * (timeout - select_timeout.tv_sec * 1000); 1000 * (timeout - select_timeout.tv_sec * 1000);
} } else {
else
{
select_timeout.tv_sec = 0; select_timeout.tv_sec = 0;
select_timeout.tv_usec = 1000 * timeout; select_timeout.tv_usec = 1000 * timeout;
} }
FD_ZERO(&read_fds); FD_ZERO(&read_fds);
FD_SET((unsigned int)BIP_Socket, &read_fds); FD_SET((unsigned int) BIP_Socket, &read_fds);
max = BIP_Socket; max = BIP_Socket;
/* see if there is a packet for us */ /* see if there is a packet for us */
if (select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0) if (select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0)
received_bytes = recvfrom(BIP_Socket, received_bytes = recvfrom(BIP_Socket,
(char *)&buf[0], MAX_MPDU, 0, (char *) &buf[0], MAX_MPDU, 0,
(struct sockaddr *)&sin, &sin_len); (struct sockaddr *) &sin, &sin_len);
else else
return 0; return 0;
@@ -256,33 +244,29 @@ uint16_t bip_receive(
/* no problem, just no bytes */ /* no problem, just no bytes */
if (received_bytes == 0) if (received_bytes == 0)
return 0; return 0;
/* the signature of a BACnet/IP packet */ /* the signature of a BACnet/IP packet */
if (buf[0] != 0x81) if (buf[0] != 0x81)
return 0; return 0;
/* Original-Broadcast-NPDU or Original-Unicast-NPDU */ /* 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 */ /* ignore messages from me */
if (sin.sin_addr.s_addr == BIP_Address.s_addr) if (sin.sin_addr.s_addr == BIP_Address.s_addr)
pdu_len = 0; pdu_len = 0;
else else {
{
/* copy the source address /* copy the source address
FIXME: IPv6? */ FIXME: IPv6? */
src->mac_len = 6; src->mac_len = 6;
(void)encode_unsigned32(&src->mac[0], (void) encode_unsigned32(&src->mac[0], sin.sin_addr.s_addr);
sin.sin_addr.s_addr); (void) encode_unsigned16(&src->mac[4], sin.sin_port);
(void)encode_unsigned16(&src->mac[4],
sin.sin_port);
// FIXME: check destination address // FIXME: check destination address
// see if it is broadcast or for us // see if it is broadcast or for us
/* decode the length of the PDU - length is inclusive of BVLC */ /* 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 */ /* copy the buffer into the PDU */
pdu_len -= 4; /* BVLC header */ pdu_len -= 4; /* BVLC header */
if (pdu_len < max_pdu) 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 // ignore packets that are too large
// clients should check my max-apdu first // clients should check my max-apdu first
else else
@@ -293,46 +277,40 @@ uint16_t bip_receive(
return pdu_len; return pdu_len;
} }
void bip_get_my_address(BACNET_ADDRESS *my_address) void bip_get_my_address(BACNET_ADDRESS * my_address)
{ {
int i = 0; 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;
}
return; my_address->mac_len = 6;
} (void) encode_unsigned32(&my_address->mac[0],
htonl(BIP_Address.s_addr));
void bip_get_broadcast_address( (void) encode_unsigned16(&my_address->mac[4], htons(BIP_Port));
BACNET_ADDRESS *dest) // destination address my_address->net = 0; /* local only, no routing */
{ my_address->len = 0; /* no SLEN */
int i = 0; // counter for (i = 0; i < MAX_MAC_LEN; i++) {
/* no SADR */
if (dest) my_address->adr[i] = 0;
{
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; 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
View File
@@ -46,58 +46,54 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
// note: define init and cleanup in your ports section // note: define init and cleanup in your ports section
bool bip_init(void); bool bip_init(void);
// normal functions... // normal functions...
void bip_cleanup(void); void bip_cleanup(void);
void bip_set_socket(int sock_fd); void bip_set_socket(int sock_fd);
bool bip_valid(void); bool bip_valid(void);
void bip_get_broadcast_address( void bip_get_broadcast_address(BACNET_ADDRESS * dest); // destination address
BACNET_ADDRESS *dest); // destination address void bip_get_my_address(BACNET_ADDRESS * my_address);
void bip_get_my_address(BACNET_ADDRESS *my_address);
/* function to send a packet out the BACnet/IP socket */ /* function to send a packet out the BACnet/IP socket */
/* returns zero on success, non-zero on failure */ /* returns zero on success, non-zero on failure */
int bip_send_pdu( int bip_send_pdu(BACNET_ADDRESS * dest, // destination address
BACNET_ADDRESS *dest, // destination address uint8_t * pdu, // any data to be sent - may be null
uint8_t *pdu, // any data to be sent - may be null unsigned pdu_len); // number of bytes of data
unsigned pdu_len); // number of bytes of data
// receives a BACnet/IP packet // receives a BACnet/IP packet
// returns the number of octets in the PDU, or zero on failure // returns the number of octets in the PDU, or zero on failure
uint16_t bip_receive( uint16_t bip_receive(BACNET_ADDRESS * src, // source address
BACNET_ADDRESS *src, // source address uint8_t * pdu, // PDU data
uint8_t *pdu, // PDU data uint16_t max_pdu, // amount of space available in the PDU
uint16_t max_pdu, // amount of space available in the PDU unsigned timeout); // milliseconds to wait for a packet
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 // use host byte order for setting
void bip_set_port(uint16_t port); void bip_set_port(uint16_t port);
// returns host byte order // returns host byte order
uint16_t bip_get_port(void); uint16_t bip_get_port(void);
// use network byte order for setting // 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 // returns host byte order
uint32_t bip_get_addr(void); uint32_t bip_get_addr(void);
// use network byte order for setting // 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 // 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 #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+9 -10
View File
@@ -7,11 +7,11 @@
#include <stdint.h> #include <stdint.h>
#ifndef LO_NIB #ifndef LO_NIB
#define LO_NIB(b) ((b) & 0xF) #define LO_NIB(b) ((b) & 0xF)
#endif #endif
#ifndef HI_NIB #ifndef HI_NIB
#define HI_NIB(b) ((b) >> 4) #define HI_NIB(b) ((b) >> 4)
#endif #endif
@@ -19,7 +19,7 @@
#ifndef LO_BYTE #ifndef LO_BYTE
#define LO_BYTE(w) ((uint8_t)(w)) #define LO_BYTE(w) ((uint8_t)(w))
#endif #endif
@@ -27,7 +27,7 @@
#ifndef HI_BYTE #ifndef HI_BYTE
#define HI_BYTE(w) ((uint8_t)((uint16_t)(w) >> 8)) #define HI_BYTE(w) ((uint8_t)((uint16_t)(w) >> 8))
#endif #endif
@@ -35,7 +35,7 @@
#ifndef LO_WORD #ifndef LO_WORD
#define LO_WORD(x) ((uint16_t)(x)) #define LO_WORD(x) ((uint16_t)(x))
#endif #endif
@@ -43,7 +43,7 @@
#ifndef HI_WORD #ifndef HI_WORD
#define HI_WORD(x) ((uint16_t)((uint32_t)(x) >> 16)) #define HI_WORD(x) ((uint16_t)((uint32_t)(x) >> 16))
#endif #endif
@@ -51,7 +51,7 @@
#ifndef MAKE_WORD #ifndef MAKE_WORD
#define MAKE_WORD(lo,hi) \ #define MAKE_WORD(lo,hi) \
((uint16_t)(((uint8_t)(lo))|(((uint16_t)((uint8_t)(hi)))<<8))) ((uint16_t)(((uint8_t)(lo))|(((uint16_t)((uint8_t)(hi)))<<8)))
#endif #endif
@@ -60,12 +60,11 @@
#ifndef MAKE_LONG #ifndef MAKE_LONG
#define MAKE_LONG(lo,hi) \ #define MAKE_LONG(lo,hi) \
((uint32_t)(((uint16_t)(lo))|(((uint32_t)((uint16_t)(hi)))<<16))) ((uint32_t)(((uint16_t)(lo))|(((uint32_t)((uint16_t)(hi)))<<16)))
#endif #endif
#endif // end of header file #endif // end of header file
+64 -64
View File
@@ -43,17 +43,17 @@
// Note: This function is copied directly from the BACnet standard. // Note: This function is copied directly from the BACnet standard.
uint8_t CRC_Calc_Header(uint8_t dataValue, uint8_t crcValue) 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) */ /* Exclusive OR the terms in the table (top down) */
crc = crc ^ (crc << 1) ^ (crc << 2) ^ (crc << 3) crc = crc ^ (crc << 1) ^ (crc << 2) ^ (crc << 3)
^ (crc << 4) ^ (crc << 5) ^ (crc << 6) ^ (crc << 4) ^ (crc << 5) ^ (crc << 6)
^ (crc << 7); ^ (crc << 7);
/* Combine bits shifted out left hand end */ /* Combine bits shifted out left hand end */
return (crc & 0xfe) ^ ((crc >> 8) & 1); return (crc & 0xfe) ^ ((crc >> 8) & 1);
} }
// Accumulate "dataValue" into the CRC in crcValue. // 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. // Note: This function is copied directly from the BACnet standard.
uint16_t CRC_Calc_Data(uint8_t dataValue, uint16_t crcValue) 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) */ /* Exclusive OR the terms in the table (top down) */
return (crcValue >>8) ^ (crcLow << 8) ^ (crcLow <<3) return (crcValue >> 8) ^ (crcLow << 8) ^ (crcLow << 3)
^ (crcLow <<12) ^ (crcLow >> 4) ^ (crcLow << 12) ^ (crcLow >> 4)
^ (crcLow & 0x0f) ^ ((crcLow & 0x0f) << 7); ^ (crcLow & 0x0f) ^ ((crcLow & 0x0f) << 7);
} }
#ifdef TEST #ifdef TEST
@@ -80,50 +80,50 @@ uint16_t CRC_Calc_Data(uint8_t dataValue, uint16_t crcValue)
#include "bytes.h" #include "bytes.h"
// test from Annex G 1.0 of BACnet Standard // 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 crc = 0xff; // accumulates the crc value
uint8_t frame_crc; // appended to the end of the frame uint8_t frame_crc; // appended to the end of the frame
crc = CRC_Calc_Header(0x00,crc); crc = CRC_Calc_Header(0x00, crc);
ct_test(pTest,crc == 0x55); ct_test(pTest, crc == 0x55);
crc = CRC_Calc_Header(0x10,crc); crc = CRC_Calc_Header(0x10, crc);
ct_test(pTest,crc == 0xC2); ct_test(pTest, crc == 0xC2);
crc = CRC_Calc_Header(0x05,crc); crc = CRC_Calc_Header(0x05, crc);
ct_test(pTest,crc == 0xBC); ct_test(pTest, crc == 0xBC);
crc = CRC_Calc_Header(0x00,crc); crc = CRC_Calc_Header(0x00, crc);
ct_test(pTest,crc == 0x95); ct_test(pTest, crc == 0x95);
crc = CRC_Calc_Header(0x00,crc); crc = CRC_Calc_Header(0x00, crc);
ct_test(pTest,crc == 0x73); ct_test(pTest, crc == 0x73);
// send the ones complement of the CRC in place of // send the ones complement of the CRC in place of
// the CRC, and the resulting CRC will always equal 0x55. // the CRC, and the resulting CRC will always equal 0x55.
frame_crc = ~crc; frame_crc = ~crc;
ct_test(pTest,frame_crc == 0x8C); ct_test(pTest, frame_crc == 0x8C);
// use the ones complement value and the next to last CRC value // use the ones complement value and the next to last CRC value
crc = CRC_Calc_Header(frame_crc,crc); crc = CRC_Calc_Header(frame_crc, crc);
ct_test(pTest,crc == 0x55); ct_test(pTest, crc == 0x55);
} }
// test from Annex G 2.0 of BACnet Standard // test from Annex G 2.0 of BACnet Standard
void testCRC16(Test* pTest) void testCRC16(Test * pTest)
{ {
uint16_t crc = 0xffff; uint16_t crc = 0xffff;
uint16_t data_crc; uint16_t data_crc;
crc = CRC_Calc_Data(0x01,crc); crc = CRC_Calc_Data(0x01, crc);
ct_test(pTest,crc == 0x1E0E); ct_test(pTest, crc == 0x1E0E);
crc = CRC_Calc_Data(0x22,crc); crc = CRC_Calc_Data(0x22, crc);
ct_test(pTest,crc == 0xEB70); ct_test(pTest, crc == 0xEB70);
crc = CRC_Calc_Data(0x30,crc); crc = CRC_Calc_Data(0x30, crc);
ct_test(pTest,crc == 0x42EF); ct_test(pTest, crc == 0x42EF);
// send the ones complement of the CRC in place of // send the ones complement of the CRC in place of
// the CRC, and the resulting CRC will always equal 0xF0B8. // the CRC, and the resulting CRC will always equal 0xF0B8.
data_crc = ~crc; data_crc = ~crc;
ct_test(pTest,data_crc == 0xBD10); ct_test(pTest, data_crc == 0xBD10);
crc = CRC_Calc_Data(LO_BYTE(data_crc),crc); crc = CRC_Calc_Data(LO_BYTE(data_crc), crc);
ct_test(pTest,crc == 0x0F3A); ct_test(pTest, crc == 0x0F3A);
crc = CRC_Calc_Data(HI_BYTE(data_crc),crc); crc = CRC_Calc_Data(HI_BYTE(data_crc), crc);
ct_test(pTest,crc == 0xF0B8); ct_test(pTest, crc == 0xF0B8);
} }
#endif #endif
@@ -131,23 +131,23 @@ void testCRC16(Test* pTest)
#ifdef TEST_CRC #ifdef TEST_CRC
int main(void) int main(void)
{ {
Test *pTest; Test *pTest;
bool rc; bool rc;
pTest = ct_create("crc", NULL); pTest = ct_create("crc", NULL);
/* individual tests */ /* individual tests */
rc = ct_addTestFunction(pTest, testCRC8); rc = ct_addTestFunction(pTest, testCRC8);
assert(rc); assert(rc);
rc = ct_addTestFunction(pTest, testCRC16); rc = ct_addTestFunction(pTest, testCRC16);
assert(rc); assert(rc);
ct_setStream(pTest, stdout); ct_setStream(pTest, stdout);
ct_run(pTest); ct_run(pTest);
(void)ct_report(pTest); (void) ct_report(pTest);
ct_destroy(pTest); ct_destroy(pTest);
return 0; return 0;
} }
#endif #endif
+4 -5
View File
@@ -40,13 +40,12 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
uint8_t CRC_Calc_Header(uint8_t dataValue, uint8_t crcValue); uint8_t CRC_Calc_Header(uint8_t dataValue, uint8_t crcValue);
uint16_t CRC_Calc_Data(uint8_t dataValue, uint16_t crcValue); uint16_t CRC_Calc_Data(uint8_t dataValue, uint16_t crcValue);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+37 -70
View File
@@ -41,121 +41,88 @@
// as part of the calls. // as part of the calls.
/* returns number of bytes sent on success, negative on failure */ /* returns number of bytes sent on success, negative on failure */
int datalink_send_pdu( int datalink_send_pdu(BACNET_ADDRESS * dest, // destination address
BACNET_ADDRESS *dest, // destination address uint8_t * pdu, // any data to be sent - may be null
uint8_t *pdu, // any data to be sent - may be null unsigned pdu_len) // number of bytes of data
unsigned pdu_len) // number of bytes of data
{ {
#ifdef BACDL_ARCNET #ifdef BACDL_ARCNET
return arcnet_send_pdu( return arcnet_send_pdu(dest, pdu, pdu_len);
dest,
pdu,
pdu_len);
#endif #endif
#ifdef BACDL_MSTP #ifdef BACDL_MSTP
return dlmstp_send_pdu( return dlmstp_send_pdu(dest, pdu, pdu_len);
dest,
pdu,
pdu_len);
#endif #endif
#ifdef BACDL_ETHERNET #ifdef BACDL_ETHERNET
return ethernet_send_pdu( return ethernet_send_pdu(dest, pdu, pdu_len);
dest,
pdu,
pdu_len);
#endif #endif
#ifdef BACDL_BIP #ifdef BACDL_BIP
return bip_send_pdu( return bip_send_pdu(dest, pdu, pdu_len);
dest,
pdu,
pdu_len);
#endif #endif
} }
// returns the number of octets in the PDU, or zero on failure // returns the number of octets in the PDU, or zero on failure
uint16_t datalink_receive( uint16_t datalink_receive(BACNET_ADDRESS * src, // source address
BACNET_ADDRESS *src, // source address uint8_t * pdu, // PDU data
uint8_t *pdu, // PDU data uint16_t max_pdu, // amount of space available in the PDU
uint16_t max_pdu, // amount of space available in the PDU unsigned timeout) // number of milliseconds to wait for a packet
unsigned timeout) // number of milliseconds to wait for a packet
{ {
#ifdef BACDL_ARCNET #ifdef BACDL_ARCNET
return arcnet_receive( return arcnet_receive(src, pdu, max_pdu, timeout);
src, #endif
pdu, #ifdef BACDL_MSTP
max_pdu, return dlmstp_receive(src, pdu, max_pdu, timeout);
timeout); #endif
#endif #ifdef BACDL_ETHERNET
#ifdef BACDL_MSTP return ethernet_receive(src, pdu, max_pdu, timeout);
return dlmstp_receive( #endif
src, #ifdef BACDL_BIP
pdu, return bip_receive(src, pdu, max_pdu, timeout);
max_pdu, #endif
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) void datalink_cleanup(void)
{ {
#ifdef BACDL_ETHERNET #ifdef BACDL_ETHERNET
ethernet_cleanup(); ethernet_cleanup();
#endif #endif
#ifdef BACDL_BIP #ifdef BACDL_BIP
bip_cleanup(); bip_cleanup();
#endif #endif
#ifdef BACDL_ARCNET #ifdef BACDL_ARCNET
arcnet_cleanup(); arcnet_cleanup();
#endif #endif
#ifdef BACDL_MSTP #ifdef BACDL_MSTP
dlmstp_cleanup(); dlmstp_cleanup();
#endif #endif
} }
void datalink_get_broadcast_address( void datalink_get_broadcast_address(BACNET_ADDRESS * dest) // destination address
BACNET_ADDRESS *dest) // destination address
{ {
#ifdef BACDL_ARCNET #ifdef BACDL_ARCNET
arcnet_get_broadcast_address(dest); arcnet_get_broadcast_address(dest);
#endif #endif
#ifdef BACDL_MSTP #ifdef BACDL_MSTP
dlmstp_get_broadcast_address(dest); dlmstp_get_broadcast_address(dest);
#endif #endif
#ifdef BACDL_ETHERNET #ifdef BACDL_ETHERNET
ethernet_get_broadcast_address(dest); ethernet_get_broadcast_address(dest);
#endif #endif
#ifdef BACDL_BIP #ifdef BACDL_BIP
bip_get_broadcast_address(dest); bip_get_broadcast_address(dest);
#endif #endif
} }
void datalink_get_my_address( void datalink_get_my_address(BACNET_ADDRESS * my_address)
BACNET_ADDRESS *my_address)
{ {
#ifdef BACDL_ARCNET #ifdef BACDL_ARCNET
arcnet_get_my_address(my_address); arcnet_get_my_address(my_address);
#endif #endif
#ifdef BACDL_MSTP #ifdef BACDL_MSTP
dlmstp_get_my_address(my_address); dlmstp_get_my_address(my_address);
#endif #endif
#ifdef BACDL_ETHERNET #ifdef BACDL_ETHERNET
ethernet_get_my_address(my_address); ethernet_get_my_address(my_address);
#endif #endif
#ifdef BACDL_BIP #ifdef BACDL_BIP
bip_get_my_address(my_address); bip_get_my_address(my_address);
#endif #endif
} }
+12 -17
View File
@@ -57,31 +57,26 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
/* returns number of bytes sent on success, negative on failure */ /* returns number of bytes sent on success, negative on failure */
int datalink_send_pdu( int datalink_send_pdu(BACNET_ADDRESS * dest, // destination address
BACNET_ADDRESS *dest, // destination address uint8_t * pdu, // any data to be sent - may be null
uint8_t *pdu, // any data to be sent - may be null unsigned pdu_len); // number of bytes of data
unsigned pdu_len); // number of bytes of data
// returns the number of octets in the PDU, or zero on failure // returns the number of octets in the PDU, or zero on failure
uint16_t datalink_receive( uint16_t datalink_receive(BACNET_ADDRESS * src, // source address
BACNET_ADDRESS *src, // source address uint8_t * pdu, // PDU data
uint8_t *pdu, // PDU data uint16_t max_pdu, // amount of space available in the PDU
uint16_t max_pdu, // amount of space available in the PDU unsigned timeout); // number of milliseconds to wait for a packet
unsigned timeout); // number of milliseconds to wait for a packet
void datalink_cleanup(void); void datalink_cleanup(void);
void datalink_get_broadcast_address( void datalink_get_broadcast_address(BACNET_ADDRESS * dest); // destination address
BACNET_ADDRESS *dest); // destination address
void datalink_get_my_address( void datalink_get_my_address(BACNET_ADDRESS * my_address);
BACNET_ADDRESS *my_address);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+168 -199
View File
@@ -42,18 +42,18 @@
/* note: time duration is given in Minutes, but in order to be accurate, /* note: time duration is given in Minutes, but in order to be accurate,
we need to count down in seconds. */ we need to count down in seconds. */
static uint32_t DCC_Time_Duration_Seconds = 0; static uint32_t DCC_Time_Duration_Seconds = 0;
static BACNET_COMMUNICATION_ENABLE_DISABLE DCC_Enable_Disable = static BACNET_COMMUNICATION_ENABLE_DISABLE DCC_Enable_Disable =
COMMUNICATION_ENABLE; COMMUNICATION_ENABLE;
/* password is optionally supported */ /* password is optionally supported */
BACNET_COMMUNICATION_ENABLE_DISABLE dcc_enable_status(void) BACNET_COMMUNICATION_ENABLE_DISABLE dcc_enable_status(void)
{ {
return DCC_Enable_Disable; return DCC_Enable_Disable;
} }
bool dcc_communication_enabled(void) bool dcc_communication_enabled(void)
{ {
return (DCC_Enable_Disable == COMMUNICATION_ENABLE); return (DCC_Enable_Disable == COMMUNICATION_ENABLE);
} }
/* When network communications are completely disabled, /* When network communications are completely disabled,
@@ -61,7 +61,7 @@ bool dcc_communication_enabled(void)
shall be processed and no messages shall be initiated.*/ shall be processed and no messages shall be initiated.*/
bool dcc_communication_disabled(void) bool dcc_communication_disabled(void)
{ {
return (DCC_Enable_Disable == COMMUNICATION_DISABLE); return (DCC_Enable_Disable == COMMUNICATION_DISABLE);
} }
/* When the initiation of communications is disabled, /* When the initiation of communications is disabled,
@@ -75,174 +75,159 @@ bool dcc_communication_disabled(void)
the device is included in the address range. */ the device is included in the address range. */
bool dcc_communication_initiation_disabled(void) 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) 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, /* called every second or so. If more than one second,
then seconds should be the number of seconds to tick away */ 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)
{ {
if (DCC_Time_Duration_Seconds) if (DCC_Time_Duration_Seconds) {
{ if (DCC_Time_Duration_Seconds > seconds)
if (DCC_Time_Duration_Seconds > seconds) DCC_Time_Duration_Seconds -= seconds;
DCC_Time_Duration_Seconds -= seconds; else
else DCC_Time_Duration_Seconds = 0;
DCC_Time_Duration_Seconds = 0; /* just expired - do something */
/* just expired - do something */ if (DCC_Time_Duration_Seconds == 0)
if (DCC_Time_Duration_Seconds == 0) DCC_Enable_Disable = COMMUNICATION_ENABLE;
DCC_Enable_Disable = COMMUNICATION_ENABLE; }
}
} }
bool dcc_set_status_duration( bool dcc_set_status_duration(BACNET_COMMUNICATION_ENABLE_DISABLE status,
BACNET_COMMUNICATION_ENABLE_DISABLE status, uint16_t minutes)
uint16_t minutes)
{ {
bool valid = false; bool valid = false;
/* valid? */ /* valid? */
if (status < MAX_BACNET_COMMUNICATION_ENABLE_DISABLE) if (status < MAX_BACNET_COMMUNICATION_ENABLE_DISABLE) {
{ DCC_Enable_Disable = status;
DCC_Enable_Disable = status; if (status == COMMUNICATION_ENABLE)
if (status == COMMUNICATION_ENABLE) DCC_Time_Duration_Seconds = 0;
DCC_Time_Duration_Seconds = 0; else
else DCC_Time_Duration_Seconds = minutes * 60;
DCC_Time_Duration_Seconds = minutes * 60; valid = true;
valid = true; }
}
return valid; return valid;
} }
/* encode service */ /* encode service */
int dcc_encode_apdu( int dcc_encode_apdu(uint8_t * apdu, uint8_t invoke_id, uint16_t timeDuration, /* 0=optional */
uint8_t *apdu, BACNET_COMMUNICATION_ENABLE_DISABLE enable_disable,
uint8_t invoke_id, BACNET_CHARACTER_STRING * password)
uint16_t timeDuration, /* 0=optional */ { /* NULL=optional */
BACNET_COMMUNICATION_ENABLE_DISABLE enable_disable, int len = 0; /* length of each encoding */
BACNET_CHARACTER_STRING *password) /* NULL=optional */ 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) if (apdu) {
{ apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST; apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU);
apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU); apdu[2] = invoke_id;
apdu[2] = invoke_id; apdu[3] = SERVICE_CONFIRMED_REINITIALIZE_DEVICE;
apdu[3] = SERVICE_CONFIRMED_REINITIALIZE_DEVICE; apdu_len = 4;
apdu_len = 4; /* optional timeDuration */
/* optional timeDuration */ if (timeDuration) {
if (timeDuration) len =
{ encode_context_unsigned(&apdu[apdu_len], 0, timeDuration);
len = encode_context_unsigned(&apdu[apdu_len], 0, timeDuration); apdu_len += len;
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 */ /* decode the service request only */
int dcc_decode_service_request( int dcc_decode_service_request(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len,
unsigned apdu_len, uint16_t * timeDuration,
uint16_t *timeDuration, BACNET_COMMUNICATION_ENABLE_DISABLE * enable_disable,
BACNET_COMMUNICATION_ENABLE_DISABLE *enable_disable, BACNET_CHARACTER_STRING * password)
BACNET_CHARACTER_STRING *password)
{ {
unsigned len = 0; unsigned len = 0;
uint8_t tag_number = 0; uint8_t tag_number = 0;
uint32_t len_value_type = 0; uint32_t len_value_type = 0;
int value = 0; int value = 0;
uint32_t value32 = 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);
}
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( int dcc_decode_apdu(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len,
unsigned apdu_len, uint8_t * invoke_id,
uint8_t *invoke_id, uint16_t * timeDuration,
uint16_t *timeDuration, BACNET_COMMUNICATION_ENABLE_DISABLE * enable_disable,
BACNET_COMMUNICATION_ENABLE_DISABLE *enable_disable, BACNET_CHARACTER_STRING * password)
BACNET_CHARACTER_STRING *password)
{ {
int len = 0; int len = 0;
unsigned offset = 0; unsigned offset = 0;
if (!apdu) if (!apdu)
return -1; return -1;
// optional checking - most likely was already done prior to this call // optional checking - most likely was already done prior to this call
if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST) if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
return -1; return -1;
// apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted()); // apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted());
*invoke_id = apdu[2]; /* invoke id - filled in by net layer */ *invoke_id = apdu[2]; /* invoke id - filled in by net layer */
if (apdu[3] != SERVICE_CONFIRMED_REINITIALIZE_DEVICE) if (apdu[3] != SERVICE_CONFIRMED_REINITIALIZE_DEVICE)
return -1; return -1;
offset = 4; offset = 4;
if (apdu_len > offset) if (apdu_len > offset) {
{ len = dcc_decode_service_request(&apdu[offset],
len = dcc_decode_service_request( apdu_len - offset, timeDuration, enable_disable, password);
&apdu[offset], }
apdu_len - offset,
timeDuration,
enable_disable,
password);
}
return len; return len;
} }
#ifdef TEST #ifdef TEST
@@ -250,71 +235,55 @@ int dcc_decode_apdu(
#include <string.h> #include <string.h>
#include "ctest.h" #include "ctest.h"
void test_DeviceCommunicationControlData( void test_DeviceCommunicationControlData(Test * pTest,
Test * pTest, uint8_t invoke_id,
uint8_t invoke_id, uint16_t timeDuration,
uint16_t timeDuration, BACNET_COMMUNICATION_ENABLE_DISABLE enable_disable,
BACNET_COMMUNICATION_ENABLE_DISABLE enable_disable, BACNET_CHARACTER_STRING * password)
BACNET_CHARACTER_STRING *password)
{ {
uint8_t apdu[480] = {0}; uint8_t apdu[480] = { 0 };
int len = 0; int len = 0;
int apdu_len = 0; int apdu_len = 0;
uint8_t test_invoke_id = 0; uint8_t test_invoke_id = 0;
uint16_t test_timeDuration = 0; uint16_t test_timeDuration = 0;
BACNET_COMMUNICATION_ENABLE_DISABLE test_enable_disable; BACNET_COMMUNICATION_ENABLE_DISABLE test_enable_disable;
BACNET_CHARACTER_STRING test_password; 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;
len = dcc_decode_apdu( len = dcc_encode_apdu(&apdu[0],
&apdu[0], invoke_id, timeDuration, enable_disable, password);
apdu_len, ct_test(pTest, len != 0);
&test_invoke_id, apdu_len = len;
&test_timeDuration,
&test_enable_disable, len = dcc_decode_apdu(&apdu[0],
&test_password); apdu_len,
ct_test(pTest, len != -1); &test_invoke_id,
ct_test(pTest, test_invoke_id == invoke_id); &test_timeDuration, &test_enable_disable, &test_password);
ct_test(pTest, test_timeDuration == timeDuration); ct_test(pTest, len != -1);
ct_test(pTest, test_enable_disable == enable_disable); ct_test(pTest, test_invoke_id == invoke_id);
ct_test(pTest, characterstring_same(&test_password,password)); 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) void test_DeviceCommunicationControl(Test * pTest)
{ {
uint8_t invoke_id = 128; uint8_t invoke_id = 128;
uint16_t timeDuration = 0; uint16_t timeDuration = 0;
BACNET_COMMUNICATION_ENABLE_DISABLE enable_disable; BACNET_COMMUNICATION_ENABLE_DISABLE enable_disable;
BACNET_CHARACTER_STRING password; BACNET_CHARACTER_STRING password;
timeDuration = 0; timeDuration = 0;
enable_disable = COMMUNICATION_DISABLE_INITIATION; enable_disable = COMMUNICATION_DISABLE_INITIATION;
characterstring_init_ansi(&password,"John 3:16"); characterstring_init_ansi(&password, "John 3:16");
test_DeviceCommunicationControlData( test_DeviceCommunicationControlData(pTest,
pTest, invoke_id, timeDuration, enable_disable, &password);
invoke_id,
timeDuration,
enable_disable,
&password);
timeDuration = 12345; timeDuration = 12345;
enable_disable = COMMUNICATION_DISABLE; enable_disable = COMMUNICATION_DISABLE;
test_DeviceCommunicationControlData( test_DeviceCommunicationControlData(pTest,
pTest, invoke_id, timeDuration, enable_disable, NULL);
invoke_id,
timeDuration,
enable_disable,
NULL);
return; return;
} }
#ifdef TEST_DEVICE_COMMUNICATION_CONTROL #ifdef TEST_DEVICE_COMMUNICATION_CONTROL
@@ -335,5 +304,5 @@ int main(void)
return 0; return 0;
} }
#endif /* TEST_DEVICE_COMMUNICATION_CONTROL */ #endif /* TEST_DEVICE_COMMUNICATION_CONTROL */
#endif /* TEST */ #endif /* TEST */
+25 -34
View File
@@ -41,55 +41,46 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
/* return the status */ /* return the status */
BACNET_COMMUNICATION_ENABLE_DISABLE dcc_enable_status(void); BACNET_COMMUNICATION_ENABLE_DISABLE dcc_enable_status(void);
bool dcc_communication_enabled(void); bool dcc_communication_enabled(void);
bool dcc_communication_disabled(void); bool dcc_communication_disabled(void);
bool dcc_communication_initiation_disabled(void); bool dcc_communication_initiation_disabled(void);
/* return the time */ /* 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, /* called every second or so. If more than one second,
then seconds should be the number of seconds to tick away */ 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 */ /* setup the communication values */
bool dcc_set_status_duration( bool dcc_set_status_duration(BACNET_COMMUNICATION_ENABLE_DISABLE
BACNET_COMMUNICATION_ENABLE_DISABLE status, status, uint16_t minutes);
uint16_t minutes);
// encode service // encode service
int dcc_encode_apdu( int dcc_encode_apdu(uint8_t * apdu, uint8_t invoke_id, uint16_t timeDuration, /* 0=optional */
uint8_t *apdu, BACNET_COMMUNICATION_ENABLE_DISABLE enable_disable, BACNET_CHARACTER_STRING * password); /* NULL=optional */
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 // decode the service request only
int dcc_decode_service_request( int dcc_decode_service_request(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len,
unsigned apdu_len, uint16_t * timeDuration,
uint16_t *timeDuration, BACNET_COMMUNICATION_ENABLE_DISABLE * enable_disable,
BACNET_COMMUNICATION_ENABLE_DISABLE *enable_disable, BACNET_CHARACTER_STRING * password);
BACNET_CHARACTER_STRING *password);
int dcc_decode_apdu(uint8_t * apdu,
int dcc_decode_apdu( unsigned apdu_len,
uint8_t *apdu, uint8_t * invoke_id,
unsigned apdu_len, uint16_t * timeDuration,
uint8_t *invoke_id, BACNET_COMMUNICATION_ENABLE_DISABLE * enable_disable,
uint16_t *timeDuration, BACNET_CHARACTER_STRING * password);
BACNET_COMMUNICATION_ENABLE_DISABLE *enable_disable,
BACNET_CHARACTER_STRING *password);
#ifdef TEST #ifdef TEST
#include "ctest.h" #include "ctest.h"
void test_DeviceCommunicationControl(Test * pTest); void test_DeviceCommunicationControl(Test * pTest);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+25 -28
View File
@@ -41,55 +41,52 @@
void dlmstp_init(void) void dlmstp_init(void)
{ {
} }
void dlmstp_cleanup(void) void dlmstp_cleanup(void)
{ {
} }
/* returns number of bytes sent on success, negative on failure */ /* returns number of bytes sent on success, negative on failure */
int dlmstp_send_pdu( int dlmstp_send_pdu(BACNET_ADDRESS * dest, // destination address
BACNET_ADDRESS *dest, // destination address uint8_t * pdu, // any data to be sent - may be null
uint8_t *pdu, // any data to be sent - may be null unsigned pdu_len) // number of bytes of data
unsigned pdu_len) // number of bytes of data
{ {
(void)dest; (void) dest;
(void)pdu; (void) pdu;
(void)pdu_len; (void) pdu_len;
return 0; return 0;
} }
// returns the number of octets in the PDU, or zero on failure // returns the number of octets in the PDU, or zero on failure
uint16_t dlmstp_receive( uint16_t dlmstp_receive(BACNET_ADDRESS * src, // source address
BACNET_ADDRESS *src, // source address uint8_t * pdu, // PDU data
uint8_t *pdu, // PDU data uint16_t max_pdu, // amount of space available in the PDU
uint16_t max_pdu, // amount of space available in the PDU unsigned timeout) // milliseconds to wait for a packet
unsigned timeout) // milliseconds to wait for a packet
{ {
(void)src; (void) src;
(void)pdu; (void) pdu;
(void)max_pdu; (void) max_pdu;
(void)timeout; (void) timeout;
return 0; 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( void dlmstp_get_broadcast_address(BACNET_ADDRESS * dest) // destination address
BACNET_ADDRESS *dest) // destination address
{ {
return; return;
} }
+14 -18
View File
@@ -46,31 +46,27 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
void dlmstp_init(void); void dlmstp_init(void);
void dlmstp_cleanup(void); void dlmstp_cleanup(void);
/* returns number of bytes sent on success, negative on failure */ /* returns number of bytes sent on success, negative on failure */
int dlmstp_send_pdu( int dlmstp_send_pdu(BACNET_ADDRESS * dest, // destination address
BACNET_ADDRESS *dest, // destination address uint8_t * pdu, // any data to be sent - may be null
uint8_t *pdu, // any data to be sent - may be null unsigned pdu_len); // number of bytes of data
unsigned pdu_len); // number of bytes of data
// returns the number of octets in the PDU, or zero on failure // returns the number of octets in the PDU, or zero on failure
uint16_t dlmstp_receive( uint16_t dlmstp_receive(BACNET_ADDRESS * src, // source address
BACNET_ADDRESS *src, // source address uint8_t * pdu, // PDU data
uint8_t *pdu, // PDU data uint16_t max_pdu, // amount of space available in the PDU
uint16_t max_pdu, // amount of space available in the PDU unsigned timeout); // milliseconds to wait for a packet
unsigned timeout); // milliseconds to wait for a packet
void dlmstp_set_my_address(BACNET_ADDRESS *my_address); void dlmstp_set_my_address(BACNET_ADDRESS * my_address);
void dlmstp_get_my_address(BACNET_ADDRESS *my_address); void dlmstp_get_my_address(BACNET_ADDRESS * my_address);
void dlmstp_get_broadcast_address( void dlmstp_get_broadcast_address(BACNET_ADDRESS * dest); // destination address
BACNET_ADDRESS *dest); // destination address
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+19 -24
View File
@@ -45,42 +45,37 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
bool ethernet_valid(void); bool ethernet_valid(void);
void ethernet_cleanup(void); void ethernet_cleanup(void);
bool ethernet_init(char *interface_name); bool ethernet_init(char *interface_name);
/* function to send a packet out the 802.2 socket */ /* function to send a packet out the 802.2 socket */
/* returns number of bytes sent on success, negative on failure */ /* returns number of bytes sent on success, negative on failure */
int ethernet_send( int ethernet_send(BACNET_ADDRESS * dest, // destination address
BACNET_ADDRESS *dest, // destination address BACNET_ADDRESS * src, // source address
BACNET_ADDRESS *src, // source address uint8_t * pdu, // any data to be sent - may be null
uint8_t *pdu, // any data to be sent - may be null unsigned pdu_len); // number of bytes of data
unsigned pdu_len); // number of bytes of data
/* function to send a packet out the 802.2 socket */ /* function to send a packet out the 802.2 socket */
/* returns number of bytes sent on success, negative on failure */ /* returns number of bytes sent on success, negative on failure */
int ethernet_send_pdu( int ethernet_send_pdu(BACNET_ADDRESS * dest, // destination address
BACNET_ADDRESS *dest, // destination address uint8_t * pdu, // any data to be sent - may be null
uint8_t *pdu, // any data to be sent - may be null unsigned pdu_len); // number of bytes of data
unsigned pdu_len); // number of bytes of data
// receives an 802.2 framed packet // receives an 802.2 framed packet
// returns the number of octets in the PDU, or zero on failure // returns the number of octets in the PDU, or zero on failure
uint16_t ethernet_receive( uint16_t ethernet_receive(BACNET_ADDRESS * src, // source address
BACNET_ADDRESS *src, // source address uint8_t * pdu, // PDU data
uint8_t *pdu, // PDU data uint16_t max_pdu, // amount of space available in the PDU
uint16_t max_pdu, // amount of space available in the PDU unsigned timeout); // milliseconds to wait for a packet
unsigned timeout); // milliseconds to wait for a packet
void ethernet_set_my_address(BACNET_ADDRESS *my_address); void ethernet_set_my_address(BACNET_ADDRESS * my_address);
void ethernet_get_my_address(BACNET_ADDRESS *my_address); void ethernet_get_my_address(BACNET_ADDRESS * my_address);
void ethernet_get_broadcast_address( void ethernet_get_broadcast_address(BACNET_ADDRESS * dest); // destination address
BACNET_ADDRESS *dest); // destination address
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+39 -41
View File
@@ -36,20 +36,19 @@
char *filename_remove_path(const char *filename_in) char *filename_remove_path(const char *filename_in)
{ {
char *filename_out = NULL; char *filename_out = NULL;
/* allow the device ID to be set */ /* allow the device ID to be set */
if (filename_in) if (filename_in) {
{ filename_out = strrchr(filename_in, '\\');
filename_out = strrchr(filename_in,'\\'); if (!filename_out)
if (!filename_out) filename_out = strrchr(filename_in, '/');
filename_out = strrchr(filename_in,'/'); /* go beyond the slash */
/* go beyond the slash */ if (filename_out)
if (filename_out) filename_out++;
filename_out++; }
}
return filename_out; return filename_out;
} }
#ifdef TEST #ifdef TEST
@@ -58,46 +57,45 @@ char *filename_remove_path(const char *filename_in)
#include "ctest.h" #include "ctest.h"
void testFilename(Test* pTest) void testFilename(Test * pTest)
{ {
char *data1 = "c:\\Joshua\\run"; char *data1 = "c:\\Joshua\\run";
char *data2 = "/home/Anna/run"; char *data2 = "/home/Anna/run";
char *data3 = "c:\\Program Files\\Christopher\\run.exe"; char *data3 = "c:\\Program Files\\Christopher\\run.exe";
char *data4 = "//Mary/data/run"; char *data4 = "//Mary/data/run";
char *filename = NULL; char *filename = NULL;
filename = filename_remove_path(data1); filename = filename_remove_path(data1);
ct_test(pTest,strcmp("run",filename) == 0); ct_test(pTest, strcmp("run", filename) == 0);
filename = filename_remove_path(data2); filename = filename_remove_path(data2);
ct_test(pTest,strcmp("run",filename) == 0); ct_test(pTest, strcmp("run", filename) == 0);
filename = filename_remove_path(data3); filename = filename_remove_path(data3);
ct_test(pTest,strcmp("run.exe",filename) == 0); ct_test(pTest, strcmp("run.exe", filename) == 0);
filename = filename_remove_path(data4); filename = filename_remove_path(data4);
ct_test(pTest,strcmp("run",filename) == 0); ct_test(pTest, strcmp("run", filename) == 0);
return; return;
} }
#ifdef TEST_FILENAME #ifdef TEST_FILENAME
int main(void) int main(void)
{ {
Test *pTest; Test *pTest;
bool rc; bool rc;
pTest = ct_create("filename remove path", NULL); pTest = ct_create("filename remove path", NULL);
/* individual tests */ /* individual tests */
rc = ct_addTestFunction(pTest, testFilename); rc = ct_addTestFunction(pTest, testFilename);
assert(rc); assert(rc);
ct_setStream(pTest, stdout); ct_setStream(pTest, stdout);
ct_run(pTest); ct_run(pTest);
(void)ct_report(pTest); (void) ct_report(pTest);
ct_destroy(pTest); ct_destroy(pTest);
return 0; return 0;
} }
#endif /* TEST_FILENAME */ #endif /* TEST_FILENAME */
#endif /* TEST */ #endif /* TEST */
+3 -4
View File
@@ -36,12 +36,11 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
char *filename_remove_path(const char *filename_in); char *filename_remove_path(const char *filename_in);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+158 -190
View File
@@ -41,162 +41,141 @@
#include "address.h" #include "address.h"
// encode I-Am service // encode I-Am service
int iam_encode_apdu( int iam_encode_apdu(uint8_t * apdu,
uint8_t *apdu, uint32_t device_id,
uint32_t device_id, unsigned max_apdu, int segmentation, uint16_t vendor_id)
unsigned max_apdu,
int segmentation,
uint16_t vendor_id)
{ {
int len = 0; // length of each encoding int len = 0; // length of each encoding
int apdu_len = 0; // total length of the apdu, return value int apdu_len = 0; // total length of the apdu, return value
if (apdu) { if (apdu) {
apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST; apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST;
apdu[1] = SERVICE_UNCONFIRMED_I_AM; // service choice apdu[1] = SERVICE_UNCONFIRMED_I_AM; // service choice
apdu_len = 2; apdu_len = 2;
len = encode_tagged_object_id( len = encode_tagged_object_id(&apdu[apdu_len],
&apdu[apdu_len], OBJECT_DEVICE, device_id);
OBJECT_DEVICE, apdu_len += len;
device_id); len = encode_tagged_unsigned(&apdu[apdu_len], max_apdu);
apdu_len += len; apdu_len += len;
len = encode_tagged_unsigned( len = encode_tagged_enumerated(&apdu[apdu_len], segmentation);
&apdu[apdu_len], apdu_len += len;
max_apdu); len = encode_tagged_unsigned(&apdu[apdu_len], vendor_id);
apdu_len += len; apdu_len += len;
len = encode_tagged_enumerated( }
&apdu[apdu_len],
segmentation); return apdu_len;
apdu_len += len;
len = encode_tagged_unsigned(
&apdu[apdu_len],
vendor_id);
apdu_len += len;
}
return apdu_len;
} }
int iam_decode_service_request( int iam_decode_service_request(uint8_t * apdu,
uint8_t *apdu, uint32_t * pDevice_id,
uint32_t *pDevice_id, unsigned *pMax_apdu, int *pSegmentation, uint16_t * pVendor_id)
unsigned *pMax_apdu,
int *pSegmentation,
uint16_t *pVendor_id)
{ {
int len = 0; int len = 0;
int apdu_len = 0; // total length of the apdu, return value int apdu_len = 0; // total length of the apdu, return value
int object_type = 0; // should be a Device Object int object_type = 0; // should be a Device Object
uint32_t object_instance = 0; uint32_t object_instance = 0;
uint8_t tag_number = 0; uint8_t tag_number = 0;
uint32_t len_value = 0; uint32_t len_value = 0;
uint32_t decoded_value = 0; uint32_t decoded_value = 0;
int decoded_integer = 0; int decoded_integer = 0;
// OBJECT ID - object id // OBJECT ID - object id
len = decode_tag_number_and_value(&apdu[apdu_len], &tag_number, &len_value); len =
apdu_len += len; decode_tag_number_and_value(&apdu[apdu_len], &tag_number,
if (tag_number != BACNET_APPLICATION_TAG_OBJECT_ID) &len_value);
return -1; apdu_len += len;
len = decode_object_id(&apdu[apdu_len], &object_type, &object_instance); if (tag_number != BACNET_APPLICATION_TAG_OBJECT_ID)
apdu_len += len; return -1;
if (object_type != OBJECT_DEVICE) len =
return -1; decode_object_id(&apdu[apdu_len], &object_type, &object_instance);
if (pDevice_id) apdu_len += len;
*pDevice_id = object_instance; if (object_type != OBJECT_DEVICE)
// MAX APDU - unsigned return -1;
len = decode_tag_number_and_value(&apdu[apdu_len], &tag_number, &len_value); if (pDevice_id)
apdu_len += len; *pDevice_id = object_instance;
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT) // MAX APDU - unsigned
return -1; len =
len = decode_unsigned(&apdu[apdu_len], len_value, &decoded_value); decode_tag_number_and_value(&apdu[apdu_len], &tag_number,
apdu_len += len; &len_value);
if (pMax_apdu) apdu_len += len;
*pMax_apdu = decoded_value; if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT)
// Segmentation - enumerated return -1;
len = decode_tag_number_and_value(&apdu[apdu_len], &tag_number, &len_value); len = decode_unsigned(&apdu[apdu_len], len_value, &decoded_value);
apdu_len += len; apdu_len += len;
if (tag_number != BACNET_APPLICATION_TAG_ENUMERATED) if (pMax_apdu)
return -1; *pMax_apdu = decoded_value;
len = decode_enumerated(&apdu[apdu_len],len_value, &decoded_integer); // Segmentation - enumerated
apdu_len += len; len =
if (decoded_integer >= MAX_BACNET_SEGMENTATION) decode_tag_number_and_value(&apdu[apdu_len], &tag_number,
return -1; &len_value);
if (pSegmentation) apdu_len += len;
*pSegmentation = decoded_integer; if (tag_number != BACNET_APPLICATION_TAG_ENUMERATED)
// Vendor ID - unsigned16 return -1;
len = decode_tag_number_and_value(&apdu[apdu_len], &tag_number, &len_value); len = decode_enumerated(&apdu[apdu_len], len_value, &decoded_integer);
apdu_len += len; apdu_len += len;
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT) if (decoded_integer >= MAX_BACNET_SEGMENTATION)
return -1; return -1;
len = decode_unsigned(&apdu[apdu_len], len_value, &decoded_value); if (pSegmentation)
apdu_len += len; *pSegmentation = decoded_integer;
if (decoded_value > 0xFFFF) // Vendor ID - unsigned16
return -1; len =
if (pVendor_id) decode_tag_number_and_value(&apdu[apdu_len], &tag_number,
*pVendor_id = (uint16_t)decoded_value; &len_value);
apdu_len += len;
return apdu_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( int iam_decode_apdu(uint8_t * apdu,
uint8_t *apdu, uint32_t * pDevice_id,
uint32_t *pDevice_id, unsigned *pMax_apdu, int *pSegmentation, uint16_t * pVendor_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? // valid data?
if (!apdu) if (!apdu)
return -1; return -1;
// optional checking - most likely was already done prior to this call // optional checking - most likely was already done prior to this call
if (apdu[0] != PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST) if (apdu[0] != PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST)
return -1; return -1;
if (apdu[1] != SERVICE_UNCONFIRMED_I_AM) if (apdu[1] != SERVICE_UNCONFIRMED_I_AM)
return -1; return -1;
apdu_len = iam_decode_service_request( apdu_len = iam_decode_service_request(&apdu[2],
&apdu[2], pDevice_id, pMax_apdu, pSegmentation, pVendor_id);
pDevice_id,
pMax_apdu, return apdu_len;
pSegmentation,
pVendor_id);
return apdu_len;
} }
int iam_send(uint8_t *buffer) int iam_send(uint8_t * buffer)
{ {
int pdu_len = 0; int pdu_len = 0;
BACNET_ADDRESS dest; BACNET_ADDRESS dest;
int bytes_sent = 0; int bytes_sent = 0;
// I-Am is a global broadcast // I-Am is a global broadcast
datalink_get_broadcast_address(&dest); datalink_get_broadcast_address(&dest);
// encode the NPDU portion of the packet // encode the NPDU portion of the packet
pdu_len = npdu_encode_apdu( pdu_len = npdu_encode_apdu(&buffer[0], &dest, NULL, false, // true for confirmed messages
&buffer[0], MESSAGE_PRIORITY_NORMAL);
&dest,
NULL,
false, // true for confirmed messages
MESSAGE_PRIORITY_NORMAL);
// encode the APDU portion of the packet // encode the APDU portion of the packet
pdu_len += iam_encode_apdu( pdu_len += iam_encode_apdu(&buffer[pdu_len],
&buffer[pdu_len], Device_Object_Instance_Number(),
Device_Object_Instance_Number(), MAX_APDU, SEGMENTATION_NONE, Device_Vendor_Identifier());
MAX_APDU,
SEGMENTATION_NONE,
Device_Vendor_Identifier());
bytes_sent = datalink_send_pdu( bytes_sent = datalink_send_pdu(&dest, // destination address
&dest, // destination address &buffer[0], pdu_len); // number of bytes of data
&buffer[0],
pdu_len); // number of bytes of data return bytes_sent;
return bytes_sent;
} }
#ifdef TEST #ifdef TEST
@@ -206,83 +185,72 @@ int iam_send(uint8_t *buffer)
void testIAm(Test * pTest) void testIAm(Test * pTest)
{ {
uint8_t apdu[480] = {0}; uint8_t apdu[480] = { 0 };
int len = 0; int len = 0;
uint32_t device_id = 42; uint32_t device_id = 42;
unsigned max_apdu = 480; unsigned max_apdu = 480;
int segmentation = SEGMENTATION_NONE; int segmentation = SEGMENTATION_NONE;
uint16_t vendor_id = 42; uint16_t vendor_id = 42;
uint32_t test_device_id = 0; uint32_t test_device_id = 0;
unsigned test_max_apdu = 0; unsigned test_max_apdu = 0;
int test_segmentation = 0; int test_segmentation = 0;
uint16_t test_vendor_id = 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);
len = iam_decode_apdu( len = iam_encode_apdu(&apdu[0],
&apdu[0], device_id, max_apdu, segmentation, vendor_id);
&test_device_id, ct_test(pTest, len != 0);
&test_max_apdu,
&test_segmentation, len = iam_decode_apdu(&apdu[0],
&test_vendor_id); &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, len != -1);
ct_test(pTest, test_vendor_id == vendor_id); ct_test(pTest, test_device_id == device_id);
ct_test(pTest, test_max_apdu == max_apdu); ct_test(pTest, test_vendor_id == vendor_id);
ct_test(pTest, test_segmentation == segmentation); ct_test(pTest, test_max_apdu == max_apdu);
ct_test(pTest, test_segmentation == segmentation);
} }
#ifdef TEST_IAM #ifdef TEST_IAM
// Dummy stubs to eliminate depencies // Dummy stubs to eliminate depencies
void datalink_get_broadcast_address( void datalink_get_broadcast_address(BACNET_ADDRESS * dest) // destination address
BACNET_ADDRESS *dest) // destination address
{ {
(void)dest; (void) dest;
} }
int datalink_send_pdu( int datalink_send_pdu(BACNET_ADDRESS * dest, // destination address
BACNET_ADDRESS *dest, // destination address uint8_t * pdu, // any data to be sent - may be null
uint8_t *pdu, // any data to be sent - may be null unsigned pdu_len) // number of bytes of data
unsigned pdu_len) // number of bytes of data
{ {
(void)dest; (void) dest;
(void)pdu; (void) pdu;
return pdu_len; return pdu_len;
} }
uint16_t Device_Vendor_Identifier(void) uint16_t Device_Vendor_Identifier(void)
{ {
return 0; return 0;
} }
uint32_t Device_Object_Instance_Number(void) uint32_t Device_Object_Instance_Number(void)
{ {
return 0; return 0;
} }
void address_add_binding( void address_add_binding(uint32_t device_id,
uint32_t device_id, unsigned max_apdu, BACNET_ADDRESS * src)
unsigned max_apdu,
BACNET_ADDRESS *src)
{ {
(void)device_id; (void) device_id;
(void)max_apdu; (void) max_apdu;
(void)src; (void) src;
} }
// dummy for apdu dependency // dummy for apdu dependency
void tsm_free_invoke_id(uint8_t invokeID) void tsm_free_invoke_id(uint8_t invokeID)
{ {
// dummy stub for testing // dummy stub for testing
(void)invokeID; (void) invokeID;
} }
+15 -25
View File
@@ -40,38 +40,28 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
int iam_encode_apdu( int iam_encode_apdu(uint8_t * apdu,
uint8_t *apdu, uint32_t device_id,
uint32_t device_id, unsigned max_apdu, int segmentation, uint16_t vendor_id);
unsigned max_apdu,
int segmentation,
uint16_t vendor_id);
int iam_decode_service_request( int iam_decode_service_request(uint8_t * apdu,
uint8_t *apdu, uint32_t * pDevice_id,
uint32_t *pDevice_id, unsigned *pMax_apdu, int *pSegmentation, uint16_t * pVendor_id);
unsigned *pMax_apdu,
int *pSegmentation, int iam_decode_apdu(uint8_t * apdu,
uint16_t *pVendor_id); uint32_t * pDevice_id,
unsigned *pMax_apdu, int *pSegmentation, uint16_t * pVendor_id);
int iam_decode_apdu(
uint8_t *apdu, int iam_send(uint8_t * buffer);
uint32_t *pDevice_id,
unsigned *pMax_apdu,
int *pSegmentation,
uint16_t *pVendor_id);
int iam_send(uint8_t *buffer);
#ifdef TEST #ifdef TEST
#include "ctest.h" #include "ctest.h"
void testIAm(Test * pTest); void testIAm(Test * pTest);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+105 -135
View File
@@ -37,108 +37,92 @@
#include "bacdef.h" #include "bacdef.h"
#include "ihave.h" #include "ihave.h"
int ihave_encode_apdu( int ihave_encode_apdu(uint8_t * apdu, BACNET_I_HAVE_DATA * data)
uint8_t *apdu,
BACNET_I_HAVE_DATA *data)
{ {
int len = 0; /* length of each encoding */ int len = 0; /* length of each encoding */
int apdu_len = 0; /* total length of the apdu, return value */ int apdu_len = 0; /* total length of the apdu, return value */
if (apdu && data) { if (apdu && data) {
apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST; apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST;
apdu[1] = SERVICE_UNCONFIRMED_I_HAVE; apdu[1] = SERVICE_UNCONFIRMED_I_HAVE;
apdu_len = 2; apdu_len = 2;
/* deviceIdentifier */ /* deviceIdentifier */
len = encode_tagged_object_id( len = encode_tagged_object_id(&apdu[apdu_len],
&apdu[apdu_len], data->device_id.type, data->device_id.instance);
data->device_id.type, apdu_len += len;
data->device_id.instance); /* objectIdentifier */
apdu_len += len; len = encode_tagged_object_id(&apdu[apdu_len],
/* objectIdentifier */ data->object_id.type, data->object_id.instance);
len = encode_tagged_object_id( apdu_len += len;
&apdu[apdu_len], /* objectName */
data->object_id.type, len = encode_tagged_character_string(&apdu[apdu_len],
data->object_id.instance); &data->object_name);
apdu_len += len; 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 */ /* decode the service request only */
int ihave_decode_service_request( int ihave_decode_service_request(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, BACNET_I_HAVE_DATA * data)
unsigned apdu_len,
BACNET_I_HAVE_DATA *data)
{ {
int len = 0; int len = 0;
uint8_t tag_number = 0; uint8_t tag_number = 0;
uint32_t len_value = 0; uint32_t len_value = 0;
int decoded_type = 0; /* for decoding */ int decoded_type = 0; /* for decoding */
if (apdu_len && data) if (apdu_len && data) {
{ /* deviceIdentifier */
/* deviceIdentifier */ len +=
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); decode_tag_number_and_value(&apdu[len], &tag_number,
if (tag_number == BACNET_APPLICATION_TAG_OBJECT_ID) &len_value);
{ if (tag_number == BACNET_APPLICATION_TAG_OBJECT_ID) {
len += decode_object_id(&apdu[len], &decoded_type, len += decode_object_id(&apdu[len], &decoded_type,
&data->device_id.instance); &data->device_id.instance);
data->device_id.type = decoded_type; data->device_id.type = decoded_type;
} } else
else return -1;
return -1; /* objectIdentifier */
/* objectIdentifier */ len +=
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); decode_tag_number_and_value(&apdu[len], &tag_number,
if (tag_number == BACNET_APPLICATION_TAG_OBJECT_ID) &len_value);
{ if (tag_number == BACNET_APPLICATION_TAG_OBJECT_ID) {
len += decode_object_id(&apdu[len], &decoded_type, len += decode_object_id(&apdu[len], &decoded_type,
&data->object_id.instance); &data->object_id.instance);
data->object_id.type = decoded_type; data->object_id.type = decoded_type;
} } else
else return -1;
return -1; /* objectName */
/* objectName */ len +=
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); decode_tag_number_and_value(&apdu[len], &tag_number,
if (tag_number == BACNET_APPLICATION_TAG_CHARACTER_STRING) &len_value);
{ if (tag_number == BACNET_APPLICATION_TAG_CHARACTER_STRING) {
len += decode_character_string(&apdu[len], len_value, len += decode_character_string(&apdu[len], len_value,
&data->object_name); &data->object_name);
} } else
else return -1;
return -1; } else
} return -1;
else
return -1;
return len; return len;
} }
int ihave_decode_apdu( int ihave_decode_apdu(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, BACNET_I_HAVE_DATA * data)
unsigned apdu_len,
BACNET_I_HAVE_DATA *data)
{ {
int len = 0; int len = 0;
if (!apdu) if (!apdu)
return -1; return -1;
/* optional checking - most likely was already done prior to this call */ /* optional checking - most likely was already done prior to this call */
if (apdu[0] != PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST) if (apdu[0] != PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST)
return -1; return -1;
if (apdu[1] != SERVICE_UNCONFIRMED_I_HAVE) if (apdu[1] != SERVICE_UNCONFIRMED_I_HAVE)
return -1; return -1;
len = ihave_decode_service_request( len = ihave_decode_service_request(&apdu[2], apdu_len - 2, data);
&apdu[2],
apdu_len - 2,
data);
return len; return len;
} }
#ifdef TEST #ifdef TEST
@@ -146,62 +130,48 @@ int ihave_decode_apdu(
#include <string.h> #include <string.h>
#include "ctest.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}; uint8_t apdu[480] = { 0 };
int len = 0; int len = 0;
int apdu_len = 0; int apdu_len = 0;
BACNET_I_HAVE_DATA test_data; BACNET_I_HAVE_DATA test_data;
len = ihave_encode_apdu( len = ihave_encode_apdu(&apdu[0], data);
&apdu[0], ct_test(pTest, len != 0);
data); apdu_len = len;
ct_test(pTest, len != 0);
apdu_len = len;
len = ihave_decode_apdu( len = ihave_decode_apdu(&apdu[0], apdu_len, &test_data);
&apdu[0], ct_test(pTest, len != -1);
apdu_len, ct_test(pTest, test_data.device_id.type == data->device_id.type);
&test_data); ct_test(pTest, test_data.device_id.instance ==
ct_test(pTest, len != -1); data->device_id.instance);
ct_test(pTest, test_data.device_id.type == ct_test(pTest, test_data.object_id.type == data->object_id.type);
data->device_id.type); ct_test(pTest, test_data.object_id.instance ==
ct_test(pTest, test_data.device_id.instance == data->object_id.instance);
data->device_id.instance); ct_test(pTest, characterstring_same(&test_data.object_name,
ct_test(pTest, test_data.object_id.type == &data->object_name));
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) void testIHave(Test * pTest)
{ {
BACNET_I_HAVE_DATA data; BACNET_I_HAVE_DATA data;
characterstring_init_ansi( characterstring_init_ansi(&data.object_name, "patricia");
&data.object_name,"patricia"); data.device_id.type = OBJECT_DEVICE;
data.device_id.type = OBJECT_DEVICE; for (data.device_id.instance = 1;
for ( data.device_id.instance <= BACNET_MAX_INSTANCE;
data.device_id.instance = 1; data.device_id.instance <<= 1) {
data.device_id.instance <= BACNET_MAX_INSTANCE; for (data.object_id.type = OBJECT_ANALOG_INPUT;
data.device_id.instance <<= 1) data.object_id.type <= MAX_BACNET_OBJECT_TYPE;
{ data.object_id.type++) {
for ( for (data.object_id.instance = 1;
data.object_id.type = OBJECT_ANALOG_INPUT; data.object_id.instance <= BACNET_MAX_INSTANCE;
data.object_id.type <= MAX_BACNET_OBJECT_TYPE; data.object_id.instance <<= 1) {
data.object_id.type++) testIHaveData(pTest, &data);
{ }
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 #ifdef TEST_I_HAVE
+12 -21
View File
@@ -38,39 +38,30 @@
#include <stdbool.h> #include <stdbool.h>
#include "bacstr.h" #include "bacstr.h"
typedef struct BACnet_I_Have_Data typedef struct BACnet_I_Have_Data {
{ BACNET_OBJECT_ID device_id;
BACNET_OBJECT_ID device_id; BACNET_OBJECT_ID object_id;
BACNET_OBJECT_ID object_id; BACNET_CHARACTER_STRING object_name;
BACNET_CHARACTER_STRING object_name;
} BACNET_I_HAVE_DATA; } BACNET_I_HAVE_DATA;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
int ihave_encode_apdu( int ihave_encode_apdu(uint8_t * apdu, BACNET_I_HAVE_DATA * data);
uint8_t *apdu,
BACNET_I_HAVE_DATA *data);
int ihave_decode_service_request( int ihave_decode_service_request(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, BACNET_I_HAVE_DATA * data);
unsigned apdu_len,
BACNET_I_HAVE_DATA *data);
int ihave_decode_apdu( int ihave_decode_apdu(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, BACNET_I_HAVE_DATA * data);
unsigned apdu_len,
BACNET_I_HAVE_DATA *data);
#ifdef TEST #ifdef TEST
#include "ctest.h" #include "ctest.h"
void testIHave(Test * pTest); void testIHave(Test * pTest);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+123 -152
View File
@@ -39,219 +39,190 @@
#define strcasecmp stricmp #define strcasecmp stricmp
#endif #endif
bool indtext_by_string( bool indtext_by_string(INDTEXT_DATA * data_list,
INDTEXT_DATA *data_list, const char *search_name, unsigned *found_index)
const char *search_name,
unsigned *found_index)
{ {
bool found = false; bool found = false;
unsigned index = 0; unsigned index = 0;
if (data_list && search_name) if (data_list && search_name) {
{ while (data_list->pString) {
while (data_list->pString) if (strcmp(data_list->pString, search_name) == 0) {
{ index = data_list->index;
if (strcmp(data_list->pString,search_name) == 0) found = true;
{ break;
index = data_list->index; }
found = true; data_list++;
break; }
}
data_list++;
} }
}
if (found && found_index) if (found && found_index)
*found_index = index; *found_index = index;
return found; return found;
} }
/* case insensitive version */ /* case insensitive version */
bool indtext_by_istring( bool indtext_by_istring(INDTEXT_DATA * data_list,
INDTEXT_DATA *data_list, const char *search_name, unsigned *found_index)
const char *search_name,
unsigned *found_index)
{ {
bool found = false; bool found = false;
unsigned index = 0; unsigned index = 0;
if (data_list && search_name) if (data_list && search_name) {
{ while (data_list->pString) {
while (data_list->pString) if (strcasecmp(data_list->pString, search_name) == 0) {
{ index = data_list->index;
if (strcasecmp(data_list->pString,search_name) == 0) found = true;
{ break;
index = data_list->index; }
found = true; data_list++;
break; }
}
data_list++;
} }
}
if (found && found_index) if (found && found_index)
*found_index = index; *found_index = index;
return found; return found;
} }
unsigned indtext_by_string_default( unsigned indtext_by_string_default(INDTEXT_DATA * data_list,
INDTEXT_DATA *data_list, const char *search_name, unsigned default_index)
const char *search_name,
unsigned default_index)
{ {
unsigned index = 0; unsigned index = 0;
if (!indtext_by_string(data_list,search_name,&index)) if (!indtext_by_string(data_list, search_name, &index))
index = default_index; index = default_index;
return index; return index;
} }
unsigned indtext_by_istring_default( unsigned indtext_by_istring_default(INDTEXT_DATA * data_list,
INDTEXT_DATA *data_list, const char *search_name, unsigned default_index)
const char *search_name,
unsigned default_index)
{ {
unsigned index = 0; unsigned index = 0;
if (!indtext_by_istring(data_list,search_name,&index)) if (!indtext_by_istring(data_list, search_name, &index))
index = default_index; index = default_index;
return index; return index;
} }
const char *indtext_by_index_default( const char *indtext_by_index_default(INDTEXT_DATA * data_list,
INDTEXT_DATA *data_list, unsigned index, const char *default_string)
unsigned index,
const char *default_string)
{ {
const char *pString = NULL; const char *pString = NULL;
if (data_list) if (data_list) {
{ while (data_list->pString) {
while (data_list->pString) if (data_list->index == index) {
{ pString = data_list->pString;
if (data_list->index == index) break;
{ }
pString = data_list->pString; data_list++;
break; }
}
data_list++;
} }
}
return pString?pString:default_string; return pString ? pString : default_string;
} }
const char *indtext_by_index_split_default( const char *indtext_by_index_split_default(INDTEXT_DATA * data_list,
INDTEXT_DATA *data_list, int index,
int index, int split_index,
int split_index, const char *before_split_default_name, const char *default_name)
const char *before_split_default_name,
const char *default_name)
{ {
if (index < split_index) if (index < split_index)
return indtext_by_index_default(data_list, index, before_split_default_name); return indtext_by_index_default(data_list, index,
else before_split_default_name);
return indtext_by_index_default(data_list, index, default_name); else
return indtext_by_index_default(data_list, index, default_name);
}; };
const char *indtext_by_index( const char *indtext_by_index(INDTEXT_DATA * data_list, unsigned index)
INDTEXT_DATA *data_list,
unsigned index)
{ {
return indtext_by_index_default( return indtext_by_index_default(data_list, index, NULL);
data_list,
index,
NULL);
} }
unsigned indtext_count( unsigned indtext_count(INDTEXT_DATA * data_list)
INDTEXT_DATA *data_list)
{ {
unsigned count = 0; /* return value */ unsigned count = 0; /* return value */
if (data_list) if (data_list) {
{ while (data_list->pString) {
while (data_list->pString) count++;
{ data_list++;
count++; }
data_list++;
} }
} return count;
return count;
} }
#ifdef TEST #ifdef TEST
#include <assert.h> #include <assert.h>
#include "ctest.h" #include "ctest.h"
static INDTEXT_DATA data_list[] = static INDTEXT_DATA data_list[] = {
{ {1, "Joshua"},
{1, "Joshua"}, {2, "Mary"},
{2, "Mary"}, {3, "Anna"},
{3, "Anna"}, {4, "Christopher"},
{4, "Christopher"}, {5, "Patricia"},
{5, "Patricia"}, {0, NULL}
{0, NULL}
}; };
void testIndexText(Test* pTest) void testIndexText(Test * pTest)
{ {
unsigned i; /*counter */ unsigned i; /*counter */
const char *pString; const char *pString;
unsigned index; unsigned index;
bool valid; bool valid;
unsigned count = 0; unsigned count = 0;
for (i = 0; i < 10; i++) for (i = 0; i < 10; i++) {
{ pString = indtext_by_index(data_list, i);
pString = indtext_by_index(data_list,i); if (pString) {
if (pString) count++;
{ valid = indtext_by_string(data_list, pString, &index);
count++; ct_test(pTest, valid == true);
valid = indtext_by_string(data_list,pString,&index); ct_test(pTest, index == i);
ct_test(pTest,valid == true); ct_test(pTest, index == indtext_by_string_default(data_list,
ct_test(pTest,index == i); pString, index));
ct_test(pTest,index == indtext_by_string_default(data_list,pString,index)); }
} }
} ct_test(pTest, indtext_count(data_list) == count);
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,"Harry",NULL) == false); ct_test(pTest, indtext_by_string(data_list, NULL, 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_string(NULL,NULL,NULL) == false); ct_test(pTest, indtext_by_index(data_list, 0) == NULL);
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(data_list,10) == NULL); ct_test(pTest, indtext_by_index(NULL, 10) == NULL);
ct_test(pTest,indtext_by_index(NULL,10) == NULL); /* case insensitive versions */
/* 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); 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);
valid = indtext_by_istring(data_list,"ANNA",&index); ct_test(pTest, index == indtext_by_istring_default(data_list, "ANNA",
ct_test(pTest,index == indtext_by_istring_default(data_list,"ANNA",index)); index));
} }
#endif #endif
#ifdef TEST_INDEX_TEXT #ifdef TEST_INDEX_TEXT
int main(void) int main(void)
{ {
Test *pTest; Test *pTest;
bool rc; bool rc;
pTest = ct_create("index text", NULL); pTest = ct_create("index text", NULL);
/* individual tests */ /* individual tests */
rc = ct_addTestFunction(pTest, testIndexText); rc = ct_addTestFunction(pTest, testIndexText);
assert(rc); assert(rc);
ct_setStream(pTest, stdout); ct_setStream(pTest, stdout);
ct_run(pTest); ct_run(pTest);
(void)ct_report(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
View File
@@ -39,74 +39,57 @@
#include <string.h> #include <string.h>
/* index and text pairs */ /* index and text pairs */
typedef struct typedef struct {
{ unsigned index; /* index number that matches the text */
unsigned index; /* index number that matches the text */ const char *pString; /* text pair - use NULL to end the list */
const char *pString; /* text pair - use NULL to end the list */
} INDTEXT_DATA; } INDTEXT_DATA;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
/* Searches for a matching string and returns the index to the string /* Searches for a matching string and returns the index to the string
in the parameter found_index. in the parameter found_index.
If the string is not found, false is returned If the string is not found, false is returned
If the string is found, true is returned and the found_index contains If the string is found, true is returned and the found_index contains
the first index where the string was found. */ the first index where the string was found. */
bool indtext_by_string( bool indtext_by_string(INDTEXT_DATA * data_list,
INDTEXT_DATA *data_list, const char *search_name, unsigned *found_index);
const char *search_name,
unsigned *found_index);
/* case insensitive version */ /* case insensitive version */
bool indtext_by_istring( bool indtext_by_istring(INDTEXT_DATA * data_list,
INDTEXT_DATA *data_list, const char *search_name, unsigned *found_index);
const char *search_name,
unsigned *found_index);
/* Searches for a matching string and returns the index to the string /* Searches for a matching string and returns the index to the string
or the default_index if the string is not found. */ or the default_index if the string is not found. */
unsigned indtext_by_string_default( unsigned indtext_by_string_default(INDTEXT_DATA * data_list,
INDTEXT_DATA *data_list, const char *search_name, unsigned default_index);
const char *search_name,
unsigned default_index);
/* case insensitive version */ /* case insensitive version */
unsigned indtext_by_istring_default( unsigned indtext_by_istring_default(INDTEXT_DATA * data_list,
INDTEXT_DATA *data_list, const char *search_name, unsigned default_index);
const char *search_name,
unsigned default_index);
/* for a given index, return the matching string, /* for a given index, return the matching string,
or NULL if not found */ or NULL if not found */
const char *indtext_by_index( const char *indtext_by_index(INDTEXT_DATA * data_list, unsigned index);
INDTEXT_DATA *data_list,
unsigned index);
/* for a given index, return the matching string, /* for a given index, return the matching string,
or default_name if not found */ or default_name if not found */
const char *indtext_by_index_default( const char *indtext_by_index_default(INDTEXT_DATA * data_list,
INDTEXT_DATA *data_list, unsigned index, const char *default_name);
unsigned index,
const char *default_name);
/* for a given index, return the matching string, /* for a given index, return the matching string,
or default_name if not found. or default_name if not found.
if the index is before the split, if the index is before the split,
the before_split_default_name is used */ the before_split_default_name is used */
const char *indtext_by_index_split_default( const char *indtext_by_index_split_default(INDTEXT_DATA * data_list,
INDTEXT_DATA *data_list, int index,
int index, int split_index,
int split_index, const char *before_split_default_name, const char *default_name);
const char *before_split_default_name,
const char *default_name);
/* returns the number of elements in the list */ /* returns the number of elements in the list */
unsigned indtext_count( unsigned indtext_count(INDTEXT_DATA * data_list);
INDTEXT_DATA *data_list);
#ifdef TEST #ifdef TEST
#include "ctest.h" #include "ctest.h"
void testIndexText(Test* pTest); void testIndexText(Test * pTest);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+15 -16
View File
@@ -43,23 +43,22 @@
int main(void) int main(void)
{ {
struct mstp_port_struct_t mstp_port; // port data struct mstp_port_struct_t mstp_port; // port data
uint8_t my_mac = 0x05; // local MAC address uint8_t my_mac = 0x05; // local MAC address
MSTP_Init(&mstp_port,my_mac); MSTP_Init(&mstp_port, my_mac);
// loop forever // loop forever
for (;;) for (;;) {
{ // input
// input RS485_Check_UART_Data(&mstp_port);
RS485_Check_UART_Data(&mstp_port); MSTP_Receive_Frame_FSM(&mstp_port);
MSTP_Receive_Frame_FSM(&mstp_port); // process
// process
// output // output
MSTP_Master_Node_FSM(&mstp_port); MSTP_Master_Node_FSM(&mstp_port);
} }
return 0; return 0;
} }
+1317 -1435
View File
File diff suppressed because it is too large Load Diff
+124 -126
View File
@@ -66,134 +66,131 @@
#define FRAME_TYPE_PROPRIETARY_MAX 255 #define FRAME_TYPE_PROPRIETARY_MAX 255
// receive FSM states // receive FSM states
typedef enum typedef enum {
{ MSTP_RECEIVE_STATE_IDLE,
MSTP_RECEIVE_STATE_IDLE, MSTP_RECEIVE_STATE_PREAMBLE,
MSTP_RECEIVE_STATE_PREAMBLE, MSTP_RECEIVE_STATE_HEADER,
MSTP_RECEIVE_STATE_HEADER, MSTP_RECEIVE_STATE_HEADER_CRC,
MSTP_RECEIVE_STATE_HEADER_CRC, MSTP_RECEIVE_STATE_DATA,
MSTP_RECEIVE_STATE_DATA, MSTP_RECEIVE_STATE_DATA_CRC
MSTP_RECEIVE_STATE_DATA_CRC
} MSTP_RECEIVE_STATE; } MSTP_RECEIVE_STATE;
// master node FSM states // master node FSM states
typedef enum typedef enum {
{ MSTP_MASTER_STATE_INITIALIZE,
MSTP_MASTER_STATE_INITIALIZE, MSTP_MASTER_STATE_IDLE,
MSTP_MASTER_STATE_IDLE, MSTP_MASTER_STATE_USE_TOKEN,
MSTP_MASTER_STATE_USE_TOKEN, MSTP_MASTER_STATE_WAIT_FOR_REPLY,
MSTP_MASTER_STATE_WAIT_FOR_REPLY, MSTP_MASTER_STATE_DONE_WITH_TOKEN,
MSTP_MASTER_STATE_DONE_WITH_TOKEN, MSTP_MASTER_STATE_PASS_TOKEN,
MSTP_MASTER_STATE_PASS_TOKEN, MSTP_MASTER_STATE_NO_TOKEN,
MSTP_MASTER_STATE_NO_TOKEN, MSTP_MASTER_STATE_POLL_FOR_MASTER,
MSTP_MASTER_STATE_POLL_FOR_MASTER, MSTP_MASTER_STATE_ANSWER_DATA_REQUEST
MSTP_MASTER_STATE_ANSWER_DATA_REQUEST
} MSTP_MASTER_STATE; } MSTP_MASTER_STATE;
struct mstp_port_struct_t struct mstp_port_struct_t {
{ MSTP_RECEIVE_STATE receive_state;
MSTP_RECEIVE_STATE receive_state; // When a master node is powered up or reset,
// When a master node is powered up or reset, // it shall unconditionally enter the INITIALIZE state.
// it shall unconditionally enter the INITIALIZE state. MSTP_MASTER_STATE master_state;
MSTP_MASTER_STATE master_state; // A Boolean flag set to TRUE by the Receive State Machine
// A Boolean flag set to TRUE by the Receive State Machine // if an error is detected during the reception of a frame.
// if an error is detected during the reception of a frame. // Set to FALSE by the main state machine.
// Set to FALSE by the main state machine. unsigned ReceiveError:1;
unsigned ReceiveError:1; // There is data in the buffer
// There is data in the buffer unsigned DataAvailable:1;
unsigned DataAvailable:1; unsigned FramingError:1; // TRUE if we got a framing error
unsigned FramingError:1; // TRUE if we got a framing error unsigned ReceivedInvalidFrame:1;
unsigned ReceivedInvalidFrame:1; // A Boolean flag set to TRUE by the Receive State Machine
// A Boolean flag set to TRUE by the Receive State Machine // if a valid frame is received.
// if a valid frame is received. // Set to FALSE by the main state machine.
// Set to FALSE by the main state machine. unsigned ReceivedValidFrame:1;
unsigned ReceivedValidFrame:1; // A Boolean flag set to TRUE by the master machine if this node is the
// A Boolean flag set to TRUE by the master machine if this node is the // only known master node.
// only known master node. unsigned SoleMaster:1;
unsigned SoleMaster:1; // After receiving a frame this value will be TRUE until Tturnaround
// After receiving a frame this value will be TRUE until Tturnaround // has expired
// has expired unsigned Turn_Around_Waiting:1;
unsigned Turn_Around_Waiting:1; // stores the latest received data
// stores the latest received data uint8_t DataRegister;
uint8_t DataRegister; // Used to accumulate the CRC on the data field of a frame.
// Used to accumulate the CRC on the data field of a frame. uint16_t DataCRC;
uint16_t DataCRC; // Used to store the data length of a received frame.
// Used to store the data length of a received frame. unsigned DataLength;
unsigned DataLength; // Used to store the destination address of a received frame.
// Used to store the destination address of a received frame. uint8_t DestinationAddress;
uint8_t DestinationAddress; // Used to count the number of received octets or errors.
// Used to count the number of received octets or errors. // This is used in the detection of link activity.
// This is used in the detection of link activity. unsigned EventCount;
unsigned EventCount; // Used to store the frame type of a received frame.
// Used to store the frame type of a received frame. uint8_t FrameType;
uint8_t FrameType; // The number of frames sent by this node during a single token hold.
// 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
// When this counter reaches the value Nmax_info_frames, the node must // pass the token.
// pass the token. unsigned FrameCount;
unsigned FrameCount; // Used to accumulate the CRC on the header of a frame.
// Used to accumulate the CRC on the header of a frame. uint8_t HeaderCRC;
uint8_t HeaderCRC; // Used as an index by the Receive State Machine, up to a maximum value of
// Used as an index by the Receive State Machine, up to a maximum value of // InputBufferSize.
// InputBufferSize. unsigned Index;
unsigned Index; // An array of octets, used to store octets as they are received.
// An array of octets, used to store octets as they are received. // InputBuffer is indexed from 0 to InputBufferSize-1.
// InputBuffer is indexed from 0 to InputBufferSize-1. // The maximum size of a frame is 501 octets.
// The maximum size of a frame is 501 octets. uint8_t InputBuffer[MAX_MPDU];
uint8_t InputBuffer[MAX_MPDU]; // "Next Station," the MAC address of the node to which This Station passes
// "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
// the token. If the Next_Station is unknown, Next_Station shall be equal to // This_Station.
// This_Station. uint8_t Next_Station;
uint8_t Next_Station; // "Poll Station," the MAC address of the node to which This Station last
// "Poll Station," the MAC address of the node to which This Station last // sent a Poll For Master. This is used during token maintenance.
// sent a Poll For Master. This is used during token maintenance. uint8_t Poll_Station;
uint8_t Poll_Station; // A counter of transmission retries used for Token and Poll For Master
// A counter of transmission retries used for Token and Poll For Master // transmission.
// transmission. unsigned RetryCount;
unsigned RetryCount; // A timer with nominal 5 millisecond resolution used to measure and
// A timer with nominal 5 millisecond resolution used to measure and // generate silence on the medium between octets. It is incremented by a
// generate silence on the medium between octets. It is incremented by a // timer process and is cleared by the Receive State Machine when activity
// timer process and is cleared by the Receive State Machine when activity // is detected and by the SendFrame procedure as each octet is transmitted.
// is detected and by the SendFrame procedure as each octet is transmitted. // Since the timer resolution is limited and the timer is not necessarily
// Since the timer resolution is limited and the timer is not necessarily // synchronized to other machine events, a timer value of N will actually
// synchronized to other machine events, a timer value of N will actually // denote intervals between N-1 and N
// denote intervals between N-1 and N unsigned SilenceTimer;
unsigned SilenceTimer;
// A timer used to measure and generate Reply Postponed frames. It is // 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 // incremented by a timer process and is cleared by the Master Node State
// Machine when a Data Expecting Reply Answer activity is completed. // Machine when a Data Expecting Reply Answer activity is completed.
unsigned ReplyPostponedTimer; unsigned ReplyPostponedTimer;
// Used to store the Source Address of a received frame. // Used to store the Source Address of a received frame.
uint8_t SourceAddress; uint8_t SourceAddress;
// The number of tokens received by this node. When this counter reaches the // 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 // 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 // additional master nodes. TokenCount is set to zero at the end of the
// polling process. // polling process.
unsigned TokenCount; unsigned TokenCount;
// "This Station," the MAC address of this node. TS is generally read from a // "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 // 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 // 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. // destination address but is not allowed as a value for TS.
uint8_t This_Station; uint8_t This_Station;
// This parameter represents the value of the Max_Info_Frames property of // 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 // 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 // maximum number of information frames the node may send before it must
// pass the token. Max_Info_Frames may have different values on different // 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 // 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 // bandwidth to particular nodes. If Max_Info_Frames is not writable in a
// node, its value shall be 1. // node, its value shall be 1.
unsigned Nmax_info_frames; unsigned Nmax_info_frames;
// This parameter represents the value of the Max_Master property of the // This parameter represents the value of the Max_Master property of the
// node's Device object. The value of Max_Master specifies the highest // node's Device object. The value of Max_Master specifies the highest
// allowable address for master nodes. The value of Max_Master shall be // 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, // less than or equal to 127. If Max_Master is not writable in a node,
// its value shall be 127. // its value shall be 127.
unsigned Nmax_master; unsigned Nmax_master;
}; };
#define DEFAULT_MAX_INFO_FRAMES 1 #define DEFAULT_MAX_INFO_FRAMES 1
@@ -206,17 +203,18 @@ struct mstp_port_struct_t
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
void MSTP_Init( void MSTP_Init(volatile struct mstp_port_struct_t *mstp_port,
volatile struct mstp_port_struct_t *mstp_port, uint8_t this_station_mac);
uint8_t this_station_mac); void MSTP_Millisecond_Timer(volatile struct mstp_port_struct_t
void MSTP_Millisecond_Timer(volatile struct mstp_port_struct_t *mstp_port); *mstp_port);
void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port); void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t
void MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port); *mstp_port);
void MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t
*mstp_port);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+340 -409
View File
@@ -40,299 +40,256 @@
#include "npdu.h" #include "npdu.h"
#include "apdu.h" #include "apdu.h"
int npdu_encode_raw( int npdu_encode_raw(uint8_t * npdu,
uint8_t *npdu, BACNET_ADDRESS * dest,
BACNET_ADDRESS *dest, BACNET_ADDRESS * src, BACNET_NPDU_DATA * npdu_data)
BACNET_ADDRESS *src,
BACNET_NPDU_DATA *npdu_data)
{ {
int len = 0; // return value - number of octets loaded in this function int len = 0; // return value - number of octets loaded in this function
int i = 0; // counter int i = 0; // counter
if (npdu && npdu_data) if (npdu && npdu_data) {
{ // Protocol Version
// Protocol Version npdu[0] = 1;
npdu[0] = 1; // control octet
// control octet npdu[1] = 0;
npdu[1] = 0; // Bit 7: 1 indicates that the NSDU conveys a network layer message.
// Bit 7: 1 indicates that the NSDU conveys a network layer message. // Message Type field is present.
// Message Type field is present. // 0 indicates that the NSDU contains a BACnet APDU.
// 0 indicates that the NSDU contains a BACnet APDU. // Message Type field is absent.
// Message Type field is absent. if (npdu_data->network_layer_message)
if (npdu_data->network_layer_message) npdu[1] |= BIT7;
npdu[1] |= BIT7; //Bit 6: Reserved. Shall be zero.
//Bit 6: Reserved. Shall be zero. //Bit 5: Destination specifier where:
//Bit 5: Destination specifier where: // 0 = DNET, DLEN, DADR, and Hop Count absent
// 0 = DNET, DLEN, DADR, and Hop Count absent // 1 = DNET, DLEN, and Hop Count present
// 1 = DNET, DLEN, and Hop Count present // DLEN = 0 denotes broadcast MAC DADR and DADR field is absent
// DLEN = 0 denotes broadcast MAC DADR and DADR field is absent // DLEN > 0 specifies length of DADR field
// DLEN > 0 specifies length of DADR field if (dest && dest->net)
if (dest && dest->net) npdu[1] |= BIT5;
npdu[1] |= BIT5; // Bit 4: Reserved. Shall be zero.
// Bit 4: Reserved. Shall be zero. // Bit 3: Source specifier where:
// Bit 3: Source specifier where: // 0 = SNET, SLEN, and SADR absent
// 0 = SNET, SLEN, and SADR absent // 1 = SNET, SLEN, and SADR present
// 1 = SNET, SLEN, and SADR present // SLEN = 0 Invalid
// SLEN = 0 Invalid // SLEN > 0 specifies length of SADR field
// SLEN > 0 specifies length of SADR field if (src && src->net)
if (src && src->net) npdu[1] |= BIT3;
npdu[1] |= BIT3; // Bit 2: The value of this bit corresponds to the data_expecting_reply
// Bit 2: The value of this bit corresponds to the data_expecting_reply // parameter in the N-UNITDATA primitives.
// parameter in the N-UNITDATA primitives. // 1 indicates that a BACnet-Confirmed-Request-PDU,
// 1 indicates that a BACnet-Confirmed-Request-PDU, // a segment of a BACnet-ComplexACK-PDU,
// a segment of a BACnet-ComplexACK-PDU, // or a network layer message expecting a reply is present.
// or a network layer message expecting a reply is present. // 0 indicates that other than a BACnet-Confirmed-Request-PDU,
// 0 indicates that other than a BACnet-Confirmed-Request-PDU, // a segment of a BACnet-ComplexACK-PDU,
// a segment of a BACnet-ComplexACK-PDU, // or a network layer message expecting a reply is present.
// or a network layer message expecting a reply is present. if (npdu_data->data_expecting_reply)
if (npdu_data->data_expecting_reply) npdu[1] |= BIT2;
npdu[1] |= BIT2; // Bits 1,0: Network priority where:
// Bits 1,0: Network priority where: // B'11' = Life Safety message
// B'11' = Life Safety message // B'10' = Critical Equipment message
// B'10' = Critical Equipment message // B'01' = Urgent message
// B'01' = Urgent message // B'00' = Normal message
// B'00' = Normal message npdu[1] |= (npdu_data->priority & 0x03);
npdu[1] |= (npdu_data->priority & 0x03); len = 2;
len = 2; if (dest && dest->net) {
if (dest && dest->net) len += encode_unsigned16(&npdu[len], dest->net);
{ npdu[len++] = dest->len;
len += encode_unsigned16(&npdu[len], dest->net); // DLEN = 0 denotes broadcast MAC DADR and DADR field is absent
npdu[len++] = dest->len; // DLEN > 0 specifies length of DADR field
// DLEN = 0 denotes broadcast MAC DADR and DADR field is absent if (dest->len) {
// DLEN > 0 specifies length of DADR field for (i = 0; i < dest->len; i++) {
if (dest->len) npdu[len++] = dest->adr[i];
{ }
for (i = 0; i < dest->len; i++) }
{
npdu[len++] = dest->adr[i];
} }
} if (src && src->net) {
} len += encode_unsigned16(&npdu[len], src->net);
if (src && src->net) npdu[len++] = src->len;
{ // SLEN = 0 denotes broadcast MAC SADR and SADR field is absent
len += encode_unsigned16(&npdu[len], src->net); // SLEN > 0 specifies length of SADR field
npdu[len++] = src->len; if (src->len) {
// SLEN = 0 denotes broadcast MAC SADR and SADR field is absent for (i = 0; i < src->len; i++) {
// SLEN > 0 specifies length of SADR field npdu[len++] = src->adr[i];
if (src->len) }
{ }
for (i = 0; i < src->len; i++) }
{ // The Hop Count field shall be present only if the message is
npdu[len++] = src->adr[i]; // 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 // encode the NPDU portion of the packet for an APDU
// This function does not handle the network messages, just APDUs. // This function does not handle the network messages, just APDUs.
int npdu_encode_apdu( int npdu_encode_apdu(uint8_t * npdu, BACNET_ADDRESS * dest, BACNET_ADDRESS * src, bool data_expecting_reply, // true for confirmed messages
uint8_t *npdu, BACNET_MESSAGE_PRIORITY priority)
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.data_expecting_reply = data_expecting_reply;
npdu_data.network_layer_message = false; // false if APDU npdu_data.network_layer_message = false; // false if APDU
npdu_data.network_message_type = 0; // optional npdu_data.network_message_type = 0; // optional
npdu_data.vendor_id = 0; // optional, if net message type is > 0x80 npdu_data.vendor_id = 0; // optional, if net message type is > 0x80
npdu_data.priority = priority; npdu_data.priority = priority;
// call the real function... // call the real function...
return npdu_encode_raw( return npdu_encode_raw(npdu, dest, src, &npdu_data);
npdu,
dest,
src,
&npdu_data);
} }
int npdu_decode( int npdu_decode(uint8_t * npdu,
uint8_t *npdu, BACNET_ADDRESS * dest,
BACNET_ADDRESS *dest, BACNET_ADDRESS * src, BACNET_NPDU_DATA * npdu_data)
BACNET_ADDRESS *src,
BACNET_NPDU_DATA *npdu_data)
{ {
int len = 0; // return value - number of octets loaded in this function int len = 0; // return value - number of octets loaded in this function
int i = 0; // counter int i = 0; // counter
uint16_t src_net = 0; uint16_t src_net = 0;
uint16_t dest_net = 0; uint16_t dest_net = 0;
uint8_t address_len = 0; uint8_t address_len = 0;
uint8_t mac_octet = 0; uint8_t mac_octet = 0;
if (npdu && npdu_data) if (npdu && npdu_data) {
{ // Protocol Version
// Protocol Version npdu_data->protocol_version = npdu[0];
npdu_data->protocol_version = npdu[0]; // control octet
// control octet // Bit 7: 1 indicates that the NSDU conveys a network layer message.
// Bit 7: 1 indicates that the NSDU conveys a network layer message. // Message Type field is present.
// Message Type field is present. // 0 indicates that the NSDU contains a BACnet APDU.
// 0 indicates that the NSDU contains a BACnet APDU. // Message Type field is absent.
// Message Type field is absent. npdu_data->network_layer_message = (npdu[1] & BIT7) ? true : false;
npdu_data->network_layer_message = (npdu[1] & BIT7) ? true : false; //Bit 6: Reserved. Shall be zero.
//Bit 6: Reserved. Shall be zero. // Bit 4: Reserved. Shall be zero.
// Bit 4: Reserved. Shall be zero. // Bit 2: The value of this bit corresponds to the data_expecting_reply
// Bit 2: The value of this bit corresponds to the data_expecting_reply // parameter in the N-UNITDATA primitives.
// parameter in the N-UNITDATA primitives. // 1 indicates that a BACnet-Confirmed-Request-PDU,
// 1 indicates that a BACnet-Confirmed-Request-PDU, // a segment of a BACnet-ComplexACK-PDU,
// a segment of a BACnet-ComplexACK-PDU, // or a network layer message expecting a reply is present.
// or a network layer message expecting a reply is present. // 0 indicates that other than a BACnet-Confirmed-Request-PDU,
// 0 indicates that other than a BACnet-Confirmed-Request-PDU, // a segment of a BACnet-ComplexACK-PDU,
// a segment of a BACnet-ComplexACK-PDU, // or a network layer message expecting a reply is present.
// or a network layer message expecting a reply is present. npdu_data->data_expecting_reply = (npdu[1] & BIT2) ? true : false;
npdu_data->data_expecting_reply = (npdu[1] & BIT2) ? true : false; // Bits 1,0: Network priority where:
// Bits 1,0: Network priority where: // B'11' = Life Safety message
// B'11' = Life Safety message // B'10' = Critical Equipment message
// B'10' = Critical Equipment message // B'01' = Urgent message
// B'01' = Urgent message // B'00' = Normal message
// B'00' = Normal message npdu_data->priority = npdu[1] & 0x03;
npdu_data->priority = npdu[1] & 0x03; // set the offset to where the optional stuff starts
// set the offset to where the optional stuff starts len = 2;
len = 2; //Bit 5: Destination specifier where:
//Bit 5: Destination specifier where: // 0 = DNET, DLEN, DADR, and Hop Count absent
// 0 = DNET, DLEN, DADR, and Hop Count absent // 1 = DNET, DLEN, and Hop Count present
// 1 = DNET, DLEN, and Hop Count present // DLEN = 0 denotes broadcast MAC DADR and DADR field is absent
// DLEN = 0 denotes broadcast MAC DADR and DADR field is absent // DLEN > 0 specifies length of DADR field
// DLEN > 0 specifies length of DADR field if (npdu[1] & BIT5) {
if (npdu[1] & BIT5) len += decode_unsigned16(&npdu[len], &dest_net);
{ // DLEN = 0 denotes broadcast MAC DADR and DADR field is absent
len += decode_unsigned16(&npdu[len], &dest_net); // DLEN > 0 specifies length of DADR field
// DLEN = 0 denotes broadcast MAC DADR and DADR field is absent address_len = npdu[len++];
// DLEN > 0 specifies length of DADR field if (dest) {
address_len = npdu[len++]; dest->net = dest_net;
if (dest) dest->len = address_len;
{ }
dest->net = dest_net; if (address_len) {
dest->len = address_len; for (i = 0; i < address_len; i++) {
} mac_octet = npdu[len++];
if (address_len) if (dest)
{ dest->adr[i] = mac_octet;
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) {
// zero out the destination address dest->net = 0;
else if (dest) dest->len = 0;
{ for (i = 0; i < MAX_MAC_LEN; i++) {
dest->net = 0; dest->adr[i] = 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;
} }
} // 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( void npdu_handler(BACNET_ADDRESS * src, // source address
BACNET_ADDRESS *src, // source address uint8_t * pdu, // PDU data
uint8_t *pdu, // PDU data uint16_t pdu_len) // length PDU
uint16_t pdu_len) // length PDU
{ {
int apdu_offset = 0; int apdu_offset = 0;
BACNET_ADDRESS dest = {0}; BACNET_ADDRESS dest = { 0 };
BACNET_NPDU_DATA npdu_data = {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);
}
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) void testNPDU2(Test * pTest)
{ {
uint8_t pdu[480] = {0}; uint8_t pdu[480] = { 0 };
BACNET_ADDRESS dest = {0}; BACNET_ADDRESS dest = { 0 };
BACNET_ADDRESS src = {0}; BACNET_ADDRESS src = { 0 };
BACNET_ADDRESS npdu_dest = {0}; BACNET_ADDRESS npdu_dest = { 0 };
BACNET_ADDRESS npdu_src = {0}; BACNET_ADDRESS npdu_src = { 0 };
int len = 0; int len = 0;
bool data_expecting_reply = false; // true for confirmed messages bool data_expecting_reply = false; // true for confirmed messages
BACNET_MESSAGE_PRIORITY priority = MESSAGE_PRIORITY_NORMAL; BACNET_MESSAGE_PRIORITY priority = MESSAGE_PRIORITY_NORMAL;
BACNET_NPDU_DATA npdu_data = {0}; BACNET_NPDU_DATA npdu_data = { 0 };
int i = 0; // counter int i = 0; // counter
int npdu_len = 0; int npdu_len = 0;
bool network_layer_message = false; // false if APDU bool network_layer_message = false; // false if APDU
BACNET_NETWORK_MESSAGE_TYPE network_message_type = 0;// optional BACNET_NETWORK_MESSAGE_TYPE network_message_type = 0; // optional
uint16_t vendor_id = 0; // optional, if net message type is > 0x80 uint16_t vendor_id = 0; // optional, if net message type is > 0x80
// mac_len = 0 if global address // mac_len = 0 if global address
dest.mac_len = 6; dest.mac_len = 6;
for (i = 0; i < dest.mac_len; i++) for (i = 0; i < dest.mac_len; i++) {
{ dest.mac[i] = i;
dest.mac[i] = i; }
} // DNET,DLEN,DADR
// DNET,DLEN,DADR dest.net = 1;
dest.net = 1; dest.len = 6;
dest.len = 6; for (i = 0; i < dest.len; i++) {
for (i = 0; i < dest.len; i++) dest.adr[i] = i * 10;
{ }
dest.adr[i] = i * 10; src.mac_len = 1;
} for (i = 0; i < src.mac_len; i++) {
src.mac_len = 1; src.mac[i] = 0x80;
for (i = 0; i < src.mac_len; i++) }
{ // SNET,SLEN,SADR
src.mac[i] = 0x80; src.net = 2;
} src.len = 1;
// SNET,SLEN,SADR for (i = 0; i < src.len; i++) {
src.net = 2; src.adr[i] = 0x40;
src.len = 1; }
for (i = 0; i < src.len; i++) len = npdu_encode_apdu(&pdu[0],
{ &dest, &src, data_expecting_reply, priority);
src.adr[i] = 0x40; ct_test(pTest, len != 0);
} // can we get the info back?
len = npdu_encode_apdu( npdu_len = npdu_decode(&pdu[0], &npdu_dest, &npdu_src, &npdu_data);
&pdu[0], ct_test(pTest, npdu_len != 0);
&dest, ct_test(pTest, npdu_data.data_expecting_reply == data_expecting_reply);
&src, ct_test(pTest,
data_expecting_reply, npdu_data.network_layer_message == network_layer_message);
priority); ct_test(pTest, npdu_data.network_message_type == network_message_type);
ct_test(pTest, len != 0); ct_test(pTest, npdu_data.vendor_id == vendor_id);
// can we get the info back? ct_test(pTest, npdu_data.priority == priority);
npdu_len = npdu_decode( // DNET,DLEN,DADR
&pdu[0], ct_test(pTest, npdu_dest.net == dest.net);
&npdu_dest, ct_test(pTest, npdu_dest.len == dest.len);
&npdu_src, for (i = 0; i < dest.len; i++) {
&npdu_data); ct_test(pTest, npdu_dest.adr[i] == dest.adr[i]);
ct_test(pTest, npdu_len != 0); }
ct_test(pTest, npdu_data.data_expecting_reply == data_expecting_reply); // SNET,SLEN,SADR
ct_test(pTest, npdu_data.network_layer_message == network_layer_message); ct_test(pTest, npdu_src.net == src.net);
ct_test(pTest, npdu_data.network_message_type == network_message_type); ct_test(pTest, npdu_src.len == src.len);
ct_test(pTest, npdu_data.vendor_id == vendor_id); for (i = 0; i < src.len; i++) {
ct_test(pTest, npdu_data.priority == priority); ct_test(pTest, npdu_src.adr[i] == src.adr[i]);
// 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) void testNPDU1(Test * pTest)
{ {
uint8_t pdu[480] = {0}; uint8_t pdu[480] = { 0 };
BACNET_ADDRESS dest = {0}; BACNET_ADDRESS dest = { 0 };
BACNET_ADDRESS src = {0}; BACNET_ADDRESS src = { 0 };
BACNET_ADDRESS npdu_dest = {0}; BACNET_ADDRESS npdu_dest = { 0 };
BACNET_ADDRESS npdu_src = {0}; BACNET_ADDRESS npdu_src = { 0 };
int len = 0; int len = 0;
bool data_expecting_reply = false; // true for confirmed messages bool data_expecting_reply = false; // true for confirmed messages
BACNET_MESSAGE_PRIORITY priority = MESSAGE_PRIORITY_NORMAL; BACNET_MESSAGE_PRIORITY priority = MESSAGE_PRIORITY_NORMAL;
BACNET_NPDU_DATA npdu_data = {0}; BACNET_NPDU_DATA npdu_data = { 0 };
int i = 0; // counter int i = 0; // counter
int npdu_len = 0; int npdu_len = 0;
bool network_layer_message = false; // false if APDU bool network_layer_message = false; // false if APDU
BACNET_NETWORK_MESSAGE_TYPE network_message_type = 0;// optional BACNET_NETWORK_MESSAGE_TYPE network_message_type = 0; // optional
uint16_t vendor_id = 0; // optional, if net message type is > 0x80 uint16_t vendor_id = 0; // optional, if net message type is > 0x80
// mac_len = 0 if global address // mac_len = 0 if global address
dest.mac_len = 0; dest.mac_len = 0;
for (i = 0; i < MAX_MAC_LEN; i++) for (i = 0; i < MAX_MAC_LEN; i++) {
{ dest.mac[i] = 0;
dest.mac[i] = 0; }
} // DNET,DLEN,DADR
// DNET,DLEN,DADR dest.net = 0;
dest.net = 0; dest.len = 0;
dest.len = 0; for (i = 0; i < MAX_MAC_LEN; i++) {
for (i = 0; i < MAX_MAC_LEN; i++) dest.adr[i] = 0;
{ }
dest.adr[i] = 0; src.mac_len = 0;
} for (i = 0; i < MAX_MAC_LEN; i++) {
src.mac_len = 0; src.mac[i] = 0;
for (i = 0; i < MAX_MAC_LEN; i++) }
{ // SNET,SLEN,SADR
src.mac[i] = 0; src.net = 0;
} src.len = 0;
// SNET,SLEN,SADR for (i = 0; i < MAX_MAC_LEN; i++) {
src.net = 0; src.adr[i] = 0;
src.len = 0; }
for (i = 0; i < MAX_MAC_LEN; i++) len = npdu_encode_apdu(&pdu[0],
{ &dest, &src, data_expecting_reply, priority);
src.adr[i] = 0; ct_test(pTest, len != 0);
} // can we get the info back?
len = npdu_encode_apdu( npdu_len = npdu_decode(&pdu[0], &npdu_dest, &npdu_src, &npdu_data);
&pdu[0], ct_test(pTest, npdu_len != 0);
&dest, ct_test(pTest, npdu_data.data_expecting_reply == data_expecting_reply);
&src, ct_test(pTest,
data_expecting_reply, npdu_data.network_layer_message == network_layer_message);
priority); ct_test(pTest, npdu_data.network_message_type == network_message_type);
ct_test(pTest, len != 0); ct_test(pTest, npdu_data.vendor_id == vendor_id);
// can we get the info back? ct_test(pTest, npdu_data.priority == priority);
npdu_len = npdu_decode( ct_test(pTest, npdu_dest.mac_len == src.mac_len);
&pdu[0], ct_test(pTest, npdu_src.mac_len == dest.mac_len);
&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 #ifdef TEST_NPDU
// dummy stub for testing // dummy stub for testing
void tsm_free_invoke_id(uint8_t invokeID) void tsm_free_invoke_id(uint8_t invokeID)
{ {
(void)invokeID; (void) invokeID;
} }
void iam_handler( void iam_handler(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len, BACNET_ADDRESS * src)
uint16_t service_len,
BACNET_ADDRESS *src)
{ {
(void)service_request; (void) service_request;
(void)service_len; (void) service_len;
(void)src; (void) src;
} }
int main(void) int main(void)
+24 -35
View File
@@ -40,50 +40,39 @@
#include "bacenum.h" #include "bacenum.h"
// an NPDU structure keeps the parameter stack to a minimum // an NPDU structure keeps the parameter stack to a minimum
typedef struct bacnet_npdu_data_t typedef struct bacnet_npdu_data_t {
{ uint8_t protocol_version;
uint8_t protocol_version; // parts of the control octet:
// parts of the control octet: bool data_expecting_reply; // true for confirmed messages
bool data_expecting_reply; // true for confirmed messages bool network_layer_message; // false if APDU
bool network_layer_message; // false if APDU BACNET_MESSAGE_PRIORITY priority;
BACNET_MESSAGE_PRIORITY priority; // optional network message info
// optional network message info BACNET_NETWORK_MESSAGE_TYPE network_message_type; // optional
BACNET_NETWORK_MESSAGE_TYPE network_message_type; // optional uint16_t vendor_id; // optional, if net message type is > 0x80
uint16_t vendor_id; // optional, if net message type is > 0x80 uint8_t hop_count;
uint8_t hop_count;
} BACNET_NPDU_DATA; } BACNET_NPDU_DATA;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
uint8_t npdu_encode_max_seg_max_apdu(int max_segs, int max_apdu); uint8_t npdu_encode_max_seg_max_apdu(int max_segs, int max_apdu);
int npdu_encode_raw( int npdu_encode_raw(uint8_t * npdu,
uint8_t *npdu, BACNET_ADDRESS * dest,
BACNET_ADDRESS *dest, BACNET_ADDRESS * src, BACNET_NPDU_DATA * npdu_data);
BACNET_ADDRESS *src,
BACNET_NPDU_DATA *npdu_data);
// encode the NPDU portion of the packet for an APDU // encode the NPDU portion of the packet for an APDU
int npdu_encode_apdu( int npdu_encode_apdu(uint8_t * npdu, BACNET_ADDRESS * dest, BACNET_ADDRESS * src, bool data_expecting_reply, // true for confirmed messages
uint8_t *npdu, BACNET_MESSAGE_PRIORITY priority);
BACNET_ADDRESS *dest,
BACNET_ADDRESS *src,
bool data_expecting_reply, // true for confirmed messages
BACNET_MESSAGE_PRIORITY priority);
int npdu_decode( int npdu_decode(uint8_t * npdu,
uint8_t *npdu, BACNET_ADDRESS * dest,
BACNET_ADDRESS *dest, BACNET_ADDRESS * src, BACNET_NPDU_DATA * npdu_data);
BACNET_ADDRESS *src,
BACNET_NPDU_DATA *npdu_data);
void npdu_handler( void npdu_handler(BACNET_ADDRESS * src, // source address
BACNET_ADDRESS *src, // source address uint8_t * pdu, // PDU data
uint8_t *pdu, // PDU data uint16_t pdu_len); // length PDU
uint16_t pdu_len); // length PDU
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+91 -112
View File
@@ -38,106 +38,93 @@
#include "rd.h" #include "rd.h"
/* encode service */ /* encode service */
int rd_encode_apdu( int rd_encode_apdu(uint8_t * apdu,
uint8_t *apdu, uint8_t invoke_id,
uint8_t invoke_id, BACNET_REINITIALIZED_STATE state, BACNET_CHARACTER_STRING * password)
BACNET_REINITIALIZED_STATE state,
BACNET_CHARACTER_STRING *password)
{ {
int len = 0; /* length of each encoding */ int len = 0; /* length of each encoding */
int apdu_len = 0; /* total length of the apdu, return value */ int apdu_len = 0; /* total length of the apdu, return value */
if (apdu) if (apdu) {
{ apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST; apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU);
apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU); apdu[2] = invoke_id;
apdu[2] = invoke_id; apdu[3] = SERVICE_CONFIRMED_REINITIALIZE_DEVICE;
apdu[3] = SERVICE_CONFIRMED_REINITIALIZE_DEVICE; apdu_len = 4;
apdu_len = 4; len = encode_context_enumerated(&apdu[apdu_len], 0, state);
len = encode_context_enumerated(&apdu[apdu_len], 0, apdu_len += len;
state); /* optional password */
apdu_len += len; if (password) {
/* optional password */ /* FIXME: must be at least 1 character, limited to 20 characters */
if (password) len = encode_context_character_string(&apdu[apdu_len], 1,
{ password);
/* FIXME: must be at least 1 character, limited to 20 characters */ apdu_len += len;
len = encode_context_character_string(&apdu[apdu_len], 1, }
password);
apdu_len += len;
} }
}
return apdu_len; return apdu_len;
} }
/* decode the service request only */ /* decode the service request only */
int rd_decode_service_request( int rd_decode_service_request(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len,
unsigned apdu_len, BACNET_REINITIALIZED_STATE * state, BACNET_CHARACTER_STRING * password)
BACNET_REINITIALIZED_STATE *state,
BACNET_CHARACTER_STRING *password)
{ {
unsigned len = 0; unsigned len = 0;
uint8_t tag_number = 0; uint8_t tag_number = 0;
uint32_t len_value_type = 0; uint32_t len_value_type = 0;
int value = 0; int value = 0;
/* check for value pointers */ /* check for value pointers */
if (apdu_len) if (apdu_len) {
{ /* Tag 0: reinitializedStateOfDevice */
/* Tag 0: reinitializedStateOfDevice */ if (!decode_is_context_tag(&apdu[len], 0))
if (!decode_is_context_tag(&apdu[len], 0)) return -1;
return -1; len += decode_tag_number_and_value(&apdu[len],
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type);
&tag_number, &len_value_type); len += decode_enumerated(&apdu[len], len_value_type, &value);
len += decode_enumerated(&apdu[len], len_value_type, &value); if (state)
if (state) *state = value;
*state = value; /* Tag 1: password - optional */
/* Tag 1: password - optional */ if (len < apdu_len) {
if (len < apdu_len) if (!decode_is_context_tag(&apdu[len], 1))
{ return -1;
if (!decode_is_context_tag(&apdu[len], 1)) len += decode_tag_number_and_value(&apdu[len],
return -1; &tag_number, &len_value_type);
len += decode_tag_number_and_value(&apdu[len], len +=
&tag_number, &len_value_type); decode_character_string(&apdu[len], len_value_type,
len += decode_character_string(&apdu[len], len_value_type, password); password);
}
} }
}
return (int)len; return (int) len;
} }
int rd_decode_apdu( int rd_decode_apdu(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len,
unsigned apdu_len, uint8_t * invoke_id,
uint8_t *invoke_id, BACNET_REINITIALIZED_STATE * state, BACNET_CHARACTER_STRING * password)
BACNET_REINITIALIZED_STATE *state,
BACNET_CHARACTER_STRING *password)
{ {
int len = 0; int len = 0;
unsigned offset = 0; unsigned offset = 0;
if (!apdu) if (!apdu)
return -1; return -1;
// optional checking - most likely was already done prior to this call // optional checking - most likely was already done prior to this call
if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST) if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
return -1; return -1;
// apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted()); // apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted());
*invoke_id = apdu[2]; /* invoke id - filled in by net layer */ *invoke_id = apdu[2]; /* invoke id - filled in by net layer */
if (apdu[3] != SERVICE_CONFIRMED_REINITIALIZE_DEVICE) if (apdu[3] != SERVICE_CONFIRMED_REINITIALIZE_DEVICE)
return -1; return -1;
offset = 4; offset = 4;
if (apdu_len > offset) if (apdu_len > offset) {
{ len = rd_decode_service_request(&apdu[offset],
len = rd_decode_service_request( apdu_len - offset, state, password);
&apdu[offset], }
apdu_len - offset,
state,
password);
}
return len; return len;
} }
#ifdef TEST #ifdef TEST
@@ -147,38 +134,30 @@ int rd_decode_apdu(
void test_ReinitializeDevice(Test * pTest) void test_ReinitializeDevice(Test * pTest)
{ {
uint8_t apdu[480] = {0}; uint8_t apdu[480] = { 0 };
int len = 0; int len = 0;
int apdu_len = 0; int apdu_len = 0;
uint8_t invoke_id = 128; uint8_t invoke_id = 128;
uint8_t test_invoke_id = 0; uint8_t test_invoke_id = 0;
BACNET_REINITIALIZED_STATE state; BACNET_REINITIALIZED_STATE state;
BACNET_REINITIALIZED_STATE test_state; BACNET_REINITIALIZED_STATE test_state;
BACNET_CHARACTER_STRING password; BACNET_CHARACTER_STRING password;
BACNET_CHARACTER_STRING test_password; BACNET_CHARACTER_STRING test_password;
state = BACNET_REINIT_WARMSTART; state = BACNET_REINIT_WARMSTART;
characterstring_init_ansi(&password,"John 3:16"); characterstring_init_ansi(&password, "John 3:16");
len = rd_encode_apdu( len = rd_encode_apdu(&apdu[0], invoke_id, state, &password);
&apdu[0], ct_test(pTest, len != 0);
invoke_id, apdu_len = len;
state,
&password);
ct_test(pTest, len != 0);
apdu_len = len;
len = rd_decode_apdu( len = rd_decode_apdu(&apdu[0],
&apdu[0], apdu_len, &test_invoke_id, &test_state, &test_password);
apdu_len, ct_test(pTest, len != -1);
&test_invoke_id, ct_test(pTest, test_invoke_id == invoke_id);
&test_state, ct_test(pTest, test_state == state);
&test_password); ct_test(pTest, characterstring_same(&test_password, &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 #ifdef TEST_REINITIALIZE_DEVICE
+17 -22
View File
@@ -39,37 +39,32 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
// encode service // encode service
int rd_encode_apdu( int rd_encode_apdu(uint8_t * apdu,
uint8_t *apdu, uint8_t invoke_id,
uint8_t invoke_id, BACNET_REINITIALIZED_STATE state,
BACNET_REINITIALIZED_STATE state, BACNET_CHARACTER_STRING * password);
BACNET_CHARACTER_STRING *password);
// decode the service request only // decode the service request only
int rd_decode_service_request( int rd_decode_service_request(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len,
unsigned apdu_len, BACNET_REINITIALIZED_STATE * state,
BACNET_REINITIALIZED_STATE *state, BACNET_CHARACTER_STRING * password);
BACNET_CHARACTER_STRING *password);
int rd_decode_apdu(uint8_t * apdu,
int rd_decode_apdu( unsigned apdu_len,
uint8_t *apdu, uint8_t * invoke_id,
unsigned apdu_len, BACNET_REINITIALIZED_STATE * state,
uint8_t *invoke_id, BACNET_CHARACTER_STRING * password);
BACNET_REINITIALIZED_STATE *state,
BACNET_CHARACTER_STRING *password);
#ifdef TEST #ifdef TEST
#include "ctest.h" #include "ctest.h"
void test_ReinitializeDevice(Test * pTest); void test_ReinitializeDevice(Test * pTest);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+80 -124
View File
@@ -37,71 +37,56 @@
#include "bacdef.h" #include "bacdef.h"
// encode service // encode service
int reject_encode_apdu( int reject_encode_apdu(uint8_t * apdu,
uint8_t *apdu, uint8_t invoke_id, uint8_t reject_reason)
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) if (apdu) {
{ apdu[0] = PDU_TYPE_REJECT;
apdu[0] = PDU_TYPE_REJECT; apdu[1] = invoke_id;
apdu[1] = invoke_id; apdu[2] = reject_reason;
apdu[2] = reject_reason; apdu_len = 3;
apdu_len = 3; }
}
return apdu_len;
return apdu_len;
} }
// decode the service request only // decode the service request only
int reject_decode_service_request( int reject_decode_service_request(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, uint8_t * invoke_id, uint8_t * reject_reason)
unsigned apdu_len,
uint8_t *invoke_id,
uint8_t *reject_reason)
{ {
int len = 0; int len = 0;
if (apdu_len) if (apdu_len) {
{ if (invoke_id)
if (invoke_id) *invoke_id = apdu[0];
*invoke_id = apdu[0]; if (reject_reason)
if (reject_reason) *reject_reason = apdu[1];
*reject_reason = apdu[1]; }
}
return len;
return len;
} }
// decode the whole APDU - mainly used for unit testing // decode the whole APDU - mainly used for unit testing
int reject_decode_apdu( int reject_decode_apdu(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, uint8_t * invoke_id, uint8_t * reject_reason)
unsigned apdu_len,
uint8_t *invoke_id,
uint8_t *reject_reason)
{ {
int len = 0; int len = 0;
if (!apdu) if (!apdu)
return -1; return -1;
// optional checking - most likely was already done prior to this call // optional checking - most likely was already done prior to this call
if (apdu_len) if (apdu_len) {
{ if (apdu[0] != PDU_TYPE_REJECT)
if (apdu[0] != PDU_TYPE_REJECT) return -1;
return -1; if (apdu_len > 1) {
if (apdu_len > 1) len = reject_decode_service_request(&apdu[1],
{ apdu_len - 1, invoke_id, reject_reason);
len = reject_decode_service_request( }
&apdu[1],
apdu_len - 1,
invoke_id,
reject_reason);
} }
}
return len;
return len;
} }
#ifdef TEST #ifdef TEST
@@ -111,83 +96,54 @@ int reject_decode_apdu(
void testReject(Test * pTest) void testReject(Test * pTest)
{ {
uint8_t apdu[480] = {0}; uint8_t apdu[480] = { 0 };
int len = 0; int len = 0;
int apdu_len = 0; int apdu_len = 0;
uint8_t invoke_id = 0; uint8_t invoke_id = 0;
uint8_t reject_reason = 0; uint8_t reject_reason = 0;
uint8_t test_invoke_id = 0; uint8_t test_invoke_id = 0;
uint8_t test_reject_reason = 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;
len = reject_decode_apdu( len = reject_encode_apdu(&apdu[0], invoke_id, reject_reason);
&apdu[0], ct_test(pTest, len != 0);
apdu_len, apdu_len = 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);
// change type to get negative response len = reject_decode_apdu(&apdu[0],
apdu[0] = PDU_TYPE_ABORT; apdu_len, &test_invoke_id, &test_reject_reason);
len = reject_decode_apdu( ct_test(pTest, len != -1);
&apdu[0], ct_test(pTest, test_invoke_id == invoke_id);
apdu_len, ct_test(pTest, test_reject_reason == reject_reason);
&test_invoke_id,
&test_reject_reason);
ct_test(pTest, len == -1);
// test NULL APDU // change type to get negative response
len = reject_decode_apdu( apdu[0] = PDU_TYPE_ABORT;
NULL, len = reject_decode_apdu(&apdu[0],
apdu_len, apdu_len, &test_invoke_id, &test_reject_reason);
&test_invoke_id, ct_test(pTest, len == -1);
&test_reject_reason);
ct_test(pTest, len == -1);
// force a zero length // test NULL APDU
len = reject_decode_apdu( len = reject_decode_apdu(NULL,
&apdu[0], apdu_len, &test_invoke_id, &test_reject_reason);
0, ct_test(pTest, len == -1);
&test_invoke_id,
&test_reject_reason); // force a zero length
ct_test(pTest, len == 0); 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; // check them all...
invoke_id < 255; for (invoke_id = 0; invoke_id < 255; invoke_id++) {
invoke_id++) for (reject_reason = 0; reject_reason < 255; reject_reason++) {
{ len = reject_encode_apdu(&apdu[0], invoke_id, reject_reason);
for ( apdu_len = len;
reject_reason = 0; ct_test(pTest, len != 0);
reject_reason < 255; len = reject_decode_apdu(&apdu[0],
reject_reason++) apdu_len, &test_invoke_id, &test_reject_reason);
{ ct_test(pTest, len != -1);
len = reject_encode_apdu( ct_test(pTest, test_invoke_id == invoke_id);
&apdu[0], ct_test(pTest, test_reject_reason == reject_reason);
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 #ifdef TEST_REJECT
+10 -20
View File
@@ -39,32 +39,22 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
int reject_encode_apdu( int reject_encode_apdu(uint8_t * apdu,
uint8_t *apdu, uint8_t invoke_id, uint8_t reject_reason);
uint8_t invoke_id,
uint8_t reject_reason);
int reject_decode_service_request( int reject_decode_service_request(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, uint8_t * invoke_id, uint8_t * reject_reason);
unsigned apdu_len,
uint8_t *invoke_id, int reject_decode_apdu(uint8_t * apdu,
uint8_t *reject_reason); 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 #ifdef TEST
void testReject(Test * pTest); void testReject(Test * pTest);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+138 -153
View File
@@ -48,7 +48,7 @@
*****************************************************************************/ *****************************************************************************/
bool Ringbuf_Empty(RING_BUFFER const *b) 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) 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 * ALGORITHM: none
* NOTES: 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) if (b->count) {
{ data = &(b->data[b->head * b->element_size]);
data = &(b->data[b->head * b->element_size]); b->head++;
b->head++; if (b->head >= b->element_count)
if (b->head >= b->element_count) b->head = 0;
b->head = 0; b->count--;
b->count--; }
}
return data; return data;
} }
/**************************************************************************** /****************************************************************************
@@ -90,34 +89,30 @@ char *Ringbuf_Pop_Front(RING_BUFFER *b)
* ALGORITHM: none * ALGORITHM: none
* NOTES: none * NOTES: none
*****************************************************************************/ *****************************************************************************/
bool Ringbuf_Put( bool Ringbuf_Put(RING_BUFFER * b, // ring buffer structure
RING_BUFFER *b, // ring buffer structure char *data_element) // one element to add to the ring
char *data_element) // one element to add to the ring
{ {
bool status = false; // return value bool status = false; // return value
unsigned offset = 0; // offset into array of data unsigned offset = 0; // offset into array of data
char *ring_data = NULL; // used to help point ring data char *ring_data = NULL; // used to help point ring data
unsigned i; // loop counter unsigned i; // loop counter
if (b && data_element) if (b && data_element) {
{ // limit the amount of data that we accept
// limit the amount of data that we accept if (b->count < b->element_count) {
if (b->count < b->element_count) offset = b->head + b->count;
{ if (offset >= b->element_count)
offset = b->head + b->count; offset -= b->element_count;
if (offset >= b->element_count) ring_data = b->data + offset * b->element_size;
offset -= b->element_count; for (i = 0; i < b->element_size; i++) {
ring_data = b->data + offset * b->element_size; ring_data[i] = data_element[i];
for(i = 0; i < b->element_size; i++) }
{ b->count++;
ring_data[i] = data_element[i]; status = true;
} }
b->count++;
status = true;
} }
}
return status; return status;
} }
/**************************************************************************** /****************************************************************************
@@ -126,19 +121,18 @@ bool Ringbuf_Put(
* ALGORITHM: none * ALGORITHM: none
* NOTES: none * NOTES: none
*****************************************************************************/ *****************************************************************************/
void Ringbuf_Init( void Ringbuf_Init(RING_BUFFER * b, // ring buffer structure
RING_BUFFER *b, // ring buffer structure char *data, // data block or array of data
char *data, // data block or array of data unsigned element_size, // size of one element in the data block
unsigned element_size, // size of one element in the data block unsigned element_count) // number of elements in the data block
unsigned element_count) // number of elements in the data block
{ {
b->head = 0; b->head = 0;
b->count = 0; b->count = 0;
b->data = data; b->data = data;
b->element_size = element_size; b->element_size = element_size;
b->element_count = element_count; b->element_count = element_count;
return; return;
} }
#ifdef TEST #ifdef TEST
@@ -150,139 +144,130 @@ void Ringbuf_Init(
// test the FIFO // test the FIFO
#define RING_BUFFER_DATA_SIZE 5 #define RING_BUFFER_DATA_SIZE 5
#define RING_BUFFER_SIZE 16 #define RING_BUFFER_SIZE 16
void testRingBuf(Test* pTest) void testRingBuf(Test * pTest)
{ {
RING_BUFFER test_buffer; RING_BUFFER test_buffer;
char data_store[RING_BUFFER_DATA_SIZE * RING_BUFFER_SIZE]; char data_store[RING_BUFFER_DATA_SIZE * RING_BUFFER_SIZE];
char data[RING_BUFFER_DATA_SIZE]; char data[RING_BUFFER_DATA_SIZE];
char *test_data; char *test_data;
unsigned index; unsigned index;
unsigned data_index; unsigned data_index;
unsigned count; unsigned count;
unsigned dummy; unsigned dummy;
bool status; bool status;
Ringbuf_Init(&test_buffer,data_store,RING_BUFFER_DATA_SIZE,RING_BUFFER_SIZE); Ringbuf_Init(&test_buffer, data_store, RING_BUFFER_DATA_SIZE,
ct_test(pTest,Ringbuf_Empty(&test_buffer)); RING_BUFFER_SIZE);
ct_test(pTest, Ringbuf_Empty(&test_buffer));
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++) for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++) {
{ data[data_index] = 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;
} }
status = Ringbuf_Put(&test_buffer, data); status = Ringbuf_Put(&test_buffer, data);
ct_test(pTest,status == true); ct_test(pTest, status == true);
ct_test(pTest,!Ringbuf_Empty(&test_buffer)); 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));
}
// check buffer full
for (index = 0; index < RING_BUFFER_SIZE; index++)
{
test_data = Ringbuf_Get_Front(&test_buffer); test_data = Ringbuf_Get_Front(&test_buffer);
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_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,test_data[data_index] == index);
} }
ct_test(pTest, !Ringbuf_Empty(&test_buffer));
test_data = Ringbuf_Pop_Front(&test_buffer); test_data = Ringbuf_Pop_Front(&test_buffer);
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_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,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 // fill to max
for (index = 0; index < RING_BUFFER_SIZE; index++) for (index = 0; index < RING_BUFFER_SIZE; index++) {
{ for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE;
for (count = 1; count < 4; count++) data_index++) {
{ data[data_index] = index;
dummy = index * count; }
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++) status = Ringbuf_Put(&test_buffer, data);
{ ct_test(pTest, status == true);
data[data_index] = dummy; ct_test(pTest, !Ringbuf_Empty(&test_buffer));
} }
status = Ringbuf_Put(&test_buffer, data); // verify actions on full buffer
ct_test(pTest,status == true); 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++) // check buffer full
{ for (index = 0; index < RING_BUFFER_SIZE; index++) {
dummy = index * count; test_data = Ringbuf_Get_Front(&test_buffer);
test_data = Ringbuf_Get_Front(&test_buffer); for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE;
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++) data_index++) {
{ ct_test(pTest, test_data[data_index] == index);
ct_test(pTest,test_data[data_index] == dummy); }
}
test_data = Ringbuf_Pop_Front(&test_buffer); test_data = Ringbuf_Pop_Front(&test_buffer);
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++) for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE;
{ data_index++) {
ct_test(pTest,test_data[data_index] == dummy); 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 #ifdef TEST_RINGBUF
int main(void) int main(void)
{ {
Test *pTest; Test *pTest;
bool rc; bool rc;
pTest = ct_create("ringbuf", NULL); pTest = ct_create("ringbuf", NULL);
/* individual tests */ /* individual tests */
rc = ct_addTestFunction(pTest, testRingBuf); rc = ct_addTestFunction(pTest, testRingBuf);
assert(rc); assert(rc);
ct_setStream(pTest, stdout); ct_setStream(pTest, stdout);
ct_run(pTest); ct_run(pTest);
(void)ct_report(pTest); (void) ct_report(pTest);
ct_destroy(pTest); ct_destroy(pTest);
return 0; return 0;
} }
#endif #endif
#endif #endif
+17 -21
View File
@@ -42,34 +42,30 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
struct ring_buffer_t struct ring_buffer_t {
{ char *data; // block of memory or array of data
char *data; // block of memory or array of data unsigned element_size; // how many bytes for each chunk
unsigned element_size; // how many bytes for each chunk unsigned element_count; // number of chunks of data
unsigned element_count; // number of chunks of data unsigned head; // first chunk of data
unsigned head; // first chunk of data unsigned count; // number of chunks in use
unsigned count; // number of chunks in use
}; };
typedef struct ring_buffer_t RING_BUFFER; typedef struct ring_buffer_t RING_BUFFER;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
bool Ringbuf_Empty(RING_BUFFER const *b); bool Ringbuf_Empty(RING_BUFFER const *b);
char *Ringbuf_Get_Front(RING_BUFFER const *b); char *Ringbuf_Get_Front(RING_BUFFER const *b);
char *Ringbuf_Pop_Front(RING_BUFFER *b); char *Ringbuf_Pop_Front(RING_BUFFER * b);
bool Ringbuf_Put( bool Ringbuf_Put(RING_BUFFER * b, // ring buffer structure
RING_BUFFER *b, // ring buffer structure char *data_element); // one element to add to the ring
char *data_element); // one element to add to the ring void Ringbuf_Init(RING_BUFFER * b, // ring buffer structure
void Ringbuf_Init( char *data, // data block or array of data
RING_BUFFER *b, // ring buffer structure unsigned element_size, // size of one element in the data block
char *data, // data block or array of data unsigned element_count); // number of elements in the data block
unsigned element_size, // size of one element in the data block
unsigned element_count); // number of elements in the data block
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+239 -291
View File
@@ -38,240 +38,203 @@
#include "rp.h" #include "rp.h"
// encode service // encode service
int rp_encode_apdu( int rp_encode_apdu(uint8_t * apdu,
uint8_t *apdu, uint8_t invoke_id, BACNET_READ_PROPERTY_DATA * data)
uint8_t invoke_id,
BACNET_READ_PROPERTY_DATA *data)
{ {
int len = 0; // length of each encoding int len = 0; // length of each encoding
int apdu_len = 0; // total length of the apdu, return value int apdu_len = 0; // total length of the apdu, return value
if (apdu) if (apdu) {
{ apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST; apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU);
apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU); apdu[2] = invoke_id;
apdu[2] = invoke_id; apdu[3] = SERVICE_CONFIRMED_READ_PROPERTY; // service choice
apdu[3] = SERVICE_CONFIRMED_READ_PROPERTY; // service choice apdu_len = 4;
apdu_len = 4; len = encode_context_object_id(&apdu[apdu_len], 0,
len = encode_context_object_id(&apdu[apdu_len], 0, data->object_type, data->object_instance);
data->object_type, data->object_instance); apdu_len += len;
apdu_len += len; len = encode_context_enumerated(&apdu[apdu_len], 1,
len = encode_context_enumerated(&apdu[apdu_len], 1, data->object_property);
data->object_property); apdu_len += len;
apdu_len += len; /* optional array index */
/* optional array index */ if (data->array_index != BACNET_ARRAY_ALL) {
if (data->array_index != BACNET_ARRAY_ALL) len = encode_context_unsigned(&apdu[apdu_len], 2,
{ data->array_index);
len = encode_context_unsigned(&apdu[apdu_len], 2, apdu_len += len;
data->array_index); }
apdu_len += len;
} }
}
return apdu_len;
return apdu_len;
} }
// decode the service request only // decode the service request only
int rp_decode_service_request( int rp_decode_service_request(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, BACNET_READ_PROPERTY_DATA * data)
unsigned apdu_len,
BACNET_READ_PROPERTY_DATA *data)
{ {
unsigned len = 0; unsigned len = 0;
uint8_t tag_number = 0; uint8_t tag_number = 0;
uint32_t len_value_type = 0; uint32_t len_value_type = 0;
int type = 0; // for decoding int type = 0; // for decoding
int property = 0; // for decoding int property = 0; // for decoding
uint32_t array_value = 0; // for decoding uint32_t array_value = 0; // for decoding
// check for value pointers // check for value pointers
if (apdu_len && data) if (apdu_len && data) {
{ // Tag 0: Object ID
// Tag 0: Object ID if (!decode_is_context_tag(&apdu[len++], 0))
if (!decode_is_context_tag(&apdu[len++], 0)) return -1;
return -1; len += decode_object_id(&apdu[len], &type, &data->object_instance);
len += decode_object_id(&apdu[len], &type, &data->object_instance); data->object_type = type;
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 // Tag 1: Property ID
len += decode_tag_number_and_value(&apdu[len], len += decode_tag_number_and_value(&apdu[len],
&tag_number, &len_value_type); &tag_number, &len_value_type);
if (tag_number != 1) if (tag_number != 1)
return -1; return -1;
len += decode_enumerated(&apdu[len], len_value_type, &property); len += decode_enumerated(&apdu[len], len_value_type, &property);
data->object_property = property; data->object_property = property;
// Tag 2: Optional Array Index // Tag 2: Optional Array Index
if (len < apdu_len) tag_len = decode_tag_number_and_value(&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_number, &len_value_type); &tag_number, &len_value_type);
if (tag_number == 2) if (tag_number == 2) {
{ len += tag_len;
len += tag_len; len += decode_unsigned(&apdu[len], len_value_type, &array_value);
len += decode_unsigned(&apdu[len], data->array_index = array_value;
len_value_type, &array_value); } else
data->array_index = array_value; data->array_index = BACNET_ARRAY_ALL;
}
else // Tag 3: opening context tag */
data->array_index = BACNET_ARRAY_ALL; if (decode_is_opening_tag_number(&apdu[len], 3)) {
// a tag number of 3 is not extended so only one octet
// Tag 3: opening context tag */ len++;
if (decode_is_opening_tag_number(&apdu[len], 3)) // don't decode the application tag number or its data here
{ data->application_data = &apdu[len];
// a tag number of 3 is not extended so only one octet data->application_data_len = apdu_len - len - 1 /*closing tag */ ;
len++; } else
// don't decode the application tag number or its data here return -1;
data->application_data = &apdu[len];
data->application_data_len = apdu_len - len - 1 /*closing tag*/; return len;
}
else
return -1;
return len;
} }
int rp_ack_decode_apdu( int rp_ack_decode_apdu(uint8_t * apdu, int apdu_len, // total length of the apdu
uint8_t *apdu, uint8_t * invoke_id, BACNET_READ_PROPERTY_DATA * data)
int apdu_len, // total length of the apdu
uint8_t *invoke_id,
BACNET_READ_PROPERTY_DATA *data)
{ {
int len = 0; int len = 0;
int offset = 0; int offset = 0;
if (!apdu) if (!apdu)
return -1; return -1;
// optional checking - most likely was already done prior to this call // optional checking - most likely was already done prior to this call
if (apdu[0] != PDU_TYPE_COMPLEX_ACK) if (apdu[0] != PDU_TYPE_COMPLEX_ACK)
return -1; return -1;
*invoke_id = apdu[1]; *invoke_id = apdu[1];
if (apdu[2] != SERVICE_CONFIRMED_READ_PROPERTY) if (apdu[2] != SERVICE_CONFIRMED_READ_PROPERTY)
return -1; return -1;
offset = 3; offset = 3;
if (apdu_len > offset) if (apdu_len > offset) {
{ len = rp_ack_decode_service_request(&apdu[offset],
len = rp_ack_decode_service_request( apdu_len - offset, data);
&apdu[offset], }
apdu_len - offset,
data); return len;
}
return len;
} }
#ifdef TEST #ifdef TEST
@@ -281,93 +244,78 @@ int rp_ack_decode_apdu(
void testReadPropertyAck(Test * pTest) void testReadPropertyAck(Test * pTest)
{ {
uint8_t apdu[480] = {0}; uint8_t apdu[480] = { 0 };
uint8_t apdu2[480] = {0}; uint8_t apdu2[480] = { 0 };
int len = 0; int len = 0;
int apdu_len = 0; int apdu_len = 0;
uint8_t invoke_id = 1; uint8_t invoke_id = 1;
uint8_t test_invoke_id = 0; uint8_t test_invoke_id = 0;
BACNET_READ_PROPERTY_DATA data; BACNET_READ_PROPERTY_DATA data;
BACNET_READ_PROPERTY_DATA test_data; BACNET_READ_PROPERTY_DATA test_data;
BACNET_OBJECT_TYPE object_type = OBJECT_DEVICE; BACNET_OBJECT_TYPE object_type = OBJECT_DEVICE;
uint32_t object_instance = 0; uint32_t object_instance = 0;
int object = 0; int object = 0;
data.object_type = OBJECT_DEVICE; data.object_type = OBJECT_DEVICE;
data.object_instance = 1; data.object_instance = 1;
data.object_property = PROP_OBJECT_IDENTIFIER; data.object_property = PROP_OBJECT_IDENTIFIER;
data.array_index = BACNET_ARRAY_ALL; data.array_index = BACNET_ARRAY_ALL;
data.application_data_len = encode_bacnet_object_id(&apdu2[0], data.application_data_len = encode_bacnet_object_id(&apdu2[0],
data.object_type, data.object_type, data.object_instance);
data.object_instance); data.application_data = &apdu2[0];
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);
ct_test(pTest, test_data.object_type == data.object_type); len = rp_ack_encode_apdu(&apdu[0], invoke_id, &data);
ct_test(pTest, test_data.object_instance == data.object_instance); ct_test(pTest, len != 0);
ct_test(pTest, test_data.object_property == data.object_property); ct_test(pTest, len != -1);
ct_test(pTest, test_data.array_index == data.array_index); apdu_len = len;
ct_test(pTest, test_data.application_data_len == data.application_data_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 ct_test(pTest, test_data.object_type == data.object_type);
the appropriate decode function */ ct_test(pTest, test_data.object_instance == data.object_instance);
len = decode_object_id( ct_test(pTest, test_data.object_property == data.object_property);
test_data.application_data, ct_test(pTest, test_data.array_index == data.array_index);
&object, ct_test(pTest,
&object_instance); test_data.application_data_len == data.application_data_len);
object_type = object;
ct_test(pTest, object_type == data.object_type); /* since object property == object_id, decode the application data using
ct_test(pTest, object_instance == data.object_instance); 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) void testReadProperty(Test * pTest)
{ {
uint8_t apdu[480] = {0}; uint8_t apdu[480] = { 0 };
int len = 0; int len = 0;
int apdu_len = 0; int apdu_len = 0;
uint8_t invoke_id = 128; uint8_t invoke_id = 128;
uint8_t test_invoke_id = 0; uint8_t test_invoke_id = 0;
BACNET_READ_PROPERTY_DATA data; BACNET_READ_PROPERTY_DATA data;
BACNET_READ_PROPERTY_DATA test_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;
len = rp_decode_apdu( data.object_type = OBJECT_DEVICE;
&apdu[0], data.object_instance = 1;
apdu_len, data.object_property = PROP_OBJECT_IDENTIFIER;
&test_invoke_id, data.array_index = BACNET_ARRAY_ALL;
&test_data); len = rp_encode_apdu(&apdu[0], invoke_id, &data);
ct_test(pTest, len != -1); ct_test(pTest, len != 0);
ct_test(pTest, test_data.object_type == data.object_type); apdu_len = len;
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; 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 #ifdef TEST_READ_PROPERTY
+26 -42
View File
@@ -37,65 +37,49 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
typedef struct BACnet_Read_Property_Data typedef struct BACnet_Read_Property_Data {
{ BACNET_OBJECT_TYPE object_type;
BACNET_OBJECT_TYPE object_type; uint32_t object_instance;
uint32_t object_instance; BACNET_PROPERTY_ID object_property;
BACNET_PROPERTY_ID object_property; int32_t array_index;
int32_t array_index; uint8_t *application_data;
uint8_t *application_data; int application_data_len;
int application_data_len;
} BACNET_READ_PROPERTY_DATA; } BACNET_READ_PROPERTY_DATA;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
// encode service // encode service
int rp_encode_apdu( int rp_encode_apdu(uint8_t * apdu,
uint8_t *apdu, uint8_t invoke_id, BACNET_READ_PROPERTY_DATA * data);
uint8_t invoke_id,
BACNET_READ_PROPERTY_DATA *data);
// decode the service request only // decode the service request only
int rp_decode_service_request( int rp_decode_service_request(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, BACNET_READ_PROPERTY_DATA * data);
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_ack_encode_apdu( int rp_decode_apdu(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len,
uint8_t invoke_id, uint8_t * invoke_id, BACNET_READ_PROPERTY_DATA * data);
BACNET_READ_PROPERTY_DATA *data);
int rp_ack_decode_service_request( int rp_ack_encode_apdu(uint8_t * apdu,
uint8_t *apdu, uint8_t invoke_id, BACNET_READ_PROPERTY_DATA * data);
int apdu_len, // total length of the apdu
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 #ifdef TEST
#include "ctest.h" #include "ctest.h"
void test_ReadProperty(Test * pTest); void test_ReadProperty(Test * pTest);
void test_ReadPropertyAck(Test * pTest); void test_ReadPropertyAck(Test * pTest);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+594 -725
View File
File diff suppressed because it is too large Load Diff
+41 -76
View File
@@ -42,7 +42,7 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
/* encode functions */ /* encode functions */
/* Start with the Init function, and then add an object, /* Start with the Init function, and then add an object,
@@ -51,104 +51,69 @@ extern "C" {
until the APDU is full.*/ until the APDU is full.*/
/* RPM */ /* RPM */
int rpm_encode_apdu_init( int rpm_encode_apdu_init(uint8_t * apdu, uint8_t invoke_id);
uint8_t *apdu,
uint8_t invoke_id);
int rpm_encode_apdu_object_begin( int rpm_encode_apdu_object_begin(uint8_t * apdu,
uint8_t *apdu, BACNET_OBJECT_TYPE object_type, uint32_t object_instance);
BACNET_OBJECT_TYPE object_type,
uint32_t object_instance);
int rpm_encode_apdu_object_property( int rpm_encode_apdu_object_property(uint8_t * apdu,
uint8_t *apdu, BACNET_PROPERTY_ID object_property, int32_t array_index);
BACNET_PROPERTY_ID object_property,
int32_t array_index);
int rpm_encode_apdu_object_end( int rpm_encode_apdu_object_end(uint8_t * apdu);
uint8_t *apdu);
int rpm_decode_apdu( int rpm_decode_apdu(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len,
unsigned apdu_len, uint8_t * invoke_id,
uint8_t *invoke_id, uint8_t ** service_request, unsigned *service_request_len);
uint8_t **service_request,
unsigned *service_request_len);
/* decode the object portion of the service request only */ /* decode the object portion of the service request only */
int rpm_decode_object_id( int rpm_decode_object_id(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len,
unsigned apdu_len, BACNET_OBJECT_TYPE * object_type, uint32_t * object_instance);
BACNET_OBJECT_TYPE *object_type,
uint32_t *object_instance);
/* is this the end of this object property list? */ /* is this the end of this object property list? */
int rpm_decode_object_end( int rpm_decode_object_end(uint8_t * apdu, unsigned apdu_len);
uint8_t *apdu,
unsigned apdu_len);
/* decode the object property portion of the service request only */ /* decode the object property portion of the service request only */
int rpm_decode_object_property( int rpm_decode_object_property(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len,
unsigned apdu_len, BACNET_PROPERTY_ID * object_property, int32_t * array_index);
BACNET_PROPERTY_ID *object_property,
int32_t *array_index);
/* RPM Ack */ /* RPM Ack */
int rpm_ack_encode_apdu_object_begin( int rpm_ack_encode_apdu_object_begin(uint8_t * apdu,
uint8_t *apdu, BACNET_OBJECT_TYPE object_type, uint32_t object_instance);
BACNET_OBJECT_TYPE object_type,
uint32_t object_instance);
int rpm_ack_encode_apdu_object_property_value( int rpm_ack_encode_apdu_object_property_value(uint8_t * apdu,
uint8_t *apdu, uint8_t * application_data, unsigned application_data_len);
uint8_t *application_data,
unsigned application_data_len);
int rpm_ack_encode_apdu_object_property_error( int rpm_ack_encode_apdu_object_property_error(uint8_t * apdu,
uint8_t *apdu, BACNET_ERROR_CLASS error_class, BACNET_ERROR_CODE error_code);
BACNET_ERROR_CLASS error_class,
BACNET_ERROR_CODE error_code);
int rpm_ack_encode_apdu_object_end( int rpm_ack_encode_apdu_object_end(uint8_t * apdu);
uint8_t *apdu);
int rpm_ack_decode_object_id( int rpm_ack_decode_object_id(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len,
unsigned apdu_len, BACNET_OBJECT_TYPE * object_type, uint32_t * object_instance);
BACNET_OBJECT_TYPE *object_type,
uint32_t *object_instance);
/* is this the end of the list of this objects properties values? */ /* is this the end of the list of this objects properties values? */
int rpm_ack_decode_object_end( int rpm_ack_decode_object_end(uint8_t * apdu, unsigned apdu_len);
uint8_t *apdu, int rpm_ack_decode_object_property(uint8_t * apdu,
unsigned apdu_len); unsigned apdu_len,
int rpm_ack_decode_object_property( BACNET_PROPERTY_ID * object_property, int32_t * array_index);
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 */ /* decode the object property value portion of the service request only */
int rpm_ack_decode_object_property_value( int rpm_ack_decode_object_property_value(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len,
unsigned apdu_len, uint8_t ** application_data, unsigned *application_data_len);
uint8_t **application_data, int rpm_ack_decode_apdu(uint8_t * apdu, int apdu_len, /* total length of the apdu */
unsigned *application_data_len); uint8_t * invoke_id,
int rpm_ack_decode_apdu( uint8_t ** service_request, unsigned *service_request_len);
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 #ifdef TEST
#include "ctest.h" #include "ctest.h"
void testReadPropertyMultiple(Test * pTest); void testReadPropertyMultiple(Test * pTest);
void testReadPropertyMultipleAck(Test * pTest); void testReadPropertyMultipleAck(Test * pTest);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+8 -11
View File
@@ -41,22 +41,19 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
void RS485_Initialize(void); void RS485_Initialize(void);
void RS485_Send_Frame( void RS485_Send_Frame(volatile struct mstp_port_struct_t *mstp_port, // port specific data
volatile struct mstp_port_struct_t *mstp_port, // port specific data uint8_t * buffer, // frame to send (up to 501 bytes of data)
uint8_t *buffer, // frame to send (up to 501 bytes of data) uint16_t nbytes); // number of bytes of data (up to 501)
uint16_t nbytes); // number of bytes of data (up to 501)
void RS485_Check_UART_Data( void RS485_Check_UART_Data(volatile struct mstp_port_struct_t *mstp_port); // port specific 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 #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+114 -125
View File
@@ -40,181 +40,170 @@
#include <stddef.h> #include <stddef.h>
#include "sbuf.h" #include "sbuf.h"
void sbuf_init( void sbuf_init(STATIC_BUFFER * b, /* static buffer structure */
STATIC_BUFFER *b, /* static buffer structure */ char *data, /* actual size, in bytes, of the data block or array of data */
char *data, /* actual size, in bytes, of the data block or array of data */ unsigned size)
unsigned size) /* number of bytes used */ { /* number of bytes used */
{ if (b) {
if (b) b->data = data;
{ b->size = size;
b->data = data; b->count = 0;
b->size = size; }
b->count = 0;
}
return; return;
} }
/* returns true if count==0, false if count > 0 */ /* returns true if count==0, false if count > 0 */
bool sbuf_empty(STATIC_BUFFER const *b) 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) 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 */ /* returns true if successful, false if not enough room to append data */
bool sbuf_put( bool sbuf_put(STATIC_BUFFER * b, /* static buffer structure */
STATIC_BUFFER *b, /* static buffer structure */ unsigned offset, /* where to start */
unsigned offset, /* where to start */ char *data, /* number of bytes used */
char *data, /* number of bytes used */ unsigned data_size)
unsigned data_size) /* how many to add */ { /* how many to add */
{ bool status = false; /* return value */
bool status = false; /* return value */
if (b && b->data) if (b && b->data) {
{ if (((offset + data_size) < b->size)) {
if (((offset + data_size) < b->size)) b->count = offset + data_size;
{ while (data_size) {
b->count = offset + data_size; b->data[offset] = *data;
while (data_size) offset++;
{ data++;
b->data[offset] = *data; data_size--;
offset++; }
data++; status = true;
data_size--; }
}
status = true;
} }
}
return status; return status;
} }
/* returns true if successful, false if not enough room to append data */ /* returns true if successful, false if not enough room to append data */
bool sbuf_append( bool sbuf_append(STATIC_BUFFER * b, /* static buffer structure */
STATIC_BUFFER *b, /* static buffer structure */ char *data, /* number of bytes used */
char *data, /* number of bytes used */ unsigned data_size)
unsigned data_size) /* how many to add */ { /* how many to add */
{ unsigned count = 0;
unsigned count = 0;
if (b)
if (b) count = b->count;
count = b->count;
return sbuf_put(b, count, data, data_size);
return sbuf_put(b, count, data, data_size);
} }
/* returns true if successful, false if not enough room to append data */ /* returns true if successful, false if not enough room to append data */
bool sbuf_truncate( bool sbuf_truncate(STATIC_BUFFER * b, /* static buffer structure */
STATIC_BUFFER *b, /* static buffer structure */ unsigned count)
unsigned count) /* total number of bytes in use */ { /* total number of bytes in use */
{ bool status = false; /* return value */
bool status = false; /* return value */
if (b) if (b) {
{ if (count < b->size) {
if (count < b->size) b->count = count;
{ status = true;
b->count = count; }
status = true;
} }
}
return status;
return status;
} }
#ifdef TEST #ifdef TEST
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include "ctest.h" #include "ctest.h"
void testStaticBuffer(Test* pTest) void testStaticBuffer(Test * pTest)
{ {
STATIC_BUFFER sbuffer; STATIC_BUFFER sbuffer;
char *data1 = "Joshua"; char *data1 = "Joshua";
char *data2 = "Anna"; char *data2 = "Anna";
char *data3 = "Christopher"; char *data3 = "Christopher";
char *data4 = "Mary"; char *data4 = "Mary";
char data_buffer[480] = ""; char data_buffer[480] = "";
char test_data_buffer[480] = ""; char test_data_buffer[480] = "";
char *data; char *data;
unsigned count; unsigned count;
sbuf_init(&sbuffer,NULL,0); sbuf_init(&sbuffer, NULL, 0);
ct_test(pTest,sbuf_empty(&sbuffer) == true); ct_test(pTest, sbuf_empty(&sbuffer) == true);
ct_test(pTest,sbuf_data(&sbuffer) == NULL); ct_test(pTest, sbuf_data(&sbuffer) == NULL);
ct_test(pTest,sbuf_size(&sbuffer) == 0); ct_test(pTest, sbuf_size(&sbuffer) == 0);
ct_test(pTest,sbuf_count(&sbuffer) == 0); ct_test(pTest, sbuf_count(&sbuffer) == 0);
ct_test(pTest,sbuf_append(&sbuffer,data1,strlen(data1)) == false); ct_test(pTest, sbuf_append(&sbuffer, data1, strlen(data1)) == false);
sbuf_init(&sbuffer,data_buffer,sizeof(data_buffer)); sbuf_init(&sbuffer, data_buffer, sizeof(data_buffer));
ct_test(pTest,sbuf_empty(&sbuffer) == true); ct_test(pTest, sbuf_empty(&sbuffer) == true);
ct_test(pTest,sbuf_data(&sbuffer) == data_buffer); ct_test(pTest, sbuf_data(&sbuffer) == data_buffer);
ct_test(pTest,sbuf_size(&sbuffer) == sizeof(data_buffer)); ct_test(pTest, sbuf_size(&sbuffer) == sizeof(data_buffer));
ct_test(pTest,sbuf_count(&sbuffer) == 0); 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));
data = sbuf_data(&sbuffer); ct_test(pTest, sbuf_append(&sbuffer, data1, strlen(data1)) == true);
count = sbuf_count(&sbuffer); ct_test(pTest, sbuf_append(&sbuffer, data2, strlen(data2)) == true);
ct_test(pTest,memcmp(data,test_data_buffer,count) == 0); ct_test(pTest, sbuf_append(&sbuffer, data3, strlen(data3)) == true);
ct_test(pTest,count == strlen(test_data_buffer)); ct_test(pTest, sbuf_append(&sbuffer, data4, strlen(data4)) == true);
strcat(test_data_buffer, data1);
ct_test(pTest,sbuf_truncate(&sbuffer,0) == true); strcat(test_data_buffer, data2);
ct_test(pTest,sbuf_count(&sbuffer) == 0); strcat(test_data_buffer, data3);
ct_test(pTest,sbuf_size(&sbuffer) == sizeof(data_buffer)); strcat(test_data_buffer, data4);
ct_test(pTest,sbuf_append(&sbuffer,data4,strlen(data4)) == true); ct_test(pTest, sbuf_count(&sbuffer) == strlen(test_data_buffer));
data = sbuf_data(&sbuffer);
count = sbuf_count(&sbuffer);
ct_test(pTest,memcmp(data,data4,count) == 0);
ct_test(pTest,count == strlen(data4));
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 #ifdef TEST_STATIC_BUFFER
int main(void) int main(void)
{ {
Test *pTest; Test *pTest;
bool rc; bool rc;
pTest = ct_create("static buffer", NULL); pTest = ct_create("static buffer", NULL);
/* individual tests */ /* individual tests */
rc = ct_addTestFunction(pTest, testStaticBuffer); rc = ct_addTestFunction(pTest, testStaticBuffer);
assert(rc); assert(rc);
ct_setStream(pTest, stdout); ct_setStream(pTest, stdout);
ct_run(pTest); ct_run(pTest);
(void)ct_report(pTest); (void) ct_report(pTest);
ct_destroy(pTest); ct_destroy(pTest);
return 0; return 0;
} }
#endif /* TEST_STATIC_BUFFER */ #endif /* TEST_STATIC_BUFFER */
#endif /* TEST */ #endif /* TEST */
+23 -29
View File
@@ -42,45 +42,39 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
struct static_buffer_t struct static_buffer_t {
{ char *data; /* block of memory or array of data */
char *data; /* block of memory or array of data */ unsigned size; /* actual size, in bytes, of the block of data */
unsigned size; /* actual size, in bytes, of the block of data */ unsigned count; /* number of bytes in use */
unsigned count; /* number of bytes in use */
}; };
typedef struct static_buffer_t STATIC_BUFFER; typedef struct static_buffer_t STATIC_BUFFER;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
void sbuf_init( void sbuf_init(STATIC_BUFFER * b, /* static buffer structure */
STATIC_BUFFER *b, /* static buffer structure */ char *data, /* actual size, in bytes, of the data block or array of data */
char *data, /* actual size, in bytes, of the data block or array of data */ unsigned size); /* number of bytes used */
unsigned size); /* number of bytes used */
/* returns true if size==0, false if size > 0 */ /* returns true if size==0, false if size > 0 */
bool sbuf_empty(STATIC_BUFFER const *b); bool sbuf_empty(STATIC_BUFFER const *b);
char *sbuf_data(STATIC_BUFFER const *b); char *sbuf_data(STATIC_BUFFER const *b);
unsigned sbuf_size(STATIC_BUFFER *b); unsigned sbuf_size(STATIC_BUFFER * b);
unsigned sbuf_count(STATIC_BUFFER *b); unsigned sbuf_count(STATIC_BUFFER * b);
/* returns true if successful, false if not enough room to append data */ /* returns true if successful, false if not enough room to append data */
bool sbuf_put( bool sbuf_put(STATIC_BUFFER * b, /* static buffer structure */
STATIC_BUFFER *b, /* static buffer structure */ unsigned offset, /* where to start */
unsigned offset, /* where to start */ char *data, /* number of bytes used */
char *data, /* number of bytes used */ unsigned data_size); /* how many to add */
unsigned data_size); /* how many to add */
/* returns true if successful, false if not enough room to append data */ /* returns true if successful, false if not enough room to append data */
bool sbuf_append( bool sbuf_append(STATIC_BUFFER * b, /* static buffer structure */
STATIC_BUFFER *b, /* static buffer structure */ char *data, /* number of bytes used */
char *data, /* number of bytes used */ unsigned data_size); /* how many to add */
unsigned data_size); /* how many to add */
/* returns true if successful, false if not enough room to append data */ /* returns true if successful, false if not enough room to append data */
bool sbuf_truncate( bool sbuf_truncate(STATIC_BUFFER * b, /* static buffer structure */
STATIC_BUFFER *b, /* static buffer structure */ unsigned count); /* total number of bytes in use */
unsigned count); /* total number of bytes in use */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+133 -166
View File
@@ -34,7 +34,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <string.h> // memmove() #include <string.h> // memmove()
#include "bits.h" #include "bits.h"
#include "apdu.h" #include "apdu.h"
#include "bacdef.h" #include "bacdef.h"
@@ -57,77 +57,69 @@
// declare space for the TSM transactions, and set it up in the init. // 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 */ /* 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 // returns MAX_TSM_TRANSACTIONS if not found
static uint8_t tsm_find_invokeID_index(uint8_t invokeID) static uint8_t tsm_find_invokeID_index(uint8_t invokeID)
{ {
unsigned i = 0; // counter unsigned i = 0; // counter
uint8_t index = MAX_TSM_TRANSACTIONS; // return value uint8_t index = MAX_TSM_TRANSACTIONS; // return value
for (i = 0; i < MAX_TSM_TRANSACTIONS; i++) for (i = 0; i < MAX_TSM_TRANSACTIONS; i++) {
{ if (TSM_List[i].InvokeID == invokeID) {
if (TSM_List[i].InvokeID == invokeID) index = i;
{ break;
index = i; }
break;
} }
}
return index; return index;
} }
static uint8_t tsm_find_first_free_index(void) static uint8_t tsm_find_first_free_index(void)
{ {
unsigned i = 0; // counter unsigned i = 0; // counter
uint8_t index = MAX_TSM_TRANSACTIONS; // return value uint8_t index = MAX_TSM_TRANSACTIONS; // return value
for (i = 0; i < MAX_TSM_TRANSACTIONS; i++) for (i = 0; i < MAX_TSM_TRANSACTIONS; i++) {
{ if (TSM_List[i].InvokeID == 0) {
if (TSM_List[i].InvokeID == 0) index = i;
{ break;
index = i; }
break;
} }
}
return index; return index;
} }
bool tsm_transaction_available(void) bool tsm_transaction_available(void)
{ {
bool status = false; // return value bool status = false; // return value
unsigned i = 0; // counter unsigned i = 0; // counter
for (i = 0; i < MAX_TSM_TRANSACTIONS; i++) for (i = 0; i < MAX_TSM_TRANSACTIONS; i++) {
{ if (TSM_List[i].InvokeID == 0) {
if (TSM_List[i].InvokeID == 0) // one is available!
{ status = true;
// one is available! break;
status = true; }
break;
} }
}
return status; return status;
} }
uint8_t tsm_transaction_idle_count(void) uint8_t tsm_transaction_idle_count(void)
{ {
uint8_t count = 0; // return value uint8_t count = 0; // return value
unsigned i = 0; // counter unsigned i = 0; // counter
for (i = 0; i < MAX_TSM_TRANSACTIONS; i++) for (i = 0; i < MAX_TSM_TRANSACTIONS; i++) {
{ if ((TSM_List[i].InvokeID == 0) &&
if ((TSM_List[i].InvokeID == 0) && (TSM_List[i].state == TSM_STATE_IDLE)) {
(TSM_List[i].state == TSM_STATE_IDLE)) // one is available!
{ count++;
// one is available! }
count++;
} }
}
return count; return count;
} }
/* gets the next free invokeID, /* gets the next free invokeID,
@@ -135,162 +127,138 @@ uint8_t tsm_transaction_idle_count(void)
returns 0 if none are available */ returns 0 if none are available */
uint8_t tsm_next_free_invokeID(void) uint8_t tsm_next_free_invokeID(void)
{ {
static uint8_t current_invokeID = 1; // incremented... static uint8_t current_invokeID = 1; // incremented...
uint8_t index = 0; uint8_t index = 0;
uint8_t invokeID = 0; uint8_t invokeID = 0;
bool found = false; bool found = false;
while (!found) while (!found) {
{ index = tsm_find_invokeID_index(current_invokeID);
index = tsm_find_invokeID_index(current_invokeID); /* not found - that is good! */
/* not found - that is good! */ if (index == MAX_TSM_TRANSACTIONS) {
if (index == MAX_TSM_TRANSACTIONS) found = true;
{ /* set this id into the table */
found = true; index = tsm_find_first_free_index();
/* set this id into the table */ if (index != MAX_TSM_TRANSACTIONS) {
index = tsm_find_first_free_index(); TSM_List[index].InvokeID = invokeID = current_invokeID;
if (index != MAX_TSM_TRANSACTIONS) TSM_List[index].state = TSM_STATE_IDLE;
{ TSM_List[index].RequestTimer = Device_APDU_Timeout();
TSM_List[index].InvokeID = invokeID = current_invokeID; /* update for the next call or check */
TSM_List[index].state = TSM_STATE_IDLE; current_invokeID++;
TSM_List[index].RequestTimer = Device_APDU_Timeout(); // skip zero - we treat that internally as invalid or no free
/* update for the next call or check */ if (current_invokeID == 0)
current_invokeID++; current_invokeID = 1;
// 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( void tsm_set_confirmed_unsegmented_transaction(uint8_t invokeID,
uint8_t invokeID, BACNET_ADDRESS * dest, uint8_t * pdu, uint16_t pdu_len)
BACNET_ADDRESS *dest,
uint8_t *pdu,
uint16_t pdu_len)
{ {
uint16_t j = 0; uint16_t j = 0;
uint8_t index; uint8_t index;
if (invokeID) if (invokeID) {
{ index = tsm_find_invokeID_index(invokeID);
index = tsm_find_invokeID_index(invokeID); if (index < MAX_TSM_TRANSACTIONS) {
if (index < MAX_TSM_TRANSACTIONS) // assign the transaction
{ TSM_List[index].state = TSM_STATE_AWAIT_CONFIRMATION;
// assign the transaction TSM_List[index].RetryCount = Device_Number_Of_APDU_Retries();
TSM_List[index].state = TSM_STATE_AWAIT_CONFIRMATION; // start the timer
TSM_List[index].RetryCount = Device_Number_Of_APDU_Retries(); TSM_List[index].RequestTimer = Device_APDU_Timeout();
// start the timer // copy the data
TSM_List[index].RequestTimer = Device_APDU_Timeout(); for (j = 0; j < pdu_len; j++) {
// copy the data TSM_List[index].pdu[j] = pdu[j];
for (j = 0; j < pdu_len; j++) }
{ TSM_List[index].pdu_len = pdu_len;
TSM_List[index].pdu[j] = pdu[j]; address_copy(&TSM_List[index].dest, dest);
} }
TSM_List[index].pdu_len = pdu_len;
address_copy(&TSM_List[index].dest,dest);
} }
}
return; return;
} }
// used to retrieve the transaction payload // used to retrieve the transaction payload
// if we wanted to find out what we sent (i.e. when we get an ack) // if we wanted to find out what we sent (i.e. when we get an ack)
bool tsm_get_transaction_pdu( bool tsm_get_transaction_pdu(uint8_t invokeID,
uint8_t invokeID, BACNET_ADDRESS * dest, uint8_t * pdu, uint16_t * pdu_len)
BACNET_ADDRESS *dest,
uint8_t *pdu,
uint16_t *pdu_len)
{ {
uint16_t j = 0; uint16_t j = 0;
uint8_t index; uint8_t index;
bool found = false; bool found = false;
if (invokeID) if (invokeID) {
{ index = tsm_find_invokeID_index(invokeID);
index = tsm_find_invokeID_index(invokeID); // how much checking is needed? state? dest match? just invokeID?
// how much checking is needed? state? dest match? just invokeID? if (index < MAX_TSM_TRANSACTIONS) {
if (index < MAX_TSM_TRANSACTIONS) // FIXME: we may want to free the transaction so it doesn't timeout
{ // retrieve the transaction
// FIXME: we may want to free the transaction so it doesn't timeout // FIXME: bounds check the pdu_len?
// retrieve the transaction *pdu_len = TSM_List[index].pdu_len;
// FIXME: bounds check the pdu_len? for (j = 0; j < *pdu_len; j++) {
*pdu_len = TSM_List[index].pdu_len; pdu[j] = TSM_List[index].pdu[j];
for (j = 0; j < *pdu_len; j++) }
{ address_copy(dest, &TSM_List[index].dest);
pdu[j] = TSM_List[index].pdu[j]; found = true;
} }
address_copy(dest,&TSM_List[index].dest);
found = true;
} }
}
return found; return found;
} }
/* called once a millisecond or slower */ /* called once a millisecond or slower */
void tsm_timer_milliseconds(uint16_t milliseconds) void tsm_timer_milliseconds(uint16_t milliseconds)
{ {
unsigned i = 0; // counter unsigned i = 0; // counter
int bytes_sent = 0; int bytes_sent = 0;
for (i = 0; i < MAX_TSM_TRANSACTIONS; i++) for (i = 0; i < MAX_TSM_TRANSACTIONS; i++) {
{ if (TSM_List[i].state == TSM_STATE_AWAIT_CONFIRMATION) {
if (TSM_List[i].state == TSM_STATE_AWAIT_CONFIRMATION) if (TSM_List[i].RequestTimer > milliseconds)
{ TSM_List[i].RequestTimer -= milliseconds;
if (TSM_List[i].RequestTimer > milliseconds) else
TSM_List[i].RequestTimer -= milliseconds; TSM_List[i].RequestTimer = 0;
else /* timeout. retry? */
TSM_List[i].RequestTimer = 0; if (TSM_List[i].RequestTimer == 0) {
/* timeout. retry? */ TSM_List[i].RetryCount--;
if (TSM_List[i].RequestTimer == 0) TSM_List[i].RequestTimer = Device_APDU_Timeout();
{ if (TSM_List[i].RetryCount) {
TSM_List[i].RetryCount--; bytes_sent = datalink_send_pdu(&TSM_List[i].dest, /* destination address */
TSM_List[i].RequestTimer = Device_APDU_Timeout(); &TSM_List[i].pdu[0], TSM_List[i].pdu_len); /* number of bytes of data */
if (TSM_List[i].RetryCount) } else {
{ TSM_List[i].InvokeID = 0;
bytes_sent = datalink_send_pdu( TSM_List[i].state = TSM_STATE_IDLE;
&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;
}
}
} }
}
} }
void tsm_free_invoke_id(uint8_t invokeID) void tsm_free_invoke_id(uint8_t invokeID)
{ {
uint8_t index; uint8_t index;
index = tsm_find_invokeID_index(invokeID); index = tsm_find_invokeID_index(invokeID);
if (index < MAX_TSM_TRANSACTIONS) if (index < MAX_TSM_TRANSACTIONS) {
{ TSM_List[index].state = TSM_STATE_IDLE;
TSM_List[index].state = TSM_STATE_IDLE; TSM_List[index].InvokeID = 0;
TSM_List[index].InvokeID = 0; }
}
} }
/* see if the invoke ID has been made free */ /* see if the invoke ID has been made free */
bool tsm_invoke_id_free(uint8_t invokeID) bool tsm_invoke_id_free(uint8_t invokeID)
{ {
bool status = true; bool status = true;
uint8_t index; uint8_t index;
index = tsm_find_invokeID_index(invokeID); index = tsm_find_invokeID_index(invokeID);
if (index < MAX_TSM_TRANSACTIONS) if (index < MAX_TSM_TRANSACTIONS)
status = false; status = false;
return status; return status;
} }
#ifdef TEST #ifdef TEST
@@ -303,8 +271,8 @@ bool I_Am_Request = true;
void testTSM(Test * pTest) void testTSM(Test * pTest)
{ {
/* FIXME: add some unit testing...*/ /* FIXME: add some unit testing... */
return; return;
} }
#ifdef TEST_TSM #ifdef TEST_TSM
@@ -327,4 +295,3 @@ int main(void)
} }
#endif /* TEST_TSM */ #endif /* TEST_TSM */
#endif /* TEST */ #endif /* TEST */
+48 -58
View File
@@ -42,81 +42,72 @@
/* note: TSM functionality is optional - only needed if we are /* note: TSM functionality is optional - only needed if we are
doing client requests */ doing client requests */
#if TSM_ENABLED #if TSM_ENABLED
typedef enum typedef enum {
{ TSM_STATE_IDLE,
TSM_STATE_IDLE, TSM_STATE_AWAIT_CONFIRMATION,
TSM_STATE_AWAIT_CONFIRMATION, TSM_STATE_AWAIT_RESPONSE,
TSM_STATE_AWAIT_RESPONSE, TSM_STATE_SEGMENTED_REQUEST,
TSM_STATE_SEGMENTED_REQUEST, TSM_STATE_SEGMENTED_CONFIRMATION
TSM_STATE_SEGMENTED_CONFIRMATION
} BACNET_TSM_STATE; } BACNET_TSM_STATE;
// 5.4.1 Variables And Parameters // 5.4.1 Variables And Parameters
// The following variables are defined for each instance of // The following variables are defined for each instance of
// Transaction State Machine: // Transaction State Machine:
typedef struct BACnet_TSM_Data typedef struct BACnet_TSM_Data {
{ // used to count APDU retries
// used to count APDU retries uint8_t RetryCount;
uint8_t RetryCount; // used to count segment retries
// used to count segment retries //uint8_t SegmentRetryCount;
//uint8_t SegmentRetryCount; // used to control APDU retries and the acceptance of server replies
// used to control APDU retries and the acceptance of server replies //bool SentAllSegments;
//bool SentAllSegments; // stores the sequence number of the last segment received in order
// stores the sequence number of the last segment received in order //uint8_t LastSequenceNumber;
//uint8_t LastSequenceNumber; // stores the sequence number of the first segment of
// stores the sequence number of the first segment of // a sequence of segments that fill a window
// a sequence of segments that fill a window //uint8_t InitialSequenceNumber;
//uint8_t InitialSequenceNumber; // stores the current window size
// stores the current window size //uint8_t ActualWindowSize;
//uint8_t ActualWindowSize; // stores the window size proposed by the segment sender
// stores the window size proposed by the segment sender //uint8_t ProposedWindowSize;
//uint8_t ProposedWindowSize; // used to perform timeout on PDU segments
// used to perform timeout on PDU segments //uint8_t SegmentTimer;
//uint8_t SegmentTimer; // used to perform timeout on Confirmed Requests
// used to perform timeout on Confirmed Requests // in milliseconds
// in milliseconds uint16_t RequestTimer;
uint16_t RequestTimer; // unique id
// unique id uint8_t InvokeID;
uint8_t InvokeID; // state that the TSM is in
// state that the TSM is in BACNET_TSM_STATE state;
BACNET_TSM_STATE state; // the address we sent it to
// the address we sent it to BACNET_ADDRESS dest;
BACNET_ADDRESS dest; // copy of the PDU, should we need to send it again
// copy of the PDU, should we need to send it again uint8_t pdu[MAX_PDU];
uint8_t pdu[MAX_PDU]; unsigned pdu_len;
unsigned pdu_len;
} BACNET_TSM_DATA; } BACNET_TSM_DATA;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
bool tsm_transaction_available(void); bool tsm_transaction_available(void);
uint8_t tsm_transaction_idle_count(void); uint8_t tsm_transaction_idle_count(void);
void tsm_timer_milliseconds(uint16_t milliseconds); void tsm_timer_milliseconds(uint16_t milliseconds);
// free the invoke ID when the reply comes back // 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 // 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 // returns the same invoke ID that was given
void tsm_set_confirmed_unsegmented_transaction( void tsm_set_confirmed_unsegmented_transaction(uint8_t invokeID,
uint8_t invokeID, BACNET_ADDRESS * dest, uint8_t * pdu, uint16_t pdu_len);
BACNET_ADDRESS *dest,
uint8_t *pdu,
uint16_t pdu_len);
// returns true if transaction is found // returns true if transaction is found
bool tsm_get_transaction_pdu( bool tsm_get_transaction_pdu(uint8_t invokeID,
uint8_t invokeID, BACNET_ADDRESS * dest, uint8_t * pdu, uint16_t * pdu_len);
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 #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
/* define out any functions necessary for compile */ /* define out any functions necessary for compile */
#else #else
@@ -125,4 +116,3 @@ bool tsm_invoke_id_free(uint8_t invokeID);
#endif #endif
#endif #endif
+151 -182
View File
@@ -39,137 +39,122 @@
/* encode service - use -1 for limit for unlimited */ /* encode service - use -1 for limit for unlimited */
int whohas_encode_apdu( int whohas_encode_apdu(uint8_t * apdu, BACNET_WHO_HAS_DATA * data)
uint8_t *apdu,
BACNET_WHO_HAS_DATA *data)
{ {
int len = 0; // length of each encoding int len = 0; // length of each encoding
int apdu_len = 0; // total length of the apdu, return value int apdu_len = 0; // total length of the apdu, return value
if (apdu && data) { if (apdu && data) {
apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST; apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST;
apdu[1] = SERVICE_UNCONFIRMED_WHO_HAS; // service choice apdu[1] = SERVICE_UNCONFIRMED_WHO_HAS; // service choice
apdu_len = 2; apdu_len = 2;
// optional limits - must be used as a pair // optional limits - must be used as a pair
if ((data->low_limit >= 0) && (data->low_limit <= BACNET_MAX_INSTANCE) && if ((data->low_limit >= 0)
(data->high_limit >= 0) && (data->high_limit <= BACNET_MAX_INSTANCE)) && (data->low_limit <= BACNET_MAX_INSTANCE)
{ && (data->high_limit >= 0)
len = encode_context_unsigned( && (data->high_limit <= BACNET_MAX_INSTANCE)) {
&apdu[apdu_len], len =
0, encode_context_unsigned(&apdu[apdu_len], 0,
data->low_limit); data->low_limit);
apdu_len += len; apdu_len += len;
len = encode_context_unsigned( len = encode_context_unsigned(&apdu[apdu_len],
&apdu[apdu_len], 1, data->high_limit);
1, apdu_len += len;
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 // decode the service request only
int whohas_decode_service_request( int whohas_decode_service_request(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, BACNET_WHO_HAS_DATA * data)
unsigned apdu_len,
BACNET_WHO_HAS_DATA *data)
{ {
int len = 0; int len = 0;
uint8_t tag_number = 0; uint8_t tag_number = 0;
uint32_t len_value = 0; uint32_t len_value = 0;
uint32_t decoded_value = 0; /* for decoding */ uint32_t decoded_value = 0; /* for decoding */
int decoded_type = 0; /* for decoding */ int decoded_type = 0; /* for decoding */
if (apdu_len && data) if (apdu_len && data) {
{ /* optional limits - must be used as a pair */
/* optional limits - must be used as a pair */ if (decode_is_context_tag(&apdu[len], 0)) {
if (decode_is_context_tag(&apdu[len], 0)) len +=
{ decode_tag_number_and_value(&apdu[len], &tag_number,
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); &len_value);
len += decode_unsigned(&apdu[len], len_value, &decoded_value); len += decode_unsigned(&apdu[len], len_value, &decoded_value);
if (decoded_value <= BACNET_MAX_INSTANCE) if (decoded_value <= BACNET_MAX_INSTANCE)
data->low_limit = decoded_value; data->low_limit = decoded_value;
if (!decode_is_context_tag(&apdu[len], 1)) if (!decode_is_context_tag(&apdu[len], 1))
return -1; return -1;
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); len +=
len += decode_unsigned(&apdu[len], decode_tag_number_and_value(&apdu[len], &tag_number,
len_value, &decoded_value); &len_value);
if (decoded_value <= BACNET_MAX_INSTANCE) len += decode_unsigned(&apdu[len], len_value, &decoded_value);
data->high_limit = 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( int whohas_decode_apdu(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, BACNET_WHO_HAS_DATA * data)
unsigned apdu_len,
BACNET_WHO_HAS_DATA *data)
{ {
int len = 0; int len = 0;
if (!apdu) if (!apdu)
return -1; return -1;
// optional checking - most likely was already done prior to this call // optional checking - most likely was already done prior to this call
if (apdu[0] != PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST) if (apdu[0] != PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST)
return -1; return -1;
if (apdu[1] != SERVICE_UNCONFIRMED_WHO_IS) if (apdu[1] != SERVICE_UNCONFIRMED_WHO_IS)
return -1; return -1;
// optional limits - must be used as a pair // optional limits - must be used as a pair
if (apdu_len > 2) if (apdu_len > 2) {
{ len = whohas_decode_service_request(&apdu[2], apdu_len - 2, data);
len = whohas_decode_service_request( }
&apdu[2],
apdu_len - 2,
data);
}
return len; return len;
} }
#ifdef TEST #ifdef TEST
@@ -177,84 +162,68 @@ int whohas_decode_apdu(
#include <string.h> #include <string.h>
#include "ctest.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}; uint8_t apdu[480] = { 0 };
int len = 0; int len = 0;
int apdu_len = 0; int apdu_len = 0;
BACNET_WHO_HAS_DATA test_data; BACNET_WHO_HAS_DATA test_data;
len = whohas_encode_apdu( len = whohas_encode_apdu(&apdu[0], data);
&apdu[0], ct_test(pTest, len != 0);
data); apdu_len = len;
ct_test(pTest, len != 0);
apdu_len = len;
len = whohas_decode_apdu( len = whohas_decode_apdu(&apdu[0], apdu_len, &test_data);
&apdu[0], ct_test(pTest, len != -1);
apdu_len, ct_test(pTest, test_data.low_limit == data->low_limit);
&test_data); ct_test(pTest, test_data.high_limit == data->high_limit);
ct_test(pTest, len != -1); ct_test(pTest, test_data.object_name == data->object_name);
ct_test(pTest, test_data.low_limit == data->low_limit); /* Object ID */
ct_test(pTest, test_data.high_limit == data->high_limit); if (data->object_name == false) {
ct_test(pTest, test_data.object_name == data->object_name); ct_test(pTest, test_data.object.identifier.type ==
/* Object ID */ data->object.identifier.type);
if (data->object_name == false) ct_test(pTest, test_data.object.identifier.instance ==
{ data->object.identifier.instance);
ct_test(pTest, test_data.object.identifier.type == }
data->object.identifier.type); /* Object Name */
ct_test(pTest, test_data.object.identifier.instance == else {
data->object.identifier.instance); ct_test(pTest, characterstring_same(&test_data.object.name,
} &data->object.name));
/* Object Name */ }
else
{
ct_test(pTest, characterstring_same(
&test_data.object.name,&data->object.name));
}
} }
void testWhoHas(Test * pTest) void testWhoHas(Test * pTest)
{ {
BACNET_WHO_HAS_DATA data; BACNET_WHO_HAS_DATA data;
data.low_limit = -1; data.low_limit = -1;
data.high_limit = -1; data.high_limit = -1;
data.object_name = false; data.object_name = false;
data.object.identifier.type = OBJECT_ANALOG_INPUT; data.object.identifier.type = OBJECT_ANALOG_INPUT;
data.object.identifier.instance = 1; data.object.identifier.instance = 1;
testWhoHasData(pTest,&data); testWhoHasData(pTest, &data);
for ( for (data.low_limit = 0;
data.low_limit = 0; data.low_limit <= BACNET_MAX_INSTANCE;
data.low_limit <= BACNET_MAX_INSTANCE; data.low_limit += (BACNET_MAX_INSTANCE / 4)) {
data.low_limit += (BACNET_MAX_INSTANCE/4)) for (data.high_limit = 0;
{ data.high_limit <= BACNET_MAX_INSTANCE;
for ( data.high_limit += (BACNET_MAX_INSTANCE / 4)) {
data.high_limit = 0; data.object_name = false;
data.high_limit <= BACNET_MAX_INSTANCE; for (data.object.identifier.type = OBJECT_ANALOG_INPUT;
data.high_limit += (BACNET_MAX_INSTANCE/4)) data.object.identifier.type <= MAX_BACNET_OBJECT_TYPE;
{ data.object.identifier.type++) {
data.object_name = false; for (data.object.identifier.instance = 1;
for ( data.object.identifier.instance <= BACNET_MAX_INSTANCE;
data.object.identifier.type = OBJECT_ANALOG_INPUT; data.object.identifier.instance <<= 1) {
data.object.identifier.type <= MAX_BACNET_OBJECT_TYPE; testWhoHasData(pTest, &data);
data.object.identifier.type++) }
{ }
for ( data.object_name = true;
data.object.identifier.instance = 1; characterstring_init_ansi(&data.object.name, "patricia");
data.object.identifier.instance <= BACNET_MAX_INSTANCE; testWhoHasData(pTest, &data);
data.object.identifier.instance <<= 1)
{
testWhoHasData(pTest,&data);
} }
}
data.object_name = true;
characterstring_init_ansi(
&data.object.name,"patricia");
testWhoHasData(pTest,&data);
} }
}
} }
#ifdef TEST_WHOHAS #ifdef TEST_WHOHAS
+16 -26
View File
@@ -38,45 +38,35 @@
#include <stdbool.h> #include <stdbool.h>
#include "bacstr.h" #include "bacstr.h"
typedef struct BACnet_Who_Has_Data typedef struct BACnet_Who_Has_Data {
{ int32_t low_limit; /* deviceInstanceRange */
int32_t low_limit; /* deviceInstanceRange */ int32_t high_limit;
int32_t high_limit; bool object_name; /* true if a string */
bool object_name; /* true if a string */ union {
union BACNET_OBJECT_ID identifier;
{ BACNET_CHARACTER_STRING name;
BACNET_OBJECT_ID identifier; } object;
BACNET_CHARACTER_STRING name;
} object;
} BACNET_WHO_HAS_DATA; } BACNET_WHO_HAS_DATA;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
// encode service - use -1 for limit if you want unlimited // encode service - use -1 for limit if you want unlimited
int whohas_encode_apdu( int whohas_encode_apdu(uint8_t * apdu, BACNET_WHO_HAS_DATA * data);
uint8_t *apdu,
BACNET_WHO_HAS_DATA *data);
int whohas_decode_service_request( int whohas_decode_service_request(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, BACNET_WHO_HAS_DATA * data);
unsigned apdu_len,
BACNET_WHO_HAS_DATA *data);
int whohas_decode_apdu( int whohas_decode_apdu(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, BACNET_WHO_HAS_DATA * data);
unsigned apdu_len,
BACNET_WHO_HAS_DATA *data);
#ifdef TEST #ifdef TEST
#include "ctest.h" #include "ctest.h"
void testWhoHas(Test * pTest); void testWhoHas(Test * pTest);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+96 -131
View File
@@ -37,103 +37,84 @@
#include "bacdef.h" #include "bacdef.h"
// encode I-Am service - use -1 for limit if you want unlimited // encode I-Am service - use -1 for limit if you want unlimited
int whois_encode_apdu( int whois_encode_apdu(uint8_t * apdu,
uint8_t *apdu, int32_t low_limit, int32_t high_limit)
int32_t low_limit,
int32_t high_limit)
{ {
int len = 0; // length of each encoding int len = 0; // length of each encoding
int apdu_len = 0; // total length of the apdu, return value int apdu_len = 0; // total length of the apdu, return value
if (apdu) { if (apdu) {
apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST; apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST;
apdu[1] = SERVICE_UNCONFIRMED_WHO_IS; // service choice apdu[1] = SERVICE_UNCONFIRMED_WHO_IS; // service choice
apdu_len = 2; apdu_len = 2;
// optional limits - must be used as a pair // optional limits - must be used as a pair
if ((low_limit >= 0) && (low_limit <= BACNET_MAX_INSTANCE) && if ((low_limit >= 0) && (low_limit <= BACNET_MAX_INSTANCE) &&
(high_limit >= 0) && (high_limit <= BACNET_MAX_INSTANCE)) (high_limit >= 0) && (high_limit <= BACNET_MAX_INSTANCE)) {
{ len = encode_context_unsigned(&apdu[apdu_len], 0, low_limit);
len = encode_context_unsigned( apdu_len += len;
&apdu[apdu_len], len = encode_context_unsigned(&apdu[apdu_len], 1, high_limit);
0, apdu_len += len;
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 // decode the service request only
int whois_decode_service_request( int whois_decode_service_request(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, int32_t * pLow_limit, int32_t * pHigh_limit)
unsigned apdu_len,
int32_t *pLow_limit,
int32_t *pHigh_limit)
{ {
int len = 0; int len = 0;
uint8_t tag_number = 0; uint8_t tag_number = 0;
uint32_t len_value = 0; uint32_t len_value = 0;
uint32_t decoded_value = 0; uint32_t decoded_value = 0;
// optional limits - must be used as a pair // optional limits - must be used as a pair
if (apdu_len) if (apdu_len) {
{ len +=
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); decode_tag_number_and_value(&apdu[len], &tag_number,
if (tag_number != 0) &len_value);
return -1; if (tag_number != 0)
len += decode_unsigned(&apdu[len], len_value, &decoded_value); return -1;
if (decoded_value <= BACNET_MAX_INSTANCE) len += decode_unsigned(&apdu[len], len_value, &decoded_value);
{ if (decoded_value <= BACNET_MAX_INSTANCE) {
if (pLow_limit) if (pLow_limit)
*pLow_limit = decoded_value; *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 len;
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;
} }
int whois_decode_apdu( int whois_decode_apdu(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, int32_t * pLow_limit, int32_t * pHigh_limit)
unsigned apdu_len,
int32_t *pLow_limit,
int32_t *pHigh_limit)
{ {
int len = 0; int len = 0;
if (!apdu) if (!apdu)
return -1; return -1;
// optional checking - most likely was already done prior to this call // optional checking - most likely was already done prior to this call
if (apdu[0] != PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST) if (apdu[0] != PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST)
return -1; return -1;
if (apdu[1] != SERVICE_UNCONFIRMED_WHO_IS) if (apdu[1] != SERVICE_UNCONFIRMED_WHO_IS)
return -1; return -1;
// optional limits - must be used as a pair // optional limits - must be used as a pair
if (apdu_len > 2) if (apdu_len > 2) {
{ len = whois_decode_service_request(&apdu[2],
len = whois_decode_service_request( apdu_len - 2, pLow_limit, pHigh_limit);
&apdu[2], }
apdu_len - 2,
pLow_limit, return len;
pHigh_limit);
}
return len;
} }
#ifdef TEST #ifdef TEST
@@ -143,56 +124,40 @@ int whois_decode_apdu(
void testWhoIs(Test * pTest) void testWhoIs(Test * pTest)
{ {
uint8_t apdu[480] = {0}; uint8_t apdu[480] = { 0 };
int len = 0; int len = 0;
int apdu_len = 0; int apdu_len = 0;
int32_t low_limit = -1; int32_t low_limit = -1;
int32_t high_limit = -1; int32_t high_limit = -1;
int32_t test_low_limit = -1; int32_t test_low_limit = -1;
int32_t test_high_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;
len = whois_decode_apdu( len = whois_encode_apdu(&apdu[0], low_limit, high_limit);
&apdu[0], ct_test(pTest, len != 0);
apdu_len, apdu_len = 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 ( len = whois_decode_apdu(&apdu[0],
low_limit = 0; apdu_len, &test_low_limit, &test_high_limit);
low_limit <= BACNET_MAX_INSTANCE; ct_test(pTest, len != -1);
low_limit += (BACNET_MAX_INSTANCE/4)) ct_test(pTest, test_low_limit == low_limit);
{ ct_test(pTest, test_high_limit == high_limit);
for (
high_limit = 0; for (low_limit = 0;
high_limit <= BACNET_MAX_INSTANCE; low_limit <= BACNET_MAX_INSTANCE;
high_limit += (BACNET_MAX_INSTANCE/4)) low_limit += (BACNET_MAX_INSTANCE / 4)) {
{ for (high_limit = 0;
len = whois_encode_apdu( high_limit <= BACNET_MAX_INSTANCE;
&apdu[0], high_limit += (BACNET_MAX_INSTANCE / 4)) {
low_limit, len = whois_encode_apdu(&apdu[0], low_limit, high_limit);
high_limit); apdu_len = len;
apdu_len = len; ct_test(pTest, len != 0);
ct_test(pTest, len != 0); len = whois_decode_apdu(&apdu[0],
len = whois_decode_apdu( apdu_len, &test_low_limit, &test_high_limit);
&apdu[0], ct_test(pTest, len != -1);
apdu_len, ct_test(pTest, test_low_limit == low_limit);
&test_low_limit, ct_test(pTest, test_high_limit == high_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 #ifdef TEST_WHOIS
+10 -20
View File
@@ -39,33 +39,23 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
// encode service - use -1 for limit if you want unlimited // encode service - use -1 for limit if you want unlimited
int whois_encode_apdu( int whois_encode_apdu(uint8_t * apdu,
uint8_t *apdu, int32_t low_limit, int32_t high_limit);
int32_t low_limit,
int32_t high_limit);
int whois_decode_service_request( int whois_decode_service_request(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, int32_t * pLow_limit, int32_t * pHigh_limit);
unsigned apdu_len,
int32_t *pLow_limit, int whois_decode_apdu(uint8_t * apdu,
int32_t *pHigh_limit); 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 #ifdef TEST
void testWhoIs(Test * pTest); void testWhoIs(Test * pTest);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+240 -265
View File
@@ -39,153 +39,138 @@
#include "wp.h" #include "wp.h"
// encode service // encode service
int wp_encode_apdu( int wp_encode_apdu(uint8_t * apdu,
uint8_t *apdu, uint8_t invoke_id, BACNET_WRITE_PROPERTY_DATA * data)
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) if (apdu) {
{ apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST; apdu[1] =
apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted()); encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted());
apdu[2] = invoke_id; apdu[2] = invoke_id;
apdu[3] = SERVICE_CONFIRMED_WRITE_PROPERTY; // service choice apdu[3] = SERVICE_CONFIRMED_WRITE_PROPERTY; // service choice
apdu_len = 4; apdu_len = 4;
apdu_len += encode_context_object_id(&apdu[apdu_len], 0, apdu_len += encode_context_object_id(&apdu[apdu_len], 0,
data->object_type, data->object_instance); data->object_type, data->object_instance);
apdu_len += encode_context_enumerated(&apdu[apdu_len], 1, apdu_len += encode_context_enumerated(&apdu[apdu_len], 1,
data->object_property); data->object_property);
/* optional array index; ALL is -1 which is assumed when missing */ /* optional array index; ALL is -1 which is assumed when missing */
if (data->array_index != BACNET_ARRAY_ALL) if (data->array_index != BACNET_ARRAY_ALL)
apdu_len += encode_context_unsigned(&apdu[apdu_len], 2, apdu_len += encode_context_unsigned(&apdu[apdu_len], 2,
data->array_index); data->array_index);
// propertyValue // propertyValue
apdu_len += encode_opening_tag(&apdu[apdu_len], 3); apdu_len += encode_opening_tag(&apdu[apdu_len], 3);
apdu_len += bacapp_encode_application_data(&apdu[apdu_len], &data->value); apdu_len +=
apdu_len += encode_closing_tag(&apdu[apdu_len], 3); bacapp_encode_application_data(&apdu[apdu_len], &data->value);
// optional priority - 0 if not set, 1..16 if set apdu_len += encode_closing_tag(&apdu[apdu_len], 3);
if (data->priority != BACNET_NO_PRIORITY) // optional priority - 0 if not set, 1..16 if set
apdu_len += encode_context_unsigned(&apdu[apdu_len], 4, if (data->priority != BACNET_NO_PRIORITY)
data->priority); apdu_len += encode_context_unsigned(&apdu[apdu_len], 4,
} data->priority);
}
return apdu_len;
return apdu_len;
} }
/* decode the service request only */ /* decode the service request only */
/* FIXME: there could be various error messages returned /* FIXME: there could be various error messages returned
using unique values less than zero */ using unique values less than zero */
int wp_decode_service_request( int wp_decode_service_request(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, BACNET_WRITE_PROPERTY_DATA * data)
unsigned apdu_len,
BACNET_WRITE_PROPERTY_DATA *data)
{ {
int len = 0; int len = 0;
int tag_len = 0; int tag_len = 0;
uint8_t tag_number = 0; uint8_t tag_number = 0;
uint32_t len_value_type = 0; uint32_t len_value_type = 0;
int type = 0; // for decoding int type = 0; // for decoding
int property = 0; // for decoding int property = 0; // for decoding
uint32_t unsigned_value = 0; uint32_t unsigned_value = 0;
// check for value pointers // check for value pointers
if (apdu_len && data) if (apdu_len && data) {
{ // Tag 0: Object ID
// Tag 0: Object ID if (!decode_is_context_tag(&apdu[len++], 0))
if (!decode_is_context_tag(&apdu[len++], 0)) return -1;
return -1; len += decode_object_id(&apdu[len], &type, &data->object_instance);
len += decode_object_id(&apdu[len], &type, &data->object_instance); data->object_type = type;
data->object_type = type; // Tag 1: Property ID
// Tag 1: Property ID len += decode_tag_number_and_value(&apdu[len],
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type);
&tag_number, &len_value_type); if (tag_number != 1)
if (tag_number != 1) return -1;
return -1; len += decode_enumerated(&apdu[len], len_value_type, &property);
len += decode_enumerated(&apdu[len], len_value_type, &property); data->object_property = property;
data->object_property = property; // Tag 2: Optional Array Index
// Tag 2: Optional Array Index // note: decode without incrementing len so we can check for opening tag
// note: decode without incrementing len so we can check for opening tag tag_len = decode_tag_number_and_value(&apdu[len],
tag_len = decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type);
&tag_number, &len_value_type); if (tag_number == 2) {
if (tag_number == 2) len += tag_len;
{ len += decode_unsigned(&apdu[len], len_value_type,
len += tag_len; &unsigned_value);
len += decode_unsigned(&apdu[len], len_value_type, data->array_index = unsigned_value;
&unsigned_value); } else
data->array_index = unsigned_value; data->array_index = BACNET_ARRAY_ALL;
} // Tag 3: opening context tag */
else if (!decode_is_opening_tag_number(&apdu[len], 3))
data->array_index = BACNET_ARRAY_ALL; return -1;
// Tag 3: opening context tag */ // a tag number of 3 is not extended so only one octet
if (!decode_is_opening_tag_number(&apdu[len], 3)) len++;
return -1; len += bacapp_decode_application_data(&apdu[len],
// a tag number of 3 is not extended so only one octet apdu_len - len, &data->value);
len++; /* FIXME: check the return value; abort if no valid data? */
len += bacapp_decode_application_data( /* FIXME: there might be more than one data element in here! */
&apdu[len], if (!decode_is_closing_tag_number(&apdu[len], 3))
apdu_len - len, return -1;
&data->value); // a tag number of 3 is not extended so only one octet
/* FIXME: check the return value; abort if no valid data? */ len++;
/* FIXME: there might be more than one data element in here! */ // Tag 4: optional Priority - assumed MAX if not explicitly set
if (!decode_is_closing_tag_number(&apdu[len], 3)) data->priority = BACNET_MAX_PRIORITY;
return -1; if ((unsigned) len < apdu_len) {
// a tag number of 3 is not extended so only one octet tag_len = decode_tag_number_and_value(&apdu[len],
len++; &tag_number, &len_value_type);
// Tag 4: optional Priority - assumed MAX if not explicitly set if (tag_number == 4) {
data->priority = BACNET_MAX_PRIORITY; len += tag_len;
if ((unsigned)len < apdu_len) len =
{ decode_unsigned(&apdu[len], len_value_type,
tag_len = decode_tag_number_and_value(&apdu[len], &unsigned_value);
&tag_number, &len_value_type); if ((unsigned_value >= BACNET_MIN_PRIORITY)
if (tag_number == 4) && (unsigned_value <= BACNET_MAX_PRIORITY)) {
{ data->priority = (uint8_t) unsigned_value;
len += tag_len; } else
len = decode_unsigned(&apdu[len], len_value_type, &unsigned_value); return -1;
if ((unsigned_value >= BACNET_MIN_PRIORITY) && }
(unsigned_value <= BACNET_MAX_PRIORITY))
{
data->priority = (uint8_t)unsigned_value;
} }
else
return -1;
}
} }
}
return len; return len;
} }
int wp_decode_apdu( int wp_decode_apdu(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len,
unsigned apdu_len, uint8_t * invoke_id, BACNET_WRITE_PROPERTY_DATA * data)
uint8_t *invoke_id,
BACNET_WRITE_PROPERTY_DATA *data)
{ {
int len = 0; int len = 0;
unsigned offset = 0; unsigned offset = 0;
if (!apdu) if (!apdu)
return -1; return -1;
// optional checking - most likely was already done prior to this call // optional checking - most likely was already done prior to this call
if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST) if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
return -1; return -1;
// apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted()); // apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted());
*invoke_id = apdu[2]; /* invoke id - filled in by net layer */ *invoke_id = apdu[2]; /* invoke id - filled in by net layer */
if (apdu[3] != SERVICE_CONFIRMED_WRITE_PROPERTY) if (apdu[3] != SERVICE_CONFIRMED_WRITE_PROPERTY)
return -1; return -1;
offset = 4; offset = 4;
if (apdu_len > offset) if (apdu_len > offset) {
{ len = wp_decode_service_request(&apdu[offset],
len = wp_decode_service_request( apdu_len - offset, data);
&apdu[offset], }
apdu_len - offset,
data); return len;
}
return len;
} }
@@ -197,169 +182,159 @@ int wp_decode_apdu(
#include <string.h> #include <string.h>
#include "ctest.h" #include "ctest.h"
void testWritePropertyTag(Test * pTest, void testWritePropertyTag(Test * pTest, BACNET_WRITE_PROPERTY_DATA * data)
BACNET_WRITE_PROPERTY_DATA *data)
{ {
BACNET_WRITE_PROPERTY_DATA test_data = {0}; BACNET_WRITE_PROPERTY_DATA test_data = { 0 };
uint8_t apdu[480] = {0}; uint8_t apdu[480] = { 0 };
int len = 0; int len = 0;
int apdu_len = 0; int apdu_len = 0;
uint8_t invoke_id = 128; uint8_t invoke_id = 128;
uint8_t test_invoke_id = 0; uint8_t test_invoke_id = 0;
len = wp_encode_apdu(
&apdu[0],
invoke_id,
data);
ct_test(pTest, len != 0);
apdu_len = len;
len = wp_decode_apdu( len = wp_encode_apdu(&apdu[0], invoke_id, data);
&apdu[0], ct_test(pTest, len != 0);
apdu_len, apdu_len = len;
&test_invoke_id,
&test_data); len = wp_decode_apdu(&apdu[0], apdu_len, &test_invoke_id, &test_data);
ct_test(pTest, len != -1); ct_test(pTest, len != -1);
ct_test(pTest, test_data.object_type == data->object_type); 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_instance == data->object_instance);
ct_test(pTest, test_data.object_property == data->object_property); 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.array_index == data->array_index);
ct_test(pTest, test_data.value.tag == data->value.tag); ct_test(pTest, test_data.value.tag == data->value.tag);
switch (test_data.value.tag) switch (test_data.value.tag) {
{
case BACNET_APPLICATION_TAG_NULL: case BACNET_APPLICATION_TAG_NULL:
break; break;
case BACNET_APPLICATION_TAG_BOOLEAN: case BACNET_APPLICATION_TAG_BOOLEAN:
ct_test(pTest, test_data.value.type.Boolean == ct_test(pTest, test_data.value.type.Boolean ==
data->value.type.Boolean); data->value.type.Boolean);
break; break;
case BACNET_APPLICATION_TAG_UNSIGNED_INT: case BACNET_APPLICATION_TAG_UNSIGNED_INT:
ct_test(pTest, test_data.value.type.Unsigned_Int == ct_test(pTest, test_data.value.type.Unsigned_Int ==
data->value.type.Unsigned_Int); data->value.type.Unsigned_Int);
break; break;
case BACNET_APPLICATION_TAG_SIGNED_INT: case BACNET_APPLICATION_TAG_SIGNED_INT:
ct_test(pTest, test_data.value.type.Signed_Int == ct_test(pTest, test_data.value.type.Signed_Int ==
data->value.type.Signed_Int); data->value.type.Signed_Int);
break; break;
case BACNET_APPLICATION_TAG_REAL: case BACNET_APPLICATION_TAG_REAL:
ct_test(pTest, test_data.value.type.Real == ct_test(pTest, test_data.value.type.Real == data->value.type.Real);
data->value.type.Real); break;
break;
case BACNET_APPLICATION_TAG_ENUMERATED: case BACNET_APPLICATION_TAG_ENUMERATED:
ct_test(pTest, test_data.value.type.Enumerated == ct_test(pTest, test_data.value.type.Enumerated ==
data->value.type.Enumerated); data->value.type.Enumerated);
break; break;
case BACNET_APPLICATION_TAG_DATE: case BACNET_APPLICATION_TAG_DATE:
ct_test(pTest, test_data.value.type.Date.year == ct_test(pTest, test_data.value.type.Date.year ==
data->value.type.Date.year); data->value.type.Date.year);
ct_test(pTest, test_data.value.type.Date.month == ct_test(pTest, test_data.value.type.Date.month ==
data->value.type.Date.month); data->value.type.Date.month);
ct_test(pTest, test_data.value.type.Date.day == ct_test(pTest, test_data.value.type.Date.day ==
data->value.type.Date.day); data->value.type.Date.day);
ct_test(pTest, test_data.value.type.Date.wday == ct_test(pTest, test_data.value.type.Date.wday ==
data->value.type.Date.wday); data->value.type.Date.wday);
break; break;
case BACNET_APPLICATION_TAG_TIME: case BACNET_APPLICATION_TAG_TIME:
ct_test(pTest, test_data.value.type.Time.hour == ct_test(pTest, test_data.value.type.Time.hour ==
data->value.type.Time.hour); data->value.type.Time.hour);
ct_test(pTest, test_data.value.type.Time.min == ct_test(pTest, test_data.value.type.Time.min ==
data->value.type.Time.min); data->value.type.Time.min);
ct_test(pTest, test_data.value.type.Time.sec == ct_test(pTest, test_data.value.type.Time.sec ==
data->value.type.Time.sec); data->value.type.Time.sec);
ct_test(pTest, test_data.value.type.Time.hundredths == ct_test(pTest, test_data.value.type.Time.hundredths ==
data->value.type.Time.hundredths); data->value.type.Time.hundredths);
break; break;
case BACNET_APPLICATION_TAG_OBJECT_ID: case BACNET_APPLICATION_TAG_OBJECT_ID:
ct_test(pTest, test_data.value.type.Object_Id.type == ct_test(pTest, test_data.value.type.Object_Id.type ==
data->value.type.Object_Id.type); data->value.type.Object_Id.type);
ct_test(pTest, test_data.value.type.Object_Id.instance == ct_test(pTest, test_data.value.type.Object_Id.instance ==
data->value.type.Object_Id.instance); data->value.type.Object_Id.instance);
break; break;
default: default:
break; break;
} }
} }
void testWriteProperty(Test * pTest) void testWriteProperty(Test * pTest)
{ {
BACNET_WRITE_PROPERTY_DATA data = {0}; BACNET_WRITE_PROPERTY_DATA data = { 0 };
data.value.tag = BACNET_APPLICATION_TAG_NULL; data.value.tag = BACNET_APPLICATION_TAG_NULL;
testWritePropertyTag(pTest, &data); testWritePropertyTag(pTest, &data);
data.value.tag = BACNET_APPLICATION_TAG_BOOLEAN; data.value.tag = BACNET_APPLICATION_TAG_BOOLEAN;
data.value.type.Boolean = true; data.value.type.Boolean = true;
testWritePropertyTag(pTest, &data); testWritePropertyTag(pTest, &data);
data.value.type.Boolean = false; data.value.type.Boolean = false;
testWritePropertyTag(pTest, &data); testWritePropertyTag(pTest, &data);
data.value.tag = BACNET_APPLICATION_TAG_UNSIGNED_INT; data.value.tag = BACNET_APPLICATION_TAG_UNSIGNED_INT;
data.value.type.Unsigned_Int = 0; data.value.type.Unsigned_Int = 0;
testWritePropertyTag(pTest, &data); testWritePropertyTag(pTest, &data);
data.value.type.Unsigned_Int = 0xFFFF; data.value.type.Unsigned_Int = 0xFFFF;
testWritePropertyTag(pTest, &data); testWritePropertyTag(pTest, &data);
data.value.type.Unsigned_Int = 0xFFFFFFFF; data.value.type.Unsigned_Int = 0xFFFFFFFF;
testWritePropertyTag(pTest, &data); testWritePropertyTag(pTest, &data);
data.value.tag = BACNET_APPLICATION_TAG_SIGNED_INT; data.value.tag = BACNET_APPLICATION_TAG_SIGNED_INT;
data.value.type.Signed_Int = 0; data.value.type.Signed_Int = 0;
testWritePropertyTag(pTest, &data); testWritePropertyTag(pTest, &data);
data.value.type.Signed_Int = -1; data.value.type.Signed_Int = -1;
testWritePropertyTag(pTest, &data); testWritePropertyTag(pTest, &data);
data.value.type.Signed_Int = 32768; data.value.type.Signed_Int = 32768;
testWritePropertyTag(pTest, &data); testWritePropertyTag(pTest, &data);
data.value.type.Signed_Int = -32768; data.value.type.Signed_Int = -32768;
testWritePropertyTag(pTest, &data); 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_TIME; data.value.tag = BACNET_APPLICATION_TAG_REAL;
data.value.type.Time.hour = 23; data.value.type.Real = 0.0;
data.value.type.Time.min = 59; testWritePropertyTag(pTest, &data);
data.value.type.Time.sec = 59; data.value.type.Real = -1.0;
data.value.type.Time.hundredths = 12; testWritePropertyTag(pTest, &data);
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.tag = BACNET_APPLICATION_TAG_ENUMERATED;
data.value.type.Object_Id.type = OBJECT_ANALOG_INPUT; data.value.type.Enumerated = 0;
data.value.type.Object_Id.instance = 0; testWritePropertyTag(pTest, &data);
testWritePropertyTag(pTest, &data); data.value.type.Enumerated = 0xFFFF;
data.value.type.Object_Id.type = OBJECT_LIFE_SAFETY_ZONE; testWritePropertyTag(pTest, &data);
data.value.type.Object_Id.instance = BACNET_MAX_INSTANCE; data.value.type.Enumerated = 0xFFFFFFFF;
testWritePropertyTag(pTest, &data); 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 #ifdef TEST_WRITE_PROPERTY
uint16_t Device_Max_APDU_Length_Accepted(void) uint16_t Device_Max_APDU_Length_Accepted(void)
{ {
return MAX_APDU; return MAX_APDU;
} }
int main(void) int main(void)
+20 -29
View File
@@ -39,49 +39,40 @@
#include "bacdcode.h" #include "bacdcode.h"
#include "bacapp.h" #include "bacapp.h"
typedef struct BACnet_Write_Property_Data typedef struct BACnet_Write_Property_Data {
{ BACNET_OBJECT_TYPE object_type;
BACNET_OBJECT_TYPE object_type; uint32_t object_instance;
uint32_t object_instance; BACNET_PROPERTY_ID object_property;
BACNET_PROPERTY_ID object_property; int32_t array_index; // use BACNET_ARRAY_ALL when not setting
int32_t array_index; // use BACNET_ARRAY_ALL when not setting BACNET_APPLICATION_DATA_VALUE value;
BACNET_APPLICATION_DATA_VALUE value; uint8_t priority; // use 0 if not setting the priority
uint8_t priority; // use 0 if not setting the priority
} BACNET_WRITE_PROPERTY_DATA; } BACNET_WRITE_PROPERTY_DATA;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
// encode service // encode service
int wp_encode_apdu( int wp_encode_apdu(uint8_t * apdu,
uint8_t *apdu, uint8_t invoke_id, BACNET_WRITE_PROPERTY_DATA * data);
uint8_t invoke_id,
BACNET_WRITE_PROPERTY_DATA *data);
// decode the service request only // decode the service request only
int wp_decode_service_request( int wp_decode_service_request(uint8_t * apdu,
uint8_t *apdu, unsigned apdu_len, BACNET_WRITE_PROPERTY_DATA * data);
unsigned apdu_len,
BACNET_WRITE_PROPERTY_DATA *data); int wp_decode_apdu(uint8_t * apdu,
unsigned apdu_len,
int wp_decode_apdu( uint8_t * invoke_id, BACNET_WRITE_PROPERTY_DATA * data);
uint8_t *apdu,
unsigned apdu_len,
uint8_t *invoke_id,
BACNET_WRITE_PROPERTY_DATA *data);
#ifdef TEST #ifdef TEST
#include "ctest.h" #include "ctest.h"
void test_ReadProperty(Test * pTest); void test_ReadProperty(Test * pTest);
void test_ReadPropertyAck(Test * pTest); void test_ReadPropertyAck(Test * pTest);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif