diff --git a/bacnet-stack/src/bacdcode.c b/bacnet-stack/src/bacdcode.c index 3b1d0b2a..6f168213 100644 --- a/bacnet-stack/src/bacdcode.c +++ b/bacnet-stack/src/bacdcode.c @@ -1181,6 +1181,41 @@ int encode_context_real( return len; } +/* from clause 20.2.7 Encoding of a Double Precision Real Number Value */ +/* and 20.2.1 General Rules for Encoding BACnet Tags */ +/* returns the number of apdu bytes consumed */ +int encode_application_double( + uint8_t * apdu, + float value) +{ + int len = 0; + + /* assumes that the tag only consumes 1 octet */ + len = encode_bacnet_double(value, &apdu[1]); + len += encode_tag(&apdu[0], BACNET_APPLICATION_TAG_DOUBLE, false, len); + + return len; +} + +int encode_context_double( + uint8_t * apdu, + int tag_number, + float value) +{ + int len = 0; + + /* assumes that the tag only consumes 1 octet */ + len = encode_bacnet_double(value, &apdu[1]); + /* we only reserved 1 byte for encoding the tag - check the limits */ + if (tag_number <= 14) { + len += encode_tag(&apdu[0], (uint8_t) tag_number, true, len); + } else { + len = 0; + } + + return len; +} + /* from clause 20.2.13 Encoding of a Time Value */ /* and 20.2.1 General Rules for Encoding BACnet Tags */ /* returns the number of apdu bytes consumed */ @@ -1520,8 +1555,8 @@ void testBACDCodeReal( { uint8_t real_array[4] = { 0 }; uint8_t encoded_array[4] = { 0 }; - float value = 42.123; - float decoded_value = 0; + float value = 42.123F; + float decoded_value = 0F; uint8_t apdu[MAX_APDU] = { 0 }; int len = 0, apdu_len = 0; uint8_t tag_number = 0; @@ -1549,6 +1584,40 @@ void testBACDCodeReal( return; } +void testBACDCodeDouble( + Test * pTest) +{ + uint8_t double_array[8] = { 0 }; + uint8_t encoded_array[8] = { 0 }; + double value = 42.123; + double decoded_value = 0; + uint8_t apdu[MAX_APDU] = { 0 }; + int len = 0, apdu_len = 0; + uint8_t tag_number = 0; + uint32_t long_value = 0; + + encode_bacnet_double(value, &double_array[0]); + decode_double(&double_array[0], &decoded_value); + ct_test(pTest, decoded_value == value); + encode_bacnet_double(value, &encoded_array[0]); + ct_test(pTest, memcmp(&double_array, &encoded_array, + sizeof(double_array)) == 0); + + /* a real will take up 4 octects plus a one octet tag */ + apdu_len = encode_application_double(&apdu[0], value); + ct_test(pTest, apdu_len == 9); + /* len tells us how many octets were used for encoding the value */ + len = decode_tag_number_and_value(&apdu[0], &tag_number, &long_value); + ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_DOUBLE); + ct_test(pTest, decode_is_context_specific(&apdu[0]) == false); + ct_test(pTest, len == 1); + ct_test(pTest, long_value == 8); + decode_real(&apdu[len], &decoded_value); + ct_test(pTest, decoded_value == value); + + return; +} + void testBACDCodeUnsignedValue( Test * pTest, uint32_t value) diff --git a/bacnet-stack/src/bacreal.c b/bacnet-stack/src/bacreal.c index 9a29bea4..e56f949b 100644 --- a/bacnet-stack/src/bacreal.c +++ b/bacnet-stack/src/bacreal.c @@ -1,6 +1,6 @@ /*####COPYRIGHTBEGIN#### ------------------------------------------- - Copyright (C) 2004 Steve Karg + Copyright (C) 2004-2008 Steve Karg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -104,6 +104,79 @@ int encode_bacnet_real( return 4; } +/* from clause 20.2.7 Encoding of a Double Precision Real Number Value */ +/* returns the number of apdu bytes consumed */ +int decode_double( + uint8_t * apdu, + double *double_value) +{ + union { + uint8_t byte[8]; + double double_value; + } my_data; + + /* NOTE: assumes the compiler stores float as IEEE-754 float */ +#if BIG_ENDIAN + my_data.byte[0] = apdu[0]; + my_data.byte[1] = apdu[1]; + my_data.byte[2] = apdu[2]; + my_data.byte[3] = apdu[3]; + my_data.byte[4] = apdu[4]; + my_data.byte[5] = apdu[5]; + my_data.byte[6] = apdu[6]; + my_data.byte[7] = apdu[7]; +#else + my_data.byte[0] = apdu[7]; + my_data.byte[1] = apdu[6]; + my_data.byte[2] = apdu[5]; + my_data.byte[3] = apdu[4]; + my_data.byte[4] = apdu[3]; + my_data.byte[5] = apdu[2]; + my_data.byte[6] = apdu[1]; + my_data.byte[7] = apdu[0]; +#endif + + *double_value = my_data.double_value; + + return 8; +} + +/* from clause 20.2.7 Encoding of a Double Precision Real Number Value */ +/* returns the number of apdu bytes consumed */ +int encode_bacnet_double( + double value, + uint8_t * apdu) +{ + union { + uint8_t byte[8]; + double double_value; + } my_data; + + /* NOTE: assumes the compiler stores float as IEEE-754 float */ + my_data.double_value = value; +#if BIG_ENDIAN + apdu[0] = my_data.byte[0]; + apdu[1] = my_data.byte[1]; + apdu[2] = my_data.byte[2]; + apdu[3] = my_data.byte[3]; + apdu[4] = my_data.byte[4]; + apdu[5] = my_data.byte[5]; + apdu[6] = my_data.byte[6]; + apdu[7] = my_data.byte[7]; +#else + apdu[0] = my_data.byte[7]; + apdu[1] = my_data.byte[6]; + apdu[2] = my_data.byte[5]; + apdu[3] = my_data.byte[4]; + apdu[4] = my_data.byte[3]; + apdu[5] = my_data.byte[2]; + apdu[6] = my_data.byte[1]; + apdu[7] = my_data.byte[0]; +#endif + + return 8; +} + /* end of decoding_encoding.c */ #ifdef TEST #include @@ -122,6 +195,21 @@ void testBACreal( ct_test(pTest, len == 4); test_len = decode_real(&apdu[0], &test_real_value); ct_test(pTest, test_len == len); + ct_test(pTest, test_real_value == real_value); +} + +void testBACdouble( + Test * pTest) +{ + double double_value = 3.1415927, test_double_value = 0.0; + uint8_t apdu[MAX_APDU] = { 0 }; + int len = 0, test_len = 0; + + len = encode_bacnet_double(double_value, &apdu[0]); + ct_test(pTest, len == 8); + test_len = decode_double(&apdu[0], &test_double_value); + ct_test(pTest, test_len == len); + ct_test(pTest, test_double_value == double_value); } #ifdef TEST_BACNET_REAL @@ -135,6 +223,8 @@ int main( /* individual tests */ rc = ct_addTestFunction(pTest, testBACreal); assert(rc); + rc = ct_addTestFunction(pTest, testBACdouble); + assert(rc); /* configure output */ ct_setStream(pTest, stdout);