diff --git a/bacnet-stack/bacdcode.c b/bacnet-stack/bacdcode.c index 024e3dd5..20aaf1a8 100644 --- a/bacnet-stack/bacdcode.c +++ b/bacnet-stack/bacdcode.c @@ -118,6 +118,77 @@ uint8_t encode_max_segs_max_apdu(int max_segs, int max_apdu) return octet; } +// from clause 20.1.2.4 max-segments-accepted +// and clause 20.1.2.5 max-APDU-length-accepted +// returns the encoded octet +int decode_max_segs(uint8_t octet) +{ + int max_segs = 0; + + switch (octet & 0xF0) + { + case 0: + max_segs = 0; + break; + case 0x10: + max_segs = 2; + break; + case 0x20: + max_segs = 4; + break; + case 0x30: + max_segs = 8; + break; + case 0x40: + max_segs = 16; + break; + case 0x50: + max_segs = 32; + break; + case 0x60: + max_segs = 64; + break; + case 0x70: + max_segs = 65; + break; + default: + break; + } + + return max_segs; +} + +int decode_max_apdu(uint8_t octet) +{ + int max_apdu = 0; + + switch (octet & 0x0F) + { + case 0: + max_apdu = 50; + break; + case 1: + max_apdu = 128; + break; + case 2: + max_apdu = 206; + break; + case 3: + max_apdu = 480; + break; + case 4: + max_apdu = 1024; + break; + case 5: + max_apdu = 1476; + break; + default: + break; + } + + return max_apdu; +} + int encode_unsigned16(uint8_t * apdu, uint16_t value) { union { @@ -1255,6 +1326,26 @@ void testBACDCodeObject(Test * pTest) return; } +void testBACDCodeMaxSegsApdu(Test * pTest) +{ + int max_segs[8] = {0,2,4,8,16,32,64,65}; + int max_apdu[6] = {50,128,206,480,1024,1476}; + int i = 0; + int j = 0; + uint8_t octet = 0; + + // test + for (i = 0; i < 8; i++) + { + for (j = 0; j < 6; j++) + { + octet = encode_max_segs_max_apdu(max_segs[i], max_apdu[j]); + ct_test(pTest, max_segs[i] == decode_max_segs(octet)); + ct_test(pTest, max_apdu[j] == decode_max_apdu(octet)); + } + } +} + #ifdef TEST_DECODE int main(void) { @@ -1277,6 +1368,9 @@ int main(void) assert(rc); rc = ct_addTestFunction(pTest, testBACDCodeObject); assert(rc); + rc = ct_addTestFunction(pTest, testBACDCodeMaxSegsApdu); + assert(rc); + // configure output ct_setStream(pTest, stdout); ct_run(pTest); (void) ct_report(pTest); diff --git a/bacnet-stack/bacdcode.h b/bacnet-stack/bacdcode.h index aa68817e..8c0ff926 100644 --- a/bacnet-stack/bacdcode.h +++ b/bacnet-stack/bacdcode.h @@ -147,5 +147,7 @@ int decode_unsigned32(uint8_t * apdu, uint32_t *value); // and clause 20.1.2.5 max-APDU-length-accepted // returns the encoded octet uint8_t encode_max_segs_max_apdu(int max_segs, int max_apdu); +int decode_max_segs(uint8_t octet); +int decode_max_apdu(uint8_t octet); #endif diff --git a/bacnet-stack/npdu.c b/bacnet-stack/npdu.c index 5b1ed523..8b902496 100644 --- a/bacnet-stack/npdu.c +++ b/bacnet-stack/npdu.c @@ -39,77 +39,7 @@ #include "bacenum.h" #include "bits.h" #include "npdu.h" - -/* max-segments-accepted - B'000' Unspecified number of segments accepted. - B'001' 2 segments accepted. - B'010' 4 segments accepted. - B'011' 8 segments accepted. - B'100' 16 segments accepted. - B'101' 32 segments accepted. - B'110' 64 segments accepted. - B'111' Greater than 64 segments accepted. -*/ - -/* max-APDU-length-accepted - B'0000' Up to MinimumMessageSize (50 octets) - B'0001' Up to 128 octets - B'0010' Up to 206 octets (fits in a LonTalk frame) - B'0011' Up to 480 octets (fits in an ARCNET frame) - B'0100' Up to 1024 octets - B'0101' Up to 1476 octets (fits in an ISO 8802-3 frame) - B'0110' reserved by ASHRAE - B'0111' reserved by ASHRAE - B'1000' reserved by ASHRAE - B'1001' reserved by ASHRAE - B'1010' reserved by ASHRAE - B'1011' reserved by ASHRAE - B'1100' reserved by ASHRAE - B'1101' reserved by ASHRAE - B'1110' reserved by ASHRAE - B'1111' reserved by ASHRAE -*/ -uint8_t npdu_encode_max_seg_max_apdu(int max_segs, int max_apdu) -{ - uint8_t octet = 0; - - if (max_segs < 2) - octet = 0; - else if (max_segs < 4) - octet = 0x10; - else if (max_segs < 8) - octet = 0x20; - else if (max_segs < 16) - octet = 0x30; - else if (max_segs < 32) - octet = 0x40; - else if (max_segs < 64) - octet = 0x50; - else if (max_segs == 64) - octet = 0x60; - else - octet = 0x70; - - // max_apdu must be 50 octets minimum - assert(max_apdu >= 50); - if (max_apdu == 50) - octet |= 0x00; - else if (max_apdu <= 128) - octet |= 0x01; - //fits in a LonTalk frame - else if (max_apdu <= 206) - octet |= 0x02; - //fits in an ARCNET or MS/TP frame - else if (max_apdu <= 480) - octet |= 0x03; - else if (max_apdu <= 1024) - octet |= 0x04; - // fits in an ISO 8802-3 frame - else if (max_apdu <= 1476) - octet |= 0x05; - - return octet; -} +#include "apdu.h" int npdu_encode_raw( uint8_t *npdu, @@ -339,6 +269,37 @@ int npdu_decode( return len; } +void npdu_handler( + BACNET_ADDRESS *src, // source address + uint8_t *pdu, // PDU data + uint16_t pdu_len) // length PDU +{ + int apdu_offset = 0; + BACNET_ADDRESS dest = {0}; + BACNET_NPDU_DATA npdu_data = {0}; + + apdu_offset = npdu_decode( + &pdu[0], // data to decode + &dest, // destination address - get the DNET/DLEN/DADR if in there + src, // source address - get the SNET/SLEN/SADR if in there + &npdu_data); // amount of data to decode + if (npdu_data.network_layer_message) + { + //FIXME: network layer message received! Handle it! + } + else + { + apdu_handler( + src, + npdu_data.data_expecting_reply, + &pdu[apdu_offset], + pdu_len - apdu_offset); + } + + return; +} + + #ifdef TEST #include #include