diff --git a/bacnet-stack/bacint.c b/bacnet-stack/bacint.c new file mode 100644 index 00000000..d9fd23c0 --- /dev/null +++ b/bacnet-stack/bacint.c @@ -0,0 +1,580 @@ +/*####COPYRIGHTBEGIN#### + ------------------------------------------- + Copyright (C) 2004 Steve Karg + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + The Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA. + + As a special exception, if other files instantiate templates or + use macros or inline functions from this file, or you compile + this file and link it with other works to produce a work based + on this file, this file does not by itself cause the resulting + work to be covered by the GNU General Public License. However + the source code for this file must still be made available in + accordance with section (3) of the GNU General Public License. + + This exception does not invalidate any other reasons why a work + based on this file might be covered by the GNU General Public + License. + ------------------------------------------- +####COPYRIGHTEND####*/ + +/* BACnet Integer encoding and decoding */ + +#include +#include + +int encode_unsigned16(uint8_t * apdu, uint16_t value) +{ +#if BIG_ENDIAN + apdu[0] = (uint8_t)(value & 0x00ff); + apdu[1] = (uint8_t)((value & 0xff00) >> 8); +#else + apdu[0] = (uint8_t)((value & 0xff00) >> 8); + apdu[1] = (uint8_t)(value & 0x00ff); +#endif + + return 2; +} + +int decode_unsigned16(uint8_t * apdu, uint16_t * value) +{ + if (value) { +#if BIG_ENDIAN + *value = (uint16_t)(apdu[0] & 0x00ff); + *value |= ((uint16_t)((apdu[1] << 8) & 0xff00)); +#else + *value = (uint16_t)((apdu[0] << 8) & 0xff00); + *value |= ((uint16_t)(apdu[1] & 0x00ff)); +#endif + } + + return 2; +} + +int encode_unsigned24(uint8_t * apdu, uint32_t value) +{ +#if BIG_ENDIAN + apdu[0] = (uint8_t)(value & 0x0000ff); + apdu[1] = (uint8_t)((value & 0x00ff00) >> 8); + apdu[2] = (uint8_t)((value & 0xff0000) >> 16); +#else + apdu[0] = (uint8_t)((value & 0xff0000) >> 16); + apdu[1] = (uint8_t)((value & 0x00ff00) >> 8); + apdu[2] = (uint8_t)(value & 0x0000ff); +#endif + + return 3; +} + +int decode_unsigned24(uint8_t * apdu, uint32_t * value) +{ + if (value) { +#if BIG_ENDIAN + *value = (uint32_t)(apdu[0] & 0x000000ff); + *value |= ((uint32_t)((apdu[1] << 8) & 0x0000ff00)); + *value |= ((uint32_t)((apdu[2] << 16) & 0x00ff0000)); +#else + *value = ((uint32_t)((apdu[0] << 16) & 0x00ff0000)); + *value |= (uint32_t)((apdu[1] << 8) & 0x0000ff00); + *value |= ((uint32_t)(apdu[2] & 0x000000ff)); +#endif + } + + return 3; +} + +int encode_unsigned32(uint8_t * apdu, uint32_t value) +{ +#if BIG_ENDIAN + apdu[0] = (uint8_t)(value & 0x000000ff); + apdu[1] = (uint8_t)((value & 0x0000ff00) >> 8); + apdu[2] = (uint8_t)((value & 0x00ff0000) >> 16); + apdu[3] = (uint8_t)((value & 0xff000000) >> 24); +#else + apdu[0] = (uint8_t)((value & 0xff000000) >> 24); + apdu[1] = (uint8_t)((value & 0x00ff0000) >> 16); + apdu[2] = (uint8_t)((value & 0x0000ff00) >> 8); + apdu[3] = (uint8_t)(value & 0x000000ff); +#endif + + return 4; +} + +int decode_unsigned32(uint8_t * apdu, uint32_t * value) +{ + if (value) { +#if BIG_ENDIAN + *value = (uint32_t)(apdu[0] & 0x000000ff); + *value |= ((uint32_t)((apdu[1] << 8) & 0x0000ff00)); + *value |= ((uint32_t)((apdu[2] << 16) & 0x00ff0000)); + *value |= ((uint32_t)((apdu[3] << 24) & 0xff000000)); +#else + *value = ((uint32_t)((apdu[0] << 24) & 0xff000000)); + *value |= ((uint32_t)((apdu[1] << 16) & 0x00ff0000)); + *value |= ((uint32_t)((apdu[2] << 8) & 0x0000ff00)); + *value |= ((uint32_t)(apdu[3] & 0x000000ff)); +#endif + } + + return 4; +} + +int encode_signed8(uint8_t * apdu, int8_t value) +{ + apdu[0] = (uint8_t)value; + + return 1; +} + +int decode_signed8(uint8_t * apdu, int32_t * value) +{ + if (value) { +#if BIG_ENDIAN + /* negative - bit 7 is set */ + if (apdu[0] & 0x80) + *value = 0x00FFFFFF; + else + *value = 0; + *value |= ((int32_t)((apdu[0] << 24) & 0xff000000)); +#else + /* negative - bit 7 is set */ + if (apdu[0] & 0x80) + *value = 0xFFFFFF00; + else + *value = 0; + *value |= ((int32_t)(apdu[0] & 0x000000ff)); +#endif + } + + return 1; +} + +int encode_signed16(uint8_t * apdu, int16_t value) +{ +#if BIG_ENDIAN + apdu[0] = (uint8_t)(value & 0x00ff); + apdu[1] = (uint8_t)((value & 0xff00) >> 8); +#else + apdu[0] = (uint8_t)((value & 0xff00) >> 8); + apdu[1] = (uint8_t)(value & 0x00ff); +#endif + + return 2; +} + +int decode_signed16(uint8_t * apdu, int32_t * value) +{ + if (value) { +#if BIG_ENDIAN + /* negative - bit 7 is set */ + if (apdu[0] & 0x80) + *value = 0x0000FFFF; + else + *value = 0; + *value |= ((int32_t)((apdu[0] << 24) & 0xff000000)); + *value |= ((int32_t)((apdu[1] << 16) & 0x00ff0000)); +#else + /* negative - bit 7 is set */ + if (apdu[0] & 0x80) + *value = 0xFFFF0000; + else + *value = 0; + *value |= ((int32_t)((apdu[0] << 8) & 0x0000ff00)); + *value |= ((int32_t)(apdu[1] & 0x000000ff)); +#endif + } + + return 2; +} + +int encode_signed24(uint8_t * apdu, int32_t value) +{ +#if BIG_ENDIAN + apdu[0] = (uint8_t)(value & 0x0000ff); + apdu[1] = (uint8_t)((value & 0x00ff00) >> 8); + apdu[2] = (uint8_t)((value & 0xff0000) >> 16); +#else + apdu[0] = (uint8_t)((value & 0xff0000) >> 16); + apdu[1] = (uint8_t)((value & 0x00ff00) >> 8); + apdu[2] = (uint8_t)(value & 0x0000ff); +#endif + + return 3; +} + +int decode_signed24(uint8_t * apdu, int32_t * value) +{ + if (value) { +#if BIG_ENDIAN + /* negative - bit 7 is set */ + if (apdu[0] & 0x80) + *value = 0x000000FF; + else + *value = 0; + *value |= ((uint32_t)((apdu[0] << 8) & 0x0000ff00)); + *value |= ((uint32_t)((apdu[1] << 16) & 0x00ff0000)); + *value |= ((uint32_t)((apdu[2] << 24) & 0xff000000)); +#else + /* negative - bit 7 is set */ + if (apdu[0] & 0x80) + *value = 0xFF000000; + else + *value = 0; + *value |= ((uint32_t)((apdu[0] << 16) & 0x00ff0000)); + *value |= ((uint32_t)((apdu[1] << 8) & 0x0000ff00)); + *value |= ((uint32_t)(apdu[2] & 0x000000ff)); +#endif + } + + return 3; +} + +int encode_signed32(uint8_t * apdu, int32_t value) +{ +#if BIG_ENDIAN + apdu[0] = (uint8_t)(value & 0x000000ff); + apdu[1] = (uint8_t)((value & 0x0000ff00) >> 8); + apdu[2] = (uint8_t)((value & 0x00ff0000) >> 16); + apdu[3] = (uint8_t)((value & 0xff000000) >> 24); +#else + apdu[0] = (uint8_t)((value & 0xff000000) >> 24); + apdu[1] = (uint8_t)((value & 0x00ff0000) >> 16); + apdu[2] = (uint8_t)((value & 0x0000ff00) >> 8); + apdu[3] = (uint8_t)(value & 0x000000ff); +#endif + + return 4; +} + +int decode_signed32(uint8_t * apdu, int32_t * value) +{ + if (value) { +#if BIG_ENDIAN + *value = (int32_t)(apdu[0] & 0x000000ff); + *value |= ((int32_t)((apdu[1] << 8) & 0x0000ff00)); + *value |= ((int32_t)((apdu[2] << 16) & 0x00ff0000)); + *value |= ((int32_t)((apdu[3] << 24) & 0xff000000)); +#else + *value = ((int32_t)((apdu[0] << 24) & 0xff000000)); + *value |= ((int32_t)((apdu[1] << 16) & 0x00ff0000)); + *value |= ((int32_t)((apdu[2] << 8) & 0x0000ff00)); + *value |= ((int32_t)(apdu[3] & 0x000000ff)); +#endif + } + + return 4; +} + +/* from clause 20.2.5 Encoding of a Signed Integer Value */ +/* and 20.2.1 General Rules for Encoding BACnet Tags */ +/* returns the number of apdu bytes consumed */ +int decode_signed(uint8_t * apdu, uint32_t len_value, int32_t * value) +{ + if (value) { + switch (len_value) { + case 1: + decode_signed8(&apdu[0], value); + break; + case 2: + decode_signed16(&apdu[0], value); + break; + case 3: + decode_signed24(&apdu[0], value); + break; + case 4: + decode_signed32(&apdu[0], value); + break; + default: + *value = 0; + break; + } + } + + return len_value; +} + +/* from clause 20.2.5 Encoding of a Signed Integer Value */ +/* and 20.2.1 General Rules for Encoding BACnet Tags */ +/* returns the number of apdu bytes consumed */ +int encode_bacnet_signed(uint8_t * apdu, int32_t value) +{ + int len = 0; /* return value */ + + /* don't encode the leading X'FF' or X'00' of the two's compliment. + That is, the first octet of any multi-octet encoded value shall + not be X'00' if the most significant bit (bit 7) of the second + octet is 0, and the first octet shall not be X'FF' if the most + significant bit of the second octet is 1. */ + if ((value >= -128) && (value < 128)) { + len = encode_signed8(&apdu[0], (int8_t) value); + } else if ((value >= -32768) && (value < 32768)) { + len = encode_signed16(&apdu[0], (int16_t) value); + } else if ((value > -8388608) && (value < 8388608)) { + len = encode_signed24(&apdu[0], value); + } else { + len = encode_signed32(&apdu[0], value); + } + + return len; +} + +/* from clause 20.2.4 Encoding of an Unsigned Integer Value */ +/* and 20.2.1 General Rules for Encoding BACnet Tags */ +/* returns the number of apdu bytes consumed */ +int encode_bacnet_unsigned(uint8_t * apdu, uint32_t value) +{ + int len = 0; /* return value */ + + if (value < 0x100) { + apdu[0] = (uint8_t) value; + len = 1; + } else if (value < 0x10000) { + len = encode_unsigned16(&apdu[0], (uint16_t) value); + } else if (value < 0x1000000) { + len = encode_unsigned24(&apdu[0], value); + } else { + len = encode_unsigned32(&apdu[0], value); + } + + return len; +} + +/* from clause 20.2.4 Encoding of an Unsigned Integer Value */ +/* and 20.2.1 General Rules for Encoding BACnet Tags */ +/* returns the number of apdu bytes consumed */ +int decode_unsigned(uint8_t * apdu, uint32_t len_value, uint32_t * value) +{ + uint16_t unsigned16_value = 0; + + if (value) { + switch (len_value) { + case 1: + *value = apdu[0]; + break; + case 2: + decode_unsigned16(&apdu[0], &unsigned16_value); + *value = unsigned16_value; + break; + case 3: + decode_unsigned24(&apdu[0], value); + break; + case 4: + decode_unsigned32(&apdu[0], value); + break; + default: + *value = 0; + break; + } + } + + return len_value; +} + +/* end of decoding_encoding.c */ +#ifdef TEST +#include +#include +#include +#include "ctest.h" + +void testBACnetUnsigned16(Test * pTest) +{ + uint8_t apdu[32] = { 0 }; + uint16_t value = 0, test_value = 0; + int len = 0; + + for (value = 0; ; value++) { + len = encode_unsigned16(&apdu[0], value); + ct_test(pTest, len == 2); + len = decode_unsigned16(&apdu[0], &test_value); + ct_test(pTest, value == test_value); + if (value == 0xFFFF) + break; + } +} + +void testBACnetUnsigned24(Test * pTest) +{ + uint8_t apdu[32] = { 0 }; + uint32_t value = 0, test_value = 0; + int len = 0; + + for (value = 0; ; value+=0xf) { + len = encode_unsigned24(&apdu[0], value); + ct_test(pTest, len == 3); + len = decode_unsigned24(&apdu[0], &test_value); + ct_test(pTest, value == test_value); + if (value == 0xffffff) + break; + } +} + +void testBACnetUnsigned32(Test * pTest) +{ + uint8_t apdu[32] = { 0 }; + uint32_t value = 0, test_value = 0; + int len = 0; + + for (value = 0; ; value+=0xff) { + len = encode_unsigned32(&apdu[0], value); + ct_test(pTest, len == 4); + len = decode_unsigned32(&apdu[0], &test_value); + ct_test(pTest, value == test_value); + if (value == 0xffffffff) + break; + } +} + +void testBACnetSigned8(Test * pTest) +{ + uint8_t apdu[32] = { 0 }; + int32_t value = 0, test_value = 0; + int len = 0; + + for (value = -127; ; value++) { + len = encode_signed8(&apdu[0], value); + ct_test(pTest, len == 1); + len = decode_signed8(&apdu[0], &test_value); + ct_test(pTest, value == test_value); + if (value == 127) + break; + } +} + +void testBACnetSigned16(Test * pTest) +{ + uint8_t apdu[32] = { 0 }; + int32_t value = 0, test_value = 0; + int len = 0; + + for (value = -32767; ; value++) { + len = encode_signed16(&apdu[0], value); + ct_test(pTest, len == 2); + len = decode_signed16(&apdu[0], &test_value); + ct_test(pTest, value == test_value); + if (value == 32767) + break; + } +} + +void testBACnetSigned24(Test * pTest) +{ + uint8_t apdu[32] = { 0 }; + int32_t value = 0, test_value = 0; + int len = 0; + + for (value = -8388607; value <= 8388607; value+=15) { + len = encode_signed24(&apdu[0], value); + ct_test(pTest, len == 3); + len = decode_signed24(&apdu[0], &test_value); + ct_test(pTest, value == test_value); + } +} + +void testBACnetSigned32(Test * pTest) +{ + uint8_t apdu[32] = { 0 }; + int32_t value = 0, test_value = 0; + int len = 0; + + for (value = -2147483647; value < 0; value+=127) { + len = encode_signed32(&apdu[0], value); + ct_test(pTest, len == 4); + len = decode_signed32(&apdu[0], &test_value); + ct_test(pTest, value == test_value); + } + for (value = 2147483647; value > 0; value-=127) { + len = encode_signed32(&apdu[0], value); + ct_test(pTest, len == 4); + len = decode_signed32(&apdu[0], &test_value); + ct_test(pTest, value == test_value); + } +} + +void testBACnetSigned(Test * pTest) +{ + uint8_t apdu[32] = { 0 }; + int32_t value = 0, test_value = 0; + int len = 0, test_len = 0; + + for (value = -2147483647; value < 0; value+=127) { + len = encode_bacnet_signed(&apdu[0], value); + test_len = decode_signed(&apdu[0], len, &test_value); + ct_test(pTest, len == test_len); + ct_test(pTest, value == test_value); + } + for (value = 2147483647; value > 0; value-=127) { + len = encode_bacnet_signed(&apdu[0], value); + test_len = decode_signed(&apdu[0], len, &test_value); + ct_test(pTest, len == test_len); + ct_test(pTest, value == test_value); + } +} + +void testBACnetUnsigned(Test * pTest) +{ + uint8_t apdu[32] = { 0 }; + uint32_t value = 0, test_value = 0; + int len = 0, test_len = 0; + + for (value = 0; ;value+=0xFF) { + len = encode_bacnet_unsigned(&apdu[0], value); + test_len = decode_unsigned(&apdu[0], len, &test_value); + ct_test(pTest, len == test_len); + ct_test(pTest, value == test_value); + if (value == 0xFFFFFFFF) + break; + } +} + + +#ifdef TEST_BACINT +int main(void) +{ + Test *pTest; + bool rc; + + pTest = ct_create("BACint", NULL); + /* individual tests */ + rc = ct_addTestFunction(pTest, testBACnetUnsigned16); + assert(rc); + rc = ct_addTestFunction(pTest, testBACnetUnsigned24); + assert(rc); + rc = ct_addTestFunction(pTest, testBACnetUnsigned32); + assert(rc); + rc = ct_addTestFunction(pTest, testBACnetSigned8); + assert(rc); + rc = ct_addTestFunction(pTest, testBACnetSigned16); + assert(rc); + rc = ct_addTestFunction(pTest, testBACnetSigned24); + assert(rc); + rc = ct_addTestFunction(pTest, testBACnetSigned32); + assert(rc); + rc = ct_addTestFunction(pTest, testBACnetSigned); + assert(rc); + rc = ct_addTestFunction(pTest, testBACnetUnsigned); + assert(rc); + /* configure output */ + ct_setStream(pTest, stdout); + ct_run(pTest); + (void) ct_report(pTest); + ct_destroy(pTest); + + return 0; +} +#endif /* TEST_DECODE */ +#endif /* TEST */ diff --git a/bacnet-stack/bacint.cbp b/bacnet-stack/bacint.cbp new file mode 100644 index 00000000..eb2d479e --- /dev/null +++ b/bacnet-stack/bacint.cbp @@ -0,0 +1,52 @@ + + + + + +