From a18d338f00d26dd58546ab223cc2419e5cb8c163 Mon Sep 17 00:00:00 2001 From: skarg Date: Mon, 18 Jun 2007 16:22:24 +0000 Subject: [PATCH] Set the EOL-style to native for most files using svn propset command. Some files also had inconsistent line endings. Seems that subversion doesn't set the eol-style automatically when files are created unless it is configured for autoprops. The autoprops setting is local to the subversion installation and not the project. --- bacnet-stack/bacint.c | 1160 ++++++------- bacnet-stack/bacnet.h | 152 +- bacnet-stack/bvlc.c | 1462 ++++++++--------- bacnet-stack/bvlc.h | 3 +- bacnet-stack/cov.c | 6 +- bacnet-stack/datetime.c | 4 +- bacnet-stack/datetime.h | 2 +- bacnet-stack/demo/object/lc.c | 316 ++-- bacnet-stack/demo/object/lo.c | 1250 +++++++------- bacnet-stack/demo/object/lsp.c | 4 +- bacnet-stack/demo/server/epics_vts3.tpi | 1518 +++++++++--------- bacnet-stack/demo/ucov/Makefile | 176 +- bacnet-stack/demo/ucov/main.c | 6 +- bacnet-stack/demo/ucov/makefile.b32 | 306 ++-- bacnet-stack/demo/writeprop/main.c | 4 +- bacnet-stack/doc/README.codeblocks | 20 +- bacnet-stack/doc/README.msvs | 14 +- bacnet-stack/doc/README.todo | 54 +- bacnet-stack/doc/htdocs/index.html | 964 +++++------ bacnet-stack/ports/pic18f6720/ai.c | 400 ++--- bacnet-stack/ports/pic18f6720/av.c | 16 +- bacnet-stack/ports/pic18f6720/bi.c | 462 +++--- bacnet-stack/ports/pic18f6720/bv.c | 640 ++++---- bacnet-stack/ports/pic18f6720/device.c | 10 +- bacnet-stack/ports/pic18f6720/h_rp.c | 144 +- bacnet-stack/ports/pic18f6720/mstp.c | 6 +- bacnet-stack/ports/pic18f6720/mstp.h | 2 +- bacnet-stack/ports/pic18f6720/pic18f6720.tpi | 816 +++++----- bacnet-stack/ports/pic18f6720/readme.txt | 88 +- bacnet-stack/ports/rtos32/dlmstp.c | 2 +- bacnet-stack/ports/win32/MAKEFILE.MAK | 302 ++-- bacnet-stack/ports/win32/bacnet/bacnet.plg | 464 +++--- bacnet-stack/ports/win32/bacnet/readme.txt | 226 +-- bacnet-stack/ports/win32/bip-init.c | 716 ++++----- bacnet-stack/ports/win32/ethernet.c | 910 +++++------ bacnet-stack/ports/win32/main.c | 514 +++--- bacnet-stack/ports/win32/net.h | 76 +- bacnet-stack/ports/win32/readme.txt | 30 +- bacnet-stack/ports/win32/setvars.bat | 4 +- bacnet-stack/ports/win32/stdbool.h | 56 +- bacnet-stack/ports/win32/stdint.h | 38 +- 41 files changed, 6673 insertions(+), 6670 deletions(-) diff --git a/bacnet-stack/bacint.c b/bacnet-stack/bacint.c index d9fd23c0..38e15c7e 100644 --- a/bacnet-stack/bacint.c +++ b/bacnet-stack/bacint.c @@ -1,580 +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 */ +/*####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/bacnet.h b/bacnet-stack/bacnet.h index 78404f2c..5c26f8ca 100644 --- a/bacnet-stack/bacnet.h +++ b/bacnet-stack/bacnet.h @@ -1,76 +1,76 @@ -/*####COPYRIGHTBEGIN#### - ------------------------------------------- - Copyright (C) 2006 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####*/ -#ifndef BACNET_H -#define BACNET_H - -/* This file is designed to reference the entire BACnet stack library */ - -/* core files */ -#include "config.h" -#include "address.h" -#include "apdu.h" -#include "bacapp.h" -#include "bacdcode.h" -#include "bacdef.h" -#include "bacenum.h" -#include "bacerror.h" -#include "bacstr.h" -#include "bactext.h" -#include "datalink.h" -#include "indtext.h" -#include "npdu.h" -#include "reject.h" -#include "tsm.h" - -/* services */ -#include "arf.h" -#include "awf.h" -#include "cov.h" -#include "dcc.h" -#include "iam.h" -#include "ihave.h" -#include "rd.h" -#include "rp.h" -#include "rpm.h" -#include "timesync.h" -#include "whohas.h" -#include "whois.h" -#include "wp.h" - -/* required object - note: developer must supply the device.c file - since it is not included in the library. However, the library - references the device.c members via the device.h API. */ -#include "device.h" - -#endif +/*####COPYRIGHTBEGIN#### + ------------------------------------------- + Copyright (C) 2006 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####*/ +#ifndef BACNET_H +#define BACNET_H + +/* This file is designed to reference the entire BACnet stack library */ + +/* core files */ +#include "config.h" +#include "address.h" +#include "apdu.h" +#include "bacapp.h" +#include "bacdcode.h" +#include "bacdef.h" +#include "bacenum.h" +#include "bacerror.h" +#include "bacstr.h" +#include "bactext.h" +#include "datalink.h" +#include "indtext.h" +#include "npdu.h" +#include "reject.h" +#include "tsm.h" + +/* services */ +#include "arf.h" +#include "awf.h" +#include "cov.h" +#include "dcc.h" +#include "iam.h" +#include "ihave.h" +#include "rd.h" +#include "rp.h" +#include "rpm.h" +#include "timesync.h" +#include "whohas.h" +#include "whois.h" +#include "wp.h" + +/* required object - note: developer must supply the device.c file + since it is not included in the library. However, the library + references the device.c members via the device.h API. */ +#include "device.h" + +#endif diff --git a/bacnet-stack/bvlc.c b/bacnet-stack/bvlc.c index 4e89cad9..c12e7bc2 100644 --- a/bacnet-stack/bvlc.c +++ b/bacnet-stack/bvlc.c @@ -1,731 +1,731 @@ -/*####COPYRIGHTBEGIN#### - ------------------------------------------- - Copyright (C) 2006 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####*/ - -#include /* for standard integer types uint8_t etc. */ -#include /* for the standard bool type. */ -#include /* for the standard bool type. */ -#include "bacdcode.h" -#include "bip.h" -#include "net.h" /* custom per port */ - -/* Handle the BACnet Virtual Link Control (BVLC), which includes: - BACnet Broadcast Management Device, - Broadcast Distribution Table, and - Foreign Device Registration */ - -typedef struct -{ - /* true if valid entry - false if not */ - bool valid; - /* BACnet/IP address */ - struct in_addr dest_address; - /* BACnet/IP port number - not always 47808=BAC0h */ - uint16_t dest_port; - /* Broadcast Distribution Mask - stored in host byte order */ - struct in_addr broadcast_mask; -} BBMD_TABLE_ENTRY; - -#define MAX_BBMD_ENTRIES 128 -static BBMD_TABLE_ENTRY BBMD_Table[MAX_BBMD_ENTRIES]; - -/*Each device that registers as a foreign device shall be placed -in an entry in the BBMD's Foreign Device Table (FDT). Each -entry shall consist of the 6-octet B/IP address of the registrant; -the 2-octet Time-to-Live value supplied at the time of -registration; and a 2-octet value representing the number of -seconds remaining before the BBMD will purge the registrant's FDT -entry if no re-registration occurs. This value will be initialized -to the 2-octet Time-to-Live value supplied at the time of -registration.*/ -typedef struct -{ - bool valid; - /* BACnet/IP address */ - struct in_addr dest_address; - /* BACnet/IP port number - not always 47808=BAC0h */ - uint16_t dest_port; - /* seconds for valid entry lifetime */ - uint16_t time_to_live; - /* our counter */ - time_t seconds_remaining; /* includes 30 second grace period */ -} FD_TABLE_ENTRY; - -#define MAX_FD_ENTRIES 128 -static FD_TABLE_ENTRY FD_Table[MAX_FD_ENTRIES]; - -void bvlc_maintenance_timer(unsigned seconds) -{ - unsigned i = 0; - - for (i = 0; i < MAX_FD_ENTRIES; i++) { - if (FD_Table[i].valid) { - if (FD_Table[i].seconds_remaining) { - if (FD_Table[i].seconds_remaining < seconds) { - FD_Table[i].seconds_remaining = 0; - } else { - FD_Table[i].seconds_remaining -= seconds; - } - if (FD_Table[i].seconds_remaining == 0) { - FD_Table[i].valid = false; - } - } - } - } -} - -int bvlc_encode_bip_address( - uint8_t * pdu, /* buffer to store encoding */ - struct in_addr *address, /* in host format */ - uint16_t port) -{ - int len = 0; - - if (pdu) { - len = encode_unsigned32(&pdu[0], address->s_addr); - len += encode_unsigned16(&pdu[len], port); - } - - return len; -} - -int bvlc_decode_bip_address( - uint8_t * pdu, /* buffer to extract encoded address */ - struct in_addr * address, /* in host format */ - uint16_t * port) -{ - int len = 0; - - if (pdu) { - (void) decode_unsigned32(&pdu[0], &(address->s_addr)); - (void) decode_unsigned16(&pdu[4], port); - len = 6; - } - - return len; -} - -/* used for both read and write entries */ -int bvlc_encode_address_entry(uint8_t * pdu, - struct in_addr *address, - uint16_t port, - struct in_addr *mask) -{ - int len = 0; - - if (pdu) { - len = bvlc_encode_bip_address(pdu, address, port); - len += encode_unsigned32(&pdu[len], mask->s_addr); - } - - return len; -} - -int bvlc_encode_bvlc_result( - uint8_t * pdu, - BACNET_BVLC_RESULT result_code) -{ - if (pdu) { - pdu[0] = BVLL_TYPE_BACNET_IP; - pdu[1] = BVLC_RESULT; - /* The 2-octet BVLC Length field is the length, in octets, - of the entire BVLL message, including the two octets of the - length field itself, most significant octet first. */ - encode_unsigned16(&pdu[2], 6); - encode_unsigned16(&pdu[4], result_code); - } - - return 6; -} - -int bvlc_encode_write_bdt_init( - uint8_t * pdu, - unsigned entries) -{ - int len = 0; - - if (pdu) { - pdu[0] = BVLL_TYPE_BACNET_IP; - pdu[1] = BVLC_WRITE_BROADCAST_DISTRIBUTION_TABLE; - /* The 2-octet BVLC Length field is the length, in octets, - of the entire BVLL message, including the two octets of the - length field itself, most significant octet first. */ - encode_unsigned16(&pdu[2], 4 + entries * 10); - len = 4; - } - - return len; -} - -int bvlc_encode_read_bdt( - uint8_t * pdu) -{ - int len = 0; - - if (pdu) { - pdu[0] = BVLL_TYPE_BACNET_IP; - pdu[1] = BVLC_READ_BROADCAST_DISTRIBUTION_TABLE; - /* The 2-octet BVLC Length field is the length, in octets, - of the entire BVLL message, including the two octets of the - length field itself, most significant octet first. */ - encode_unsigned16(&pdu[2], 4); - len = 4; - } - - return len; -} - -int bvlc_encode_read_bdt_ack_init( - uint8_t * pdu, - unsigned entries) -{ - int len = 0; - - if (pdu) { - pdu[0] = BVLL_TYPE_BACNET_IP; - pdu[1] = BVLC_READ_BROADCAST_DISTRIBUTION_TABLE_ACK; - /* The 2-octet BVLC Length field is the length, in octets, - of the entire BVLL message, including the two octets of the - length field itself, most significant octet first. */ - encode_unsigned16(&pdu[2], 4 + entries * 10); - len = 4; - } - - return len; -} - -int bvlc_encode_forwarded_npdu(uint8_t * pdu, - BACNET_ADDRESS * src, - uint8_t * npdu, - unsigned npdu_length) -{ - int len = 0; - - unsigned i; /* for loop counter */ - - if (pdu) { - pdu[0] = BVLL_TYPE_BACNET_IP; - pdu[1] = BVLC_FORWARDED_NPDU; - /* The 2-octet BVLC Length field is the length, in octets, - of the entire BVLL message, including the two octets of the - length field itself, most significant octet first. */ - encode_unsigned16(&pdu[2], 4 + 6 + npdu_length); - len = 4; - for (i = 0; i < 6; i++) { - pdu[len] = src->adr[i]; - len++; - } - for (i = 0; i < npdu_length; i++) { - pdu[len] = npdu[i]; - len++; - } - } - - return len; -} - - -int bvlc_encode_register_foreign_device(uint8_t * pdu, - uint16_t time_to_live_seconds) -{ - int len = 0; - - if (pdu) { - pdu[0] = BVLL_TYPE_BACNET_IP; - pdu[1] = BVLC_REGISTER_FOREIGN_DEVICE; - /* The 2-octet BVLC Length field is the length, in octets, - of the entire BVLL message, including the two octets of the - length field itself, most significant octet first. */ - encode_unsigned16(&pdu[2], 6); - encode_unsigned16(&pdu[2], time_to_live_seconds); - len = 6; - } - - return len; -} - -int bvlc_encode_read_fdt( - uint8_t * pdu) -{ - int len = 0; - - if (pdu) { - pdu[0] = BVLL_TYPE_BACNET_IP; - pdu[1] = BVLC_READ_FOREIGN_DEVICE_TABLE; - /* The 2-octet BVLC Length field is the length, in octets, - of the entire BVLL message, including the two octets of the - length field itself, most significant octet first. */ - encode_unsigned16(&pdu[2], 4); - len = 4; - } - - return len; -} - -int bvlc_encode_read_fdt_ack_init( - uint8_t * pdu, - unsigned entries) -{ - int len = 0; - - if (pdu) { - pdu[0] = BVLL_TYPE_BACNET_IP; - pdu[1] = BVLC_READ_FOREIGN_DEVICE_TABLE_ACK; - /* The 2-octet BVLC Length field is the length, in octets, - of the entire BVLL message, including the two octets of the - length field itself, most significant octet first. */ - encode_unsigned16(&pdu[2], 4 + entries * 10); - len = 4; - } - - return len; -} - -int bvlc_encode_delete_fdt_entry(uint8_t * pdu, - struct in_addr *address, - uint16_t port) -{ - int len = 0; - - if (pdu) { - pdu[0] = BVLL_TYPE_BACNET_IP; - pdu[1] = BVLC_READ_FOREIGN_DEVICE_TABLE; - /* The 2-octet BVLC Length field is the length, in octets, - of the entire BVLL message, including the two octets of the - length field itself, most significant octet first. */ - encode_unsigned16(&pdu[2], 10); - /* FDT Entry */ - encode_unsigned32(&pdu[0], address->s_addr); - encode_unsigned16(&pdu[4], port); - len = 10; - } - - return len; -} - -int bvlc_encode_distribute_broadcast_to_network(uint8_t * pdu, - uint8_t * npdu, - unsigned npdu_length) -{ - int len = 0; /* return value */ - unsigned i; /* for loop counter */ - - if (pdu) { - pdu[0] = BVLL_TYPE_BACNET_IP; - pdu[1] = BVLC_DISTRIBUTE_BROADCAST_TO_NETWORK; - /* The 2-octet BVLC Length field is the length, in octets, - of the entire BVLL message, including the two octets of the - length field itself, most significant octet first. */ - len = encode_unsigned16(&pdu[2], 4 + npdu_length) + 2; - for (i = 0; i < npdu_length; i++) { - pdu[len] = npdu[i]; - len++; - } - } - - return len; -} - -int bvlc_encode_original_unicast_npdu(uint8_t * pdu, - uint8_t * npdu, - unsigned npdu_length) -{ - int len = 0; /* return value */ - unsigned i = 0; /* loop counter */ - - if (pdu) { - pdu[0] = BVLL_TYPE_BACNET_IP; - pdu[1] = BVLC_ORIGINAL_UNICAST_NPDU; - /* The 2-octet BVLC Length field is the length, in octets, - of the entire BVLL message, including the two octets of the - length field itself, most significant octet first. */ - len = encode_unsigned16(&pdu[2], 4 + npdu_length) + 2; - for (i = 0; i < npdu_length; i++) { - pdu[len] = npdu[i]; - len++; - } - } - - return len; -} - - -int bvlc_encode_original_broadcast_npdu(uint8_t * pdu, - uint8_t * npdu, - unsigned npdu_length) -{ - int len = 0; /* return value */ - unsigned i = 0; /* loop counter */ - - if (pdu) { - pdu[0] = BVLL_TYPE_BACNET_IP; - pdu[1] = BVLC_ORIGINAL_BROADCAST_NPDU; - /* The 2-octet BVLC Length field is the length, in octets, - of the entire BVLL message, including the two octets of the - length field itself, most significant octet first. */ - len = encode_unsigned16(&pdu[2], 4 + npdu_length) + 2; - for (i = 0; i < npdu_length; i++) { - pdu[len] = npdu[i]; - len++; - } - } - - return len; -} - -/* copy the source internet address to the BACnet address */ -/* FIXME: IPv6? */ -void bvlc_internet_to_bacnet_address( - BACNET_ADDRESS * src, /* returns the BACnet source address */ - struct sockaddr_in *sin) -{ /* source internet address */ - int len = 0; - uint32_t address; - uint16_t port; - - if (src && sin) { - address = ntohl(sin->sin_addr.s_addr); - len = encode_unsigned32(&src->mac[0], address); - port = ntohs(sin->sin_port); - len += encode_unsigned16(&src->mac[4], port); - src->mac_len = len; - src->net = 0; - src->len = 0; - } - - return; -} - -/* copy the source internet address to the BACnet address */ -/* FIXME: IPv6? */ -/* FIXME: is sockaddr_in host or network order? */ -void bvlc_bacnet_to_internet_address( - struct sockaddr_in *sin, /* source internet address */ - BACNET_ADDRESS * src) /* returns the BACnet source address */ -{ - int len = 0; - uint32_t address; - uint16_t port; - - if (src && sin) { - if (src->mac_len == 6) { - len = decode_unsigned32(&src->mac[0], &address); - len += decode_unsigned16(&src->mac[4], &port ); - sin->sin_addr.s_addr = htonl(address); - sin->sin_port = htons(port); - } - } - - return; -} - -void bvlc_bdt_forward_npdu( - struct sockaddr_in *sin, /* the source address */ - uint8_t * npdu, /* the NPDU */ - uint16_t npdu_length) -{ /* length of the NPDU */ - uint8_t mtu[MAX_MPDU] = {0}; - int mtu_len = 0; - int bytes_sent = 0; - unsigned i = 0; /* loop counter */ - struct sockaddr_in bip_dest; - BACNET_ADDRESS src; - - /* assumes that the driver has already been initialized */ - if (bip_socket() < 0) { - return; - } - bvlc_internet_to_bacnet_address(&src, sin); - mtu_len = bvlc_encode_forwarded_npdu( - &mtu[0], - &src, - npdu, - npdu_length); - /* load destination IP address */ - bip_dest.sin_family = AF_INET; - /* loop through the BDT and send one to each entry, except us */ - for (i = 0; i < MAX_BBMD_ENTRIES; i++) { - if (BBMD_Table[i].valid) { - /* The B/IP address to which the Forwarded-NPDU message is - sent is formed by inverting the broadcast distribution - mask in the BDT entry and logically ORing it with the - BBMD address of the same entry. */ - bip_dest.sin_addr.s_addr = - htonl(((~BBMD_Table[i].broadcast_mask.s_addr) | - BBMD_Table[i].dest_address.s_addr)); - bip_dest.sin_port = htons(BBMD_Table[i].dest_port); - /* Send the packet */ - bytes_sent = - sendto(bip_socket(), (char *) mtu, mtu_len, 0, - (struct sockaddr *) &bip_dest, - sizeof(struct sockaddr)); - } - } - - return; -} - -void bvlc_fdt_forward_npdu( - struct sockaddr_in *sin, /* the source address */ - uint8_t * npdu, /* returns the NPDU */ - uint16_t max_npdu) /* amount of space available in the NPDU */ -{ - - /* FIXME: add the code */ -} - -uint16_t bvlc_handler( - BACNET_ADDRESS * src, /* returns the source address */ - uint8_t * npdu, /* returns the NPDU */ - uint16_t max_npdu, /* amount of space available in the NPDU */ - unsigned timeout) /* number of milliseconds to wait for a packet */ -{ - uint8_t buf[MAX_MPDU] = {0}; /* data */ - uint16_t pdu_len = 0; /* return value */ - fd_set read_fds; - int max; - struct timeval select_timeout; - struct sockaddr_in sin = { -1 }; - socklen_t sin_len = sizeof(sin); - int function_type = 0; - int received_bytes; - - /* Make sure the socket is open */ - if (BIP_Socket < 0) { - return 0; - } - - /* we could just use a non-blocking socket, but that consumes all - the CPU time. We can use a timeout; it is only supported as - a select. */ - if (timeout >= 1000) { - select_timeout.tv_sec = timeout / 1000; - select_timeout.tv_usec = - 1000 * (timeout - select_timeout.tv_sec * 1000); - } else { - select_timeout.tv_sec = 0; - select_timeout.tv_usec = 1000 * timeout; - } - FD_ZERO(&read_fds); - FD_SET((unsigned int) BIP_Socket, &read_fds); - max = BIP_Socket; - /* see if there is a packet for us */ - if (select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0) { - received_bytes = recvfrom( - BIP_Socket, - (char *) &buf[0], - MAX_MPDU, 0, - (struct sockaddr *) &sin, &sin_len); - } else { - return 0; - } - /* See if there is a problem */ - if (received_bytes < 0) { - return 0; - } - /* no problem, just no bytes */ - if (received_bytes == 0) { - return 0; - } - /* the signature of a BACnet/IP packet */ - if (buf[0] != BVLL_TYPE_BACNET_IP) { - return 0; - } - function_type = buf[1]; - /* decode the length of the PDU - length is inclusive of BVLC */ - (void) decode_unsigned16(&buf[2], &npdu_len); - /* subtract off the BVLC header */ - npdu_len -= 4; - switch (function_type) { - case BVLC_RESULT: - break; - case BVLC_WRITE_BROADCAST_DISTRIBUTION_TABLE: - /* Upon receipt of a BVLL Write-Broadcast-Distribution-Table - message, a BBMD shall attempt to create or replace its BDT, - depending on whether or not a BDT has previously existed. - If the creation or replacement of the BDT is successful, the BBMD - shall return a BVLC-Result message to the originating device with - a result code of X'0000'. Otherwise, the BBMD shall return a - BVLC-Result message to the originating device with a result code - of X'0010' indicating that the write attempt has failed. */ - break; - case BVLC_READ_BROADCAST_DISTRIBUTION_TABLE: - break; - case BVLC_READ_BROADCAST_DISTRIBUTION_TABLE_ACK: - break; - case BVLC_FORWARDED_NPDU: - /* Upon receipt of a BVLL Forwarded-NPDU message, a BBMD shall - process it according to whether it was received from a peer - BBMD as the result of a directed broadcast or a unicast - transmission. A BBMD may ascertain the method by which Forwarded- - NPDU messages will arrive by inspecting the broadcast distribution - mask field in its own BDT entry since all BDTs are required - to be identical. If the message arrived via directed broadcast, - it was also received by the other devices on the BBMD's subnet. In - this case the BBMD merely retransmits the message directly to each - foreign device currently in the BBMD's FDT. If the - message arrived via a unicast transmission it has not yet been - received by the other devices on the BBMD's subnet. In this case, - the message is sent to the devices on the BBMD's subnet using the - B/IP broadcast address as well as to each foreign device - currently in the BBMD's FDT. A BBMD on a subnet with no other - BACnet devices may omit the broadcast using the B/IP - broadcast address. The method by which a BBMD determines whether - or not other BACnet devices are present is a local matter. */ - bvlc_broadcast_npdu(&sin, &buf[4], npdu_len); - bvlc_fdt_forward_npdu(&sin, &buf[4], npdu_len); - break; - case BVLC_REGISTER_FOREIGN_DEVICE: - break; - case BVLC_READ_FOREIGN_DEVICE_TABLE: - break; - case BVLC_READ_FOREIGN_DEVICE_TABLE_ACK: - break; - case BVLC_DELETE_FOREIGN_DEVICE_TABLE_ENTRY: - break; - case BVLC_DISTRIBUTE_BROADCAST_TO_NETWORK: - bvlc_broadcast_forward_npdu(&sin, &buf[4], npdu_len); - bvlc_fdt_forward_npdu(&sin, &buf[4], npdu_len); - break; - case BVLC_ORIGINAL_UNICAST_NPDU: - /* ignore messages from me */ - if (sin.sin_addr.s_addr == BIP_Address.s_addr) { - npdu_len = 0; - } else { - bvlc_internet_to_bacnet_address(src, &sin); - if (npdu_len < max_npdu) { - /* copy the buffer into the PDU */ - memmove(&npdu[0], &buf[4], npdu_len); - } else { - /* ignore packets that are too large */ - /* clients should check my max-apdu first */ - npdu_len = 0; - } - } - break; - case BVLC_ORIGINAL_BROADCAST_NPDU: - /* Upon receipt of a BVLL Original-Broadcast-NPDU message, - a BBMD shall construct a BVLL Forwarded-NPDU message and - send it to each IP subnet in its BDT with the exception - of its own. The B/IP address to which the Forwarded-NPDU - message is sent is formed by inverting the broadcast - distribution mask in the BDT entry and logically ORing it - with the BBMD address of the same entry. This process - produces either the directed broadcast address of the remote - subnet or the unicast address of the BBMD on that subnet - depending on the contents of the broadcast distribution - mask. See J.4.3.2.. In addition, the received BACnet NPDU - shall be sent directly to each foreign device currently in - the BBMD's FDT also using the BVLL Forwarded-NPDU message. */ - bvlc_internet_to_bacnet_address(src, &sin); - if (npdu_len < max_npdu) { - /* copy the buffer into the PDU */ - memmove(&npdu[0], &buf[4], npdu_len); - } else { - /* ignore packets that are too large */ - /* clients should check my max-apdu first */ - npdu_len = 0; - } - /* if BDT or FDT entries exist, Forward the NPDU */ - bvlc_bdt_forward_npdu(&sin, &buf[4], npdu_len); - bvlc_fdt_forward_npdu(&sin, &buf[4], npdu_len); - break; - default: - break; - } - - return npdu_len; -} - -#ifdef TEST -#include -#include -#include "ctest.h" - -void testBIPAddress(Test * pTest) -{ - uint8_t apdu[50] = { 0 }; - uint32_t value = 0, test_value = 0; - int len = 0, test_len = 0; - struct in_addr address; - struct in_addr test_address; - uint16_t port = 0, test_port = 0; - - address.s_addr = 42; - len = bvlc_encode_bip_address(&apdu[0], - &address, port); - test_len = bvlc_decode_bip_address(&apdu[0], - &test_address, &test_port); - ct_test(pTest, len == test_len); - ct_test(pTest, address.s_addr == test_address.s_addr); - ct_test(pTest, port == test_port); -} - -void testInternetAddress(Test * pTest) -{ - BACNET_ADDRESS src; - BACNET_ADDRESS test_src; - struct sockaddr_in sin; - struct sockaddr_in test_sin; - - sin.sin_port = htons(0xBAC0); - sin.sin_addr.s_addr = inet_addr("192.168.0.1"); - bvlc_internet_to_bacnet_address(&src, &sin); - bvlc_bacnet_to_internet_address(&test_sin, &src); - ct_test(pTest, sin.sin_port == test_sin.sin_port); - ct_test(pTest, sin.sin_addr.s_addr == test_sin.sin_addr.s_addr); -} - -#ifdef TEST_BVLC -int main(void) -{ - Test * pTest; - bool rc; - - pTest = ct_create("BACnet Virtual Link Control", NULL); - /* individual tests */ - rc = ct_addTestFunction(pTest, testBIPAddress); - assert(rc); - rc = ct_addTestFunction(pTest, testInternetAddress); - assert(rc); - /* configure output */ - ct_setStream(pTest, stdout); - ct_run(pTest); - (void) ct_report(pTest); - ct_destroy(pTest); - - return 0; -} - -#endif /* TEST_BBMD */ -#endif /* TEST */ +/*####COPYRIGHTBEGIN#### + ------------------------------------------- + Copyright (C) 2006 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####*/ + +#include /* for standard integer types uint8_t etc. */ +#include /* for the standard bool type. */ +#include /* for the standard bool type. */ +#include "bacdcode.h" +#include "bip.h" +#include "net.h" /* custom per port */ + +/* Handle the BACnet Virtual Link Control (BVLC), which includes: + BACnet Broadcast Management Device, + Broadcast Distribution Table, and + Foreign Device Registration */ + +typedef struct +{ + /* true if valid entry - false if not */ + bool valid; + /* BACnet/IP address */ + struct in_addr dest_address; + /* BACnet/IP port number - not always 47808=BAC0h */ + uint16_t dest_port; + /* Broadcast Distribution Mask - stored in host byte order */ + struct in_addr broadcast_mask; +} BBMD_TABLE_ENTRY; + +#define MAX_BBMD_ENTRIES 128 +static BBMD_TABLE_ENTRY BBMD_Table[MAX_BBMD_ENTRIES]; + +/*Each device that registers as a foreign device shall be placed +in an entry in the BBMD's Foreign Device Table (FDT). Each +entry shall consist of the 6-octet B/IP address of the registrant; +the 2-octet Time-to-Live value supplied at the time of +registration; and a 2-octet value representing the number of +seconds remaining before the BBMD will purge the registrant's FDT +entry if no re-registration occurs. This value will be initialized +to the 2-octet Time-to-Live value supplied at the time of +registration.*/ +typedef struct +{ + bool valid; + /* BACnet/IP address */ + struct in_addr dest_address; + /* BACnet/IP port number - not always 47808=BAC0h */ + uint16_t dest_port; + /* seconds for valid entry lifetime */ + uint16_t time_to_live; + /* our counter */ + time_t seconds_remaining; /* includes 30 second grace period */ +} FD_TABLE_ENTRY; + +#define MAX_FD_ENTRIES 128 +static FD_TABLE_ENTRY FD_Table[MAX_FD_ENTRIES]; + +void bvlc_maintenance_timer(unsigned seconds) +{ + unsigned i = 0; + + for (i = 0; i < MAX_FD_ENTRIES; i++) { + if (FD_Table[i].valid) { + if (FD_Table[i].seconds_remaining) { + if (FD_Table[i].seconds_remaining < seconds) { + FD_Table[i].seconds_remaining = 0; + } else { + FD_Table[i].seconds_remaining -= seconds; + } + if (FD_Table[i].seconds_remaining == 0) { + FD_Table[i].valid = false; + } + } + } + } +} + +int bvlc_encode_bip_address( + uint8_t * pdu, /* buffer to store encoding */ + struct in_addr *address, /* in host format */ + uint16_t port) +{ + int len = 0; + + if (pdu) { + len = encode_unsigned32(&pdu[0], address->s_addr); + len += encode_unsigned16(&pdu[len], port); + } + + return len; +} + +int bvlc_decode_bip_address( + uint8_t * pdu, /* buffer to extract encoded address */ + struct in_addr * address, /* in host format */ + uint16_t * port) +{ + int len = 0; + + if (pdu) { + (void) decode_unsigned32(&pdu[0], &(address->s_addr)); + (void) decode_unsigned16(&pdu[4], port); + len = 6; + } + + return len; +} + +/* used for both read and write entries */ +int bvlc_encode_address_entry(uint8_t * pdu, + struct in_addr *address, + uint16_t port, + struct in_addr *mask) +{ + int len = 0; + + if (pdu) { + len = bvlc_encode_bip_address(pdu, address, port); + len += encode_unsigned32(&pdu[len], mask->s_addr); + } + + return len; +} + +int bvlc_encode_bvlc_result( + uint8_t * pdu, + BACNET_BVLC_RESULT result_code) +{ + if (pdu) { + pdu[0] = BVLL_TYPE_BACNET_IP; + pdu[1] = BVLC_RESULT; + /* The 2-octet BVLC Length field is the length, in octets, + of the entire BVLL message, including the two octets of the + length field itself, most significant octet first. */ + encode_unsigned16(&pdu[2], 6); + encode_unsigned16(&pdu[4], result_code); + } + + return 6; +} + +int bvlc_encode_write_bdt_init( + uint8_t * pdu, + unsigned entries) +{ + int len = 0; + + if (pdu) { + pdu[0] = BVLL_TYPE_BACNET_IP; + pdu[1] = BVLC_WRITE_BROADCAST_DISTRIBUTION_TABLE; + /* The 2-octet BVLC Length field is the length, in octets, + of the entire BVLL message, including the two octets of the + length field itself, most significant octet first. */ + encode_unsigned16(&pdu[2], 4 + entries * 10); + len = 4; + } + + return len; +} + +int bvlc_encode_read_bdt( + uint8_t * pdu) +{ + int len = 0; + + if (pdu) { + pdu[0] = BVLL_TYPE_BACNET_IP; + pdu[1] = BVLC_READ_BROADCAST_DISTRIBUTION_TABLE; + /* The 2-octet BVLC Length field is the length, in octets, + of the entire BVLL message, including the two octets of the + length field itself, most significant octet first. */ + encode_unsigned16(&pdu[2], 4); + len = 4; + } + + return len; +} + +int bvlc_encode_read_bdt_ack_init( + uint8_t * pdu, + unsigned entries) +{ + int len = 0; + + if (pdu) { + pdu[0] = BVLL_TYPE_BACNET_IP; + pdu[1] = BVLC_READ_BROADCAST_DISTRIBUTION_TABLE_ACK; + /* The 2-octet BVLC Length field is the length, in octets, + of the entire BVLL message, including the two octets of the + length field itself, most significant octet first. */ + encode_unsigned16(&pdu[2], 4 + entries * 10); + len = 4; + } + + return len; +} + +int bvlc_encode_forwarded_npdu(uint8_t * pdu, + BACNET_ADDRESS * src, + uint8_t * npdu, + unsigned npdu_length) +{ + int len = 0; + + unsigned i; /* for loop counter */ + + if (pdu) { + pdu[0] = BVLL_TYPE_BACNET_IP; + pdu[1] = BVLC_FORWARDED_NPDU; + /* The 2-octet BVLC Length field is the length, in octets, + of the entire BVLL message, including the two octets of the + length field itself, most significant octet first. */ + encode_unsigned16(&pdu[2], 4 + 6 + npdu_length); + len = 4; + for (i = 0; i < 6; i++) { + pdu[len] = src->adr[i]; + len++; + } + for (i = 0; i < npdu_length; i++) { + pdu[len] = npdu[i]; + len++; + } + } + + return len; +} + + +int bvlc_encode_register_foreign_device(uint8_t * pdu, + uint16_t time_to_live_seconds) +{ + int len = 0; + + if (pdu) { + pdu[0] = BVLL_TYPE_BACNET_IP; + pdu[1] = BVLC_REGISTER_FOREIGN_DEVICE; + /* The 2-octet BVLC Length field is the length, in octets, + of the entire BVLL message, including the two octets of the + length field itself, most significant octet first. */ + encode_unsigned16(&pdu[2], 6); + encode_unsigned16(&pdu[2], time_to_live_seconds); + len = 6; + } + + return len; +} + +int bvlc_encode_read_fdt( + uint8_t * pdu) +{ + int len = 0; + + if (pdu) { + pdu[0] = BVLL_TYPE_BACNET_IP; + pdu[1] = BVLC_READ_FOREIGN_DEVICE_TABLE; + /* The 2-octet BVLC Length field is the length, in octets, + of the entire BVLL message, including the two octets of the + length field itself, most significant octet first. */ + encode_unsigned16(&pdu[2], 4); + len = 4; + } + + return len; +} + +int bvlc_encode_read_fdt_ack_init( + uint8_t * pdu, + unsigned entries) +{ + int len = 0; + + if (pdu) { + pdu[0] = BVLL_TYPE_BACNET_IP; + pdu[1] = BVLC_READ_FOREIGN_DEVICE_TABLE_ACK; + /* The 2-octet BVLC Length field is the length, in octets, + of the entire BVLL message, including the two octets of the + length field itself, most significant octet first. */ + encode_unsigned16(&pdu[2], 4 + entries * 10); + len = 4; + } + + return len; +} + +int bvlc_encode_delete_fdt_entry(uint8_t * pdu, + struct in_addr *address, + uint16_t port) +{ + int len = 0; + + if (pdu) { + pdu[0] = BVLL_TYPE_BACNET_IP; + pdu[1] = BVLC_READ_FOREIGN_DEVICE_TABLE; + /* The 2-octet BVLC Length field is the length, in octets, + of the entire BVLL message, including the two octets of the + length field itself, most significant octet first. */ + encode_unsigned16(&pdu[2], 10); + /* FDT Entry */ + encode_unsigned32(&pdu[0], address->s_addr); + encode_unsigned16(&pdu[4], port); + len = 10; + } + + return len; +} + +int bvlc_encode_distribute_broadcast_to_network(uint8_t * pdu, + uint8_t * npdu, + unsigned npdu_length) +{ + int len = 0; /* return value */ + unsigned i; /* for loop counter */ + + if (pdu) { + pdu[0] = BVLL_TYPE_BACNET_IP; + pdu[1] = BVLC_DISTRIBUTE_BROADCAST_TO_NETWORK; + /* The 2-octet BVLC Length field is the length, in octets, + of the entire BVLL message, including the two octets of the + length field itself, most significant octet first. */ + len = encode_unsigned16(&pdu[2], 4 + npdu_length) + 2; + for (i = 0; i < npdu_length; i++) { + pdu[len] = npdu[i]; + len++; + } + } + + return len; +} + +int bvlc_encode_original_unicast_npdu(uint8_t * pdu, + uint8_t * npdu, + unsigned npdu_length) +{ + int len = 0; /* return value */ + unsigned i = 0; /* loop counter */ + + if (pdu) { + pdu[0] = BVLL_TYPE_BACNET_IP; + pdu[1] = BVLC_ORIGINAL_UNICAST_NPDU; + /* The 2-octet BVLC Length field is the length, in octets, + of the entire BVLL message, including the two octets of the + length field itself, most significant octet first. */ + len = encode_unsigned16(&pdu[2], 4 + npdu_length) + 2; + for (i = 0; i < npdu_length; i++) { + pdu[len] = npdu[i]; + len++; + } + } + + return len; +} + + +int bvlc_encode_original_broadcast_npdu(uint8_t * pdu, + uint8_t * npdu, + unsigned npdu_length) +{ + int len = 0; /* return value */ + unsigned i = 0; /* loop counter */ + + if (pdu) { + pdu[0] = BVLL_TYPE_BACNET_IP; + pdu[1] = BVLC_ORIGINAL_BROADCAST_NPDU; + /* The 2-octet BVLC Length field is the length, in octets, + of the entire BVLL message, including the two octets of the + length field itself, most significant octet first. */ + len = encode_unsigned16(&pdu[2], 4 + npdu_length) + 2; + for (i = 0; i < npdu_length; i++) { + pdu[len] = npdu[i]; + len++; + } + } + + return len; +} + +/* copy the source internet address to the BACnet address */ +/* FIXME: IPv6? */ +void bvlc_internet_to_bacnet_address( + BACNET_ADDRESS * src, /* returns the BACnet source address */ + struct sockaddr_in *sin) +{ /* source internet address */ + int len = 0; + uint32_t address; + uint16_t port; + + if (src && sin) { + address = ntohl(sin->sin_addr.s_addr); + len = encode_unsigned32(&src->mac[0], address); + port = ntohs(sin->sin_port); + len += encode_unsigned16(&src->mac[4], port); + src->mac_len = len; + src->net = 0; + src->len = 0; + } + + return; +} + +/* copy the source internet address to the BACnet address */ +/* FIXME: IPv6? */ +/* FIXME: is sockaddr_in host or network order? */ +void bvlc_bacnet_to_internet_address( + struct sockaddr_in *sin, /* source internet address */ + BACNET_ADDRESS * src) /* returns the BACnet source address */ +{ + int len = 0; + uint32_t address; + uint16_t port; + + if (src && sin) { + if (src->mac_len == 6) { + len = decode_unsigned32(&src->mac[0], &address); + len += decode_unsigned16(&src->mac[4], &port ); + sin->sin_addr.s_addr = htonl(address); + sin->sin_port = htons(port); + } + } + + return; +} + +void bvlc_bdt_forward_npdu( + struct sockaddr_in *sin, /* the source address */ + uint8_t * npdu, /* the NPDU */ + uint16_t npdu_length) +{ /* length of the NPDU */ + uint8_t mtu[MAX_MPDU] = {0}; + int mtu_len = 0; + int bytes_sent = 0; + unsigned i = 0; /* loop counter */ + struct sockaddr_in bip_dest; + BACNET_ADDRESS src; + + /* assumes that the driver has already been initialized */ + if (bip_socket() < 0) { + return; + } + bvlc_internet_to_bacnet_address(&src, sin); + mtu_len = bvlc_encode_forwarded_npdu( + &mtu[0], + &src, + npdu, + npdu_length); + /* load destination IP address */ + bip_dest.sin_family = AF_INET; + /* loop through the BDT and send one to each entry, except us */ + for (i = 0; i < MAX_BBMD_ENTRIES; i++) { + if (BBMD_Table[i].valid) { + /* The B/IP address to which the Forwarded-NPDU message is + sent is formed by inverting the broadcast distribution + mask in the BDT entry and logically ORing it with the + BBMD address of the same entry. */ + bip_dest.sin_addr.s_addr = + htonl(((~BBMD_Table[i].broadcast_mask.s_addr) | + BBMD_Table[i].dest_address.s_addr)); + bip_dest.sin_port = htons(BBMD_Table[i].dest_port); + /* Send the packet */ + bytes_sent = + sendto(bip_socket(), (char *) mtu, mtu_len, 0, + (struct sockaddr *) &bip_dest, + sizeof(struct sockaddr)); + } + } + + return; +} + +void bvlc_fdt_forward_npdu( + struct sockaddr_in *sin, /* the source address */ + uint8_t * npdu, /* returns the NPDU */ + uint16_t max_npdu) /* amount of space available in the NPDU */ +{ + + /* FIXME: add the code */ +} + +uint16_t bvlc_handler( + BACNET_ADDRESS * src, /* returns the source address */ + uint8_t * npdu, /* returns the NPDU */ + uint16_t max_npdu, /* amount of space available in the NPDU */ + unsigned timeout) /* number of milliseconds to wait for a packet */ +{ + uint8_t buf[MAX_MPDU] = {0}; /* data */ + uint16_t pdu_len = 0; /* return value */ + fd_set read_fds; + int max; + struct timeval select_timeout; + struct sockaddr_in sin = { -1 }; + socklen_t sin_len = sizeof(sin); + int function_type = 0; + int received_bytes; + + /* Make sure the socket is open */ + if (BIP_Socket < 0) { + return 0; + } + + /* we could just use a non-blocking socket, but that consumes all + the CPU time. We can use a timeout; it is only supported as + a select. */ + if (timeout >= 1000) { + select_timeout.tv_sec = timeout / 1000; + select_timeout.tv_usec = + 1000 * (timeout - select_timeout.tv_sec * 1000); + } else { + select_timeout.tv_sec = 0; + select_timeout.tv_usec = 1000 * timeout; + } + FD_ZERO(&read_fds); + FD_SET((unsigned int) BIP_Socket, &read_fds); + max = BIP_Socket; + /* see if there is a packet for us */ + if (select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0) { + received_bytes = recvfrom( + BIP_Socket, + (char *) &buf[0], + MAX_MPDU, 0, + (struct sockaddr *) &sin, &sin_len); + } else { + return 0; + } + /* See if there is a problem */ + if (received_bytes < 0) { + return 0; + } + /* no problem, just no bytes */ + if (received_bytes == 0) { + return 0; + } + /* the signature of a BACnet/IP packet */ + if (buf[0] != BVLL_TYPE_BACNET_IP) { + return 0; + } + function_type = buf[1]; + /* decode the length of the PDU - length is inclusive of BVLC */ + (void) decode_unsigned16(&buf[2], &npdu_len); + /* subtract off the BVLC header */ + npdu_len -= 4; + switch (function_type) { + case BVLC_RESULT: + break; + case BVLC_WRITE_BROADCAST_DISTRIBUTION_TABLE: + /* Upon receipt of a BVLL Write-Broadcast-Distribution-Table + message, a BBMD shall attempt to create or replace its BDT, + depending on whether or not a BDT has previously existed. + If the creation or replacement of the BDT is successful, the BBMD + shall return a BVLC-Result message to the originating device with + a result code of X'0000'. Otherwise, the BBMD shall return a + BVLC-Result message to the originating device with a result code + of X'0010' indicating that the write attempt has failed. */ + break; + case BVLC_READ_BROADCAST_DISTRIBUTION_TABLE: + break; + case BVLC_READ_BROADCAST_DISTRIBUTION_TABLE_ACK: + break; + case BVLC_FORWARDED_NPDU: + /* Upon receipt of a BVLL Forwarded-NPDU message, a BBMD shall + process it according to whether it was received from a peer + BBMD as the result of a directed broadcast or a unicast + transmission. A BBMD may ascertain the method by which Forwarded- + NPDU messages will arrive by inspecting the broadcast distribution + mask field in its own BDT entry since all BDTs are required + to be identical. If the message arrived via directed broadcast, + it was also received by the other devices on the BBMD's subnet. In + this case the BBMD merely retransmits the message directly to each + foreign device currently in the BBMD's FDT. If the + message arrived via a unicast transmission it has not yet been + received by the other devices on the BBMD's subnet. In this case, + the message is sent to the devices on the BBMD's subnet using the + B/IP broadcast address as well as to each foreign device + currently in the BBMD's FDT. A BBMD on a subnet with no other + BACnet devices may omit the broadcast using the B/IP + broadcast address. The method by which a BBMD determines whether + or not other BACnet devices are present is a local matter. */ + bvlc_broadcast_npdu(&sin, &buf[4], npdu_len); + bvlc_fdt_forward_npdu(&sin, &buf[4], npdu_len); + break; + case BVLC_REGISTER_FOREIGN_DEVICE: + break; + case BVLC_READ_FOREIGN_DEVICE_TABLE: + break; + case BVLC_READ_FOREIGN_DEVICE_TABLE_ACK: + break; + case BVLC_DELETE_FOREIGN_DEVICE_TABLE_ENTRY: + break; + case BVLC_DISTRIBUTE_BROADCAST_TO_NETWORK: + bvlc_broadcast_forward_npdu(&sin, &buf[4], npdu_len); + bvlc_fdt_forward_npdu(&sin, &buf[4], npdu_len); + break; + case BVLC_ORIGINAL_UNICAST_NPDU: + /* ignore messages from me */ + if (sin.sin_addr.s_addr == BIP_Address.s_addr) { + npdu_len = 0; + } else { + bvlc_internet_to_bacnet_address(src, &sin); + if (npdu_len < max_npdu) { + /* copy the buffer into the PDU */ + memmove(&npdu[0], &buf[4], npdu_len); + } else { + /* ignore packets that are too large */ + /* clients should check my max-apdu first */ + npdu_len = 0; + } + } + break; + case BVLC_ORIGINAL_BROADCAST_NPDU: + /* Upon receipt of a BVLL Original-Broadcast-NPDU message, + a BBMD shall construct a BVLL Forwarded-NPDU message and + send it to each IP subnet in its BDT with the exception + of its own. The B/IP address to which the Forwarded-NPDU + message is sent is formed by inverting the broadcast + distribution mask in the BDT entry and logically ORing it + with the BBMD address of the same entry. This process + produces either the directed broadcast address of the remote + subnet or the unicast address of the BBMD on that subnet + depending on the contents of the broadcast distribution + mask. See J.4.3.2.. In addition, the received BACnet NPDU + shall be sent directly to each foreign device currently in + the BBMD's FDT also using the BVLL Forwarded-NPDU message. */ + bvlc_internet_to_bacnet_address(src, &sin); + if (npdu_len < max_npdu) { + /* copy the buffer into the PDU */ + memmove(&npdu[0], &buf[4], npdu_len); + } else { + /* ignore packets that are too large */ + /* clients should check my max-apdu first */ + npdu_len = 0; + } + /* if BDT or FDT entries exist, Forward the NPDU */ + bvlc_bdt_forward_npdu(&sin, &buf[4], npdu_len); + bvlc_fdt_forward_npdu(&sin, &buf[4], npdu_len); + break; + default: + break; + } + + return npdu_len; +} + +#ifdef TEST +#include +#include +#include "ctest.h" + +void testBIPAddress(Test * pTest) +{ + uint8_t apdu[50] = { 0 }; + uint32_t value = 0, test_value = 0; + int len = 0, test_len = 0; + struct in_addr address; + struct in_addr test_address; + uint16_t port = 0, test_port = 0; + + address.s_addr = 42; + len = bvlc_encode_bip_address(&apdu[0], + &address, port); + test_len = bvlc_decode_bip_address(&apdu[0], + &test_address, &test_port); + ct_test(pTest, len == test_len); + ct_test(pTest, address.s_addr == test_address.s_addr); + ct_test(pTest, port == test_port); +} + +void testInternetAddress(Test * pTest) +{ + BACNET_ADDRESS src; + BACNET_ADDRESS test_src; + struct sockaddr_in sin; + struct sockaddr_in test_sin; + + sin.sin_port = htons(0xBAC0); + sin.sin_addr.s_addr = inet_addr("192.168.0.1"); + bvlc_internet_to_bacnet_address(&src, &sin); + bvlc_bacnet_to_internet_address(&test_sin, &src); + ct_test(pTest, sin.sin_port == test_sin.sin_port); + ct_test(pTest, sin.sin_addr.s_addr == test_sin.sin_addr.s_addr); +} + +#ifdef TEST_BVLC +int main(void) +{ + Test * pTest; + bool rc; + + pTest = ct_create("BACnet Virtual Link Control", NULL); + /* individual tests */ + rc = ct_addTestFunction(pTest, testBIPAddress); + assert(rc); + rc = ct_addTestFunction(pTest, testInternetAddress); + assert(rc); + /* configure output */ + ct_setStream(pTest, stdout); + ct_run(pTest); + (void) ct_report(pTest); + ct_destroy(pTest); + + return 0; +} + +#endif /* TEST_BBMD */ +#endif /* TEST */ diff --git a/bacnet-stack/bvlc.h b/bacnet-stack/bvlc.h index 3b2756e5..849d2d1e 100644 --- a/bacnet-stack/bvlc.h +++ b/bacnet-stack/bvlc.h @@ -49,4 +49,5 @@ extern "C" { #ifdef __cplusplus } #endif /* __cplusplus */ -#endif /* */ +#endif /* */ + diff --git a/bacnet-stack/cov.c b/bacnet-stack/cov.c index 08fa8b50..97c26a4f 100644 --- a/bacnet-stack/cov.c +++ b/bacnet-stack/cov.c @@ -840,9 +840,9 @@ void testCOVSubscribeData(Test * pTest, test_data->monitoredObjectIdentifier.instance == data->monitoredObjectIdentifier.instance); ct_test(pTest, - test_data->cancellationRequest == data->cancellationRequest); - if (test_data->cancellationRequest != data->cancellationRequest) { - printf("cancellation request failed!\n"); + test_data->cancellationRequest == data->cancellationRequest); + if (test_data->cancellationRequest != data->cancellationRequest) { + printf("cancellation request failed!\n"); } if (!test_data->cancellationRequest) { ct_test(pTest, diff --git a/bacnet-stack/datetime.c b/bacnet-stack/datetime.c index 14226fa6..fdbf60a6 100644 --- a/bacnet-stack/datetime.c +++ b/bacnet-stack/datetime.c @@ -354,7 +354,7 @@ bool datetime_wildcard(BACNET_DATE_TIME * bdatetime) return wildcard_present; } - + void datetime_date_wildcard_set(BACNET_DATE * bdate) { if (bdate) { @@ -364,7 +364,7 @@ void datetime_date_wildcard_set(BACNET_DATE * bdate) bdate->wday = 0xFF; } } - + void datetime_time_wildcard_set(BACNET_TIME * btime) { if (btime) { diff --git a/bacnet-stack/datetime.h b/bacnet-stack/datetime.h index dc3f7fcf..49f7f160 100644 --- a/bacnet-stack/datetime.h +++ b/bacnet-stack/datetime.h @@ -104,7 +104,7 @@ extern "C" { /* date and time wildcards */ bool datetime_wildcard(BACNET_DATE_TIME * bdatetime); - void datetime_wildcard_set(BACNET_DATE_TIME * bdatetime); + void datetime_wildcard_set(BACNET_DATE_TIME * bdatetime); void datetime_date_wildcard_set(BACNET_DATE * bdate); void datetime_time_wildcard_set(BACNET_TIME * btime); diff --git a/bacnet-stack/demo/object/lc.c b/bacnet-stack/demo/object/lc.c index 1174792d..3b2e7c92 100644 --- a/bacnet-stack/demo/object/lc.c +++ b/bacnet-stack/demo/object/lc.c @@ -400,15 +400,15 @@ void Load_Control_State_Machine(int object_index) { unsigned i = 0; /* loop counter */ int diff = 0; /* used for datetime comparison */ - + /* is the state machine enabled? */ - if (!Load_Control_Enable[object_index]) { + if (!Load_Control_Enable[object_index]) { Load_Control_State[object_index] = SHED_INACTIVE; return; - } - + } + switch (Load_Control_State[object_index]) { - case SHED_REQUEST_PENDING: + case SHED_REQUEST_PENDING: if (Load_Control_Request_Written[object_index]) { Load_Control_Request_Written[object_index] = false; /* request to cancel using default values? */ @@ -996,195 +996,195 @@ static void Load_Control_WriteProperty_Request_Shed_Percent(Test * pTest, int instance, unsigned percent) { bool status = false; - BACNET_APPLICATION_DATA_VALUE value; + BACNET_APPLICATION_DATA_VALUE value; BACNET_WRITE_PROPERTY_DATA wp_data; - BACNET_ERROR_CLASS error_class; - BACNET_ERROR_CODE error_code; + BACNET_ERROR_CLASS error_class; + BACNET_ERROR_CODE error_code; wp_data.object_type = OBJECT_LOAD_CONTROL; - wp_data.object_instance = instance; - wp_data.array_index = BACNET_ARRAY_ALL; - wp_data.priority = BACNET_NO_PRIORITY; - wp_data.object_property = PROP_REQUESTED_SHED_LEVEL; - value.context_specific = true; - value.context_tag = 0; - value.tag = BACNET_APPLICATION_TAG_UNSIGNED_INT; - value.type.Unsigned_Int = percent; - wp_data.application_data_len = - bacapp_encode_data(&wp_data.application_data[0], &value); - ct_test(pTest, wp_data.application_data_len > 0); - status = Load_Control_Write_Property(&wp_data, + wp_data.object_instance = instance; + wp_data.array_index = BACNET_ARRAY_ALL; + wp_data.priority = BACNET_NO_PRIORITY; + wp_data.object_property = PROP_REQUESTED_SHED_LEVEL; + value.context_specific = true; + value.context_tag = 0; + value.tag = BACNET_APPLICATION_TAG_UNSIGNED_INT; + value.type.Unsigned_Int = percent; + wp_data.application_data_len = + bacapp_encode_data(&wp_data.application_data[0], &value); + ct_test(pTest, wp_data.application_data_len > 0); + status = Load_Control_Write_Property(&wp_data, &error_class, &error_code); - ct_test(pTest, status == true); + ct_test(pTest, status == true); } -#endif +#endif static void Load_Control_WriteProperty_Request_Shed_Level(Test * pTest, int instance, unsigned level) { bool status = false; - BACNET_APPLICATION_DATA_VALUE value; + BACNET_APPLICATION_DATA_VALUE value; BACNET_WRITE_PROPERTY_DATA wp_data; - BACNET_ERROR_CLASS error_class; - BACNET_ERROR_CODE error_code; + BACNET_ERROR_CLASS error_class; + BACNET_ERROR_CODE error_code; wp_data.object_type = OBJECT_LOAD_CONTROL; - wp_data.object_instance = instance; - wp_data.array_index = BACNET_ARRAY_ALL; - wp_data.priority = BACNET_NO_PRIORITY; - wp_data.object_property = PROP_REQUESTED_SHED_LEVEL; - value.context_specific = true; - value.context_tag = 1; - value.tag = BACNET_APPLICATION_TAG_UNSIGNED_INT; - value.type.Unsigned_Int = level; - wp_data.application_data_len = - bacapp_encode_data(&wp_data.application_data[0], &value); - ct_test(pTest, wp_data.application_data_len > 0); - status = Load_Control_Write_Property(&wp_data, + wp_data.object_instance = instance; + wp_data.array_index = BACNET_ARRAY_ALL; + wp_data.priority = BACNET_NO_PRIORITY; + wp_data.object_property = PROP_REQUESTED_SHED_LEVEL; + value.context_specific = true; + value.context_tag = 1; + value.tag = BACNET_APPLICATION_TAG_UNSIGNED_INT; + value.type.Unsigned_Int = level; + wp_data.application_data_len = + bacapp_encode_data(&wp_data.application_data[0], &value); + ct_test(pTest, wp_data.application_data_len > 0); + status = Load_Control_Write_Property(&wp_data, &error_class, &error_code); - ct_test(pTest, status == true); -} + ct_test(pTest, status == true); +} #if 0 static void Load_Control_WriteProperty_Request_Shed_Amount(Test * pTest, int instance, float amount) { bool status = false; - BACNET_APPLICATION_DATA_VALUE value; + BACNET_APPLICATION_DATA_VALUE value; BACNET_WRITE_PROPERTY_DATA wp_data; - BACNET_ERROR_CLASS error_class; - BACNET_ERROR_CODE error_code; + BACNET_ERROR_CLASS error_class; + BACNET_ERROR_CODE error_code; wp_data.object_type = OBJECT_LOAD_CONTROL; - wp_data.object_instance = instance; - wp_data.array_index = BACNET_ARRAY_ALL; - wp_data.priority = BACNET_NO_PRIORITY; - wp_data.object_property = PROP_REQUESTED_SHED_LEVEL; - value.context_specific = true; - value.context_tag = 2; - value.tag = BACNET_APPLICATION_TAG_REAL; - value.type.Real = amount; - wp_data.application_data_len = - bacapp_encode_data(&wp_data.application_data[0], &value); - ct_test(pTest, wp_data.application_data_len > 0); - status = Load_Control_Write_Property(&wp_data, + wp_data.object_instance = instance; + wp_data.array_index = BACNET_ARRAY_ALL; + wp_data.priority = BACNET_NO_PRIORITY; + wp_data.object_property = PROP_REQUESTED_SHED_LEVEL; + value.context_specific = true; + value.context_tag = 2; + value.tag = BACNET_APPLICATION_TAG_REAL; + value.type.Real = amount; + wp_data.application_data_len = + bacapp_encode_data(&wp_data.application_data[0], &value); + ct_test(pTest, wp_data.application_data_len > 0); + status = Load_Control_Write_Property(&wp_data, &error_class, &error_code); - ct_test(pTest, status == true); + ct_test(pTest, status == true); } -#endif +#endif static void Load_Control_WriteProperty_Enable(Test * pTest, int instance, bool enable) { bool status = false; - BACNET_APPLICATION_DATA_VALUE value; + BACNET_APPLICATION_DATA_VALUE value; BACNET_WRITE_PROPERTY_DATA wp_data; - BACNET_ERROR_CLASS error_class; - BACNET_ERROR_CODE error_code; + BACNET_ERROR_CLASS error_class; + BACNET_ERROR_CODE error_code; wp_data.object_type = OBJECT_LOAD_CONTROL; - wp_data.object_instance = instance; - wp_data.array_index = BACNET_ARRAY_ALL; - wp_data.priority = BACNET_NO_PRIORITY; - /* Set Enable=TRUE */ - wp_data.object_property = PROP_ENABLE; - value.context_specific = false; - value.context_tag = 0; - value.tag = BACNET_APPLICATION_TAG_BOOLEAN; - value.type.Boolean = enable; - wp_data.application_data_len = - bacapp_encode_data(&wp_data.application_data[0], &value); - ct_test(pTest, wp_data.application_data_len > 0); - status = Load_Control_Write_Property(&wp_data, + wp_data.object_instance = instance; + wp_data.array_index = BACNET_ARRAY_ALL; + wp_data.priority = BACNET_NO_PRIORITY; + /* Set Enable=TRUE */ + wp_data.object_property = PROP_ENABLE; + value.context_specific = false; + value.context_tag = 0; + value.tag = BACNET_APPLICATION_TAG_BOOLEAN; + value.type.Boolean = enable; + wp_data.application_data_len = + bacapp_encode_data(&wp_data.application_data[0], &value); + ct_test(pTest, wp_data.application_data_len > 0); + status = Load_Control_Write_Property(&wp_data, &error_class, &error_code); - ct_test(pTest, status == true); -} + ct_test(pTest, status == true); +} static void Load_Control_WriteProperty_Shed_Duration(Test * pTest, int instance, unsigned duration) { bool status = false; - BACNET_APPLICATION_DATA_VALUE value; + BACNET_APPLICATION_DATA_VALUE value; BACNET_WRITE_PROPERTY_DATA wp_data; - BACNET_ERROR_CLASS error_class; - BACNET_ERROR_CODE error_code; + BACNET_ERROR_CLASS error_class; + BACNET_ERROR_CODE error_code; wp_data.object_type = OBJECT_LOAD_CONTROL; - wp_data.object_instance = instance; - wp_data.array_index = BACNET_ARRAY_ALL; - wp_data.priority = BACNET_NO_PRIORITY; - wp_data.object_property = PROP_SHED_DURATION; - value.context_specific = false; - value.context_tag = 0; - value.tag = BACNET_APPLICATION_TAG_UNSIGNED_INT; - value.type.Unsigned_Int = duration; - wp_data.application_data_len = - bacapp_encode_data(&wp_data.application_data[0], &value); - ct_test(pTest, wp_data.application_data_len > 0); - status = Load_Control_Write_Property(&wp_data, + wp_data.object_instance = instance; + wp_data.array_index = BACNET_ARRAY_ALL; + wp_data.priority = BACNET_NO_PRIORITY; + wp_data.object_property = PROP_SHED_DURATION; + value.context_specific = false; + value.context_tag = 0; + value.tag = BACNET_APPLICATION_TAG_UNSIGNED_INT; + value.type.Unsigned_Int = duration; + wp_data.application_data_len = + bacapp_encode_data(&wp_data.application_data[0], &value); + ct_test(pTest, wp_data.application_data_len > 0); + status = Load_Control_Write_Property(&wp_data, &error_class, &error_code); - ct_test(pTest, status == true); -} + ct_test(pTest, status == true); +} static void Load_Control_WriteProperty_Duty_Window(Test * pTest, int instance, unsigned duration) { bool status = false; - BACNET_APPLICATION_DATA_VALUE value; + BACNET_APPLICATION_DATA_VALUE value; BACNET_WRITE_PROPERTY_DATA wp_data; - BACNET_ERROR_CLASS error_class; - BACNET_ERROR_CODE error_code; + BACNET_ERROR_CLASS error_class; + BACNET_ERROR_CODE error_code; wp_data.object_type = OBJECT_LOAD_CONTROL; - wp_data.object_instance = instance; - wp_data.array_index = BACNET_ARRAY_ALL; - wp_data.priority = BACNET_NO_PRIORITY; - wp_data.object_property = PROP_DUTY_WINDOW; - value.context_specific = false; - value.context_tag = 0; - value.tag = BACNET_APPLICATION_TAG_UNSIGNED_INT; - value.type.Unsigned_Int = duration; - wp_data.application_data_len = - bacapp_encode_data(&wp_data.application_data[0], &value); - ct_test(pTest, wp_data.application_data_len > 0); - status = Load_Control_Write_Property(&wp_data, + wp_data.object_instance = instance; + wp_data.array_index = BACNET_ARRAY_ALL; + wp_data.priority = BACNET_NO_PRIORITY; + wp_data.object_property = PROP_DUTY_WINDOW; + value.context_specific = false; + value.context_tag = 0; + value.tag = BACNET_APPLICATION_TAG_UNSIGNED_INT; + value.type.Unsigned_Int = duration; + wp_data.application_data_len = + bacapp_encode_data(&wp_data.application_data[0], &value); + ct_test(pTest, wp_data.application_data_len > 0); + status = Load_Control_Write_Property(&wp_data, &error_class, &error_code); - ct_test(pTest, status == true); -} + ct_test(pTest, status == true); +} static void Load_Control_WriteProperty_Start_Time_Wildcards(Test * pTest, int instance) { int len = 0; bool status = false; - BACNET_APPLICATION_DATA_VALUE value; + BACNET_APPLICATION_DATA_VALUE value; BACNET_WRITE_PROPERTY_DATA wp_data; - BACNET_ERROR_CLASS error_class; - BACNET_ERROR_CODE error_code; + BACNET_ERROR_CLASS error_class; + BACNET_ERROR_CODE error_code; wp_data.object_type = OBJECT_LOAD_CONTROL; - wp_data.object_instance = instance; - wp_data.array_index = BACNET_ARRAY_ALL; - wp_data.priority = BACNET_NO_PRIORITY; - wp_data.object_property = PROP_START_TIME; - value.context_specific = false; - value.context_tag = 0; - value.tag = BACNET_APPLICATION_TAG_DATE; + wp_data.object_instance = instance; + wp_data.array_index = BACNET_ARRAY_ALL; + wp_data.priority = BACNET_NO_PRIORITY; + wp_data.object_property = PROP_START_TIME; + value.context_specific = false; + value.context_tag = 0; + value.tag = BACNET_APPLICATION_TAG_DATE; datetime_date_wildcard_set(&value.type.Date); - wp_data.application_data_len = - bacapp_encode_data(&wp_data.application_data[0], &value); - ct_test(pTest, wp_data.application_data_len > 0); - len = wp_data.application_data_len; - value.tag = BACNET_APPLICATION_TAG_TIME; + wp_data.application_data_len = + bacapp_encode_data(&wp_data.application_data[0], &value); + ct_test(pTest, wp_data.application_data_len > 0); + len = wp_data.application_data_len; + value.tag = BACNET_APPLICATION_TAG_TIME; datetime_time_wildcard_set(&value.type.Time); - wp_data.application_data_len = - bacapp_encode_data(&wp_data.application_data[len], &value); - ct_test(pTest, wp_data.application_data_len > 0); - wp_data.application_data_len += len; - status = Load_Control_Write_Property(&wp_data, + wp_data.application_data_len = + bacapp_encode_data(&wp_data.application_data[len], &value); + ct_test(pTest, wp_data.application_data_len > 0); + wp_data.application_data_len += len; + status = Load_Control_Write_Property(&wp_data, &error_class, &error_code); - ct_test(pTest, status == true); -} + ct_test(pTest, status == true); +} static void Load_Control_WriteProperty_Start_Time(Test * pTest, int instance, uint16_t year, uint8_t month, uint8_t day, @@ -1192,38 +1192,38 @@ static void Load_Control_WriteProperty_Start_Time(Test * pTest, int instance, { int len = 0; bool status = false; - BACNET_APPLICATION_DATA_VALUE value; + BACNET_APPLICATION_DATA_VALUE value; BACNET_WRITE_PROPERTY_DATA wp_data; - BACNET_ERROR_CLASS error_class; - BACNET_ERROR_CODE error_code; + BACNET_ERROR_CLASS error_class; + BACNET_ERROR_CODE error_code; wp_data.object_type = OBJECT_LOAD_CONTROL; - wp_data.object_instance = instance; - wp_data.array_index = BACNET_ARRAY_ALL; - wp_data.priority = BACNET_NO_PRIORITY; - wp_data.object_property = PROP_START_TIME; - value.context_specific = false; - value.context_tag = 0; - value.tag = BACNET_APPLICATION_TAG_DATE; + wp_data.object_instance = instance; + wp_data.array_index = BACNET_ARRAY_ALL; + wp_data.priority = BACNET_NO_PRIORITY; + wp_data.object_property = PROP_START_TIME; + value.context_specific = false; + value.context_tag = 0; + value.tag = BACNET_APPLICATION_TAG_DATE; datetime_set_date(&value.type.Date, year, month, day); wp_data.application_data_len = - bacapp_encode_data(&wp_data.application_data[0], &value); - ct_test(pTest, wp_data.application_data_len > 0); - len = wp_data.application_data_len; - value.tag = BACNET_APPLICATION_TAG_TIME; + bacapp_encode_data(&wp_data.application_data[0], &value); + ct_test(pTest, wp_data.application_data_len > 0); + len = wp_data.application_data_len; + value.tag = BACNET_APPLICATION_TAG_TIME; datetime_set_time(&value.type.Time, hour, minute, seconds, hundredths); wp_data.application_data_len = - bacapp_encode_data(&wp_data.application_data[len], &value); - ct_test(pTest, wp_data.application_data_len > 0); - wp_data.application_data_len += len; - status = Load_Control_Write_Property(&wp_data, + bacapp_encode_data(&wp_data.application_data[len], &value); + ct_test(pTest, wp_data.application_data_len > 0); + wp_data.application_data_len += len; + status = Load_Control_Write_Property(&wp_data, &error_class, &error_code); - ct_test(pTest, status == true); -} + ct_test(pTest, status == true); +} void testLoadControlStateMachine(Test * pTest) { - unsigned i = 0, j = 0; + unsigned i = 0, j = 0; uint8_t level = 0; Load_Control_Init(); @@ -1233,13 +1233,13 @@ void testLoadControlStateMachine(Test * pTest) for (i = 0; i < MAX_LOAD_CONTROLS; i++) { ct_test(pTest, Load_Control_State[i] == SHED_INACTIVE); } - } - /* SHED_REQUEST_PENDING */ - /* CancelShed - Start time has wildcards */ - Load_Control_WriteProperty_Enable(pTest, 0, true); - Load_Control_WriteProperty_Shed_Duration(pTest, 0, 60); - Load_Control_WriteProperty_Start_Time_Wildcards(pTest, 0); - Load_Control_State_Machine(0); + } + /* SHED_REQUEST_PENDING */ + /* CancelShed - Start time has wildcards */ + Load_Control_WriteProperty_Enable(pTest, 0, true); + Load_Control_WriteProperty_Shed_Duration(pTest, 0, 60); + Load_Control_WriteProperty_Start_Time_Wildcards(pTest, 0); + Load_Control_State_Machine(0); ct_test(pTest, Load_Control_State[0] == SHED_REQUEST_PENDING); Load_Control_State_Machine(0); ct_test(pTest, Load_Control_State[0] == SHED_INACTIVE); diff --git a/bacnet-stack/demo/object/lo.c b/bacnet-stack/demo/object/lo.c index b8d7d62d..6708b214 100644 --- a/bacnet-stack/demo/object/lo.c +++ b/bacnet-stack/demo/object/lo.c @@ -1,625 +1,625 @@ -/************************************************************************** -* -* Copyright (C) 2007 Steve Karg -* -* Permission is hereby granted, free of charge, to any person obtaining -* a copy of this software and associated documentation files (the -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to -* permit persons to whom the Software is furnished to do so, subject to -* the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -* -*********************************************************************/ - -/* Lighting Output Objects - customize for your use */ - -#include -#include -#include -#include "bacdef.h" -#include "bacdcode.h" -#include "bacenum.h" -#include "bacapp.h" -#include "config.h" /* the custom stuff */ -#include "wp.h" - -#define MAX_LIGHTING_OUTPUTS 5 - -/* we choose to have a NULL level in our system represented by */ -/* a particular value. When the priorities are not in use, they */ -/* will be relinquished (i.e. set to the NULL level). */ -#define LIGHTING_LEVEL_NULL 255 -/* When all the priorities are level null, the present value returns */ -/* the Relinquish Default value */ -#define LIGHTING_RELINQUISH_DEFAULT 0 - -/* note: although the standard specifies REAL values for some - of the optional parameters, we represent them interally as - integers. */ -typedef struct LightingCommand { - BACNET_LIGHTING_OPERATION operation; - uint8_t level; /* 0..100 percent, 255=not used */ - uint8_t ramp_rate; /* 0..100 percent-per-second, 255=not used */ - uint8_t step_increment; /* 0..100 amount to step, 255=not used */ - uint16_t fade_time; /* 1..65535 seconds to transition, 0=not used */ - uint16_t duration; /* 1..65535 minutes until relinquish, 0=not used */ -} BACNET_LIGHTING_COMMAND; - -/* Here is our Priority Array. They are supposed to be Real, but */ -/* we might not have that kind of memory, so we will use a single byte */ -/* and load a Real for returning the value when asked. */ -static uint8_t - Lighting_Output_Level[MAX_LIGHTING_OUTPUTS][BACNET_MAX_PRIORITY]; -/* The Progress_Value tracks changes such as ramp and fade */ -static uint8_t Lighting_Output_Progress[MAX_LIGHTING_OUTPUTS]; -/* The minimum and maximum present values are used for clamping */ -static uint8_t Lighting_Output_Min_Present_Value[MAX_LIGHTING_OUTPUTS]; -static uint8_t Lighting_Output_Max_Present_Value[MAX_LIGHTING_OUTPUTS]; -/* Writable out-of-service allows others to play with our Present Value */ -/* without changing the physical output */ -static bool Lighting_Output_Out_Of_Service[MAX_LIGHTING_OUTPUTS]; -/* the lighting command is what we are doing */ -static uint8_t Lighting_Command_Priority = 16; -static BACNET_LIGHTING_COMMAND Lighting_Command[MAX_LIGHTING_OUTPUTS]; -/* we need to have our arrays initialized before answering any calls */ -static bool Lighting_Output_Initialized = false; - -int Lighting_Output_Encode_Lighting_Command(uint8_t * apdu, - BACNET_LIGHTING_COMMAND * data) -{ - int apdu_len = 0; /* total length of the apdu, return value */ - int len = 0; /* total length of the apdu, return value */ - float real_value = 0.0; - uint32_t unsigned_value = 0; - - if (apdu) { - len = encode_context_enumerated(&apdu[apdu_len], 0, - data->operation); - apdu_len += len; - /* optional level? */ - if (data->level != 255) { - real_value = data->level; - len = encode_context_real(&apdu[apdu_len], 1, - real_value); - apdu_len += len; - } - /* optional ramp-rate */ - if (data->ramp_rate != 255) { - real_value = data->ramp_rate; - len = encode_context_real(&apdu[apdu_len], 2, - real_value); - apdu_len += len; - } - /* optional step increment */ - if (data->step_increment != 255) { - real_value = data->step_increment; - len = encode_context_real(&apdu[apdu_len], 3, - real_value); - apdu_len += len; - } - /* optional fade time */ - if (data->fade_time != 0) { - real_value = data->fade_time; - len = encode_context_real(&apdu[apdu_len], 4, - real_value); - apdu_len += len; - } - /* optional duration */ - if (data->duration != 0) { - unsigned_value = data->duration; - len = encode_context_unsigned(&apdu[apdu_len], 5, - unsigned_value); - apdu_len += len; - } - } - - return apdu_len; -} - -int Lighting_Output_Decode_Lighting_Command(uint8_t * apdu, - unsigned apdu_max_len, BACNET_LIGHTING_COMMAND * data) -{ - int len = 0; - int apdu_len = 0; - int tag_len = 0; - uint8_t tag_number = 0; - uint32_t len_value_type = 0; - int type = 0; /* for decoding */ - int property = 0; /* for decoding */ - uint32_t unsigned_value = 0; - int i = 0; /* loop counter */ - float real_value = 0.0; - - /* check for value pointers */ - if (apdu_len && data) { - /* Tag 0: operation */ - if (!decode_is_context_tag(&apdu[apdu_len], 0)) - return -1; - len = decode_tag_number_and_value(&apdu[apdu_len], - &tag_number, &len_value_type); - apdu_len += len; - len = decode_enumerated(&apdu[apdu_len], len_value_type, &data->operation); - apdu_len += len; - /* Tag 1: level - OPTIONAL */ - if (decode_is_context_tag(&apdu[apdu_len], 1)) { - len = decode_tag_number_and_value(&apdu[apdu_len], - &tag_number, &len_value_type); - apdu_len += len; - len = decode_real(&apdu[apdu_len], &real_value); - apdu_len += len; - data->level = real_value; - /* FIXME: are we going to flag errors in decoding values here? */ - } - /* FIXME: finish me! */ - /* Tag 2: */ - - } - - return len; -} - - -void Lighting_Output_Init(void) -{ - unsigned i, j; - - if (!Lighting_Output_Initialized) { - Lighting_Output_Initialized = true; - - /* initialize all the analog output priority arrays to NULL */ - for (i = 0; i < MAX_LIGHTING_OUTPUTS; i++) { - for (j = 0; j < BACNET_MAX_PRIORITY; j++) { - Lighting_Output_Level[i][j] = LIGHTING_LEVEL_NULL; - } - Lighting_Command[i].operation = BACNET_LIGHTS_STOP; - Lighting_Output_Out_Of_Service[i] = false; - Lighting_Output_Progress[i] = LIGHTING_RELINQUISH_DEFAULT; - Lighting_Output_Min_Present_Value[i] = 0; - Lighting_Output_Max_Present_Value[i] = 100; - } - } - - return; -} - -/* we simply have 0-n object instances. Yours might be */ -/* more complex, and then you need validate that the */ -/* given instance exists */ -bool Lighting_Output_Valid_Instance(uint32_t object_instance) -{ - Lighting_Output_Init(); - if (object_instance < MAX_LIGHTING_OUTPUTS) - return true; - - return false; -} - -/* we simply have 0-n object instances. Yours might be */ -/* more complex, and then count how many you have */ -unsigned Lighting_Output_Count(void) -{ - Lighting_Output_Init(); - return MAX_LIGHTING_OUTPUTS; -} - -/* we simply have 0-n object instances. Yours might be */ -/* more complex, and then you need to return the instance */ -/* that correlates to the correct index */ -uint32_t Lighting_Output_Index_To_Instance(unsigned index) -{ - Lighting_Output_Init(); - return index; -} - -/* we simply have 0-n object instances. Yours might be */ -/* more complex, and then you need to return the index */ -/* that correlates to the correct instance number */ -unsigned Lighting_Output_Instance_To_Index(uint32_t object_instance) -{ - unsigned index = MAX_LIGHTING_OUTPUTS; - - Lighting_Output_Init(); - if (object_instance < MAX_LIGHTING_OUTPUTS) - index = object_instance; - - return index; -} - -float Lighting_Output_Present_Value(uint32_t object_instance) -{ - float value = LIGHTING_RELINQUISH_DEFAULT; - unsigned index = 0; - unsigned i = 0; - - Lighting_Output_Init(); - index = Lighting_Output_Instance_To_Index(object_instance); - if (index < MAX_LIGHTING_OUTPUTS) { - for (i = 0; i < BACNET_MAX_PRIORITY; i++) { - if (Lighting_Output_Level[index][i] != LIGHTING_LEVEL_NULL) { - value = Lighting_Output_Level[index][i]; - break; - } - } - } - - return value; -} - -unsigned Lighting_Output_Present_Value_Priority(uint32_t object_instance) -{ - unsigned index = 0; /* instance to index conversion */ - unsigned i = 0; /* loop counter */ - unsigned priority = 0; /* return value */ - - Lighting_Output_Init(); - index = Lighting_Output_Instance_To_Index(object_instance); - if (index < MAX_LIGHTING_OUTPUTS) { - for (i = 0; i < BACNET_MAX_PRIORITY; i++) { - if (Lighting_Output_Level[index][i] != LIGHTING_LEVEL_NULL) { - priority = i + 1; - break; - } - } - } - - return priority; -} - -bool Lighting_Output_Present_Value_Set(uint32_t object_instance, - float value, unsigned priority) -{ - unsigned index = 0; - bool status = false; - - index = Lighting_Output_Instance_To_Index(object_instance); - if (index < MAX_LIGHTING_OUTPUTS) { - if (priority && (priority <= BACNET_MAX_PRIORITY) && - (priority != 6 /* reserved */ ) && - (value >= 0.0) && (value <= 100.0)) { - Lighting_Output_Level[index][priority-1] = (uint8_t) value; - /* Note: you could set the physical output here to the next - highest priority, or to the relinquish default if no - priorities are set. - However, if Out of Service is TRUE, then don't set the - physical output. This comment may apply to the - main loop (i.e. check out of service before changing output) */ - status = true; - } - } - - return status; -} - -bool Lighting_Output_Present_Value_Relinquish(uint32_t object_instance, - int priority) -{ - unsigned index = 0; - bool status = false; - - index = Lighting_Output_Instance_To_Index(object_instance); - if (index < MAX_LIGHTING_OUTPUTS) { - if (priority && (priority <= BACNET_MAX_PRIORITY) && - (priority != 6 /* reserved */ )) { - Lighting_Output_Level[index][priority-1] = LIGHTING_LEVEL_NULL; - /* Note: you could set the physical output here to the next - highest priority, or to the relinquish default if no - priorities are set. - However, if Out of Service is TRUE, then don't set the - physical output. This comment may apply to the - main loop (i.e. check out of service before changing output) */ - status = true; - } - } - - return status; -} - -float Lighting_Output_Progress_Value(uint32_t object_instance) -{ - float value = LIGHTING_RELINQUISH_DEFAULT; - unsigned index = 0; - - Lighting_Output_Init(); - index = Lighting_Output_Instance_To_Index(object_instance); - if (index < MAX_LIGHTING_OUTPUTS) { - value = Lighting_Output_Progress[index]; - } - - return value; -} - -/* note: the object name must be unique within this device */ -char *Lighting_Output_Name(uint32_t object_instance) -{ - static char text_string[32] = ""; /* okay for single thread */ - - if (object_instance < MAX_LIGHTING_OUTPUTS) { - sprintf(text_string, "LIGHTING OUTPUT %u", object_instance); - return text_string; - } - - return NULL; -} - -/* return apdu len, or -1 on error */ -int Lighting_Output_Encode_Property_APDU(uint8_t * apdu, - uint32_t object_instance, - BACNET_PROPERTY_ID property, - int32_t array_index, - BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code) -{ - int len = 0; - int apdu_len = 0; /* return value */ - BACNET_BIT_STRING bit_string; - BACNET_CHARACTER_STRING char_string; - float real_value = (float) 1.414; - unsigned object_index = 0; - unsigned i = 0; - bool state = false; - - Lighting_Output_Init(); - switch (property) { - case PROP_OBJECT_IDENTIFIER: - apdu_len = encode_tagged_object_id(&apdu[0], OBJECT_LIGHTING_OUTPUT, - object_instance); - break; - case PROP_OBJECT_NAME: - case PROP_DESCRIPTION: - /* object name must be unique in this device. */ - /* FIXME: description could be writable and different than object name */ - characterstring_init_ansi(&char_string, - Lighting_Output_Name(object_instance)); - apdu_len = encode_tagged_character_string(&apdu[0], &char_string); - break; - case PROP_OBJECT_TYPE: - apdu_len = - encode_tagged_enumerated(&apdu[0], OBJECT_LIGHTING_OUTPUT); - break; - case PROP_PRESENT_VALUE: - real_value = Lighting_Output_Present_Value(object_instance); - apdu_len = encode_tagged_real(&apdu[0], real_value); - break; - case PROP_PROGRESS_VALUE: - real_value = Lighting_Output_Progress_Value(object_instance); - apdu_len = encode_tagged_real(&apdu[0], real_value); - break; - case PROP_LIGHTING_COMMAND: - apdu_len = Lighting_Output_Encode_Lighting_Command(&apdu[0], - &Lighting_Command[object_instance]); - break; - case PROP_STATUS_FLAGS: - bitstring_init(&bit_string); - bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); - bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); - bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); - bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); - apdu_len = encode_tagged_bitstring(&apdu[0], &bit_string); - break; - case PROP_EVENT_STATE: - apdu_len = encode_tagged_enumerated(&apdu[0], EVENT_STATE_NORMAL); - break; - case PROP_OUT_OF_SERVICE: - object_index = Lighting_Output_Instance_To_Index(object_instance); - state = Lighting_Output_Out_Of_Service[object_index]; - apdu_len = encode_tagged_boolean(&apdu[0], state); - break; - case PROP_UNITS: - apdu_len = encode_tagged_enumerated(&apdu[0], UNITS_PERCENT); - break; - case PROP_PRIORITY_ARRAY: - /* Array element zero is the number of elements in the array */ - if (array_index == 0) - apdu_len = - encode_tagged_unsigned(&apdu[0], BACNET_MAX_PRIORITY); - /* if no index was specified, then try to encode the entire list */ - /* into one packet. */ - else if (array_index == BACNET_ARRAY_ALL) { - object_index = - Lighting_Output_Instance_To_Index(object_instance); - for (i = 0; i < BACNET_MAX_PRIORITY; i++) { - /* FIXME: check if we have room before adding it to APDU */ - if (Lighting_Output_Level[object_index][i] == LIGHTING_LEVEL_NULL) - len = encode_tagged_null(&apdu[apdu_len]); - else { - real_value = Lighting_Output_Level[object_index][i]; - len = encode_tagged_real(&apdu[apdu_len], real_value); - } - /* add it if we have room */ - if ((apdu_len + len) < MAX_APDU) - apdu_len += len; - else { - *error_class = ERROR_CLASS_SERVICES; - *error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT; - apdu_len = -1; - break; - } - } - } else { - object_index = - Lighting_Output_Instance_To_Index(object_instance); - if (array_index <= BACNET_MAX_PRIORITY) { - if (Lighting_Output_Level[object_index][array_index - 1] == - LIGHTING_LEVEL_NULL) - apdu_len = encode_tagged_null(&apdu[0]); - else { - real_value = - Lighting_Output_Level[object_index][array_index - 1]; - apdu_len = encode_tagged_real(&apdu[0], real_value); - } - } else { - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_INVALID_ARRAY_INDEX; - apdu_len = -1; - } - } - - break; - case PROP_RELINQUISH_DEFAULT: - real_value = LIGHTING_RELINQUISH_DEFAULT; - apdu_len = encode_tagged_real(&apdu[0], real_value); - break; - default: - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_UNKNOWN_PROPERTY; - apdu_len = -1; - break; - } - - return apdu_len; -} - -/* returns true if successful */ -bool Lighting_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, - BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code) -{ - bool status = false; /* return value */ - unsigned int object_index = 0; - uint8_t level = LIGHTING_LEVEL_NULL; - int len = 0; - BACNET_APPLICATION_DATA_VALUE value; - - Lighting_Output_Init(); - if (!Lighting_Output_Valid_Instance(wp_data->object_instance)) { - *error_class = ERROR_CLASS_OBJECT; - *error_code = ERROR_CODE_UNKNOWN_OBJECT; - return false; - } - /* decode the some of the request */ - len = bacapp_decode_application_data(wp_data->application_data, - wp_data->application_data_len, &value); - /* FIXME: len < application_data_len: more data? */ - /* FIXME: len == 0: unable to decode? */ - switch (wp_data->object_property) { - case PROP_PRESENT_VALUE: - if (value.tag == BACNET_APPLICATION_TAG_REAL) { - /* Command priority 6 is reserved for use by Minimum On/Off - algorithm and may not be used for other purposes in any - object. */ - status = - Lighting_Output_Present_Value_Set(wp_data->object_instance, - value.type.Real, wp_data->priority); - if (wp_data->priority == 6) { - /* Command priority 6 is reserved for use by Minimum On/Off - algorithm and may not be used for other purposes in any - object. */ - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; - } else if (!status) { - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; - } - } else if (value.tag == BACNET_APPLICATION_TAG_NULL) { - level = LIGHTING_LEVEL_NULL; - object_index = - Lighting_Output_Instance_To_Index(wp_data->object_instance); - status = - Lighting_Output_Present_Value_Relinquish(wp_data-> - object_instance, wp_data->priority); - if (wp_data->priority == 6) { - /* Command priority 6 is reserved for use by Minimum On/Off - algorithm and may not be used for other purposes in any - object. */ - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; - } else if (!status) { - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; - } - } else { - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_INVALID_DATA_TYPE; - } - break; - case PROP_LIGHTING_COMMAND: - /* FIXME: error checking? */ - Lighting_Output_Decode_Lighting_Command(wp_data->application_data, - wp_data->application_data_len, - &Lighting_Command[wp_data->object_instance]); - break; - case PROP_OUT_OF_SERVICE: - if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) { - object_index = - Lighting_Output_Instance_To_Index(wp_data->object_instance); - Lighting_Output_Out_Of_Service[object_index] = - value.type.Boolean; - status = true; - } else { - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_INVALID_DATA_TYPE; - } - break; - default: - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; - break; - } - - return status; -} - - -#ifdef TEST -#include -#include -#include "ctest.h" - -void testLightingOutput(Test * pTest) -{ - uint8_t apdu[MAX_APDU] = { 0 }; - int len = 0; - uint32_t len_value = 0; - uint8_t tag_number = 0; - BACNET_OBJECT_TYPE decoded_type = OBJECT_LIGHTING_OUTPUT; - uint32_t decoded_instance = 0; - uint32_t instance = 123; - BACNET_ERROR_CLASS error_class; - BACNET_ERROR_CODE error_code; - - - len = Lighting_Output_Encode_Property_APDU(&apdu[0], - instance, - PROP_OBJECT_IDENTIFIER, - BACNET_ARRAY_ALL, &error_class, &error_code); - ct_test(pTest, len != 0); - len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value); - ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID); - len = decode_object_id(&apdu[len], - (int *) &decoded_type, &decoded_instance); - ct_test(pTest, decoded_type == OBJECT_LIGHTING_OUTPUT); - ct_test(pTest, decoded_instance == instance); - - return; -} - -#ifdef TEST_LIGHTING_OUTPUT -int main(void) -{ - Test *pTest; - bool rc; - - pTest = ct_create("BACnet Lighting Output", NULL); - /* individual tests */ - rc = ct_addTestFunction(pTest, testLightingOutput); - assert(rc); - - ct_setStream(pTest, stdout); - ct_run(pTest); - (void) ct_report(pTest); - ct_destroy(pTest); - - return 0; -} -#endif /* TEST_LIGHTING_INPUT */ -#endif /* TEST */ +/************************************************************************** +* +* Copyright (C) 2007 Steve Karg +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*********************************************************************/ + +/* Lighting Output Objects - customize for your use */ + +#include +#include +#include +#include "bacdef.h" +#include "bacdcode.h" +#include "bacenum.h" +#include "bacapp.h" +#include "config.h" /* the custom stuff */ +#include "wp.h" + +#define MAX_LIGHTING_OUTPUTS 5 + +/* we choose to have a NULL level in our system represented by */ +/* a particular value. When the priorities are not in use, they */ +/* will be relinquished (i.e. set to the NULL level). */ +#define LIGHTING_LEVEL_NULL 255 +/* When all the priorities are level null, the present value returns */ +/* the Relinquish Default value */ +#define LIGHTING_RELINQUISH_DEFAULT 0 + +/* note: although the standard specifies REAL values for some + of the optional parameters, we represent them interally as + integers. */ +typedef struct LightingCommand { + BACNET_LIGHTING_OPERATION operation; + uint8_t level; /* 0..100 percent, 255=not used */ + uint8_t ramp_rate; /* 0..100 percent-per-second, 255=not used */ + uint8_t step_increment; /* 0..100 amount to step, 255=not used */ + uint16_t fade_time; /* 1..65535 seconds to transition, 0=not used */ + uint16_t duration; /* 1..65535 minutes until relinquish, 0=not used */ +} BACNET_LIGHTING_COMMAND; + +/* Here is our Priority Array. They are supposed to be Real, but */ +/* we might not have that kind of memory, so we will use a single byte */ +/* and load a Real for returning the value when asked. */ +static uint8_t + Lighting_Output_Level[MAX_LIGHTING_OUTPUTS][BACNET_MAX_PRIORITY]; +/* The Progress_Value tracks changes such as ramp and fade */ +static uint8_t Lighting_Output_Progress[MAX_LIGHTING_OUTPUTS]; +/* The minimum and maximum present values are used for clamping */ +static uint8_t Lighting_Output_Min_Present_Value[MAX_LIGHTING_OUTPUTS]; +static uint8_t Lighting_Output_Max_Present_Value[MAX_LIGHTING_OUTPUTS]; +/* Writable out-of-service allows others to play with our Present Value */ +/* without changing the physical output */ +static bool Lighting_Output_Out_Of_Service[MAX_LIGHTING_OUTPUTS]; +/* the lighting command is what we are doing */ +static uint8_t Lighting_Command_Priority = 16; +static BACNET_LIGHTING_COMMAND Lighting_Command[MAX_LIGHTING_OUTPUTS]; +/* we need to have our arrays initialized before answering any calls */ +static bool Lighting_Output_Initialized = false; + +int Lighting_Output_Encode_Lighting_Command(uint8_t * apdu, + BACNET_LIGHTING_COMMAND * data) +{ + int apdu_len = 0; /* total length of the apdu, return value */ + int len = 0; /* total length of the apdu, return value */ + float real_value = 0.0; + uint32_t unsigned_value = 0; + + if (apdu) { + len = encode_context_enumerated(&apdu[apdu_len], 0, + data->operation); + apdu_len += len; + /* optional level? */ + if (data->level != 255) { + real_value = data->level; + len = encode_context_real(&apdu[apdu_len], 1, + real_value); + apdu_len += len; + } + /* optional ramp-rate */ + if (data->ramp_rate != 255) { + real_value = data->ramp_rate; + len = encode_context_real(&apdu[apdu_len], 2, + real_value); + apdu_len += len; + } + /* optional step increment */ + if (data->step_increment != 255) { + real_value = data->step_increment; + len = encode_context_real(&apdu[apdu_len], 3, + real_value); + apdu_len += len; + } + /* optional fade time */ + if (data->fade_time != 0) { + real_value = data->fade_time; + len = encode_context_real(&apdu[apdu_len], 4, + real_value); + apdu_len += len; + } + /* optional duration */ + if (data->duration != 0) { + unsigned_value = data->duration; + len = encode_context_unsigned(&apdu[apdu_len], 5, + unsigned_value); + apdu_len += len; + } + } + + return apdu_len; +} + +int Lighting_Output_Decode_Lighting_Command(uint8_t * apdu, + unsigned apdu_max_len, BACNET_LIGHTING_COMMAND * data) +{ + int len = 0; + int apdu_len = 0; + int tag_len = 0; + uint8_t tag_number = 0; + uint32_t len_value_type = 0; + int type = 0; /* for decoding */ + int property = 0; /* for decoding */ + uint32_t unsigned_value = 0; + int i = 0; /* loop counter */ + float real_value = 0.0; + + /* check for value pointers */ + if (apdu_len && data) { + /* Tag 0: operation */ + if (!decode_is_context_tag(&apdu[apdu_len], 0)) + return -1; + len = decode_tag_number_and_value(&apdu[apdu_len], + &tag_number, &len_value_type); + apdu_len += len; + len = decode_enumerated(&apdu[apdu_len], len_value_type, &data->operation); + apdu_len += len; + /* Tag 1: level - OPTIONAL */ + if (decode_is_context_tag(&apdu[apdu_len], 1)) { + len = decode_tag_number_and_value(&apdu[apdu_len], + &tag_number, &len_value_type); + apdu_len += len; + len = decode_real(&apdu[apdu_len], &real_value); + apdu_len += len; + data->level = real_value; + /* FIXME: are we going to flag errors in decoding values here? */ + } + /* FIXME: finish me! */ + /* Tag 2: */ + + } + + return len; +} + + +void Lighting_Output_Init(void) +{ + unsigned i, j; + + if (!Lighting_Output_Initialized) { + Lighting_Output_Initialized = true; + + /* initialize all the analog output priority arrays to NULL */ + for (i = 0; i < MAX_LIGHTING_OUTPUTS; i++) { + for (j = 0; j < BACNET_MAX_PRIORITY; j++) { + Lighting_Output_Level[i][j] = LIGHTING_LEVEL_NULL; + } + Lighting_Command[i].operation = BACNET_LIGHTS_STOP; + Lighting_Output_Out_Of_Service[i] = false; + Lighting_Output_Progress[i] = LIGHTING_RELINQUISH_DEFAULT; + Lighting_Output_Min_Present_Value[i] = 0; + Lighting_Output_Max_Present_Value[i] = 100; + } + } + + return; +} + +/* we simply have 0-n object instances. Yours might be */ +/* more complex, and then you need validate that the */ +/* given instance exists */ +bool Lighting_Output_Valid_Instance(uint32_t object_instance) +{ + Lighting_Output_Init(); + if (object_instance < MAX_LIGHTING_OUTPUTS) + return true; + + return false; +} + +/* we simply have 0-n object instances. Yours might be */ +/* more complex, and then count how many you have */ +unsigned Lighting_Output_Count(void) +{ + Lighting_Output_Init(); + return MAX_LIGHTING_OUTPUTS; +} + +/* we simply have 0-n object instances. Yours might be */ +/* more complex, and then you need to return the instance */ +/* that correlates to the correct index */ +uint32_t Lighting_Output_Index_To_Instance(unsigned index) +{ + Lighting_Output_Init(); + return index; +} + +/* we simply have 0-n object instances. Yours might be */ +/* more complex, and then you need to return the index */ +/* that correlates to the correct instance number */ +unsigned Lighting_Output_Instance_To_Index(uint32_t object_instance) +{ + unsigned index = MAX_LIGHTING_OUTPUTS; + + Lighting_Output_Init(); + if (object_instance < MAX_LIGHTING_OUTPUTS) + index = object_instance; + + return index; +} + +float Lighting_Output_Present_Value(uint32_t object_instance) +{ + float value = LIGHTING_RELINQUISH_DEFAULT; + unsigned index = 0; + unsigned i = 0; + + Lighting_Output_Init(); + index = Lighting_Output_Instance_To_Index(object_instance); + if (index < MAX_LIGHTING_OUTPUTS) { + for (i = 0; i < BACNET_MAX_PRIORITY; i++) { + if (Lighting_Output_Level[index][i] != LIGHTING_LEVEL_NULL) { + value = Lighting_Output_Level[index][i]; + break; + } + } + } + + return value; +} + +unsigned Lighting_Output_Present_Value_Priority(uint32_t object_instance) +{ + unsigned index = 0; /* instance to index conversion */ + unsigned i = 0; /* loop counter */ + unsigned priority = 0; /* return value */ + + Lighting_Output_Init(); + index = Lighting_Output_Instance_To_Index(object_instance); + if (index < MAX_LIGHTING_OUTPUTS) { + for (i = 0; i < BACNET_MAX_PRIORITY; i++) { + if (Lighting_Output_Level[index][i] != LIGHTING_LEVEL_NULL) { + priority = i + 1; + break; + } + } + } + + return priority; +} + +bool Lighting_Output_Present_Value_Set(uint32_t object_instance, + float value, unsigned priority) +{ + unsigned index = 0; + bool status = false; + + index = Lighting_Output_Instance_To_Index(object_instance); + if (index < MAX_LIGHTING_OUTPUTS) { + if (priority && (priority <= BACNET_MAX_PRIORITY) && + (priority != 6 /* reserved */ ) && + (value >= 0.0) && (value <= 100.0)) { + Lighting_Output_Level[index][priority-1] = (uint8_t) value; + /* Note: you could set the physical output here to the next + highest priority, or to the relinquish default if no + priorities are set. + However, if Out of Service is TRUE, then don't set the + physical output. This comment may apply to the + main loop (i.e. check out of service before changing output) */ + status = true; + } + } + + return status; +} + +bool Lighting_Output_Present_Value_Relinquish(uint32_t object_instance, + int priority) +{ + unsigned index = 0; + bool status = false; + + index = Lighting_Output_Instance_To_Index(object_instance); + if (index < MAX_LIGHTING_OUTPUTS) { + if (priority && (priority <= BACNET_MAX_PRIORITY) && + (priority != 6 /* reserved */ )) { + Lighting_Output_Level[index][priority-1] = LIGHTING_LEVEL_NULL; + /* Note: you could set the physical output here to the next + highest priority, or to the relinquish default if no + priorities are set. + However, if Out of Service is TRUE, then don't set the + physical output. This comment may apply to the + main loop (i.e. check out of service before changing output) */ + status = true; + } + } + + return status; +} + +float Lighting_Output_Progress_Value(uint32_t object_instance) +{ + float value = LIGHTING_RELINQUISH_DEFAULT; + unsigned index = 0; + + Lighting_Output_Init(); + index = Lighting_Output_Instance_To_Index(object_instance); + if (index < MAX_LIGHTING_OUTPUTS) { + value = Lighting_Output_Progress[index]; + } + + return value; +} + +/* note: the object name must be unique within this device */ +char *Lighting_Output_Name(uint32_t object_instance) +{ + static char text_string[32] = ""; /* okay for single thread */ + + if (object_instance < MAX_LIGHTING_OUTPUTS) { + sprintf(text_string, "LIGHTING OUTPUT %u", object_instance); + return text_string; + } + + return NULL; +} + +/* return apdu len, or -1 on error */ +int Lighting_Output_Encode_Property_APDU(uint8_t * apdu, + uint32_t object_instance, + BACNET_PROPERTY_ID property, + int32_t array_index, + BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code) +{ + int len = 0; + int apdu_len = 0; /* return value */ + BACNET_BIT_STRING bit_string; + BACNET_CHARACTER_STRING char_string; + float real_value = (float) 1.414; + unsigned object_index = 0; + unsigned i = 0; + bool state = false; + + Lighting_Output_Init(); + switch (property) { + case PROP_OBJECT_IDENTIFIER: + apdu_len = encode_tagged_object_id(&apdu[0], OBJECT_LIGHTING_OUTPUT, + object_instance); + break; + case PROP_OBJECT_NAME: + case PROP_DESCRIPTION: + /* object name must be unique in this device. */ + /* FIXME: description could be writable and different than object name */ + characterstring_init_ansi(&char_string, + Lighting_Output_Name(object_instance)); + apdu_len = encode_tagged_character_string(&apdu[0], &char_string); + break; + case PROP_OBJECT_TYPE: + apdu_len = + encode_tagged_enumerated(&apdu[0], OBJECT_LIGHTING_OUTPUT); + break; + case PROP_PRESENT_VALUE: + real_value = Lighting_Output_Present_Value(object_instance); + apdu_len = encode_tagged_real(&apdu[0], real_value); + break; + case PROP_PROGRESS_VALUE: + real_value = Lighting_Output_Progress_Value(object_instance); + apdu_len = encode_tagged_real(&apdu[0], real_value); + break; + case PROP_LIGHTING_COMMAND: + apdu_len = Lighting_Output_Encode_Lighting_Command(&apdu[0], + &Lighting_Command[object_instance]); + break; + case PROP_STATUS_FLAGS: + bitstring_init(&bit_string); + bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); + bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); + bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); + bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); + apdu_len = encode_tagged_bitstring(&apdu[0], &bit_string); + break; + case PROP_EVENT_STATE: + apdu_len = encode_tagged_enumerated(&apdu[0], EVENT_STATE_NORMAL); + break; + case PROP_OUT_OF_SERVICE: + object_index = Lighting_Output_Instance_To_Index(object_instance); + state = Lighting_Output_Out_Of_Service[object_index]; + apdu_len = encode_tagged_boolean(&apdu[0], state); + break; + case PROP_UNITS: + apdu_len = encode_tagged_enumerated(&apdu[0], UNITS_PERCENT); + break; + case PROP_PRIORITY_ARRAY: + /* Array element zero is the number of elements in the array */ + if (array_index == 0) + apdu_len = + encode_tagged_unsigned(&apdu[0], BACNET_MAX_PRIORITY); + /* if no index was specified, then try to encode the entire list */ + /* into one packet. */ + else if (array_index == BACNET_ARRAY_ALL) { + object_index = + Lighting_Output_Instance_To_Index(object_instance); + for (i = 0; i < BACNET_MAX_PRIORITY; i++) { + /* FIXME: check if we have room before adding it to APDU */ + if (Lighting_Output_Level[object_index][i] == LIGHTING_LEVEL_NULL) + len = encode_tagged_null(&apdu[apdu_len]); + else { + real_value = Lighting_Output_Level[object_index][i]; + len = encode_tagged_real(&apdu[apdu_len], real_value); + } + /* add it if we have room */ + if ((apdu_len + len) < MAX_APDU) + apdu_len += len; + else { + *error_class = ERROR_CLASS_SERVICES; + *error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT; + apdu_len = -1; + break; + } + } + } else { + object_index = + Lighting_Output_Instance_To_Index(object_instance); + if (array_index <= BACNET_MAX_PRIORITY) { + if (Lighting_Output_Level[object_index][array_index - 1] == + LIGHTING_LEVEL_NULL) + apdu_len = encode_tagged_null(&apdu[0]); + else { + real_value = + Lighting_Output_Level[object_index][array_index - 1]; + apdu_len = encode_tagged_real(&apdu[0], real_value); + } + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_INVALID_ARRAY_INDEX; + apdu_len = -1; + } + } + + break; + case PROP_RELINQUISH_DEFAULT: + real_value = LIGHTING_RELINQUISH_DEFAULT; + apdu_len = encode_tagged_real(&apdu[0], real_value); + break; + default: + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_UNKNOWN_PROPERTY; + apdu_len = -1; + break; + } + + return apdu_len; +} + +/* returns true if successful */ +bool Lighting_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, + BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code) +{ + bool status = false; /* return value */ + unsigned int object_index = 0; + uint8_t level = LIGHTING_LEVEL_NULL; + int len = 0; + BACNET_APPLICATION_DATA_VALUE value; + + Lighting_Output_Init(); + if (!Lighting_Output_Valid_Instance(wp_data->object_instance)) { + *error_class = ERROR_CLASS_OBJECT; + *error_code = ERROR_CODE_UNKNOWN_OBJECT; + return false; + } + /* decode the some of the request */ + len = bacapp_decode_application_data(wp_data->application_data, + wp_data->application_data_len, &value); + /* FIXME: len < application_data_len: more data? */ + /* FIXME: len == 0: unable to decode? */ + switch (wp_data->object_property) { + case PROP_PRESENT_VALUE: + if (value.tag == BACNET_APPLICATION_TAG_REAL) { + /* Command priority 6 is reserved for use by Minimum On/Off + algorithm and may not be used for other purposes in any + object. */ + status = + Lighting_Output_Present_Value_Set(wp_data->object_instance, + value.type.Real, wp_data->priority); + if (wp_data->priority == 6) { + /* Command priority 6 is reserved for use by Minimum On/Off + algorithm and may not be used for other purposes in any + object. */ + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + } else if (!status) { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + } else if (value.tag == BACNET_APPLICATION_TAG_NULL) { + level = LIGHTING_LEVEL_NULL; + object_index = + Lighting_Output_Instance_To_Index(wp_data->object_instance); + status = + Lighting_Output_Present_Value_Relinquish(wp_data-> + object_instance, wp_data->priority); + if (wp_data->priority == 6) { + /* Command priority 6 is reserved for use by Minimum On/Off + algorithm and may not be used for other purposes in any + object. */ + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + } else if (!status) { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_INVALID_DATA_TYPE; + } + break; + case PROP_LIGHTING_COMMAND: + /* FIXME: error checking? */ + Lighting_Output_Decode_Lighting_Command(wp_data->application_data, + wp_data->application_data_len, + &Lighting_Command[wp_data->object_instance]); + break; + case PROP_OUT_OF_SERVICE: + if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) { + object_index = + Lighting_Output_Instance_To_Index(wp_data->object_instance); + Lighting_Output_Out_Of_Service[object_index] = + value.type.Boolean; + status = true; + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_INVALID_DATA_TYPE; + } + break; + default: + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + break; + } + + return status; +} + + +#ifdef TEST +#include +#include +#include "ctest.h" + +void testLightingOutput(Test * pTest) +{ + uint8_t apdu[MAX_APDU] = { 0 }; + int len = 0; + uint32_t len_value = 0; + uint8_t tag_number = 0; + BACNET_OBJECT_TYPE decoded_type = OBJECT_LIGHTING_OUTPUT; + uint32_t decoded_instance = 0; + uint32_t instance = 123; + BACNET_ERROR_CLASS error_class; + BACNET_ERROR_CODE error_code; + + + len = Lighting_Output_Encode_Property_APDU(&apdu[0], + instance, + PROP_OBJECT_IDENTIFIER, + BACNET_ARRAY_ALL, &error_class, &error_code); + ct_test(pTest, len != 0); + len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value); + ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID); + len = decode_object_id(&apdu[len], + (int *) &decoded_type, &decoded_instance); + ct_test(pTest, decoded_type == OBJECT_LIGHTING_OUTPUT); + ct_test(pTest, decoded_instance == instance); + + return; +} + +#ifdef TEST_LIGHTING_OUTPUT +int main(void) +{ + Test *pTest; + bool rc; + + pTest = ct_create("BACnet Lighting Output", NULL); + /* individual tests */ + rc = ct_addTestFunction(pTest, testLightingOutput); + assert(rc); + + ct_setStream(pTest, stdout); + ct_run(pTest); + (void) ct_report(pTest); + ct_destroy(pTest); + + return 0; +} +#endif /* TEST_LIGHTING_INPUT */ +#endif /* TEST */ diff --git a/bacnet-stack/demo/object/lsp.c b/bacnet-stack/demo/object/lsp.c index 703764f6..9d849d09 100644 --- a/bacnet-stack/demo/object/lsp.c +++ b/bacnet-stack/demo/object/lsp.c @@ -159,7 +159,8 @@ int Life_Safety_Point_Encode_Property_APDU(uint8_t * apdu, unsigned object_index = 0; bool state = false; BACNET_RELIABILITY reliability = RELIABILITY_NO_FAULT_DETECTED; - (void) array_index; /* currently not used */ + + (void) array_index; /* currently not used */ Life_Safety_Point_Init(); switch (property) { case PROP_OBJECT_IDENTIFIER: @@ -354,3 +355,4 @@ int main(void) } #endif /* TEST_LIFE_SAFETY_POINT */ #endif /* TEST */ + diff --git a/bacnet-stack/demo/server/epics_vts3.tpi b/bacnet-stack/demo/server/epics_vts3.tpi index 487ea5e4..e5c056ed 100644 --- a/bacnet-stack/demo/server/epics_vts3.tpi +++ b/bacnet-stack/demo/server/epics_vts3.tpi @@ -1,759 +1,759 @@ -PICS 0 -BACnet Protocol Implementation Conformance Statement - --- --- --- BACnet Stack Demo --- bacnet.sourceforge.net --- Author: Steve Karg --- --- - -Vendor Name: "ASHRAE" -Product Name: "SimpleServer" -Product Model Number: "GNU" -Product Description: "server" - -BIBBs Supported: -{ --- The BIBBs may be any of: --- DS-RP-A - DS-RP-B --- DS-RPM-A DS-RPM-B --- DS-RPC-A DS-RPC-B --- DS-WP-A - DS-WP-B --- DS-WPM-A DS-WPM-B --- DS-COV-A DS-COV-B --- DS-COVP-A DS-COVP-B --- DS-COVU-A DS-COVU-B --- AE-N-A AE-N-I-B AE-N-E-B --- AE-ACK-A AE-ACK-B --- AE-ASUM-A AE-ASUM-B --- AE-ESUM-A AE-ESUM-B --- AE-INFO-A AE-INFO-B --- AE-LS-A AE-LS-B --- SCHED-A SCHED-I-B SCHED-E-B --- T-VMT-A T-VMT-I-B T-VMT-E-B --- T-ATR-A T-ATR-B --- DM-DDB-A - DM-DDB-B --- DM-DOB-A - DM-DOB-B --- DM-DCC-A - DM-DCC-B --- DM-PT-A DM-PT-B --- DM-TM-A DM-TM-B --- DM-TS-A - DM-TS-B --- DM-UTC-A - DM-UTC-B --- DM-RD-A - DM-RD-B --- DM-BR-A DM-BR-B --- DM-R-A DM-R-B --- DM-LM-A DM-LM-B --- DM-OCD-A DM-OCD-B --- DM-VT-A DM-VT-B --- NM-CE-A NM-CE-B --- NM-RC-A NM-RC-B -} - -BACnet Standard Application Services Supported: -{ --- AcknowledgeAlarm Initiate Execute --- ConfirmedCOVNotification Initiate Execute - UnconfirmedCOVNotification Initiate --- ConfirmedEventNotification Initiate Execute --- UnconfirmedEventNotification Initiate Execute --- GetAlarmSummary Initiate Execute --- GetEnrollmentSummary Initiate Execute - AtomicReadFile Initiate Execute --- AtomicWriteFile Initiate Execute --- AddListElement Initiate Execute --- RemoveListElement Initiate Execute --- CreateObject Initiate Execute --- DeleteObject Initiate Execute - ReadProperty Initiate Execute --- ReadpropertyConditional Initiate Execute --- ReadPropertyMultiple Initiate Execute --- SubscribeCOV Initiate Execute - WriteProperty Initiate Execute --- WritePropertyMultiple Initiate Execute - DeviceCommunicationControl Initiate Execute --- ConfirmedPrivateTransfer Initiate Execute --- UnconfirmedPrivateTransfer Initiate Execute - TimeSynchronization Initiate Execute - Who-Has Initiate Execute - I-Have Initiate - Who-Is Initiate Execute - I-Am Initiate --- VT-Open Initiate Execute --- VT-Close Initiate Execute --- VT-Data Initiate Execute --- ConfirmedTextMessage Initiate Execute --- UnconfirmedTextMessage Initiate Execute - ReinitializeDevice Initiate Execute --- RequestKey Initiate Execute --- Authenticate Initiate Execute - UTCTimeSynchronization Initiate Execute --- ReadRange Initiate Execute --- GetEventInformation Initiate Execute --- LifeSafetyOperation Initiate Execute --- SubscribeCOVProperty Initiate Execute --- RequestKey Initiate Execute --- Authenticate Initiate Execute -} - -Standard Object-Types Supported: -{ - Analog Input - Analog Output - Analog Value --- Averaging Createable Deleteable - Binary Input - Binary Output - Binary Value --- Calendar Createable Deleteable --- Command Createable Deleteable - Device --- Event Enrollment Createable Deleteable - File --- Group Createable Deleteable --- Loop Createable Deleteable --- Multi-state Input Createable Deleteable -Multi-state Output --- Multi-state Value Createable Deleteable --- Notification Class Createable Deleteable --- Program Createable Deleteable --- Schedule Createable Deleteable - Life Safety Point --- Life Safety Zone Createable Deleteable --- Trend Log Createable Deleteable - Load Control -} - -Data Link Layer Option: -{ --- ISO 8802-3, 10BASE5 --- ISO 8802-3, 10BASE2 --- ISO 8802-3, 10BASET --- ISO 8802-3, Fiber --- ARCNET, coax star --- ARCNET, coax bus --- ARCNET, twisted pair star --- ARCNET, twisted pair bus --- ARCNET, fiber star --- MS/TP master. Baud rate(s): 9600 --- MS/TP slave. Baud rate(s): 9600 --- Point-To-Point. Modem, Baud rate(s): 14.4k --- Point-To-Point. Modem, Autobaud range: 9600 to 28.8k - BACnet/IP, 'DIX' Ethernet --- BACnet/IP, PPP --- Other -} - -Character Sets Supported: -{ - ANSI X3.4 --- Other Character Sets not supported --- IBM/Microsoft DBCS --- JIS C 6226 --- ISO 10646 (ICS-4) --- ISO 10646 (UCS2) -} - -Special Functionality: -{ - Maximum APDU size in octets: 480 -- Arcnet Maximum 501 less NL Header --- Maximum APDU size in octets: 480 --- Segmented Requests Supported, window size: 1 --- Segmented Responses Supported, window size: 1 --- Router -} - -List of Objects in test device: -{ - { - object-identifier: (device,123) - object-name: "SimpleServer" - object-type: device - system-status: operational - vendor-name: "ASHRAE" - vendor-identifier: 0 - model-name: "GNU" - firmware-revision: "1.0" - application-software-version: "1.0" - protocol-version: 1 - protocol-revision: 5 - protocol-conformance-class: 1 - protocol-services-supported: (F,F,F,F,F,F,T,F,F,F,F,F,T,F,F,T,F,T,F,F,T,F,F,F,F,F,F,F,F,F,F,F,T,T,T,F,T,F,F,F) - protocol-object-types-supported: (T,T,T,T,T,T,F,F,T,F,T,F,F,F,T,F,F,F,F,F,F,T,F,F,F) - max-apdu-length-accepted: 480 - segmentation-supported: no-segmentation - apdu-timeout: 3000 - number-of-apdu-retries: 3 - device-address-binding: ? - local-time: ? - local-date: ? - utc-offset: ? - daylight-savings-status: ? - database-revision: ? - object-list: { - (device,123),(analog-input,0),(analog-input,1), - (analog-input,2),(analog-input,3),(analog-input,4), - (analog-input,5),(analog-input,6),(analog-output,0), - (analog-output,1),(analog-output,2),(analog-output,3), - (analog-value,0),(analog-value,1),(analog-value,2), - (analog-value,3),(binary-input,0),(binary-input,1), - (binary-input,2),(binary-input,3),(binary-input,4), - (binary-output,0),(binary-output,1),(binary-output,2), - (binary-output,3),(binary-output,4),(binary-output,5), - (binary-value,0),(binary-value,1),(life-safety-point,0), - (life-safety-point,1),(life-safety-point,2),(life-safety-point,3), - (life-safety-point,4),(life-safety-point,5),(life-safety-point,6), - (multi-state-output,0),(multi-state-output,1),(multi-state-output,2), - (multi-state-output,3),(file,0),(file,1), - (file,2) - } - }, - { - object-identifier: (analog-input,0) - object-name: "ANALOG INPUT 0" - object-type: analog-input - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - units: percent - description: "ANALOG INPUT 0" - }, - { - object-identifier: (analog-input,1) - object-name: "ANALOG INPUT 1" - object-type: analog-input - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - units: percent - description: "ANALOG INPUT 1" - }, - { - object-identifier: (analog-input,2) - object-name: "ANALOG INPUT 2" - object-type: analog-input - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - units: percent - description: "ANALOG INPUT 2" - }, - { - object-identifier: (analog-input,3) - object-name: "ANALOG INPUT 3" - object-type: analog-input - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - units: percent - description: "ANALOG INPUT 3" - }, - { - object-identifier: (analog-input,4) - object-name: "ANALOG INPUT 4" - object-type: analog-input - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - units: percent - description: "ANALOG INPUT 4" - }, - { - object-identifier: (analog-input,5) - object-name: "ANALOG INPUT 5" - object-type: analog-input - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - units: percent - description: "ANALOG INPUT 5" - }, - { - object-identifier: (analog-input,6) - object-name: "ANALOG INPUT 6" - object-type: analog-input - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - units: percent - description: "ANALOG INPUT 6" - }, - { - object-identifier: (analog-output,0) - object-name: "ANALOG OUTPUT 0" - object-type: analog-output - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - units: percent - priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} - relinquish-default: 0.000000 - description: "ANALOG OUTPUT 0" - }, - { - object-identifier: (analog-output,1) - object-name: "ANALOG OUTPUT 1" - object-type: analog-output - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - units: percent - priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} - relinquish-default: 0.000000 - description: "ANALOG OUTPUT 1" - }, - { - object-identifier: (analog-output,2) - object-name: "ANALOG OUTPUT 2" - object-type: analog-output - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - units: percent - priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} - relinquish-default: 0.000000 - description: "ANALOG OUTPUT 2" - }, - { - object-identifier: (analog-output,3) - object-name: "ANALOG OUTPUT 3" - object-type: analog-output - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - units: percent - priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} - relinquish-default: 0.000000 - description: "ANALOG OUTPUT 3" - }, - { - object-identifier: (analog-value,0) - object-name: "ANALOG VALUE 0" - object-type: analog-value - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - units: percent - relinquish-default: 0.000000 - description: "ANALOG VALUE 0" - priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} - relinquish-default: 0.000000 - }, - { - object-identifier: (analog-value,1) - object-name: "ANALOG VALUE 1" - object-type: analog-value - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - units: percent - relinquish-default: 0.000000 - description: "ANALOG VALUE 1" - priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} - relinquish-default: 0.000000 - }, - { - object-identifier: (analog-value,2) - object-name: "ANALOG VALUE 2" - object-type: analog-value - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - units: percent - relinquish-default: 0.000000 - description: "ANALOG VALUE 2" - priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} - relinquish-default: 0.000000 - }, - { - object-identifier: (analog-value,3) - object-name: "ANALOG VALUE 3" - object-type: analog-value - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - units: percent - relinquish-default: 0.000000 - description: "ANALOG VALUE 3" - priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} - relinquish-default: 0.000000 - }, - { - object-identifier: (binary-input,0) - object-name: "BINARY INPUT 0" - object-type: binary-input - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - polarity: normal - description: "BINARY INPUT 0" - }, - { - object-identifier: (binary-input,1) - object-name: "BINARY INPUT 1" - object-type: binary-input - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - polarity: normal - description: "BINARY INPUT 1" - }, - { - object-identifier: (binary-input,2) - object-name: "BINARY INPUT 2" - object-type: binary-input - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - polarity: normal - description: "BINARY INPUT 2" - }, - { - object-identifier: (binary-input,3) - object-name: "BINARY INPUT 3" - object-type: binary-input - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - polarity: normal - description: "BINARY INPUT 3" - }, - { - object-identifier: (binary-input,4) - object-name: "BINARY INPUT 4" - object-type: binary-input - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - polarity: normal - description: "BINARY INPUT 4" - }, - { - object-identifier: (binary-output,0) - object-name: "BINARY OUTPUT 0" - object-type: binary-output - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - polarity: normal - priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} - relinquish-default: inactive - description: "BINARY OUTPUT 0" - }, - { - object-identifier: (binary-output,1) - object-name: "BINARY OUTPUT 1" - object-type: binary-output - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - polarity: normal - priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} - relinquish-default: inactive - description: "BINARY OUTPUT 1" - }, - { - object-identifier: (binary-output,2) - object-name: "BINARY OUTPUT 2" - object-type: binary-output - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - polarity: normal - priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} - relinquish-default: inactive - description: "BINARY OUTPUT 2" - }, - { - object-identifier: (binary-output,3) - object-name: "BINARY OUTPUT 3" - object-type: binary-output - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - polarity: normal - priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} - relinquish-default: inactive - description: "BINARY OUTPUT 3" - }, - { - object-identifier: (binary-output,4) - object-name: "BINARY OUTPUT 4" - object-type: binary-output - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - polarity: normal - priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} - relinquish-default: inactive - description: "BINARY OUTPUT 4" - }, - { - object-identifier: (binary-output,5) - object-name: "BINARY OUTPUT 5" - object-type: binary-output - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - polarity: normal - priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} - relinquish-default: inactive - description: "BINARY OUTPUT 5" - }, - { - object-identifier: (binary-value,0) - object-name: "BINARY VALUE 0" - object-type: binary-value - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - description: "BINARY VALUE 0" - priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} - relinquish-default: inactive - }, - { - object-identifier: (binary-value,1) - object-name: "BINARY VALUE 1" - object-type: binary-value - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - description: "BINARY VALUE 1" - priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} - relinquish-default: inactive - }, - { - object-identifier: (life-safety-point,0) - object-name: "LS POINT 0" - object-type: life-safety-point - description: "LS POINT 0" - present-value: ? - device-type: ? - status-flags: (F,F,F,F) - event-state: normal - reliability: ? - out-of-service: F - mode: ? W - silenced: ? - operation-expected: ? - }, - { - object-identifier: (life-safety-point,1) - object-name: "LS POINT 1" - object-type: life-safety-point - description: "LS POINT 1" - present-value: ? - device-type: ? - status-flags: (F,F,F,F) - event-state: normal - reliability: ? - out-of-service: F - mode: ? W - silenced: ? - operation-expected: ? - }, - { - object-identifier: (life-safety-point,2) - object-name: "LS POINT 2" - object-type: life-safety-point - description: "LS POINT 2" - present-value: ? - device-type: ? - status-flags: (F,F,F,F) - event-state: normal - reliability: ? - out-of-service: F - mode: ? W - silenced: ? - operation-expected: ? - }, - { - object-identifier: (life-safety-point,3) - object-name: "LS POINT 3" - object-type: life-safety-point - description: "LS POINT 3" - present-value: ? - device-type: ? - status-flags: (F,F,F,F) - event-state: normal - reliability: ? - out-of-service: F - mode: ? W - silenced: ? - operation-expected: ? - }, - { - object-identifier: (life-safety-point,4) - object-name: "LS POINT 4" - object-type: life-safety-point - description: "LS POINT 4" - present-value: ? - device-type: ? - status-flags: (F,F,F,F) - event-state: normal - reliability: ? - out-of-service: F - mode: ? W - silenced: ? - operation-expected: ? - }, - { - object-identifier: (life-safety-point,5) - object-name: "LS POINT 5" - object-type: life-safety-point - description: "LS POINT 5" - present-value: ? - device-type: ? - status-flags: (F,F,F,F) - event-state: normal - reliability: ? - out-of-service: F - mode: ? W - silenced: ? - operation-expected: ? - }, - { - object-identifier: (life-safety-point,6) - object-name: "LS POINT 6" - object-type: life-safety-point - description: "LS POINT 6" - present-value: ? - device-type: ? - status-flags: (F,F,F,F) - event-state: normal - reliability: ? - out-of-service: F - mode: ? W - silenced: ? - operation-expected: ? - }, - { - object-identifier: (multi-state-output,0) - object-name: "MULTISTATE OUTPUT 0" - object-type: multi-state-output - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} - relinquish-default: inactive - number-of-states: 254 - description: "MULTISTATE OUTPUT 0" - }, - { - object-identifier: (multi-state-output,1) - object-name: "MULTISTATE OUTPUT 1" - object-type: multi-state-output - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} - relinquish-default: inactive - number-of-states: 254 - description: "MULTISTATE OUTPUT 1" - }, - { - object-identifier: (multi-state-output,2) - object-name: "MULTISTATE OUTPUT 2" - object-type: multi-state-output - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} - relinquish-default: inactive - number-of-states: 254 - description: "MULTISTATE OUTPUT 2" - }, - { - object-identifier: (multi-state-output,3) - object-name: "MULTISTATE OUTPUT 3" - object-type: multi-state-output - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} - relinquish-default: inactive - number-of-states: 254 - description: "MULTISTATE OUTPUT 3" - }, - { - object-identifier: (file,0) - object-name: "FILE 0" - object-type: file - file-type: "TEXT" - file-size: 0 - modification-date: ? - archive: ? W - read-only: T - file-access-method: stream-access - description: "test.log" - }, - { - object-identifier: (file,1) - object-name: "FILE 1" - object-type: file - file-type: "TEXT" - file-size: 0 - modification-date: ? - archive: ? W - read-only: T - file-access-method: stream-access - description: "script.txt" - }, - { - object-identifier: (file,2) - object-name: "FILE 2" - object-type: file - file-type: "TEXT" - file-size: 39582 - modification-date: ? - archive: ? W - read-only: T - file-access-method: stream-access - description: "bacenum.h" - } -} - -End of BACnet Protocol Implementation Conformance Statement - - +PICS 0 +BACnet Protocol Implementation Conformance Statement + +-- +-- +-- BACnet Stack Demo +-- bacnet.sourceforge.net +-- Author: Steve Karg +-- +-- + +Vendor Name: "ASHRAE" +Product Name: "SimpleServer" +Product Model Number: "GNU" +Product Description: "server" + +BIBBs Supported: +{ +-- The BIBBs may be any of: +-- DS-RP-A + DS-RP-B +-- DS-RPM-A DS-RPM-B +-- DS-RPC-A DS-RPC-B +-- DS-WP-A + DS-WP-B +-- DS-WPM-A DS-WPM-B +-- DS-COV-A DS-COV-B +-- DS-COVP-A DS-COVP-B +-- DS-COVU-A DS-COVU-B +-- AE-N-A AE-N-I-B AE-N-E-B +-- AE-ACK-A AE-ACK-B +-- AE-ASUM-A AE-ASUM-B +-- AE-ESUM-A AE-ESUM-B +-- AE-INFO-A AE-INFO-B +-- AE-LS-A AE-LS-B +-- SCHED-A SCHED-I-B SCHED-E-B +-- T-VMT-A T-VMT-I-B T-VMT-E-B +-- T-ATR-A T-ATR-B +-- DM-DDB-A + DM-DDB-B +-- DM-DOB-A + DM-DOB-B +-- DM-DCC-A + DM-DCC-B +-- DM-PT-A DM-PT-B +-- DM-TM-A DM-TM-B +-- DM-TS-A + DM-TS-B +-- DM-UTC-A + DM-UTC-B +-- DM-RD-A + DM-RD-B +-- DM-BR-A DM-BR-B +-- DM-R-A DM-R-B +-- DM-LM-A DM-LM-B +-- DM-OCD-A DM-OCD-B +-- DM-VT-A DM-VT-B +-- NM-CE-A NM-CE-B +-- NM-RC-A NM-RC-B +} + +BACnet Standard Application Services Supported: +{ +-- AcknowledgeAlarm Initiate Execute +-- ConfirmedCOVNotification Initiate Execute + UnconfirmedCOVNotification Initiate +-- ConfirmedEventNotification Initiate Execute +-- UnconfirmedEventNotification Initiate Execute +-- GetAlarmSummary Initiate Execute +-- GetEnrollmentSummary Initiate Execute + AtomicReadFile Initiate Execute +-- AtomicWriteFile Initiate Execute +-- AddListElement Initiate Execute +-- RemoveListElement Initiate Execute +-- CreateObject Initiate Execute +-- DeleteObject Initiate Execute + ReadProperty Initiate Execute +-- ReadpropertyConditional Initiate Execute +-- ReadPropertyMultiple Initiate Execute +-- SubscribeCOV Initiate Execute + WriteProperty Initiate Execute +-- WritePropertyMultiple Initiate Execute + DeviceCommunicationControl Initiate Execute +-- ConfirmedPrivateTransfer Initiate Execute +-- UnconfirmedPrivateTransfer Initiate Execute + TimeSynchronization Initiate Execute + Who-Has Initiate Execute + I-Have Initiate + Who-Is Initiate Execute + I-Am Initiate +-- VT-Open Initiate Execute +-- VT-Close Initiate Execute +-- VT-Data Initiate Execute +-- ConfirmedTextMessage Initiate Execute +-- UnconfirmedTextMessage Initiate Execute + ReinitializeDevice Initiate Execute +-- RequestKey Initiate Execute +-- Authenticate Initiate Execute + UTCTimeSynchronization Initiate Execute +-- ReadRange Initiate Execute +-- GetEventInformation Initiate Execute +-- LifeSafetyOperation Initiate Execute +-- SubscribeCOVProperty Initiate Execute +-- RequestKey Initiate Execute +-- Authenticate Initiate Execute +} + +Standard Object-Types Supported: +{ + Analog Input + Analog Output + Analog Value +-- Averaging Createable Deleteable + Binary Input + Binary Output + Binary Value +-- Calendar Createable Deleteable +-- Command Createable Deleteable + Device +-- Event Enrollment Createable Deleteable + File +-- Group Createable Deleteable +-- Loop Createable Deleteable +-- Multi-state Input Createable Deleteable +Multi-state Output +-- Multi-state Value Createable Deleteable +-- Notification Class Createable Deleteable +-- Program Createable Deleteable +-- Schedule Createable Deleteable + Life Safety Point +-- Life Safety Zone Createable Deleteable +-- Trend Log Createable Deleteable + Load Control +} + +Data Link Layer Option: +{ +-- ISO 8802-3, 10BASE5 +-- ISO 8802-3, 10BASE2 +-- ISO 8802-3, 10BASET +-- ISO 8802-3, Fiber +-- ARCNET, coax star +-- ARCNET, coax bus +-- ARCNET, twisted pair star +-- ARCNET, twisted pair bus +-- ARCNET, fiber star +-- MS/TP master. Baud rate(s): 9600 +-- MS/TP slave. Baud rate(s): 9600 +-- Point-To-Point. Modem, Baud rate(s): 14.4k +-- Point-To-Point. Modem, Autobaud range: 9600 to 28.8k + BACnet/IP, 'DIX' Ethernet +-- BACnet/IP, PPP +-- Other +} + +Character Sets Supported: +{ + ANSI X3.4 +-- Other Character Sets not supported +-- IBM/Microsoft DBCS +-- JIS C 6226 +-- ISO 10646 (ICS-4) +-- ISO 10646 (UCS2) +} + +Special Functionality: +{ + Maximum APDU size in octets: 480 -- Arcnet Maximum 501 less NL Header +-- Maximum APDU size in octets: 480 +-- Segmented Requests Supported, window size: 1 +-- Segmented Responses Supported, window size: 1 +-- Router +} + +List of Objects in test device: +{ + { + object-identifier: (device,123) + object-name: "SimpleServer" + object-type: device + system-status: operational + vendor-name: "ASHRAE" + vendor-identifier: 0 + model-name: "GNU" + firmware-revision: "1.0" + application-software-version: "1.0" + protocol-version: 1 + protocol-revision: 5 + protocol-conformance-class: 1 + protocol-services-supported: (F,F,F,F,F,F,T,F,F,F,F,F,T,F,F,T,F,T,F,F,T,F,F,F,F,F,F,F,F,F,F,F,T,T,T,F,T,F,F,F) + protocol-object-types-supported: (T,T,T,T,T,T,F,F,T,F,T,F,F,F,T,F,F,F,F,F,F,T,F,F,F) + max-apdu-length-accepted: 480 + segmentation-supported: no-segmentation + apdu-timeout: 3000 + number-of-apdu-retries: 3 + device-address-binding: ? + local-time: ? + local-date: ? + utc-offset: ? + daylight-savings-status: ? + database-revision: ? + object-list: { + (device,123),(analog-input,0),(analog-input,1), + (analog-input,2),(analog-input,3),(analog-input,4), + (analog-input,5),(analog-input,6),(analog-output,0), + (analog-output,1),(analog-output,2),(analog-output,3), + (analog-value,0),(analog-value,1),(analog-value,2), + (analog-value,3),(binary-input,0),(binary-input,1), + (binary-input,2),(binary-input,3),(binary-input,4), + (binary-output,0),(binary-output,1),(binary-output,2), + (binary-output,3),(binary-output,4),(binary-output,5), + (binary-value,0),(binary-value,1),(life-safety-point,0), + (life-safety-point,1),(life-safety-point,2),(life-safety-point,3), + (life-safety-point,4),(life-safety-point,5),(life-safety-point,6), + (multi-state-output,0),(multi-state-output,1),(multi-state-output,2), + (multi-state-output,3),(file,0),(file,1), + (file,2) + } + }, + { + object-identifier: (analog-input,0) + object-name: "ANALOG INPUT 0" + object-type: analog-input + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + units: percent + description: "ANALOG INPUT 0" + }, + { + object-identifier: (analog-input,1) + object-name: "ANALOG INPUT 1" + object-type: analog-input + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + units: percent + description: "ANALOG INPUT 1" + }, + { + object-identifier: (analog-input,2) + object-name: "ANALOG INPUT 2" + object-type: analog-input + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + units: percent + description: "ANALOG INPUT 2" + }, + { + object-identifier: (analog-input,3) + object-name: "ANALOG INPUT 3" + object-type: analog-input + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + units: percent + description: "ANALOG INPUT 3" + }, + { + object-identifier: (analog-input,4) + object-name: "ANALOG INPUT 4" + object-type: analog-input + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + units: percent + description: "ANALOG INPUT 4" + }, + { + object-identifier: (analog-input,5) + object-name: "ANALOG INPUT 5" + object-type: analog-input + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + units: percent + description: "ANALOG INPUT 5" + }, + { + object-identifier: (analog-input,6) + object-name: "ANALOG INPUT 6" + object-type: analog-input + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + units: percent + description: "ANALOG INPUT 6" + }, + { + object-identifier: (analog-output,0) + object-name: "ANALOG OUTPUT 0" + object-type: analog-output + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + units: percent + priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} + relinquish-default: 0.000000 + description: "ANALOG OUTPUT 0" + }, + { + object-identifier: (analog-output,1) + object-name: "ANALOG OUTPUT 1" + object-type: analog-output + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + units: percent + priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} + relinquish-default: 0.000000 + description: "ANALOG OUTPUT 1" + }, + { + object-identifier: (analog-output,2) + object-name: "ANALOG OUTPUT 2" + object-type: analog-output + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + units: percent + priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} + relinquish-default: 0.000000 + description: "ANALOG OUTPUT 2" + }, + { + object-identifier: (analog-output,3) + object-name: "ANALOG OUTPUT 3" + object-type: analog-output + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + units: percent + priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} + relinquish-default: 0.000000 + description: "ANALOG OUTPUT 3" + }, + { + object-identifier: (analog-value,0) + object-name: "ANALOG VALUE 0" + object-type: analog-value + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + units: percent + relinquish-default: 0.000000 + description: "ANALOG VALUE 0" + priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} + relinquish-default: 0.000000 + }, + { + object-identifier: (analog-value,1) + object-name: "ANALOG VALUE 1" + object-type: analog-value + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + units: percent + relinquish-default: 0.000000 + description: "ANALOG VALUE 1" + priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} + relinquish-default: 0.000000 + }, + { + object-identifier: (analog-value,2) + object-name: "ANALOG VALUE 2" + object-type: analog-value + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + units: percent + relinquish-default: 0.000000 + description: "ANALOG VALUE 2" + priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} + relinquish-default: 0.000000 + }, + { + object-identifier: (analog-value,3) + object-name: "ANALOG VALUE 3" + object-type: analog-value + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + units: percent + relinquish-default: 0.000000 + description: "ANALOG VALUE 3" + priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} + relinquish-default: 0.000000 + }, + { + object-identifier: (binary-input,0) + object-name: "BINARY INPUT 0" + object-type: binary-input + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + polarity: normal + description: "BINARY INPUT 0" + }, + { + object-identifier: (binary-input,1) + object-name: "BINARY INPUT 1" + object-type: binary-input + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + polarity: normal + description: "BINARY INPUT 1" + }, + { + object-identifier: (binary-input,2) + object-name: "BINARY INPUT 2" + object-type: binary-input + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + polarity: normal + description: "BINARY INPUT 2" + }, + { + object-identifier: (binary-input,3) + object-name: "BINARY INPUT 3" + object-type: binary-input + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + polarity: normal + description: "BINARY INPUT 3" + }, + { + object-identifier: (binary-input,4) + object-name: "BINARY INPUT 4" + object-type: binary-input + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + polarity: normal + description: "BINARY INPUT 4" + }, + { + object-identifier: (binary-output,0) + object-name: "BINARY OUTPUT 0" + object-type: binary-output + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + polarity: normal + priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} + relinquish-default: inactive + description: "BINARY OUTPUT 0" + }, + { + object-identifier: (binary-output,1) + object-name: "BINARY OUTPUT 1" + object-type: binary-output + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + polarity: normal + priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} + relinquish-default: inactive + description: "BINARY OUTPUT 1" + }, + { + object-identifier: (binary-output,2) + object-name: "BINARY OUTPUT 2" + object-type: binary-output + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + polarity: normal + priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} + relinquish-default: inactive + description: "BINARY OUTPUT 2" + }, + { + object-identifier: (binary-output,3) + object-name: "BINARY OUTPUT 3" + object-type: binary-output + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + polarity: normal + priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} + relinquish-default: inactive + description: "BINARY OUTPUT 3" + }, + { + object-identifier: (binary-output,4) + object-name: "BINARY OUTPUT 4" + object-type: binary-output + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + polarity: normal + priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} + relinquish-default: inactive + description: "BINARY OUTPUT 4" + }, + { + object-identifier: (binary-output,5) + object-name: "BINARY OUTPUT 5" + object-type: binary-output + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + polarity: normal + priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} + relinquish-default: inactive + description: "BINARY OUTPUT 5" + }, + { + object-identifier: (binary-value,0) + object-name: "BINARY VALUE 0" + object-type: binary-value + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + description: "BINARY VALUE 0" + priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} + relinquish-default: inactive + }, + { + object-identifier: (binary-value,1) + object-name: "BINARY VALUE 1" + object-type: binary-value + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + description: "BINARY VALUE 1" + priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} + relinquish-default: inactive + }, + { + object-identifier: (life-safety-point,0) + object-name: "LS POINT 0" + object-type: life-safety-point + description: "LS POINT 0" + present-value: ? + device-type: ? + status-flags: (F,F,F,F) + event-state: normal + reliability: ? + out-of-service: F + mode: ? W + silenced: ? + operation-expected: ? + }, + { + object-identifier: (life-safety-point,1) + object-name: "LS POINT 1" + object-type: life-safety-point + description: "LS POINT 1" + present-value: ? + device-type: ? + status-flags: (F,F,F,F) + event-state: normal + reliability: ? + out-of-service: F + mode: ? W + silenced: ? + operation-expected: ? + }, + { + object-identifier: (life-safety-point,2) + object-name: "LS POINT 2" + object-type: life-safety-point + description: "LS POINT 2" + present-value: ? + device-type: ? + status-flags: (F,F,F,F) + event-state: normal + reliability: ? + out-of-service: F + mode: ? W + silenced: ? + operation-expected: ? + }, + { + object-identifier: (life-safety-point,3) + object-name: "LS POINT 3" + object-type: life-safety-point + description: "LS POINT 3" + present-value: ? + device-type: ? + status-flags: (F,F,F,F) + event-state: normal + reliability: ? + out-of-service: F + mode: ? W + silenced: ? + operation-expected: ? + }, + { + object-identifier: (life-safety-point,4) + object-name: "LS POINT 4" + object-type: life-safety-point + description: "LS POINT 4" + present-value: ? + device-type: ? + status-flags: (F,F,F,F) + event-state: normal + reliability: ? + out-of-service: F + mode: ? W + silenced: ? + operation-expected: ? + }, + { + object-identifier: (life-safety-point,5) + object-name: "LS POINT 5" + object-type: life-safety-point + description: "LS POINT 5" + present-value: ? + device-type: ? + status-flags: (F,F,F,F) + event-state: normal + reliability: ? + out-of-service: F + mode: ? W + silenced: ? + operation-expected: ? + }, + { + object-identifier: (life-safety-point,6) + object-name: "LS POINT 6" + object-type: life-safety-point + description: "LS POINT 6" + present-value: ? + device-type: ? + status-flags: (F,F,F,F) + event-state: normal + reliability: ? + out-of-service: F + mode: ? W + silenced: ? + operation-expected: ? + }, + { + object-identifier: (multi-state-output,0) + object-name: "MULTISTATE OUTPUT 0" + object-type: multi-state-output + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} + relinquish-default: inactive + number-of-states: 254 + description: "MULTISTATE OUTPUT 0" + }, + { + object-identifier: (multi-state-output,1) + object-name: "MULTISTATE OUTPUT 1" + object-type: multi-state-output + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} + relinquish-default: inactive + number-of-states: 254 + description: "MULTISTATE OUTPUT 1" + }, + { + object-identifier: (multi-state-output,2) + object-name: "MULTISTATE OUTPUT 2" + object-type: multi-state-output + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} + relinquish-default: inactive + number-of-states: 254 + description: "MULTISTATE OUTPUT 2" + }, + { + object-identifier: (multi-state-output,3) + object-name: "MULTISTATE OUTPUT 3" + object-type: multi-state-output + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + priority-array: {?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?} + relinquish-default: inactive + number-of-states: 254 + description: "MULTISTATE OUTPUT 3" + }, + { + object-identifier: (file,0) + object-name: "FILE 0" + object-type: file + file-type: "TEXT" + file-size: 0 + modification-date: ? + archive: ? W + read-only: T + file-access-method: stream-access + description: "test.log" + }, + { + object-identifier: (file,1) + object-name: "FILE 1" + object-type: file + file-type: "TEXT" + file-size: 0 + modification-date: ? + archive: ? W + read-only: T + file-access-method: stream-access + description: "script.txt" + }, + { + object-identifier: (file,2) + object-name: "FILE 2" + object-type: file + file-type: "TEXT" + file-size: 39582 + modification-date: ? + archive: ? W + read-only: T + file-access-method: stream-access + description: "bacenum.h" + } +} + +End of BACnet Protocol Implementation Conformance Statement + + diff --git a/bacnet-stack/demo/ucov/Makefile b/bacnet-stack/demo/ucov/Makefile index ec29af06..d5ceae3e 100644 --- a/bacnet-stack/demo/ucov/Makefile +++ b/bacnet-stack/demo/ucov/Makefile @@ -1,88 +1,88 @@ -#Makefile to build BACnet Application for the Linux Port -CC = gcc -BASEDIR = . -#CFLAGS = -Wall -I. -# -g for debugging with gdb -#CFLAGS = -Wall -I. -O2 -g -# Note: you can strip out symbols using the strip command -# to get an idea of how big the compile really is. - -# Configure the BACnet Datalink Layer -#BACDL_DEFINE=-DBACDL_ETHERNET=1 -#BACDL_DEFINE=-DBACDL_ARCNET=1 -BACDL_DEFINE=-DBACDL_BIP=1 -BACNET_DEFINES=-DBACFILE=1 -DTSM_ENABLED=0 -DBIG_ENDIAN=0 -DPRINT_ENABLED=1 -DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE) - -BACNET_PORT = ../../ports/linux -BACNET_OBJECT = ../object -BACNET_HANDLER = ../handler -BACNET_ROOT = ../.. -INCLUDES = -I$(BACNET_ROOT) -I$(BACNET_PORT) -I$(BACNET_OBJECT) -I$(BACNET_HANDLER) - -CFLAGS = -Wall -g $(INCLUDES) $(DEFINES) - -TARGET = bacucov - -SRCS = main.c \ - $(BACNET_PORT)/bip-init.c \ - $(BACNET_PORT)/ethernet.c \ - $(BACNET_PORT)/arcnet.c \ - $(BACNET_ROOT)/bip.c \ - $(BACNET_HANDLER)/txbuf.c \ - $(BACNET_HANDLER)/noserv.c \ - $(BACNET_HANDLER)/h_whois.c \ - $(BACNET_HANDLER)/h_rp.c \ - $(BACNET_HANDLER)/h_iam.c \ - $(BACNET_OBJECT)/device.c \ - $(BACNET_OBJECT)/ai.c \ - $(BACNET_OBJECT)/ao.c \ - $(BACNET_OBJECT)/av.c \ - $(BACNET_OBJECT)/bi.c \ - $(BACNET_OBJECT)/bo.c \ - $(BACNET_OBJECT)/bv.c \ - $(BACNET_OBJECT)/lc.c \ - $(BACNET_OBJECT)/lsp.c \ - $(BACNET_OBJECT)/mso.c \ - $(BACNET_OBJECT)/bacfile.c \ - $(BACNET_ROOT)/filename.c \ - $(BACNET_ROOT)/rp.c \ - $(BACNET_ROOT)/wp.c \ - $(BACNET_ROOT)/bacdcode.c \ - $(BACNET_ROOT)/bacapp.c \ - $(BACNET_ROOT)/bacprop.c \ - $(BACNET_ROOT)/bacstr.c \ - $(BACNET_ROOT)/bactext.c \ - $(BACNET_ROOT)/indtext.c \ - $(BACNET_ROOT)/datetime.c \ - $(BACNET_ROOT)/whois.c \ - $(BACNET_ROOT)/iam.c \ - $(BACNET_ROOT)/address.c \ - $(BACNET_ROOT)/arf.c \ - $(BACNET_ROOT)/cov.c \ - $(BACNET_ROOT)/dcc.c \ - $(BACNET_ROOT)/abort.c \ - $(BACNET_ROOT)/reject.c \ - $(BACNET_ROOT)/bacerror.c \ - $(BACNET_ROOT)/apdu.c \ - $(BACNET_ROOT)/npdu.c - -OBJS = ${SRCS:.c=.o} - -all: ${TARGET} - -${TARGET}: ${OBJS} - ${CC} -o $@ ${OBJS} - -.c.o: - ${CC} -c ${CFLAGS} $*.c -o $@ - -depend: - rm -f .depend - ${CC} -MM ${CFLAGS} *.c >> .depend - -clean: - rm -rf core ${TARGET} $(OBJS) *.bak ports/linux/*.bak *.1 *.ini - -include: .depend - +#Makefile to build BACnet Application for the Linux Port +CC = gcc +BASEDIR = . +#CFLAGS = -Wall -I. +# -g for debugging with gdb +#CFLAGS = -Wall -I. -O2 -g +# Note: you can strip out symbols using the strip command +# to get an idea of how big the compile really is. + +# Configure the BACnet Datalink Layer +#BACDL_DEFINE=-DBACDL_ETHERNET=1 +#BACDL_DEFINE=-DBACDL_ARCNET=1 +BACDL_DEFINE=-DBACDL_BIP=1 +BACNET_DEFINES=-DBACFILE=1 -DTSM_ENABLED=0 -DBIG_ENDIAN=0 -DPRINT_ENABLED=1 +DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE) + +BACNET_PORT = ../../ports/linux +BACNET_OBJECT = ../object +BACNET_HANDLER = ../handler +BACNET_ROOT = ../.. +INCLUDES = -I$(BACNET_ROOT) -I$(BACNET_PORT) -I$(BACNET_OBJECT) -I$(BACNET_HANDLER) + +CFLAGS = -Wall -g $(INCLUDES) $(DEFINES) + +TARGET = bacucov + +SRCS = main.c \ + $(BACNET_PORT)/bip-init.c \ + $(BACNET_PORT)/ethernet.c \ + $(BACNET_PORT)/arcnet.c \ + $(BACNET_ROOT)/bip.c \ + $(BACNET_HANDLER)/txbuf.c \ + $(BACNET_HANDLER)/noserv.c \ + $(BACNET_HANDLER)/h_whois.c \ + $(BACNET_HANDLER)/h_rp.c \ + $(BACNET_HANDLER)/h_iam.c \ + $(BACNET_OBJECT)/device.c \ + $(BACNET_OBJECT)/ai.c \ + $(BACNET_OBJECT)/ao.c \ + $(BACNET_OBJECT)/av.c \ + $(BACNET_OBJECT)/bi.c \ + $(BACNET_OBJECT)/bo.c \ + $(BACNET_OBJECT)/bv.c \ + $(BACNET_OBJECT)/lc.c \ + $(BACNET_OBJECT)/lsp.c \ + $(BACNET_OBJECT)/mso.c \ + $(BACNET_OBJECT)/bacfile.c \ + $(BACNET_ROOT)/filename.c \ + $(BACNET_ROOT)/rp.c \ + $(BACNET_ROOT)/wp.c \ + $(BACNET_ROOT)/bacdcode.c \ + $(BACNET_ROOT)/bacapp.c \ + $(BACNET_ROOT)/bacprop.c \ + $(BACNET_ROOT)/bacstr.c \ + $(BACNET_ROOT)/bactext.c \ + $(BACNET_ROOT)/indtext.c \ + $(BACNET_ROOT)/datetime.c \ + $(BACNET_ROOT)/whois.c \ + $(BACNET_ROOT)/iam.c \ + $(BACNET_ROOT)/address.c \ + $(BACNET_ROOT)/arf.c \ + $(BACNET_ROOT)/cov.c \ + $(BACNET_ROOT)/dcc.c \ + $(BACNET_ROOT)/abort.c \ + $(BACNET_ROOT)/reject.c \ + $(BACNET_ROOT)/bacerror.c \ + $(BACNET_ROOT)/apdu.c \ + $(BACNET_ROOT)/npdu.c + +OBJS = ${SRCS:.c=.o} + +all: ${TARGET} + +${TARGET}: ${OBJS} + ${CC} -o $@ ${OBJS} + +.c.o: + ${CC} -c ${CFLAGS} $*.c -o $@ + +depend: + rm -f .depend + ${CC} -MM ${CFLAGS} *.c >> .depend + +clean: + rm -rf core ${TARGET} $(OBJS) *.bak ports/linux/*.bak *.1 *.ini + +include: .depend + diff --git a/bacnet-stack/demo/ucov/main.c b/bacnet-stack/demo/ucov/main.c index fabd8d42..1d4b399e 100644 --- a/bacnet-stack/demo/ucov/main.c +++ b/bacnet-stack/demo/ucov/main.c @@ -204,9 +204,9 @@ int main(int argc, char *argv[]) } /* setup my info */ Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE); - Init_Service_Handlers(); - if (!datalink_init(NULL)) - return 1; + Init_Service_Handlers(); + if (!datalink_init(NULL)) + return 1; /* only one value in our value list */ cov_data.listOfValues.next = NULL; ucov_notify_send(&Handler_Transmit_Buffer[0], &cov_data); diff --git a/bacnet-stack/demo/ucov/makefile.b32 b/bacnet-stack/demo/ucov/makefile.b32 index 3ca3a77d..da5c3b94 100644 --- a/bacnet-stack/demo/ucov/makefile.b32 +++ b/bacnet-stack/demo/ucov/makefile.b32 @@ -1,153 +1,153 @@ -# -# Simple makefile to build an executable for Win32 -# -# This makefile assumes Borland bcc32 development environment -# on Windows NT/9x/2000/XP -# - -!ifndef BORLAND_DIR -BORLAND_DIR_Not_Defined: - @echo . - @echo You must define environment variable BORLAND_DIR to compile. -!endif - -PRODUCT = bacucov -PRODUCT_EXE = $(PRODUCT).exe - -# Choose the Data Link Layer to Enable -DEFINES = -DBACDL_BIP=1;TSM_ENABLED=0;BIG_ENDIAN=0;PRINT_ENABLED=1 - -SRCS = main.c \ - ..\..\ports\win32\bip-init.c \ - ..\..\filename.c \ - ..\..\bip.c \ - ..\..\demo\handler\txbuf.c \ - ..\..\demo\handler\noserv.c \ - ..\..\demo\handler\h_whois.c \ - ..\..\demo\handler\h_iam.c \ - ..\..\demo\handler\h_rp.c \ - ..\..\bacdcode.c \ - ..\..\bacapp.c \ - ..\..\bacstr.c \ - ..\..\bactext.c \ - ..\..\indtext.c \ - ..\..\datetime.c \ - ..\..\whois.c \ - ..\..\iam.c \ - ..\..\rp.c \ - ..\..\wp.c \ - ..\..\arf.c \ - ..\..\awf.c \ - ..\..\cov.c \ - ..\..\dcc.c \ - ..\..\demo\object\bacfile.c \ - ..\..\demo\object\device.c \ - ..\..\demo\object\ai.c \ - ..\..\demo\object\ao.c \ - ..\..\demo\object\av.c \ - ..\..\demo\object\bi.c \ - ..\..\demo\object\bo.c \ - ..\..\demo\object\bv.c \ - ..\..\demo\object\lc.c \ - ..\..\demo\object\lsp.c \ - ..\..\demo\object\mso.c \ - ..\..\address.c \ - ..\..\abort.c \ - ..\..\reject.c \ - ..\..\bacerror.c \ - ..\..\apdu.c \ - ..\..\npdu.c - -OBJS = $(SRCS:.c=.obj) - -# Compiler definitions -# -CC = $(BORLAND_DIR)\bin\bcc32 +bcc32.cfg -#LINK = $(BORLAND_DIR)\bin\tlink32 -LINK = $(BORLAND_DIR)\bin\ilink32 -TLIB = $(BORLAND_DIR)\bin\tlib - -# -# Include directories -# -CC_DIR = $(BORLAND_DIR)\BIN -INCL_DIRS = -I$(BORLAND_DIR)\include;..\..\;..\..\demo\object\;..\..\demo\handler\;..\..\ports\win32\;. - -CFLAGS = $(INCL_DIRS) $(CS_FLAGS) $(DEFINES) - -# Libraries -# -C_LIB_DIR = $(BORLAND_DIR)\lib - -LIBS = $(C_LIB_DIR)\IMPORT32.lib \ -$(C_LIB_DIR)\CW32MT.lib - -# -# Main target -# -# This should be the first one in the makefile - -all : bcc32.cfg $(PRODUCT_EXE) - -install: $(PRODUCT_EXE) - copy $(PRODUCT_EXE) ..\..\utils\$(PRODUCT_EXE) - -# Linker specific: the link below is for BCC linker/compiler. If you link -# with a different linker - please change accordingly. -# - -# need a temp response file (@&&) because command line is too long -$(PRODUCT_EXE) : $(OBJS) - @echo Running Linker for $(PRODUCT_EXE) - $(LINK) -L$(C_LIB_DIR) -m -c -s -v @&&| # temp response file, starts with | - $(BORLAND_DIR)\lib\c0x32.obj $** # $** lists each dependency - $< - $*.map - $(LIBS) -| # end of temp response file - -# -# Utilities - -clean : - @echo Deleting obj files, $(PRODUCT_EXE) and map files. -# del $(OBJS) # command too long, bummer! - del *.obj - del ..\..\*.obj - del ..\..\demo\handler\*.obj - del ..\..\demo\object\*.obj - del ..\..\ports\win32\*.obj - del $(PRODUCT_EXE) - del *.map - del bcc32.cfg - -# -# Generic rules -# -.SUFFIXES: .cpp .c .sbr .obj - -# -# cc generic rule -# -.c.obj: - $(CC) -o$@ $< - -# Compiler configuration file -bcc32.cfg : - Copy &&| -$(CFLAGS) --c --y #include line numbers in OBJ's --v #include debug info --w+ #turn on all warnings --Od #disable all optimizations -#-a4 #32 bit data alignment -#-M # generate link map -#-ls # linker options -#-WM- #not multithread --WM #multithread --w-aus # ignore warning assigned a value that is never used --w-sig # ignore warning conversion may lose sig digits -| $@ - -# EOF: makefile +# +# Simple makefile to build an executable for Win32 +# +# This makefile assumes Borland bcc32 development environment +# on Windows NT/9x/2000/XP +# + +!ifndef BORLAND_DIR +BORLAND_DIR_Not_Defined: + @echo . + @echo You must define environment variable BORLAND_DIR to compile. +!endif + +PRODUCT = bacucov +PRODUCT_EXE = $(PRODUCT).exe + +# Choose the Data Link Layer to Enable +DEFINES = -DBACDL_BIP=1;TSM_ENABLED=0;BIG_ENDIAN=0;PRINT_ENABLED=1 + +SRCS = main.c \ + ..\..\ports\win32\bip-init.c \ + ..\..\filename.c \ + ..\..\bip.c \ + ..\..\demo\handler\txbuf.c \ + ..\..\demo\handler\noserv.c \ + ..\..\demo\handler\h_whois.c \ + ..\..\demo\handler\h_iam.c \ + ..\..\demo\handler\h_rp.c \ + ..\..\bacdcode.c \ + ..\..\bacapp.c \ + ..\..\bacstr.c \ + ..\..\bactext.c \ + ..\..\indtext.c \ + ..\..\datetime.c \ + ..\..\whois.c \ + ..\..\iam.c \ + ..\..\rp.c \ + ..\..\wp.c \ + ..\..\arf.c \ + ..\..\awf.c \ + ..\..\cov.c \ + ..\..\dcc.c \ + ..\..\demo\object\bacfile.c \ + ..\..\demo\object\device.c \ + ..\..\demo\object\ai.c \ + ..\..\demo\object\ao.c \ + ..\..\demo\object\av.c \ + ..\..\demo\object\bi.c \ + ..\..\demo\object\bo.c \ + ..\..\demo\object\bv.c \ + ..\..\demo\object\lc.c \ + ..\..\demo\object\lsp.c \ + ..\..\demo\object\mso.c \ + ..\..\address.c \ + ..\..\abort.c \ + ..\..\reject.c \ + ..\..\bacerror.c \ + ..\..\apdu.c \ + ..\..\npdu.c + +OBJS = $(SRCS:.c=.obj) + +# Compiler definitions +# +CC = $(BORLAND_DIR)\bin\bcc32 +bcc32.cfg +#LINK = $(BORLAND_DIR)\bin\tlink32 +LINK = $(BORLAND_DIR)\bin\ilink32 +TLIB = $(BORLAND_DIR)\bin\tlib + +# +# Include directories +# +CC_DIR = $(BORLAND_DIR)\BIN +INCL_DIRS = -I$(BORLAND_DIR)\include;..\..\;..\..\demo\object\;..\..\demo\handler\;..\..\ports\win32\;. + +CFLAGS = $(INCL_DIRS) $(CS_FLAGS) $(DEFINES) + +# Libraries +# +C_LIB_DIR = $(BORLAND_DIR)\lib + +LIBS = $(C_LIB_DIR)\IMPORT32.lib \ +$(C_LIB_DIR)\CW32MT.lib + +# +# Main target +# +# This should be the first one in the makefile + +all : bcc32.cfg $(PRODUCT_EXE) + +install: $(PRODUCT_EXE) + copy $(PRODUCT_EXE) ..\..\utils\$(PRODUCT_EXE) + +# Linker specific: the link below is for BCC linker/compiler. If you link +# with a different linker - please change accordingly. +# + +# need a temp response file (@&&) because command line is too long +$(PRODUCT_EXE) : $(OBJS) + @echo Running Linker for $(PRODUCT_EXE) + $(LINK) -L$(C_LIB_DIR) -m -c -s -v @&&| # temp response file, starts with | + $(BORLAND_DIR)\lib\c0x32.obj $** # $** lists each dependency + $< + $*.map + $(LIBS) +| # end of temp response file + +# +# Utilities + +clean : + @echo Deleting obj files, $(PRODUCT_EXE) and map files. +# del $(OBJS) # command too long, bummer! + del *.obj + del ..\..\*.obj + del ..\..\demo\handler\*.obj + del ..\..\demo\object\*.obj + del ..\..\ports\win32\*.obj + del $(PRODUCT_EXE) + del *.map + del bcc32.cfg + +# +# Generic rules +# +.SUFFIXES: .cpp .c .sbr .obj + +# +# cc generic rule +# +.c.obj: + $(CC) -o$@ $< + +# Compiler configuration file +bcc32.cfg : + Copy &&| +$(CFLAGS) +-c +-y #include line numbers in OBJ's +-v #include debug info +-w+ #turn on all warnings +-Od #disable all optimizations +#-a4 #32 bit data alignment +#-M # generate link map +#-ls # linker options +#-WM- #not multithread +-WM #multithread +-w-aus # ignore warning assigned a value that is never used +-w-sig # ignore warning conversion may lose sig digits +| $@ + +# EOF: makefile diff --git a/bacnet-stack/demo/writeprop/main.c b/bacnet-stack/demo/writeprop/main.c index 9ad374d7..195ea8db 100644 --- a/bacnet-stack/demo/writeprop/main.c +++ b/bacnet-stack/demo/writeprop/main.c @@ -310,8 +310,8 @@ int main(int argc, char *argv[]) Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE); address_init(); Init_Service_Handlers(); - if (!datalink_init(NULL)) - return 1; + if (!datalink_init(NULL)) + return 1; /* configure the timeout values */ last_seconds = time(NULL); timeout_seconds = (Device_APDU_Timeout() / 1000) * diff --git a/bacnet-stack/doc/README.codeblocks b/bacnet-stack/doc/README.codeblocks index 53afc2c5..44d86d2c 100644 --- a/bacnet-stack/doc/README.codeblocks +++ b/bacnet-stack/doc/README.codeblocks @@ -1,10 +1,10 @@ -BACnet Stack @ SourceForge.net -Build using Code Blocks - -Q1: GNU GCC Compiler, undefined reference to closesocket - -A1: Under Project->Build Options->Linker settings, -add "ws2_32" to Link Libraries. - - - +BACnet Stack @ SourceForge.net +Build using Code Blocks + +Q1: GNU GCC Compiler, undefined reference to closesocket + +A1: Under Project->Build Options->Linker settings, +add "ws2_32" to Link Libraries. + + + diff --git a/bacnet-stack/doc/README.msvs b/bacnet-stack/doc/README.msvs index 4f0f5e8f..4a34905e 100644 --- a/bacnet-stack/doc/README.msvs +++ b/bacnet-stack/doc/README.msvs @@ -1,7 +1,7 @@ -BACnet Stack - SourceForge.net -Build for Visual Studio 2005 Express Edition - -Q1: Cannot open include file: 'winsock2.h' - -A1: Install the Microsoft Platform SDK: -http://msdn.microsoft.com/vstudio/express/visualc/usingpsdk/default.aspx +BACnet Stack - SourceForge.net +Build for Visual Studio 2005 Express Edition + +Q1: Cannot open include file: 'winsock2.h' + +A1: Install the Microsoft Platform SDK: +http://msdn.microsoft.com/vstudio/express/visualc/usingpsdk/default.aspx diff --git a/bacnet-stack/doc/README.todo b/bacnet-stack/doc/README.todo index 8f3043ce..a05812b7 100644 --- a/bacnet-stack/doc/README.todo +++ b/bacnet-stack/doc/README.todo @@ -1,27 +1,27 @@ -To Do List - BACnet Stack at SourceForge - -For this release, here are some things to do: - -1. Change bip_init to datalink_init in demos (done, STK) -2. Change demos main file to main.c (done, STK) -3. Add parameter passing for IP address or interface for - multi homed systems. (done, STK) -4. Validate the unit tests compile after BIG_ENDIAN change. (done,STK) -5. Add arcnet.c and ethernet.c to all the linux Makefiles (done, STK) -6. Refactor Makefile DEFINES like demo/server/Makefile. (done, STK) - -For a later release, here are some things to do: - -1. Finish demo/epics/main.c - EPICS demo -2. Finish demo/object/lo.c - Lighting Output object demo -3. Complete bvlc.c and use it instead of or in compliment to bip.c -4. Complete demo for ReadPropertyMultiple from rpm.c -5. Add HTTP demo like bacnet4linux -6. Add subscribe to change of value support in server demo -7. Add hooks to increment Database_Revision property -8. Add BBMD and FD support to server example for BACnet/IP. -9. Add Foreign Device registration options to client examples. -A. Change bip.c to not use extra buffer (shift data) -B. Finish subscribe COV support in server demo. -C. Add Visual Studio 2005 makefiles or projects for demos. -D. Add Code::Blocks projects for demos. +To Do List - BACnet Stack at SourceForge + +For this release, here are some things to do: + +1. Change bip_init to datalink_init in demos (done, STK) +2. Change demos main file to main.c (done, STK) +3. Add parameter passing for IP address or interface for + multi homed systems. (done, STK) +4. Validate the unit tests compile after BIG_ENDIAN change. (done,STK) +5. Add arcnet.c and ethernet.c to all the linux Makefiles (done, STK) +6. Refactor Makefile DEFINES like demo/server/Makefile. (done, STK) + +For a later release, here are some things to do: + +1. Finish demo/epics/main.c - EPICS demo +2. Finish demo/object/lo.c - Lighting Output object demo +3. Complete bvlc.c and use it instead of or in compliment to bip.c +4. Complete demo for ReadPropertyMultiple from rpm.c +5. Add HTTP demo like bacnet4linux +6. Add subscribe to change of value support in server demo +7. Add hooks to increment Database_Revision property +8. Add BBMD and FD support to server example for BACnet/IP. +9. Add Foreign Device registration options to client examples. +A. Change bip.c to not use extra buffer (shift data) +B. Finish subscribe COV support in server demo. +C. Add Visual Studio 2005 makefiles or projects for demos. +D. Add Code::Blocks projects for demos. diff --git a/bacnet-stack/doc/htdocs/index.html b/bacnet-stack/doc/htdocs/index.html index a40309e3..48ae0b9c 100644 --- a/bacnet-stack/doc/htdocs/index.html +++ b/bacnet-stack/doc/htdocs/index.html @@ -1,436 +1,436 @@ - - - - - BACnet stack - open source BACnet protocol stack - - -

BACnet Stack

-

An open source BACnet protocol stack for embedded systems

-
-

About this Project

-

This BACnet protocol stack library - provides a BACnet application layer, network layer and media access (MAC) + + + + + BACnet stack - open source BACnet protocol stack + + +

BACnet Stack

+

An open source BACnet protocol stack for embedded systems

+
+

About this Project

+

This BACnet protocol stack library + provides a BACnet application layer, network layer and media access (MAC) layer communications services. It is an open source, royalty-free library for an embedded system, Windows, Linux, or other operating system. Example - BACnet client and server applications are included.

- -

BACnet - A Data Communication Protocol for Building - Automation and Control Networks - see bacnet.org. BACnet is a standard data - communication protocol for Building Automation and Control Networks. BACnet - is an open protocol, which means anyone can contribute to the standard, and - anyone may use it. The only caveat is that the BACnet standard document - itself is copyrighted by ASHRAE, and they sell the document to help defray - costs of developing and maintaining the standard (just like IEEE or ANSI or - ISO).

- -

For software developers, the BACnet protocol is a standard way to send and - receive messages on the wire containing data that is understood by other - BACnet compliant devices. The BACnet standard defines a standard way to - communicate over a number of wires, known as Data Link/Physical Layers: - Ethernet, EIA-485, EIA-232, ARCNET, and LonTalk. The BACnet standard also - defines a standard way to communicate using UDP, IP and HTTP (Web - Services).

- - There are other open source projects for BACnet:

-
    -
  • VTS - visual test shell for - Win32, used for Visually testing a BACnet implementation. It also includes - a detailed network sniffer for BACnet messages, and the ability to send - any BACnet services. The source code is in the public domain.
  • -
  • Wireshark - an open source, - cross platform protocol analyzer with BACnet support. The detailed BACnet - support began in version 0.10.11 released on May 4, 2005 when Wireshark - was known as Ethereal.
  • -
  • BACnet4Linux - an - LGPL BACnet application that requires Linux as the OS.
  • -
  • BACnet Firewall Router -an - application that combines BACnet routing capability with traffic management - functions to carefully control access to building automation and control - networks.
  • -
  • BACpypes - a - BACnet stack written in Python.
  • -
- -

There are also commercial BACnet protocol source code libraries for BACnet - that are designed for embedded use:

-
    -
  • CimetricsTM - has a source library - called BACstac/32 as part of their BACNet Protocol Stack SDK.
  • -
  • Polarsoft - has a - protocol stack source library for embedded use called FreeRangeTM and PolarSoft® FreeRange VSB (Very - Small BACnet stack).
  • -
  • SCADA Engine - The BACnet - Linux Server is a complete BACnet Device running on the linux platform. - The entire source code is available for custom applications and has been - written in ANSI C which has been succesfully ported to Unix, - VxWorks etc.
  • -
- -

Licensing

-

Our BACnet protocol stack implementation is specifically designed for the - embedded BACnet appliance, using a GPL with exception license (like eCos), - which means that any changes to the core code that are distributed are - made available, but the BACnet library can be linked to - proprietary code without it becoming licensed under the GPL. + BACnet client and server applications are included.

+ +

BACnet - A Data Communication Protocol for Building + Automation and Control Networks - see bacnet.org. BACnet is a standard data + communication protocol for Building Automation and Control Networks. BACnet + is an open protocol, which means anyone can contribute to the standard, and + anyone may use it. The only caveat is that the BACnet standard document + itself is copyrighted by ASHRAE, and they sell the document to help defray + costs of developing and maintaining the standard (just like IEEE or ANSI or + ISO).

+ +

For software developers, the BACnet protocol is a standard way to send and + receive messages on the wire containing data that is understood by other + BACnet compliant devices. The BACnet standard defines a standard way to + communicate over a number of wires, known as Data Link/Physical Layers: + Ethernet, EIA-485, EIA-232, ARCNET, and LonTalk. The BACnet standard also + defines a standard way to communicate using UDP, IP and HTTP (Web + Services).

+ + There are other open source projects for BACnet:

+
    +
  • VTS - visual test shell for + Win32, used for Visually testing a BACnet implementation. It also includes + a detailed network sniffer for BACnet messages, and the ability to send + any BACnet services. The source code is in the public domain.
  • +
  • Wireshark - an open source, + cross platform protocol analyzer with BACnet support. The detailed BACnet + support began in version 0.10.11 released on May 4, 2005 when Wireshark + was known as Ethereal.
  • +
  • BACnet4Linux - an + LGPL BACnet application that requires Linux as the OS.
  • +
  • BACnet Firewall Router -an + application that combines BACnet routing capability with traffic management + functions to carefully control access to building automation and control + networks.
  • +
  • BACpypes - a + BACnet stack written in Python.
  • +
+ +

There are also commercial BACnet protocol source code libraries for BACnet + that are designed for embedded use:

+
    +
  • CimetricsTM - has a source library + called BACstac/32 as part of their BACNet Protocol Stack SDK.
  • +
  • Polarsoft - has a + protocol stack source library for embedded use called FreeRangeTM and PolarSoft® FreeRange VSB (Very + Small BACnet stack).
  • +
  • SCADA Engine - The BACnet + Linux Server is a complete BACnet Device running on the linux platform. + The entire source code is available for custom applications and has been + written in ANSI C which has been succesfully ported to Unix, + VxWorks etc.
  • +
+ +

Licensing

+

Our BACnet protocol stack implementation is specifically designed for the + embedded BACnet appliance, using a GPL with exception license (like eCos), + which means that any changes to the core code that are distributed are + made available, but the BACnet library can be linked to + proprietary code without it becoming licensed under the GPL. See the eCos license overview for - easy to read details about this exception to the GPL. - The license does not require users to release the source code of any + easy to read details about this exception to the GPL. + The license does not require users to release the source code of any applications that are developed with this BACnet stack - only portions of the BACnet stack that have been modified. Note that those files in this BACnet stack that are expected to be modified are licensed using the - MIT License.

- -

The text of the GPL exception included in each source file is as - follows:

- -
-

"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."

-

- -

The source code

-

The source code is written in C for portability, and includes - unit tests (PC based unit tests) and example application code. - Since the code is designed to be - portable, it compiles with GCC as well as other compilers, - such as Borland C++, Visual C++, MinGW, Code Warrior, or MicroChip C18. - The source code is also designed to be readable, understandable, - and most importantly, easy to use.

- -

The BACnet protocol is an ASHRAE/ANSI/ISO standard, so this library - adheres to that standard. BACnet has no royalties or licensing restrictions, - and registration for a BACnet - vendor ID is free.

- -

What the code does

- -

The BACnet stack comes with example applications - that can be run under Linux, Win32, RTOS-32, and just about any embedded - microcontroller.

- -

The BACnet stack includes unit tests can be run in a command shell on Linux using the - unittest.sh script, or using individual .mak files. They were tested under - Debian GNU/Linux and Ubuntu Linux.

- -

The BACnet stack was functionally tested - using VTS (Visual Test Shell), - another project hosted on SourceForge, as well as various BACnet controllers, - BACnet workstations, and through BACnet routers.

- -

Using a master Makefile in the project root directory, a dozen or so - demo applications can be created that run under Linux or Win32. - Linux supports BACnet Ethernet, BACnet/IP, or ARCNET data link layer - for communication, and BACnet/IP is supported under Win32. BACnet Ethernet - can also be used under Win32 with the WinPcap library. - Root priveleges are required to run the Ethernet or ARCNET interfaces - on Linux, but not needed to run BACnet/IP.

- - - $ make clean all
- $ demo/server/bacsrv 123
- BACnet Server Demo - Device #123
-
- $ demo/readprop/bacrp
- bacrp device-instance object-type object-instance property [index]
-
- $ demo/writeprop/bacwp
- bacwp device-instance object-type object-instance property tag value [priority] [index]
-
- $ demo/readfile/bacarf
- bacarf device-instance file-instance local-name
-
- $ demo/writefile/bacawf
- bacawf device-instance file-instance local-name
-
- $ demo/reinit/bacrd
- Usage: bacrd device-instance state [password]
- Send BACnet ReinitializeDevice service to device.
-
- $ demo/whohas/bacwh
- Usage: bacwh object-type object-instance | object-name
- Send BACnet WhoHas request to devices, and wait for responses.
-
- $ demo/dcc/bacdcc
- Usage: bacdcc device-instance state timeout [password]
- Send BACnet DeviceCommunicationControl service to device.
-
- $ demo/timesync/bacts
- Received TimeSyncronization Request
- 2006/8/30 07:10:45.00
-
- $ demo/ucov/bacucov
- Usage: bacucov pid device-id object-type object-instance time property tag value [priority] [index]
-
- $ demo/whois/bacwi
- Usage: bacwi device-instance | device-instance-min device-instance-max
- Send BACnet WhoIs request to devices, and wait for responses.
-
- The device-instance can be 0 to 4194303, or -1 for ALL.
- The device-instance can also be specified as a range.
-
-
- -

The demos can be compiled under Win32 using Borland C++ or - Microsoft Visual C++, both of which - are free (as in beer) command line compilers. Be sure to pick up the free - patches (service packs) for the Borland C++ compiler (SP1, SP2), as well as the free turbo debugger. It might also be possible to create Win32 projects using the free Visual Studio Express Edition or MinGW - Minimalist GNU for Windows, but I have haven't tried it. I have used Code::Blocks for compiling the unit tests using the MinGW compiler, but have not tried to get the demos working with MinGW. I have used Code::Blocks with the Borland C++ compiler and it successfully compiles the code.

- -

There is a Makefile in the ports/rtos32 directory, and a sample - application that runs under RTOS-32. - It currently uses the BACnet/IP data link layer for communication, and also - has an MS/TP datalink layer sample application. - It compiles using Borland C++.

- -

There is a project in the ports/pic18f6720 directory, and a sample - application that can be build using MP-Lab + MIT License.

+ +

The text of the GPL exception included in each source file is as + follows:

+ +
+

"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."

+

+ +

The source code

+

The source code is written in C for portability, and includes + unit tests (PC based unit tests) and example application code. + Since the code is designed to be + portable, it compiles with GCC as well as other compilers, + such as Borland C++, Visual C++, MinGW, Code Warrior, or MicroChip C18. + The source code is also designed to be readable, understandable, + and most importantly, easy to use.

+ +

The BACnet protocol is an ASHRAE/ANSI/ISO standard, so this library + adheres to that standard. BACnet has no royalties or licensing restrictions, + and registration for a BACnet + vendor ID is free.

+ +

What the code does

+ +

The BACnet stack comes with example applications + that can be run under Linux, Win32, RTOS-32, and just about any embedded + microcontroller.

+ +

The BACnet stack includes unit tests can be run in a command shell on Linux using the + unittest.sh script, or using individual .mak files. They were tested under + Debian GNU/Linux and Ubuntu Linux.

+ +

The BACnet stack was functionally tested + using VTS (Visual Test Shell), + another project hosted on SourceForge, as well as various BACnet controllers, + BACnet workstations, and through BACnet routers.

+ +

Using a master Makefile in the project root directory, a dozen or so + demo applications can be created that run under Linux or Win32. + Linux supports BACnet Ethernet, BACnet/IP, or ARCNET data link layer + for communication, and BACnet/IP is supported under Win32. BACnet Ethernet + can also be used under Win32 with the WinPcap library. + Root priveleges are required to run the Ethernet or ARCNET interfaces + on Linux, but not needed to run BACnet/IP.

+ + + $ make clean all
+ $ demo/server/bacsrv 123
+ BACnet Server Demo - Device #123
+
+ $ demo/readprop/bacrp
+ bacrp device-instance object-type object-instance property [index]
+
+ $ demo/writeprop/bacwp
+ bacwp device-instance object-type object-instance property tag value [priority] [index]
+
+ $ demo/readfile/bacarf
+ bacarf device-instance file-instance local-name
+
+ $ demo/writefile/bacawf
+ bacawf device-instance file-instance local-name
+
+ $ demo/reinit/bacrd
+ Usage: bacrd device-instance state [password]
+ Send BACnet ReinitializeDevice service to device.
+
+ $ demo/whohas/bacwh
+ Usage: bacwh object-type object-instance | object-name
+ Send BACnet WhoHas request to devices, and wait for responses.
+
+ $ demo/dcc/bacdcc
+ Usage: bacdcc device-instance state timeout [password]
+ Send BACnet DeviceCommunicationControl service to device.
+
+ $ demo/timesync/bacts
+ Received TimeSyncronization Request
+ 2006/8/30 07:10:45.00
+
+ $ demo/ucov/bacucov
+ Usage: bacucov pid device-id object-type object-instance time property tag value [priority] [index]
+
+ $ demo/whois/bacwi
+ Usage: bacwi device-instance | device-instance-min device-instance-max
+ Send BACnet WhoIs request to devices, and wait for responses.
+
+ The device-instance can be 0 to 4194303, or -1 for ALL.
+ The device-instance can also be specified as a range.
+
+
+ +

The demos can be compiled under Win32 using Borland C++ or + Microsoft Visual C++, both of which + are free (as in beer) command line compilers. Be sure to pick up the free + patches (service packs) for the Borland C++ compiler (SP1, SP2), as well as the free turbo debugger. It might also be possible to create Win32 projects using the free Visual Studio Express Edition or MinGW - Minimalist GNU for Windows, but I have haven't tried it. I have used Code::Blocks for compiling the unit tests using the MinGW compiler, but have not tried to get the demos working with MinGW. I have used Code::Blocks with the Borland C++ compiler and it successfully compiles the code.

+ +

There is a Makefile in the ports/rtos32 directory, and a sample + application that runs under RTOS-32. + It currently uses the BACnet/IP data link layer for communication, and also + has an MS/TP datalink layer sample application. + It compiles using Borland C++.

+ +

There is a project in the ports/pic18f6720 directory, and a sample + application that can be build using MP-Lab and the Microchip compiler MCC18. The datalink layer uses BACnet MS/TP - and the example uses several different objects and services.

- - - -

BACnet services supported matrix

-

The BACnet stack currently implements the following services listed in the - the table. We plan to add the rest of the services as we go. - With the services that are implemented, you could build a BACnet device - that meets the standardized profile for a BACnet Smart Sensor, - BACnet Smart Actuator, or a BACnet Application Specific Controller.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BACnet ServiceInitiateExecute
Who IsYesYes
I AmYesYes
Who HasYesYes
I HaveYesYes
Read PropertyYesYes
Write PropertyYesYes
Device Communication ControlYesYes
ReinitializeDeviceYesYes
Atomic Read FileYesYes
Atomic Write FileYesYes
Time SynchronizationYesYes
UTC Time SynchronizationYesYes
Subscribe COV--
Confirmed COV NotificationYesYes
Unconfirmed COV NotificationYesYes
Read Property Multiple--
Read Property Conditional--
Read Range--
Write Property Multiple--
Get Alarm Summary--
Get Event Information--
Get Enrollment Summary--
Acknowledge Alarm--
Confirmed Event Notification--
Unconfirmed Event Notification--
Unconfirmed Text Message--
Confirmed Text Message--
Add List Element--
Remove List Element--
Create Object--
Delete Object--
Unconfirmed Private Transfer--
Confirmed Private Transfer--
VT Open--
VT Data--
VT Close--
- -

BACnet Objects

- -

The BACnet stack currently implements a Device Object, and - handles all of the ReadProperty inquiries for the required - Device Object properties. The stack handles Who-Is inquiries - with an I-Am, WhoHas with I-Have, and handles reject messages for - services not currently supported. There is built in handling for - DeviceCommunicationControl.

- -

The example handlers interact with example objects, including - Analog Input, Analog Output, Analog Value, Binary Input, - Binary Output, Binary Value, Load Control, Life Safety Point, - and Multi-state Output objects. - The objects can be accessed using WriteProperty, - ReadProperty, or Who-Has services. Adding other BACnet objects - is only a matter of setting up ReadProperty, WriteProperty, or - I-Have handling for the required properties and any other - properties that you want to support.

- -

File Objects are conditionally included in the demonstation - applications. The files can be access using WriteProperty, - ReadProperty, Who-Has, AtomicWriteFile, or AtomicReadFile services.

- -

Getting Involved

- -

If you want to help out on this project, join the developers mailing list, introduce yourself, and tell us what you would like to do. - If you are trying to implement a BACnet device or service using this project, - you are welcome to join the developers mailing list as well.

- -

More details about the project can be found on - the BACnet Source Forge Project Page

- -

There is documentation that describes the mechanisms in the BACnet Stack. - I wrote up some answers to some frequently asked questions. Of course, - there are a handful of text files in the doc directory of the project.

- -

BACnet + and the example uses several different objects and services.

+ + + +

BACnet services supported matrix

+

The BACnet stack currently implements the following services listed in the + the table. We plan to add the rest of the services as we go. + With the services that are implemented, you could build a BACnet device + that meets the standardized profile for a BACnet Smart Sensor, + BACnet Smart Actuator, or a BACnet Application Specific Controller.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BACnet ServiceInitiateExecute
Who IsYesYes
I AmYesYes
Who HasYesYes
I HaveYesYes
Read PropertyYesYes
Write PropertyYesYes
Device Communication ControlYesYes
ReinitializeDeviceYesYes
Atomic Read FileYesYes
Atomic Write FileYesYes
Time SynchronizationYesYes
UTC Time SynchronizationYesYes
Subscribe COV--
Confirmed COV NotificationYesYes
Unconfirmed COV NotificationYesYes
Read Property Multiple--
Read Property Conditional--
Read Range--
Write Property Multiple--
Get Alarm Summary--
Get Event Information--
Get Enrollment Summary--
Acknowledge Alarm--
Confirmed Event Notification--
Unconfirmed Event Notification--
Unconfirmed Text Message--
Confirmed Text Message--
Add List Element--
Remove List Element--
Create Object--
Delete Object--
Unconfirmed Private Transfer--
Confirmed Private Transfer--
VT Open--
VT Data--
VT Close--
+ +

BACnet Objects

+ +

The BACnet stack currently implements a Device Object, and + handles all of the ReadProperty inquiries for the required + Device Object properties. The stack handles Who-Is inquiries + with an I-Am, WhoHas with I-Have, and handles reject messages for + services not currently supported. There is built in handling for + DeviceCommunicationControl.

+ +

The example handlers interact with example objects, including + Analog Input, Analog Output, Analog Value, Binary Input, + Binary Output, Binary Value, Load Control, Life Safety Point, + and Multi-state Output objects. + The objects can be accessed using WriteProperty, + ReadProperty, or Who-Has services. Adding other BACnet objects + is only a matter of setting up ReadProperty, WriteProperty, or + I-Have handling for the required properties and any other + properties that you want to support.

+ +

File Objects are conditionally included in the demonstation + applications. The files can be access using WriteProperty, + ReadProperty, Who-Has, AtomicWriteFile, or AtomicReadFile services.

+ +

Getting Involved

+ +

If you want to help out on this project, join the developers mailing list, introduce yourself, and tell us what you would like to do. + If you are trying to implement a BACnet device or service using this project, + you are welcome to join the developers mailing list as well.

+ +

More details about the project can be found on + the BACnet Source Forge Project Page

+ +

There is documentation that describes the mechanisms in the BACnet Stack. + I wrote up some answers to some frequently asked questions. Of course, + there are a handful of text files in the doc directory of the project.

+ +

BACnet Stack released files download

You can get the latest BACnet protocol stack source code using @@ -449,64 +449,64 @@ or
svn co https://bacnet.svn.sourceforge.net/svnroot/bacnet/tags/bacnet-stack-0-3-0/ - -

BACnet Developer Resources

- -There are a number of resources that can help you develop a BACnet product or project. - -
    -
  • VTS - visual test shell for - Win32, used for Visually testing a BACnet implementation. It also includes - a detailed network sniffer for BACnet messages, and the ability to send - any BACnet services. The source code is in the public domain.
  • -
  • Wireshark - an open source, - cross platform protocol analyzer with BACnet support. The detailed BACnet - support in began in version 0.10.11 released on May 4, 2005 when Wireshark - was known as Ethereal.
  • -
  • Ubuntu Linux or - Debian Linux - my - development platforms of choice. - Linux makes a great development platform - because all the necessary development tools are included.
  • -
  • Code::Blocks - a free cross-platform + +

    BACnet Developer Resources

    + +There are a number of resources that can help you develop a BACnet product or project. + +
      +
    • VTS - visual test shell for + Win32, used for Visually testing a BACnet implementation. It also includes + a detailed network sniffer for BACnet messages, and the ability to send + any BACnet services. The source code is in the public domain.
    • +
    • Wireshark - an open source, + cross platform protocol analyzer with BACnet support. The detailed BACnet + support in began in version 0.10.11 released on May 4, 2005 when Wireshark + was known as Ethereal.
    • +
    • Ubuntu Linux or + Debian Linux - my + development platforms of choice. + Linux makes a great development platform + because all the necessary development tools are included.
    • +
    • Code::Blocks - a free cross-platform open source C/C++ IDE. Includes the MinGW compiler for Win32.
    • -
    • Win32 development can use Borland C++ or +
    • Win32 development can use Borland C++ or Microsoft Visual C++, - both of which are free (as in beer) command line compilers. Be sure to pick up the free + both of which are free (as in beer) command line compilers. Be sure to pick up the free patches (service packs) for the Borland C++ compiler (SP1, SP2), - as well as the free turbo debugger.
    • -
    - -

    BACnet Developer Help

    - -

    BACnet International Developer Resources

    - -

    Products and Projects that use this BACnet Stack

    - -

    Did you develop a product using this BACnet stack? Let us know, and you -can get a little recognition for your hard work!

    - -

    SCInterface™ = Sensor Control Interface - middleware - platform for managing legacy and modern-day sensors through a centralized - interface

    - -

    BACnetSim - a -portable implementation of the BACnet data communication protocol. -BACnetSim is meant for embedded devices and use MS/TP as the media -access layer. BACnetSim is a fork of bacnet-stack-0.0.1

    - -
    - - SourceForge.net Logo - -

    ASHRAE® and - BACnet® are registered trademarks of the American - Society of Heating, Refrigerating and Air-Conditioning Engineers, Inc., - 1791 Tullie Circle NE, Atlanta, GA 30329.

    -

    Website updated 2-Apr-2007 by Steve Karg

    - - + as well as the free turbo debugger.
  • +
+ +

BACnet Developer Help

+ +

BACnet International Developer Resources

+ +

Products and Projects that use this BACnet Stack

+ +

Did you develop a product using this BACnet stack? Let us know, and you +can get a little recognition for your hard work!

+ +

SCInterface™ = Sensor Control Interface - middleware + platform for managing legacy and modern-day sensors through a centralized + interface

+ +

BACnetSim - a +portable implementation of the BACnet data communication protocol. +BACnetSim is meant for embedded devices and use MS/TP as the media +access layer. BACnetSim is a fork of bacnet-stack-0.0.1

+ +
+ + SourceForge.net Logo + +

ASHRAE® and + BACnet® are registered trademarks of the American + Society of Heating, Refrigerating and Air-Conditioning Engineers, Inc., + 1791 Tullie Circle NE, Atlanta, GA 30329.

+

Website updated 2-Apr-2007 by Steve Karg

+ + diff --git a/bacnet-stack/ports/pic18f6720/ai.c b/bacnet-stack/ports/pic18f6720/ai.c index 31adc66b..7115a11b 100644 --- a/bacnet-stack/ports/pic18f6720/ai.c +++ b/bacnet-stack/ports/pic18f6720/ai.c @@ -1,200 +1,200 @@ -/************************************************************************** -* -* Copyright (C) 2005 Steve Karg -* -* Permission is hereby granted, free of charge, to any person obtaining -* a copy of this software and associated documentation files (the -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to -* permit persons to whom the Software is furnished to do so, subject to -* the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -* -*********************************************************************/ - -/* Analog Input Objects customize for your use */ - -#include -#include -#include -#include "bacdef.h" -#include "bacdcode.h" -#include "bacenum.h" -#include "config.h" - -/* Analog Input = Photocell */ -#define MAX_ANALOG_INPUTS 2 - -static uint8_t Present_Value[MAX_ANALOG_INPUTS]; - -/* we simply have 0-n object instances. Yours might be */ -/* more complex, and then you need validate that the */ -/* given instance exists */ -bool Analog_Input_Valid_Instance(uint32_t object_instance) -{ - if (object_instance < MAX_ANALOG_INPUTS) - return true; - - return false; -} - -/* we simply have 0-n object instances. */ -unsigned Analog_Input_Count(void) -{ - return MAX_ANALOG_INPUTS; -} - -/* we simply have 0-n object instances. */ -uint32_t Analog_Input_Index_To_Instance(unsigned index) -{ - return index; -} - -char *Analog_Input_Name(uint32_t object_instance) -{ - static char text_string[16] = ""; /* okay for single thread */ - - if (object_instance < MAX_ANALOG_INPUTS) { - sprintf(text_string, "AI-%lu", object_instance); - return text_string; - } - - return NULL; -} - -static float Analog_Input_Present_Value(uint32_t object_instance) -{ - float value = 0.0; - - if (object_instance < MAX_ANALOG_INPUTS) - value = Present_Value[object_instance]; - - return value; -} - -/* return apdu length, or -1 on error */ -/* assumption - object has already exists */ -int Analog_Input_Encode_Property_APDU(uint8_t * apdu, - uint32_t object_instance, - BACNET_PROPERTY_ID property, - int32_t array_index, - BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code) -{ - int apdu_len = 0; /* return value */ - BACNET_BIT_STRING bit_string; - BACNET_CHARACTER_STRING char_string; - - (void) array_index; - switch (property) { - case PROP_OBJECT_IDENTIFIER: - apdu_len = encode_tagged_object_id(&apdu[0], OBJECT_ANALOG_INPUT, - object_instance); - break; - /* note: Name and Description don't have to be the same. - You could make Description writable and different */ - case PROP_OBJECT_NAME: - case PROP_DESCRIPTION: - characterstring_init_ansi(&char_string, - Analog_Input_Name(object_instance)); - apdu_len = encode_tagged_character_string(&apdu[0], &char_string); - break; - case PROP_OBJECT_TYPE: - apdu_len = encode_tagged_enumerated(&apdu[0], - OBJECT_ANALOG_INPUT); - break; - case PROP_PRESENT_VALUE: - apdu_len = encode_tagged_real(&apdu[0], - Analog_Input_Present_Value(object_instance)); - break; - case PROP_STATUS_FLAGS: - bitstring_init(&bit_string); - bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); - bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); - bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); - bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); - apdu_len = encode_tagged_bitstring(&apdu[0], &bit_string); - break; - case PROP_EVENT_STATE: - apdu_len = encode_tagged_enumerated(&apdu[0], EVENT_STATE_NORMAL); - break; - case PROP_OUT_OF_SERVICE: - apdu_len = encode_tagged_boolean(&apdu[0], false); - break; - case PROP_UNITS: - apdu_len = encode_tagged_enumerated(&apdu[0], UNITS_PERCENT); - break; - default: - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_UNKNOWN_PROPERTY; - apdu_len = -1; - break; - } - - return apdu_len; -} - -#ifdef TEST -#include -#include -#include "ctest.h" - -void testAnalogInput(Test * pTest) -{ - uint8_t apdu[MAX_APDU] = { 0 }; - int len = 0; - uint32_t len_value = 0; - uint8_t tag_number = 0; - BACNET_OBJECT_TYPE decoded_type = OBJECT_ANALOG_OUTPUT; - uint32_t decoded_instance = 0; - uint32_t instance = 123; - BACNET_ERROR_CLASS error_class; - BACNET_ERROR_CODE error_code; - - - /* FIXME: we should do a lot more testing here... */ - len = Analog_Input_Encode_Property_APDU(&apdu[0], - instance, - PROP_OBJECT_IDENTIFIER, - BACNET_ARRAY_ALL, &error_class, &error_code); - ct_test(pTest, len >= 0); - len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value); - ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID); - len = decode_object_id(&apdu[len], - (int *) &decoded_type, &decoded_instance); - ct_test(pTest, decoded_type == OBJECT_ANALOG_INPUT); - ct_test(pTest, decoded_instance == instance); - - return; -} - -#ifdef TEST_ANALOG_INPUT -int main(void) -{ - Test *pTest; - bool rc; - - pTest = ct_create("BACnet Analog Input", NULL); - /* individual tests */ - rc = ct_addTestFunction(pTest, testAnalogInput); - assert(rc); - - ct_setStream(pTest, stdout); - ct_run(pTest); - (void) ct_report(pTest); - ct_destroy(pTest); - - return 0; -} -#endif /* TEST_ANALOG_INPUT */ -#endif /* TEST */ +/************************************************************************** +* +* Copyright (C) 2005 Steve Karg +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*********************************************************************/ + +/* Analog Input Objects customize for your use */ + +#include +#include +#include +#include "bacdef.h" +#include "bacdcode.h" +#include "bacenum.h" +#include "config.h" + +/* Analog Input = Photocell */ +#define MAX_ANALOG_INPUTS 2 + +static uint8_t Present_Value[MAX_ANALOG_INPUTS]; + +/* we simply have 0-n object instances. Yours might be */ +/* more complex, and then you need validate that the */ +/* given instance exists */ +bool Analog_Input_Valid_Instance(uint32_t object_instance) +{ + if (object_instance < MAX_ANALOG_INPUTS) + return true; + + return false; +} + +/* we simply have 0-n object instances. */ +unsigned Analog_Input_Count(void) +{ + return MAX_ANALOG_INPUTS; +} + +/* we simply have 0-n object instances. */ +uint32_t Analog_Input_Index_To_Instance(unsigned index) +{ + return index; +} + +char *Analog_Input_Name(uint32_t object_instance) +{ + static char text_string[16] = ""; /* okay for single thread */ + + if (object_instance < MAX_ANALOG_INPUTS) { + sprintf(text_string, "AI-%lu", object_instance); + return text_string; + } + + return NULL; +} + +static float Analog_Input_Present_Value(uint32_t object_instance) +{ + float value = 0.0; + + if (object_instance < MAX_ANALOG_INPUTS) + value = Present_Value[object_instance]; + + return value; +} + +/* return apdu length, or -1 on error */ +/* assumption - object has already exists */ +int Analog_Input_Encode_Property_APDU(uint8_t * apdu, + uint32_t object_instance, + BACNET_PROPERTY_ID property, + int32_t array_index, + BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code) +{ + int apdu_len = 0; /* return value */ + BACNET_BIT_STRING bit_string; + BACNET_CHARACTER_STRING char_string; + + (void) array_index; + switch (property) { + case PROP_OBJECT_IDENTIFIER: + apdu_len = encode_tagged_object_id(&apdu[0], OBJECT_ANALOG_INPUT, + object_instance); + break; + /* note: Name and Description don't have to be the same. + You could make Description writable and different */ + case PROP_OBJECT_NAME: + case PROP_DESCRIPTION: + characterstring_init_ansi(&char_string, + Analog_Input_Name(object_instance)); + apdu_len = encode_tagged_character_string(&apdu[0], &char_string); + break; + case PROP_OBJECT_TYPE: + apdu_len = encode_tagged_enumerated(&apdu[0], + OBJECT_ANALOG_INPUT); + break; + case PROP_PRESENT_VALUE: + apdu_len = encode_tagged_real(&apdu[0], + Analog_Input_Present_Value(object_instance)); + break; + case PROP_STATUS_FLAGS: + bitstring_init(&bit_string); + bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); + bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); + bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); + bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); + apdu_len = encode_tagged_bitstring(&apdu[0], &bit_string); + break; + case PROP_EVENT_STATE: + apdu_len = encode_tagged_enumerated(&apdu[0], EVENT_STATE_NORMAL); + break; + case PROP_OUT_OF_SERVICE: + apdu_len = encode_tagged_boolean(&apdu[0], false); + break; + case PROP_UNITS: + apdu_len = encode_tagged_enumerated(&apdu[0], UNITS_PERCENT); + break; + default: + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_UNKNOWN_PROPERTY; + apdu_len = -1; + break; + } + + return apdu_len; +} + +#ifdef TEST +#include +#include +#include "ctest.h" + +void testAnalogInput(Test * pTest) +{ + uint8_t apdu[MAX_APDU] = { 0 }; + int len = 0; + uint32_t len_value = 0; + uint8_t tag_number = 0; + BACNET_OBJECT_TYPE decoded_type = OBJECT_ANALOG_OUTPUT; + uint32_t decoded_instance = 0; + uint32_t instance = 123; + BACNET_ERROR_CLASS error_class; + BACNET_ERROR_CODE error_code; + + + /* FIXME: we should do a lot more testing here... */ + len = Analog_Input_Encode_Property_APDU(&apdu[0], + instance, + PROP_OBJECT_IDENTIFIER, + BACNET_ARRAY_ALL, &error_class, &error_code); + ct_test(pTest, len >= 0); + len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value); + ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID); + len = decode_object_id(&apdu[len], + (int *) &decoded_type, &decoded_instance); + ct_test(pTest, decoded_type == OBJECT_ANALOG_INPUT); + ct_test(pTest, decoded_instance == instance); + + return; +} + +#ifdef TEST_ANALOG_INPUT +int main(void) +{ + Test *pTest; + bool rc; + + pTest = ct_create("BACnet Analog Input", NULL); + /* individual tests */ + rc = ct_addTestFunction(pTest, testAnalogInput); + assert(rc); + + ct_setStream(pTest, stdout); + ct_run(pTest); + (void) ct_report(pTest); + ct_destroy(pTest); + + return 0; +} +#endif /* TEST_ANALOG_INPUT */ +#endif /* TEST */ diff --git a/bacnet-stack/ports/pic18f6720/av.c b/bacnet-stack/ports/pic18f6720/av.c index 36ff384f..dd6511c8 100644 --- a/bacnet-stack/ports/pic18f6720/av.c +++ b/bacnet-stack/ports/pic18f6720/av.c @@ -186,16 +186,16 @@ int Analog_Value_Encode_Property_APDU(uint8_t * apdu, apdu_len = encode_tagged_enumerated(&apdu[0], EVENT_STATE_NORMAL); break; case PROP_OUT_OF_SERVICE: -#if 0 +#if 0 object_index = Analog_Value_Instance_To_Index(object_instance); - state = Analog_Value_Out_Of_Service[object_index]; + state = Analog_Value_Out_Of_Service[object_index]; #endif apdu_len = encode_tagged_boolean(&apdu[0], false); break; case PROP_UNITS: apdu_len = encode_tagged_enumerated(&apdu[0], UNITS_PERCENT); break; -#if 0 +#if 0 case PROP_PRIORITY_ARRAY: /* Array element zero is the number of elements in the array */ if (array_index == 0) @@ -247,7 +247,7 @@ int Analog_Value_Encode_Property_APDU(uint8_t * apdu, real_value = ANALOG_RELINQUISH_DEFAULT; apdu_len = encode_tagged_real(&apdu[0], real_value); break; -#endif +#endif default: *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_UNKNOWN_PROPERTY; @@ -312,7 +312,7 @@ bool Analog_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; } -#if 0 +#if 0 } else if (value.tag == BACNET_APPLICATION_TAG_NULL) { level = ANALOG_LEVEL_NULL; object_index = @@ -332,13 +332,13 @@ bool Analog_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; } -#endif +#endif } else { *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_INVALID_DATA_TYPE; } break; -#if 0 +#if 0 case PROP_OUT_OF_SERVICE: if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) { object_index = @@ -350,7 +350,7 @@ bool Analog_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, *error_code = ERROR_CODE_INVALID_DATA_TYPE; } break; -#endif +#endif default: *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; diff --git a/bacnet-stack/ports/pic18f6720/bi.c b/bacnet-stack/ports/pic18f6720/bi.c index e3f5fe33..f01eee35 100644 --- a/bacnet-stack/ports/pic18f6720/bi.c +++ b/bacnet-stack/ports/pic18f6720/bi.c @@ -1,232 +1,232 @@ -/************************************************************************** -* -* Copyright (C) 2006 Steve Karg -* -* Permission is hereby granted, free of charge, to any person obtaining -* a copy of this software and associated documentation files (the -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to -* permit persons to whom the Software is furnished to do so, subject to -* the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -* -*********************************************************************/ - -/* Binary Input Objects customize for your use */ - -#include -#include -#include -#include "bacdef.h" -#include "bacdcode.h" -#include "bacenum.h" -#include "config.h" - -#define MAX_BINARY_INPUTS 8 - -static BACNET_BINARY_PV Present_Value[MAX_BINARY_INPUTS]; - -static void Binary_Input_Initialize(void) -{ - static bool initialized = false; - unsigned i; - - if (!initialized) { - initialized = true; - for (i = 0; i < MAX_BINARY_INPUTS; i++) { - Present_Value[i] = BINARY_INACTIVE; - } - } +/************************************************************************** +* +* Copyright (C) 2006 Steve Karg +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*********************************************************************/ + +/* Binary Input Objects customize for your use */ + +#include +#include +#include +#include "bacdef.h" +#include "bacdcode.h" +#include "bacenum.h" +#include "config.h" + +#define MAX_BINARY_INPUTS 8 + +static BACNET_BINARY_PV Present_Value[MAX_BINARY_INPUTS]; + +static void Binary_Input_Initialize(void) +{ + static bool initialized = false; + unsigned i; + + if (!initialized) { + initialized = true; + for (i = 0; i < MAX_BINARY_INPUTS; i++) { + Present_Value[i] = BINARY_INACTIVE; + } + } } - -/* we simply have 0-n object instances. */ -bool Binary_Input_Valid_Instance(uint32_t object_instance) -{ - if (object_instance < MAX_BINARY_INPUTS) - return true; - - return false; -} - -/* we simply have 0-n object instances. */ -unsigned Binary_Input_Count(void) -{ - return MAX_BINARY_INPUTS; -} - -/* we simply have 0-n object instances.*/ -uint32_t Binary_Input_Index_To_Instance(unsigned index) -{ - return index; -} - -/* we simply have 0-n object instances. Yours might be */ -/* more complex, and then you need to return the index */ -/* that correlates to the correct instance number */ -unsigned Binary_Input_Instance_To_Index(uint32_t object_instance) -{ - unsigned index = MAX_BINARY_INPUTS; - - if (object_instance < MAX_BINARY_INPUTS) - index = object_instance; - - return index; -} - -static BACNET_BINARY_PV Binary_Input_Present_Value(uint32_t - object_instance) -{ - BACNET_BINARY_PV value = BINARY_INACTIVE; - unsigned index = 0; - - Binary_Input_Initialize(); - index = Binary_Input_Instance_To_Index(object_instance); - if (index < MAX_BINARY_INPUTS) { - value = Present_Value[index]; - } - - return value; -} - -char *Binary_Input_Name(uint32_t object_instance) -{ - static char text_string[16] = ""; /* okay for single thread */ - - if (object_instance < MAX_BINARY_INPUTS) { - sprintf(text_string, "BI-%lu", object_instance); - return text_string; - } - - return NULL; -} - -/* return apdu length, or -1 on error */ -/* assumption - object already exists, and has been bounds checked */ -int Binary_Input_Encode_Property_APDU(uint8_t * apdu, - uint32_t object_instance, - BACNET_PROPERTY_ID property, - int32_t array_index, - BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code) -{ - int apdu_len = 0; /* return value */ - BACNET_BIT_STRING bit_string; - BACNET_CHARACTER_STRING char_string; - BACNET_POLARITY polarity = POLARITY_NORMAL; - BACNET_BINARY_PV value = BINARY_INACTIVE; - - - (void) array_index; - Binary_Input_Initialize(); - switch (property) { - case PROP_OBJECT_IDENTIFIER: - apdu_len = encode_tagged_object_id(&apdu[0], OBJECT_BINARY_INPUT, - object_instance); - break; - case PROP_OBJECT_NAME: - case PROP_DESCRIPTION: - /* note: object name must be unique in our device */ - characterstring_init_ansi(&char_string, - Binary_Input_Name(object_instance)); - apdu_len = encode_tagged_character_string(&apdu[0], &char_string); - break; - case PROP_OBJECT_TYPE: - apdu_len = encode_tagged_enumerated(&apdu[0], OBJECT_BINARY_INPUT); - break; - case PROP_PRESENT_VALUE: - value = Binary_Input_Present_Value(object_instance); - apdu_len = encode_tagged_enumerated(&apdu[0],value); - break; - case PROP_STATUS_FLAGS: - /* note: see the details in the standard on how to use these */ - bitstring_init(&bit_string); - bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); - bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); - bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); - bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); - apdu_len = encode_tagged_bitstring(&apdu[0], &bit_string); - break; - case PROP_EVENT_STATE: - /* note: see the details in the standard on how to use this */ - apdu_len = encode_tagged_enumerated(&apdu[0], EVENT_STATE_NORMAL); - break; - case PROP_OUT_OF_SERVICE: - apdu_len = encode_tagged_boolean(&apdu[0], false); - break; - case PROP_POLARITY: - apdu_len = encode_tagged_enumerated(&apdu[0], polarity); - break; - default: - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_UNKNOWN_PROPERTY; - apdu_len = -1; - break; - } - - return apdu_len; -} - -#ifdef TEST -#include -#include -#include "ctest.h" - -void testBinaryInput(Test * pTest) -{ - uint8_t apdu[MAX_APDU] = { 0 }; - int len = 0; - uint32_t len_value = 0; - uint8_t tag_number = 0; - BACNET_OBJECT_TYPE decoded_type = OBJECT_BINARY_OUTPUT; - uint32_t decoded_instance = 0; - uint32_t instance = 123; - BACNET_ERROR_CLASS error_class; - BACNET_ERROR_CODE error_code; - - - /* FIXME: we should do a lot more testing here... */ - len = Binary_Input_Encode_Property_APDU(&apdu[0], - instance, - PROP_OBJECT_IDENTIFIER, - BACNET_ARRAY_ALL, &error_class, &error_code); - ct_test(pTest, len >= 0); - len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value); - ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID); - len = decode_object_id(&apdu[len], - (int *) &decoded_type, &decoded_instance); - ct_test(pTest, decoded_type == OBJECT_BINARY_INPUT); - ct_test(pTest, decoded_instance == instance); - - return; -} - -#ifdef TEST_BINARY_INPUT -int main(void) -{ - Test *pTest; - bool rc; - - pTest = ct_create("BACnet Binary Input", NULL); - /* individual tests */ - rc = ct_addTestFunction(pTest, testBinaryInput); - assert(rc); - - ct_setStream(pTest, stdout); - ct_run(pTest); - (void) ct_report(pTest); - ct_destroy(pTest); - - return 0; -} -#endif /* TEST_BINARY_INPUT */ -#endif /* TEST */ + +/* we simply have 0-n object instances. */ +bool Binary_Input_Valid_Instance(uint32_t object_instance) +{ + if (object_instance < MAX_BINARY_INPUTS) + return true; + + return false; +} + +/* we simply have 0-n object instances. */ +unsigned Binary_Input_Count(void) +{ + return MAX_BINARY_INPUTS; +} + +/* we simply have 0-n object instances.*/ +uint32_t Binary_Input_Index_To_Instance(unsigned index) +{ + return index; +} + +/* we simply have 0-n object instances. Yours might be */ +/* more complex, and then you need to return the index */ +/* that correlates to the correct instance number */ +unsigned Binary_Input_Instance_To_Index(uint32_t object_instance) +{ + unsigned index = MAX_BINARY_INPUTS; + + if (object_instance < MAX_BINARY_INPUTS) + index = object_instance; + + return index; +} + +static BACNET_BINARY_PV Binary_Input_Present_Value(uint32_t + object_instance) +{ + BACNET_BINARY_PV value = BINARY_INACTIVE; + unsigned index = 0; + + Binary_Input_Initialize(); + index = Binary_Input_Instance_To_Index(object_instance); + if (index < MAX_BINARY_INPUTS) { + value = Present_Value[index]; + } + + return value; +} + +char *Binary_Input_Name(uint32_t object_instance) +{ + static char text_string[16] = ""; /* okay for single thread */ + + if (object_instance < MAX_BINARY_INPUTS) { + sprintf(text_string, "BI-%lu", object_instance); + return text_string; + } + + return NULL; +} + +/* return apdu length, or -1 on error */ +/* assumption - object already exists, and has been bounds checked */ +int Binary_Input_Encode_Property_APDU(uint8_t * apdu, + uint32_t object_instance, + BACNET_PROPERTY_ID property, + int32_t array_index, + BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code) +{ + int apdu_len = 0; /* return value */ + BACNET_BIT_STRING bit_string; + BACNET_CHARACTER_STRING char_string; + BACNET_POLARITY polarity = POLARITY_NORMAL; + BACNET_BINARY_PV value = BINARY_INACTIVE; + + + (void) array_index; + Binary_Input_Initialize(); + switch (property) { + case PROP_OBJECT_IDENTIFIER: + apdu_len = encode_tagged_object_id(&apdu[0], OBJECT_BINARY_INPUT, + object_instance); + break; + case PROP_OBJECT_NAME: + case PROP_DESCRIPTION: + /* note: object name must be unique in our device */ + characterstring_init_ansi(&char_string, + Binary_Input_Name(object_instance)); + apdu_len = encode_tagged_character_string(&apdu[0], &char_string); + break; + case PROP_OBJECT_TYPE: + apdu_len = encode_tagged_enumerated(&apdu[0], OBJECT_BINARY_INPUT); + break; + case PROP_PRESENT_VALUE: + value = Binary_Input_Present_Value(object_instance); + apdu_len = encode_tagged_enumerated(&apdu[0],value); + break; + case PROP_STATUS_FLAGS: + /* note: see the details in the standard on how to use these */ + bitstring_init(&bit_string); + bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); + bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); + bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); + bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); + apdu_len = encode_tagged_bitstring(&apdu[0], &bit_string); + break; + case PROP_EVENT_STATE: + /* note: see the details in the standard on how to use this */ + apdu_len = encode_tagged_enumerated(&apdu[0], EVENT_STATE_NORMAL); + break; + case PROP_OUT_OF_SERVICE: + apdu_len = encode_tagged_boolean(&apdu[0], false); + break; + case PROP_POLARITY: + apdu_len = encode_tagged_enumerated(&apdu[0], polarity); + break; + default: + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_UNKNOWN_PROPERTY; + apdu_len = -1; + break; + } + + return apdu_len; +} + +#ifdef TEST +#include +#include +#include "ctest.h" + +void testBinaryInput(Test * pTest) +{ + uint8_t apdu[MAX_APDU] = { 0 }; + int len = 0; + uint32_t len_value = 0; + uint8_t tag_number = 0; + BACNET_OBJECT_TYPE decoded_type = OBJECT_BINARY_OUTPUT; + uint32_t decoded_instance = 0; + uint32_t instance = 123; + BACNET_ERROR_CLASS error_class; + BACNET_ERROR_CODE error_code; + + + /* FIXME: we should do a lot more testing here... */ + len = Binary_Input_Encode_Property_APDU(&apdu[0], + instance, + PROP_OBJECT_IDENTIFIER, + BACNET_ARRAY_ALL, &error_class, &error_code); + ct_test(pTest, len >= 0); + len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value); + ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID); + len = decode_object_id(&apdu[len], + (int *) &decoded_type, &decoded_instance); + ct_test(pTest, decoded_type == OBJECT_BINARY_INPUT); + ct_test(pTest, decoded_instance == instance); + + return; +} + +#ifdef TEST_BINARY_INPUT +int main(void) +{ + Test *pTest; + bool rc; + + pTest = ct_create("BACnet Binary Input", NULL); + /* individual tests */ + rc = ct_addTestFunction(pTest, testBinaryInput); + assert(rc); + + ct_setStream(pTest, stdout); + ct_run(pTest); + (void) ct_report(pTest); + ct_destroy(pTest); + + return 0; +} +#endif /* TEST_BINARY_INPUT */ +#endif /* TEST */ diff --git a/bacnet-stack/ports/pic18f6720/bv.c b/bacnet-stack/ports/pic18f6720/bv.c index c56158ab..2ff66ddb 100644 --- a/bacnet-stack/ports/pic18f6720/bv.c +++ b/bacnet-stack/ports/pic18f6720/bv.c @@ -1,338 +1,338 @@ -/************************************************************************** -* -* Copyright (C) 2006 Steve Karg -* -* Permission is hereby granted, free of charge, to any person obtaining -* a copy of this software and associated documentation files (the -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to -* permit persons to whom the Software is furnished to do so, subject to -* the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -* -*********************************************************************/ - -/* Binary Value Objects - customize for your use */ - -#include -#include -#include -#include "bacdef.h" -#include "bacdcode.h" -#include "bacenum.h" -#include "config.h" /* the custom stuff */ -#include "wp.h" - -#define MAX_BINARY_VALUES 8 - +/************************************************************************** +* +* Copyright (C) 2006 Steve Karg +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*********************************************************************/ + +/* Binary Value Objects - customize for your use */ + +#include +#include +#include +#include "bacdef.h" +#include "bacdcode.h" +#include "bacenum.h" +#include "config.h" /* the custom stuff */ +#include "wp.h" + +#define MAX_BINARY_VALUES 8 + static BACNET_BINARY_PV Present_Value[MAX_BINARY_VALUES]; - -static void Binary_Value_Initialize(void) -{ - static bool initialized = false; - unsigned i; - - if (!initialized) { - initialized = true; - for (i = 0; i < MAX_BINARY_VALUES; i++) { - Present_Value[i] = BINARY_INACTIVE; - } - } + +static void Binary_Value_Initialize(void) +{ + static bool initialized = false; + unsigned i; + + if (!initialized) { + initialized = true; + for (i = 0; i < MAX_BINARY_VALUES; i++) { + Present_Value[i] = BINARY_INACTIVE; + } + } } - -/* we simply have 0-n object instances. */ -bool Binary_Value_Valid_Instance(uint32_t object_instance) -{ - if (object_instance < MAX_BINARY_VALUES) - return true; - - return false; -} - -/* we simply have 0-n object instances. */ -unsigned Binary_Value_Count(void) -{ - return MAX_BINARY_VALUES; -} - -/* we simply have 0-n object instances. */ -uint32_t Binary_Value_Index_To_Instance(unsigned index) -{ - return index; -} - -/* we simply have 0-n object instances. */ -unsigned Binary_Value_Instance_To_Index(uint32_t object_instance) -{ - unsigned index = MAX_BINARY_VALUES; - - if (object_instance < MAX_BINARY_VALUES) - index = object_instance; - - return index; -} - -static BACNET_BINARY_PV Binary_Value_Present_Value(uint32_t - object_instance) -{ - BACNET_BINARY_PV value = BINARY_INACTIVE; - - Binary_Value_Initialize(); - if (object_instance < MAX_BINARY_VALUES) { - value = Present_Value[object_instance]; - } - - return value; -} - -/* note: the object name must be unique within this device */ -char *Binary_Value_Name(uint32_t object_instance) -{ - static char text_string[16] = ""; /* okay for single thread */ - - if (object_instance < MAX_BINARY_VALUES) { - sprintf(text_string, "BV-%lu", object_instance); - return text_string; - } - - return NULL; -} - -/* return apdu len, or -1 on error */ -int Binary_Value_Encode_Property_APDU(uint8_t * apdu, - uint32_t object_instance, - BACNET_PROPERTY_ID property, - int32_t array_index, - BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code) -{ - int len = 0; - int apdu_len = 0; /* return value */ - BACNET_BIT_STRING bit_string; - BACNET_CHARACTER_STRING char_string; - BACNET_BINARY_PV present_value = BINARY_INACTIVE; - BACNET_POLARITY polarity = POLARITY_NORMAL; - unsigned object_index = 0; - unsigned i = 0; - bool state = false; - - Binary_Value_Initialize(); - switch (property) { - case PROP_OBJECT_IDENTIFIER: - apdu_len = encode_tagged_object_id(&apdu[0], OBJECT_BINARY_VALUE, - object_instance); - break; - /* note: Name and Description don't have to be the same. - You could make Description writable and different */ - case PROP_OBJECT_NAME: - case PROP_DESCRIPTION: - characterstring_init_ansi(&char_string, - Binary_Value_Name(object_instance)); - apdu_len = encode_tagged_character_string(&apdu[0], &char_string); - break; - case PROP_OBJECT_TYPE: - apdu_len = encode_tagged_enumerated(&apdu[0], OBJECT_BINARY_VALUE); - break; - case PROP_PRESENT_VALUE: - present_value = Binary_Value_Present_Value(object_instance); - apdu_len = encode_tagged_enumerated(&apdu[0], present_value); - break; - case PROP_STATUS_FLAGS: - /* note: see the details in the standard on how to use these */ - bitstring_init(&bit_string); - bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); - bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); - bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); - bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); - apdu_len = encode_tagged_bitstring(&apdu[0], &bit_string); - break; - case PROP_EVENT_STATE: - /* note: see the details in the standard on how to use this */ - apdu_len = encode_tagged_enumerated(&apdu[0], EVENT_STATE_NORMAL); - break; - case PROP_OUT_OF_SERVICE: - apdu_len = encode_tagged_boolean(&apdu[0], false); - break; - case PROP_POLARITY: - /* FIXME: figure out the polarity */ - apdu_len = encode_tagged_enumerated(&apdu[0], polarity); - break; - default: - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_UNKNOWN_PROPERTY; - apdu_len = -1; - break; - } - - return apdu_len; -} - -/* returns true if successful */ -bool Binary_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, - BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code) -{ - bool status = false; /* return value */ - unsigned int object_index = 0; - unsigned int priority = 0; - BACNET_BINARY_PV level = BINARY_NULL; + +/* we simply have 0-n object instances. */ +bool Binary_Value_Valid_Instance(uint32_t object_instance) +{ + if (object_instance < MAX_BINARY_VALUES) + return true; + + return false; +} + +/* we simply have 0-n object instances. */ +unsigned Binary_Value_Count(void) +{ + return MAX_BINARY_VALUES; +} + +/* we simply have 0-n object instances. */ +uint32_t Binary_Value_Index_To_Instance(unsigned index) +{ + return index; +} + +/* we simply have 0-n object instances. */ +unsigned Binary_Value_Instance_To_Index(uint32_t object_instance) +{ + unsigned index = MAX_BINARY_VALUES; + + if (object_instance < MAX_BINARY_VALUES) + index = object_instance; + + return index; +} + +static BACNET_BINARY_PV Binary_Value_Present_Value(uint32_t + object_instance) +{ + BACNET_BINARY_PV value = BINARY_INACTIVE; + + Binary_Value_Initialize(); + if (object_instance < MAX_BINARY_VALUES) { + value = Present_Value[object_instance]; + } + + return value; +} + +/* note: the object name must be unique within this device */ +char *Binary_Value_Name(uint32_t object_instance) +{ + static char text_string[16] = ""; /* okay for single thread */ + + if (object_instance < MAX_BINARY_VALUES) { + sprintf(text_string, "BV-%lu", object_instance); + return text_string; + } + + return NULL; +} + +/* return apdu len, or -1 on error */ +int Binary_Value_Encode_Property_APDU(uint8_t * apdu, + uint32_t object_instance, + BACNET_PROPERTY_ID property, + int32_t array_index, + BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code) +{ + int len = 0; + int apdu_len = 0; /* return value */ + BACNET_BIT_STRING bit_string; + BACNET_CHARACTER_STRING char_string; + BACNET_BINARY_PV present_value = BINARY_INACTIVE; + BACNET_POLARITY polarity = POLARITY_NORMAL; + unsigned object_index = 0; + unsigned i = 0; + bool state = false; + + Binary_Value_Initialize(); + switch (property) { + case PROP_OBJECT_IDENTIFIER: + apdu_len = encode_tagged_object_id(&apdu[0], OBJECT_BINARY_VALUE, + object_instance); + break; + /* note: Name and Description don't have to be the same. + You could make Description writable and different */ + case PROP_OBJECT_NAME: + case PROP_DESCRIPTION: + characterstring_init_ansi(&char_string, + Binary_Value_Name(object_instance)); + apdu_len = encode_tagged_character_string(&apdu[0], &char_string); + break; + case PROP_OBJECT_TYPE: + apdu_len = encode_tagged_enumerated(&apdu[0], OBJECT_BINARY_VALUE); + break; + case PROP_PRESENT_VALUE: + present_value = Binary_Value_Present_Value(object_instance); + apdu_len = encode_tagged_enumerated(&apdu[0], present_value); + break; + case PROP_STATUS_FLAGS: + /* note: see the details in the standard on how to use these */ + bitstring_init(&bit_string); + bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); + bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); + bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); + bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); + apdu_len = encode_tagged_bitstring(&apdu[0], &bit_string); + break; + case PROP_EVENT_STATE: + /* note: see the details in the standard on how to use this */ + apdu_len = encode_tagged_enumerated(&apdu[0], EVENT_STATE_NORMAL); + break; + case PROP_OUT_OF_SERVICE: + apdu_len = encode_tagged_boolean(&apdu[0], false); + break; + case PROP_POLARITY: + /* FIXME: figure out the polarity */ + apdu_len = encode_tagged_enumerated(&apdu[0], polarity); + break; + default: + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_UNKNOWN_PROPERTY; + apdu_len = -1; + break; + } + + return apdu_len; +} + +/* returns true if successful */ +bool Binary_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, + BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code) +{ + bool status = false; /* return value */ + unsigned int object_index = 0; + unsigned int priority = 0; + BACNET_BINARY_PV level = BINARY_NULL; int len = 0; BACNET_APPLICATION_DATA_VALUE value; - - if (!Binary_Value_Valid_Instance(wp_data->object_instance)) { - *error_class = ERROR_CLASS_OBJECT; - *error_code = ERROR_CODE_UNKNOWN_OBJECT; - return false; - } - /* decode the some of the request */ + + if (!Binary_Value_Valid_Instance(wp_data->object_instance)) { + *error_class = ERROR_CLASS_OBJECT; + *error_code = ERROR_CODE_UNKNOWN_OBJECT; + return false; + } + /* decode the some of the request */ len = bacapp_decode_application_data(wp_data->application_data, wp_data->application_data_len, &value); /* FIXME: len < application_data_len: more data? */ /* FIXME: len == 0: unable to decode? */ - switch (wp_data->object_property) { - case PROP_PRESENT_VALUE: + switch (wp_data->object_property) { + case PROP_PRESENT_VALUE: if (value.tag == BACNET_APPLICATION_TAG_ENUMERATED) { - priority = wp_data->priority; - /* Command priority 6 is reserved for use by Minimum On/Off - algorithm and may not be used for other purposes in any - object. */ - if (priority && (priority <= BACNET_MAX_PRIORITY) && - (priority != 6 /* reserved */ ) && + priority = wp_data->priority; + /* Command priority 6 is reserved for use by Minimum On/Off + algorithm and may not be used for other purposes in any + object. */ + if (priority && (priority <= BACNET_MAX_PRIORITY) && + (priority != 6 /* reserved */ ) && (value.type.Enumerated >= MIN_BINARY_PV) && (value.type.Enumerated <= MAX_BINARY_PV)) { level = value.type.Enumerated; - object_index = - Binary_Value_Instance_To_Index(wp_data-> - object_instance); - priority--; + object_index = + Binary_Value_Instance_To_Index(wp_data-> + object_instance); + priority--; /* NOTE: this Binary value has no priority array */ - Present_Value[object_index] = level; + Present_Value[object_index] = level; /* Note: you could set the physical output here if we - are the highest priority. - However, if Out of Service is TRUE, then don't set the - physical output. */ - status = true; - } else if (priority == 6) { - /* Command priority 6 is reserved for use by Minimum On/Off - algorithm and may not be used for other purposes in any - object. */ - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; - } else { - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; - } + are the highest priority. + However, if Out of Service is TRUE, then don't set the + physical output. */ + status = true; + } else if (priority == 6) { + /* Command priority 6 is reserved for use by Minimum On/Off + algorithm and may not be used for other purposes in any + object. */ + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } } else if (value.tag == BACNET_APPLICATION_TAG_NULL) { -#if 0 - /* NOTE: this Binary Value has no priority array */ - level = BINARY_NULL; - object_index = - Binary_Value_Instance_To_Index(wp_data->object_instance); - priority = wp_data->priority; - if (priority && (priority <= BACNET_MAX_PRIORITY)) { - priority--; - Binary_Value_Level[object_index][priority] = level; - /* Note: you could set the physical output here to the next - highest priority, or to the relinquish default if no - priorities are set. - However, if Out of Service is TRUE, then don't set the - physical output. This comment may apply to the - main loop (i.e. check out of service before changing output) */ - status = true; - } else { - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; - } -#else - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_INVALID_DATA_TYPE; -#endif +#if 0 + /* NOTE: this Binary Value has no priority array */ + level = BINARY_NULL; + object_index = + Binary_Value_Instance_To_Index(wp_data->object_instance); + priority = wp_data->priority; + if (priority && (priority <= BACNET_MAX_PRIORITY)) { + priority--; + Binary_Value_Level[object_index][priority] = level; + /* Note: you could set the physical output here to the next + highest priority, or to the relinquish default if no + priorities are set. + However, if Out of Service is TRUE, then don't set the + physical output. This comment may apply to the + main loop (i.e. check out of service before changing output) */ + status = true; + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } +#else + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_INVALID_DATA_TYPE; +#endif } else { - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_INVALID_DATA_TYPE; - } - break; -#if 0 - case PROP_OUT_OF_SERVICE: + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_INVALID_DATA_TYPE; + } + break; +#if 0 + case PROP_OUT_OF_SERVICE: if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) { - object_index = - Binary_Value_Instance_To_Index(wp_data->object_instance); + object_index = + Binary_Value_Instance_To_Index(wp_data->object_instance); Binary_Value_Out_Of_Service[object_index] = value.type.Boolean; - status = true; - } else { - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_INVALID_DATA_TYPE; - } - break; -#endif - default: - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; - break; - } - - return status; -} - -#ifdef TEST -#include -#include -#include "ctest.h" - -void testBinary_Value(Test * pTest) -{ - uint8_t apdu[MAX_APDU] = { 0 }; - int len = 0; - uint32_t len_value = 0; - uint8_t tag_number = 0; - BACNET_OBJECT_TYPE decoded_type = OBJECT_BINARY_VALUE; - uint32_t decoded_instance = 0; - uint32_t instance = 123; - BACNET_ERROR_CLASS error_class; - BACNET_ERROR_CODE error_code; - - - len = Binary_Value_Encode_Property_APDU(&apdu[0], - instance, - PROP_OBJECT_IDENTIFIER, - BACNET_ARRAY_ALL, &error_class, &error_code); - ct_test(pTest, len != 0); - len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value); - ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID); - len = decode_object_id(&apdu[len], - (int *) &decoded_type, &decoded_instance); - ct_test(pTest, decoded_type == OBJECT_BINARY_VALUE); - ct_test(pTest, decoded_instance == instance); - - return; -} - -#ifdef TEST_BINARY_VALUE -int main(void) -{ - Test *pTest; - bool rc; - - pTest = ct_create("BACnet Binary_Value", NULL); - /* individual tests */ - rc = ct_addTestFunction(pTest, testBinary_Value); - assert(rc); - - ct_setStream(pTest, stdout); - ct_run(pTest); - (void) ct_report(pTest); - ct_destroy(pTest); - - return 0; -} -#endif /* TEST_BINARY_VALUE */ -#endif /* TEST */ + status = true; + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_INVALID_DATA_TYPE; + } + break; +#endif + default: + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + break; + } + + return status; +} + +#ifdef TEST +#include +#include +#include "ctest.h" + +void testBinary_Value(Test * pTest) +{ + uint8_t apdu[MAX_APDU] = { 0 }; + int len = 0; + uint32_t len_value = 0; + uint8_t tag_number = 0; + BACNET_OBJECT_TYPE decoded_type = OBJECT_BINARY_VALUE; + uint32_t decoded_instance = 0; + uint32_t instance = 123; + BACNET_ERROR_CLASS error_class; + BACNET_ERROR_CODE error_code; + + + len = Binary_Value_Encode_Property_APDU(&apdu[0], + instance, + PROP_OBJECT_IDENTIFIER, + BACNET_ARRAY_ALL, &error_class, &error_code); + ct_test(pTest, len != 0); + len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value); + ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID); + len = decode_object_id(&apdu[len], + (int *) &decoded_type, &decoded_instance); + ct_test(pTest, decoded_type == OBJECT_BINARY_VALUE); + ct_test(pTest, decoded_instance == instance); + + return; +} + +#ifdef TEST_BINARY_VALUE +int main(void) +{ + Test *pTest; + bool rc; + + pTest = ct_create("BACnet Binary_Value", NULL); + /* individual tests */ + rc = ct_addTestFunction(pTest, testBinary_Value); + assert(rc); + + ct_setStream(pTest, stdout); + ct_run(pTest); + (void) ct_report(pTest); + ct_destroy(pTest); + + return 0; +} +#endif /* TEST_BINARY_VALUE */ +#endif /* TEST */ diff --git a/bacnet-stack/ports/pic18f6720/device.c b/bacnet-stack/ports/pic18f6720/device.c index 7fb4a622..d0274b08 100644 --- a/bacnet-stack/ports/pic18f6720/device.c +++ b/bacnet-stack/ports/pic18f6720/device.c @@ -186,7 +186,7 @@ bool Device_Object_List_Identifier(unsigned array_index, /* normalize the index since we know it is not the previous objects */ /* array index starts at 1 */ - object_index = array_index - 1; + object_index = array_index - 1; /* 1 for the device object */ object_count = 1; /* FIXME: add objects as needed */ @@ -538,10 +538,10 @@ bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, if (len <= 20) { /* FIXME: set the name */ /* Display_Set_Name( - characterstring_value(&value.type.Character_String)); */ - /* FIXME: All the object names in a device must be unique. - Disallow setting the Device Object Name to any objects in - the device. */ + characterstring_value(&value.type.Character_String)); */ + /* FIXME: All the object names in a device must be unique. + Disallow setting the Device Object Name to any objects in + the device. */ } else { *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY; diff --git a/bacnet-stack/ports/pic18f6720/h_rp.c b/bacnet-stack/ports/pic18f6720/h_rp.c index 01df2e86..f3998e53 100644 --- a/bacnet-stack/ports/pic18f6720/h_rp.c +++ b/bacnet-stack/ports/pic18f6720/h_rp.c @@ -98,78 +98,78 @@ void handler_read_property(uint8_t * service_request, } } break; - case OBJECT_ANALOG_INPUT: - if (Analog_Input_Valid_Instance(data.object_instance)) { - len = Analog_Input_Encode_Property_APDU(&Temp_Buf[0], - data.object_instance, - data.object_property, - data.array_index, &error_class, &error_code); - if (len >= 0) { - /* encode the APDU portion of the packet */ - data.application_data = &Temp_Buf[0]; - data.application_data_len = len; - /* FIXME: probably need a length limitation sent with encode */ - len = - rp_ack_encode_apdu(&Handler_Transmit_Buffer - [pdu_len], service_data->invoke_id, &data); - error = false; - } - } - break; - case OBJECT_BINARY_INPUT: - if (Binary_Input_Valid_Instance(data.object_instance)) { - len = Binary_Input_Encode_Property_APDU(&Temp_Buf[0], - data.object_instance, - data.object_property, - data.array_index, &error_class, &error_code); - if (len >= 0) { - /* encode the APDU portion of the packet */ - data.application_data = &Temp_Buf[0]; - data.application_data_len = len; - /* FIXME: probably need a length limitation sent with encode */ - len = - rp_ack_encode_apdu(&Handler_Transmit_Buffer - [pdu_len], service_data->invoke_id, &data); - error = false; - } - } - break; - case OBJECT_BINARY_VALUE: - if (Binary_Value_Valid_Instance(data.object_instance)) { - len = Binary_Value_Encode_Property_APDU(&Temp_Buf[0], - data.object_instance, - data.object_property, - data.array_index, &error_class, &error_code); - if (len >= 0) { - /* encode the APDU portion of the packet */ - data.application_data = &Temp_Buf[0]; - data.application_data_len = len; - /* FIXME: probably need a length limitation sent with encode */ - len = - rp_ack_encode_apdu(&Handler_Transmit_Buffer - [pdu_len], service_data->invoke_id, &data); - error = false; - } - } - break; - case OBJECT_ANALOG_VALUE: - if (Analog_Value_Valid_Instance(data.object_instance)) { - len = Analog_Value_Encode_Property_APDU(&Temp_Buf[0], - data.object_instance, - data.object_property, - data.array_index, &error_class, &error_code); - if (len >= 0) { - /* encode the APDU portion of the packet */ - data.application_data = &Temp_Buf[0]; - data.application_data_len = len; - /* FIXME: probably need a length limitation sent with encode */ - len = - rp_ack_encode_apdu(&Handler_Transmit_Buffer - [pdu_len], service_data->invoke_id, &data); - error = false; - } - } - break; + case OBJECT_ANALOG_INPUT: + if (Analog_Input_Valid_Instance(data.object_instance)) { + len = Analog_Input_Encode_Property_APDU(&Temp_Buf[0], + data.object_instance, + data.object_property, + data.array_index, &error_class, &error_code); + if (len >= 0) { + /* encode the APDU portion of the packet */ + data.application_data = &Temp_Buf[0]; + data.application_data_len = len; + /* FIXME: probably need a length limitation sent with encode */ + len = + rp_ack_encode_apdu(&Handler_Transmit_Buffer + [pdu_len], service_data->invoke_id, &data); + error = false; + } + } + break; + case OBJECT_BINARY_INPUT: + if (Binary_Input_Valid_Instance(data.object_instance)) { + len = Binary_Input_Encode_Property_APDU(&Temp_Buf[0], + data.object_instance, + data.object_property, + data.array_index, &error_class, &error_code); + if (len >= 0) { + /* encode the APDU portion of the packet */ + data.application_data = &Temp_Buf[0]; + data.application_data_len = len; + /* FIXME: probably need a length limitation sent with encode */ + len = + rp_ack_encode_apdu(&Handler_Transmit_Buffer + [pdu_len], service_data->invoke_id, &data); + error = false; + } + } + break; + case OBJECT_BINARY_VALUE: + if (Binary_Value_Valid_Instance(data.object_instance)) { + len = Binary_Value_Encode_Property_APDU(&Temp_Buf[0], + data.object_instance, + data.object_property, + data.array_index, &error_class, &error_code); + if (len >= 0) { + /* encode the APDU portion of the packet */ + data.application_data = &Temp_Buf[0]; + data.application_data_len = len; + /* FIXME: probably need a length limitation sent with encode */ + len = + rp_ack_encode_apdu(&Handler_Transmit_Buffer + [pdu_len], service_data->invoke_id, &data); + error = false; + } + } + break; + case OBJECT_ANALOG_VALUE: + if (Analog_Value_Valid_Instance(data.object_instance)) { + len = Analog_Value_Encode_Property_APDU(&Temp_Buf[0], + data.object_instance, + data.object_property, + data.array_index, &error_class, &error_code); + if (len >= 0) { + /* encode the APDU portion of the packet */ + data.application_data = &Temp_Buf[0]; + data.application_data_len = len; + /* FIXME: probably need a length limitation sent with encode */ + len = + rp_ack_encode_apdu(&Handler_Transmit_Buffer + [pdu_len], service_data->invoke_id, &data); + error = false; + } + } + break; default: break; } diff --git a/bacnet-stack/ports/pic18f6720/mstp.c b/bacnet-stack/ports/pic18f6720/mstp.c index e586c210..47a3d6bd 100644 --- a/bacnet-stack/ports/pic18f6720/mstp.c +++ b/bacnet-stack/ports/pic18f6720/mstp.c @@ -770,7 +770,7 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t * mstp_port) mstp_port->DataLength); break; case FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY: - /*mstp_port->ReplyPostponedTimer = 0; */ + /*mstp_port->ReplyPostponedTimer = 0; */ /* indicate successful reception to the higher layers */ dlmstp_put_receive(mstp_port->SourceAddress, (uint8_t *) & mstp_port->InputBuffer[0], @@ -1217,12 +1217,12 @@ void MSTP_Init(volatile struct mstp_port_struct_t *mstp_port) mstp_port->ReceivedValidFrame = false; mstp_port->RetryCount = 0; mstp_port->SilenceTimer = 0; -/* mstp_port->ReplyPostponedTimer = 0; */ +/* mstp_port->ReplyPostponedTimer = 0; */ mstp_port->SoleMaster = false; mstp_port->SourceAddress = 0; mstp_port->TokenCount = 0; #if 0 - /* these are adjustable, so should already be set */ + /* these are adjustable, so should already be set */ mstp_port->Nmax_info_frames = DEFAULT_MAX_INFO_FRAMES; mstp_port->Nmax_master = DEFAULT_MAX_MASTER; #endif diff --git a/bacnet-stack/ports/pic18f6720/mstp.h b/bacnet-stack/ports/pic18f6720/mstp.h index 3a658cdd..7ff3e79e 100644 --- a/bacnet-stack/ports/pic18f6720/mstp.h +++ b/bacnet-stack/ports/pic18f6720/mstp.h @@ -162,7 +162,7 @@ struct mstp_port_struct_t { /* Machine when a Data Expecting Reply Answer activity is completed. */ /* note: we always send a reply postponed since a message other than the reply may be in the transmit queue */ -/* uint16_t ReplyPostponedTimer; */ +/* uint16_t ReplyPostponedTimer; */ /* Used to store the Source Address of a received frame. */ uint8_t SourceAddress; diff --git a/bacnet-stack/ports/pic18f6720/pic18f6720.tpi b/bacnet-stack/ports/pic18f6720/pic18f6720.tpi index 5370f652..acc13425 100644 --- a/bacnet-stack/ports/pic18f6720/pic18f6720.tpi +++ b/bacnet-stack/ports/pic18f6720/pic18f6720.tpi @@ -1,408 +1,408 @@ -PICS 0 -BACnet Protocol Implementation Conformance Statement - --- --- --- BACnet Stack Demo --- bacnet.sourceforge.net --- Author: Steve Karg --- --- -Vendor Name: "ASHRAE" -Product Name: "PIC18F6720 Device" -Product Model Number: "GNU Demo" -Product Description: "BACnet Demo" - -BIBBs Supported: -{ --- The BIBBs may be any of: --- DS-RP-A - DS-RP-B --- DS-RPM-A DS-RPM-B --- DS-RPC-A DS-RPC-B --- DS-WP-A - DS-WP-B --- DS-WPM-A DS-WPM-B --- DS-COV-A DS-COV-B --- DS-COVP-A DS-COVP-B --- DS-COVU-A DS-COVU-B --- AE-N-A AE-N-I-B AE-N-E-B --- AE-ACK-A AE-ACK-B --- AE-ASUM-A AE-ASUM-B --- AE-ESUM-A AE-ESUM-B --- AE-INFO-A AE-INFO-B --- AE-LS-A AE-LS-B --- SCHED-A SCHED-I-B SCHED-E-B --- T-VMT-A T-VMT-I-B T-VMT-E-B --- T-ATR-A T-ATR-B --- DM-DDB-A - DM-DDB-B --- DM-DOB-A --- DM-DOB-B --- DM-DCC-A - DM-DCC-B --- DM-PT-A DM-PT-B --- DM-TM-A DM-TM-B --- DM-TS-A --- DM-TS-B --- DM-UTC-A --- DM-UTC-B --- DM-RD-A - DM-RD-B --- DM-BR-A DM-BR-B --- DM-R-A DM-R-B --- DM-LM-A DM-LM-B --- DM-OCD-A DM-OCD-B --- DM-VT-A DM-VT-B --- NM-CE-A NM-CE-B --- NM-RC-A NM-RC-B -} - -BACnet Standard Application Services Supported: -{ --- AcknowledgeAlarm Initiate Execute --- ConfirmedCOVNotification Initiate Execute --- UnconfirmedCOVNotification Initiate --- ConfirmedEventNotification Initiate Execute --- UnconfirmedEventNotification Initiate Execute --- GetAlarmSummary Initiate Execute --- GetEnrollmentSummary Initiate Execute --- AtomicReadFile Initiate Execute --- AtomicWriteFile Initiate Execute --- AddListElement Initiate Execute --- RemoveListElement Initiate Execute --- CreateObject Initiate Execute --- DeleteObject Initiate Execute - ReadProperty Execute --- ReadpropertyConditional Initiate Execute --- ReadPropertyMultiple Initiate Execute --- SubscribeCOV Initiate Execute - WriteProperty Execute --- WritePropertyMultiple Initiate Execute - DeviceCommunicationControl Execute --- ConfirmedPrivateTransfer Initiate Execute --- UnconfirmedPrivateTransfer Initiate Execute --- TimeSynchronization Initiate Execute --- Who-Has Execute --- I-Have Initiate - Who-Is Execute - I-Am Initiate --- VT-Open Initiate Execute --- VT-Close Initiate Execute --- VT-Data Initiate Execute --- ConfirmedTextMessage Initiate Execute --- UnconfirmedTextMessage Initiate Execute - ReinitializeDevice Execute --- RequestKey Initiate Execute --- Authenticate Initiate Execute --- UTCTimeSynchronization Initiate Execute --- ReadRange Initiate Execute --- GetEventInformation Initiate Execute --- LifeSafetyOperation Initiate Execute --- SubscribeCOVProperty Initiate Execute --- RequestKey Initiate Execute --- Authenticate Initiate Execute -} - -Standard Object-Types Supported: -{ - Analog Input --- Analog Output - Analog Value --- Averaging Createable Deleteable - Binary Input --- Binary Output - Binary Value --- Calendar Createable Deleteable --- Command Createable Deleteable - Device --- Event Enrollment Createable Deleteable --- File --- Group Createable Deleteable --- Loop Createable Deleteable --- Multi-state Input Createable Deleteable --- Multi-state Output --- Multi-state Value Createable Deleteable --- Notification Class Createable Deleteable --- Program Createable Deleteable --- Schedule Createable Deleteable --- Life Safety Point --- Life Safety Zone Createable Deleteable --- Trend Log Createable Deleteable --- Load Control -} - -Data Link Layer Option: -{ --- ISO 8802-3, 10BASE5 --- ISO 8802-3, 10BASE2 --- ISO 8802-3, 10BASET --- ISO 8802-3, Fiber --- ARCNET, coax star --- ARCNET, coax bus --- ARCNET, twisted pair star --- ARCNET, twisted pair bus --- ARCNET, fiber star -MS/TP master. Baud rate(s): 9600, 19200, 38400, 76800 --- MS/TP slave. Baud rate(s): 9600 --- Point-To-Point. Modem, Baud rate(s): 14.4k --- Point-To-Point. Modem, Autobaud range: 9600 to 28.8k --- BACnet/IP, 'DIX' Ethernet --- BACnet/IP, PPP --- Other -} - -Character Sets Supported: -{ - ANSI X3.4 --- Other Character Sets not supported --- IBM/Microsoft DBCS --- JIS C 6226 --- ISO 10646 (ICS-4) --- ISO 10646 (UCS2) -} - -Special Functionality: -{ - Maximum APDU size in octets: 50 --- Maximum APDU size in octets: 480 --- Segmented Requests Supported, window size: 1 --- Segmented Responses Supported, window size: 1 --- Router -} - -List of Objects in test device: -{ - { - object-identifier: (device,12345) - object-name: "PIC18F6720 Device" - object-type: device - system-status: operational - vendor-name: "ASHRAE" - vendor-identifier: 0 - model-name: "GNU Demo" - firmware-revision: "1.00" - application-software-version: "1.00" - location: "USA" - description: "BACnet Demo" - protocol-version: 1 - protocol-conformance-class: 1 - protocol-services-supported: (T,F,F,F,F,F,F,F,F,F,F,F,T,F,F,T,F,T,F,F,T,F,F, -F,F,F,F,F,F,F,F,F,F,F,T,F,F,F,F,F) - protocol-object-types-supported: (T,F,T,T,F,T,F,F,T,F,F,F,F,F,F,F,F,F,F,F,F, -F,F,F,F,F,F,F,F,F,F,F) - max-apdu-length-accepted: 50 - segmentation-supported: no-segmentation - local-time: ? - local-date: ? - utc-offset: ? - daylight-savings-status: ? - database-revision: ? - apdu-timeout: 60000 - number-of-apdu-retries: 0 - max-master: 127 - max-info-frames: 1 - device-address-binding: ? - object-list: { - (device,12345),(binary-value,0),(binary-value,1), - (binary-value,2),(binary-value,3),(binary-value,4), - (binary-value,5),(binary-value,6),(binary-value,7), - (analog-value,0),(analog-value,1),(analog-value,2), - (analog-value,3),(analog-input,0),(analog-input,1), - (binary-input,0),(binary-input,1),(binary-input,2), - (binary-input,3) - } - }, - { - object-identifier: (binary-value,0) - object-name: "BV-0" - object-type: binary-value - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - description: "BV-0" - }, - { - object-identifier: (binary-value,1) - object-name: "BV-1" - object-type: binary-value - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - description: "BV-1" - }, - { - object-identifier: (binary-value,2) - object-name: "BV-2" - object-type: binary-value - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - description: "BV-2" - }, - { - object-identifier: (binary-value,3) - object-name: "BV-3" - object-type: binary-value - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - description: "BV-3" - }, - { - object-identifier: (binary-value,4) - object-name: "BV-4" - object-type: binary-value - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - description: "BV-4" - }, - { - object-identifier: (binary-value,5) - object-name: "BV-5" - object-type: binary-value - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - description: "BV-5" - }, - { - object-identifier: (binary-value,6) - object-name: "BV-6" - object-type: binary-value - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - description: "BV-6" - }, - { - object-identifier: (binary-value,7) - object-name: "BV-7" - object-type: binary-value - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - description: "BV-7" - }, - { - object-identifier: (analog-value,0) - object-name: "AV-0" - object-type: analog-value - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - units: percent - description: "AV-0" - }, - { - object-identifier: (analog-value,1) - object-name: "AV-1" - object-type: analog-value - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - units: percent - description: "AV-1" - }, - { - object-identifier: (analog-value,2) - object-name: "AV-2" - object-type: analog-value - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - units: percent - description: "AV-2" - }, - { - object-identifier: (analog-value,3) - object-name: "AV-3" - object-type: analog-value - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - units: percent - description: "AV-3" - }, - { - object-identifier: (analog-input,0) - object-name: "AI-0" - object-type: analog-input - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - units: percent - description: "AI-0" - }, - { - object-identifier: (analog-input,1) - object-name: "AI-1" - object-type: analog-input - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - units: percent - description: "AI-1" - }, - { - object-identifier: (binary-input,0) - object-name: "BI-0" - object-type: binary-input - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - polarity: normal - description: "BI-0" - }, - { - object-identifier: (binary-input,1) - object-name: "BI-1" - object-type: binary-input - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - polarity: normal - description: "BI-1" - }, - { - object-identifier: (binary-input,2) - object-name: "BI-2" - object-type: binary-input - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - polarity: normal - description: "BI-2" - }, - { - object-identifier: (binary-input,3) - object-name: "BI-3" - object-type: binary-input - present-value: ? - status-flags: (F,F,F,F) - event-state: normal - out-of-service: F - polarity: normal - description: "BI-3" - } -} - -End of BACnet Protocol Implementation Conformance Statement +PICS 0 +BACnet Protocol Implementation Conformance Statement + +-- +-- +-- BACnet Stack Demo +-- bacnet.sourceforge.net +-- Author: Steve Karg +-- +-- +Vendor Name: "ASHRAE" +Product Name: "PIC18F6720 Device" +Product Model Number: "GNU Demo" +Product Description: "BACnet Demo" + +BIBBs Supported: +{ +-- The BIBBs may be any of: +-- DS-RP-A + DS-RP-B +-- DS-RPM-A DS-RPM-B +-- DS-RPC-A DS-RPC-B +-- DS-WP-A + DS-WP-B +-- DS-WPM-A DS-WPM-B +-- DS-COV-A DS-COV-B +-- DS-COVP-A DS-COVP-B +-- DS-COVU-A DS-COVU-B +-- AE-N-A AE-N-I-B AE-N-E-B +-- AE-ACK-A AE-ACK-B +-- AE-ASUM-A AE-ASUM-B +-- AE-ESUM-A AE-ESUM-B +-- AE-INFO-A AE-INFO-B +-- AE-LS-A AE-LS-B +-- SCHED-A SCHED-I-B SCHED-E-B +-- T-VMT-A T-VMT-I-B T-VMT-E-B +-- T-ATR-A T-ATR-B +-- DM-DDB-A + DM-DDB-B +-- DM-DOB-A +-- DM-DOB-B +-- DM-DCC-A + DM-DCC-B +-- DM-PT-A DM-PT-B +-- DM-TM-A DM-TM-B +-- DM-TS-A +-- DM-TS-B +-- DM-UTC-A +-- DM-UTC-B +-- DM-RD-A + DM-RD-B +-- DM-BR-A DM-BR-B +-- DM-R-A DM-R-B +-- DM-LM-A DM-LM-B +-- DM-OCD-A DM-OCD-B +-- DM-VT-A DM-VT-B +-- NM-CE-A NM-CE-B +-- NM-RC-A NM-RC-B +} + +BACnet Standard Application Services Supported: +{ +-- AcknowledgeAlarm Initiate Execute +-- ConfirmedCOVNotification Initiate Execute +-- UnconfirmedCOVNotification Initiate +-- ConfirmedEventNotification Initiate Execute +-- UnconfirmedEventNotification Initiate Execute +-- GetAlarmSummary Initiate Execute +-- GetEnrollmentSummary Initiate Execute +-- AtomicReadFile Initiate Execute +-- AtomicWriteFile Initiate Execute +-- AddListElement Initiate Execute +-- RemoveListElement Initiate Execute +-- CreateObject Initiate Execute +-- DeleteObject Initiate Execute + ReadProperty Execute +-- ReadpropertyConditional Initiate Execute +-- ReadPropertyMultiple Initiate Execute +-- SubscribeCOV Initiate Execute + WriteProperty Execute +-- WritePropertyMultiple Initiate Execute + DeviceCommunicationControl Execute +-- ConfirmedPrivateTransfer Initiate Execute +-- UnconfirmedPrivateTransfer Initiate Execute +-- TimeSynchronization Initiate Execute +-- Who-Has Execute +-- I-Have Initiate + Who-Is Execute + I-Am Initiate +-- VT-Open Initiate Execute +-- VT-Close Initiate Execute +-- VT-Data Initiate Execute +-- ConfirmedTextMessage Initiate Execute +-- UnconfirmedTextMessage Initiate Execute + ReinitializeDevice Execute +-- RequestKey Initiate Execute +-- Authenticate Initiate Execute +-- UTCTimeSynchronization Initiate Execute +-- ReadRange Initiate Execute +-- GetEventInformation Initiate Execute +-- LifeSafetyOperation Initiate Execute +-- SubscribeCOVProperty Initiate Execute +-- RequestKey Initiate Execute +-- Authenticate Initiate Execute +} + +Standard Object-Types Supported: +{ + Analog Input +-- Analog Output + Analog Value +-- Averaging Createable Deleteable + Binary Input +-- Binary Output + Binary Value +-- Calendar Createable Deleteable +-- Command Createable Deleteable + Device +-- Event Enrollment Createable Deleteable +-- File +-- Group Createable Deleteable +-- Loop Createable Deleteable +-- Multi-state Input Createable Deleteable +-- Multi-state Output +-- Multi-state Value Createable Deleteable +-- Notification Class Createable Deleteable +-- Program Createable Deleteable +-- Schedule Createable Deleteable +-- Life Safety Point +-- Life Safety Zone Createable Deleteable +-- Trend Log Createable Deleteable +-- Load Control +} + +Data Link Layer Option: +{ +-- ISO 8802-3, 10BASE5 +-- ISO 8802-3, 10BASE2 +-- ISO 8802-3, 10BASET +-- ISO 8802-3, Fiber +-- ARCNET, coax star +-- ARCNET, coax bus +-- ARCNET, twisted pair star +-- ARCNET, twisted pair bus +-- ARCNET, fiber star +MS/TP master. Baud rate(s): 9600, 19200, 38400, 76800 +-- MS/TP slave. Baud rate(s): 9600 +-- Point-To-Point. Modem, Baud rate(s): 14.4k +-- Point-To-Point. Modem, Autobaud range: 9600 to 28.8k +-- BACnet/IP, 'DIX' Ethernet +-- BACnet/IP, PPP +-- Other +} + +Character Sets Supported: +{ + ANSI X3.4 +-- Other Character Sets not supported +-- IBM/Microsoft DBCS +-- JIS C 6226 +-- ISO 10646 (ICS-4) +-- ISO 10646 (UCS2) +} + +Special Functionality: +{ + Maximum APDU size in octets: 50 +-- Maximum APDU size in octets: 480 +-- Segmented Requests Supported, window size: 1 +-- Segmented Responses Supported, window size: 1 +-- Router +} + +List of Objects in test device: +{ + { + object-identifier: (device,12345) + object-name: "PIC18F6720 Device" + object-type: device + system-status: operational + vendor-name: "ASHRAE" + vendor-identifier: 0 + model-name: "GNU Demo" + firmware-revision: "1.00" + application-software-version: "1.00" + location: "USA" + description: "BACnet Demo" + protocol-version: 1 + protocol-conformance-class: 1 + protocol-services-supported: (T,F,F,F,F,F,F,F,F,F,F,F,T,F,F,T,F,T,F,F,T,F,F, +F,F,F,F,F,F,F,F,F,F,F,T,F,F,F,F,F) + protocol-object-types-supported: (T,F,T,T,F,T,F,F,T,F,F,F,F,F,F,F,F,F,F,F,F, +F,F,F,F,F,F,F,F,F,F,F) + max-apdu-length-accepted: 50 + segmentation-supported: no-segmentation + local-time: ? + local-date: ? + utc-offset: ? + daylight-savings-status: ? + database-revision: ? + apdu-timeout: 60000 + number-of-apdu-retries: 0 + max-master: 127 + max-info-frames: 1 + device-address-binding: ? + object-list: { + (device,12345),(binary-value,0),(binary-value,1), + (binary-value,2),(binary-value,3),(binary-value,4), + (binary-value,5),(binary-value,6),(binary-value,7), + (analog-value,0),(analog-value,1),(analog-value,2), + (analog-value,3),(analog-input,0),(analog-input,1), + (binary-input,0),(binary-input,1),(binary-input,2), + (binary-input,3) + } + }, + { + object-identifier: (binary-value,0) + object-name: "BV-0" + object-type: binary-value + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + description: "BV-0" + }, + { + object-identifier: (binary-value,1) + object-name: "BV-1" + object-type: binary-value + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + description: "BV-1" + }, + { + object-identifier: (binary-value,2) + object-name: "BV-2" + object-type: binary-value + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + description: "BV-2" + }, + { + object-identifier: (binary-value,3) + object-name: "BV-3" + object-type: binary-value + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + description: "BV-3" + }, + { + object-identifier: (binary-value,4) + object-name: "BV-4" + object-type: binary-value + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + description: "BV-4" + }, + { + object-identifier: (binary-value,5) + object-name: "BV-5" + object-type: binary-value + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + description: "BV-5" + }, + { + object-identifier: (binary-value,6) + object-name: "BV-6" + object-type: binary-value + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + description: "BV-6" + }, + { + object-identifier: (binary-value,7) + object-name: "BV-7" + object-type: binary-value + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + description: "BV-7" + }, + { + object-identifier: (analog-value,0) + object-name: "AV-0" + object-type: analog-value + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + units: percent + description: "AV-0" + }, + { + object-identifier: (analog-value,1) + object-name: "AV-1" + object-type: analog-value + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + units: percent + description: "AV-1" + }, + { + object-identifier: (analog-value,2) + object-name: "AV-2" + object-type: analog-value + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + units: percent + description: "AV-2" + }, + { + object-identifier: (analog-value,3) + object-name: "AV-3" + object-type: analog-value + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + units: percent + description: "AV-3" + }, + { + object-identifier: (analog-input,0) + object-name: "AI-0" + object-type: analog-input + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + units: percent + description: "AI-0" + }, + { + object-identifier: (analog-input,1) + object-name: "AI-1" + object-type: analog-input + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + units: percent + description: "AI-1" + }, + { + object-identifier: (binary-input,0) + object-name: "BI-0" + object-type: binary-input + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + polarity: normal + description: "BI-0" + }, + { + object-identifier: (binary-input,1) + object-name: "BI-1" + object-type: binary-input + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + polarity: normal + description: "BI-1" + }, + { + object-identifier: (binary-input,2) + object-name: "BI-2" + object-type: binary-input + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + polarity: normal + description: "BI-2" + }, + { + object-identifier: (binary-input,3) + object-name: "BI-3" + object-type: binary-input + present-value: ? + status-flags: (F,F,F,F) + event-state: normal + out-of-service: F + polarity: normal + description: "BI-3" + } +} + +End of BACnet Protocol Implementation Conformance Statement diff --git a/bacnet-stack/ports/pic18f6720/readme.txt b/bacnet-stack/ports/pic18f6720/readme.txt index 8692000e..c5095c69 100644 --- a/bacnet-stack/ports/pic18f6720/readme.txt +++ b/bacnet-stack/ports/pic18f6720/readme.txt @@ -1,44 +1,44 @@ -BACnet Stack - SourceForge.net -Build for MPLAB IDE - -These are some settings that are important when building -the BACnet Stack using MPLAB IDE and MCC18 Compiler, - -1. Add the files to the project that you need: -abort.c, apdu.c, bacapp.c, bacdcode.c, bacerror.c, -bacstr.c, crc.c, datetime.c, dcc.c, iam.c, -npdu.c, rd.c, reject.c, rp.c, whois.c, wp.c - -From ports/picxx: isr.c, main.c, rs485.c, mstp.c, dlmstp.c - -From demo/object/: device.c or dev_tiny.c -objects as needed: ai.c, ao.c, etc. - -From demo/handler/: txbuf.c, h_dcc.c, h_rd.c, h_rp.c or h_rp_tiny.c -Additional handlers as needed: h_wp.c - -2. Project->Options->Project - -General Tab: Include Path: -C:\code\bacnet-stack\;C:\code\bacnet-stack\demo\handler\;C:\code\bacnet-stack\demo\object\;C:\code\bacnet-stack\ports\pic18f6720\ - -MPLAB C18 Tab: Memory Model: -Code: Large Code Model -Data: Large Data Model -Stack: Multi-bank Model - -MPLAB C18 Tab: General: Macro Definitions: -PRINT_ENABLED=0 -BACDL_MSTP=1 -TSM_ENABLED=0 -BIG_ENDIAN=0 - -3. The linker script must reserve some extra stack space. - -//DATABANK NAME=gpr12 START=0xC00 END=0xCFF -//DATABANK NAME=gpr13 START=0xD00 END=0xDFF -DATABANK NAME=stackreg START=0xC00 END=0xDFF PROTECTED - -//STACK SIZE=0x100 RAM=gpr13 -STACK SIZE=0x200 RAM=stackreg - +BACnet Stack - SourceForge.net +Build for MPLAB IDE + +These are some settings that are important when building +the BACnet Stack using MPLAB IDE and MCC18 Compiler, + +1. Add the files to the project that you need: +abort.c, apdu.c, bacapp.c, bacdcode.c, bacerror.c, +bacstr.c, crc.c, datetime.c, dcc.c, iam.c, +npdu.c, rd.c, reject.c, rp.c, whois.c, wp.c + +From ports/picxx: isr.c, main.c, rs485.c, mstp.c, dlmstp.c + +From demo/object/: device.c or dev_tiny.c +objects as needed: ai.c, ao.c, etc. + +From demo/handler/: txbuf.c, h_dcc.c, h_rd.c, h_rp.c or h_rp_tiny.c +Additional handlers as needed: h_wp.c + +2. Project->Options->Project + +General Tab: Include Path: +C:\code\bacnet-stack\;C:\code\bacnet-stack\demo\handler\;C:\code\bacnet-stack\demo\object\;C:\code\bacnet-stack\ports\pic18f6720\ + +MPLAB C18 Tab: Memory Model: +Code: Large Code Model +Data: Large Data Model +Stack: Multi-bank Model + +MPLAB C18 Tab: General: Macro Definitions: +PRINT_ENABLED=0 +BACDL_MSTP=1 +TSM_ENABLED=0 +BIG_ENDIAN=0 + +3. The linker script must reserve some extra stack space. + +//DATABANK NAME=gpr12 START=0xC00 END=0xCFF +//DATABANK NAME=gpr13 START=0xD00 END=0xDFF +DATABANK NAME=stackreg START=0xC00 END=0xDFF PROTECTED + +//STACK SIZE=0x100 RAM=gpr13 +STACK SIZE=0x200 RAM=stackreg + diff --git a/bacnet-stack/ports/rtos32/dlmstp.c b/bacnet-stack/ports/rtos32/dlmstp.c index 8775972e..7dcec4a1 100644 --- a/bacnet-stack/ports/rtos32/dlmstp.c +++ b/bacnet-stack/ports/rtos32/dlmstp.c @@ -43,7 +43,7 @@ static uint8_t PDU_Buffer[MAX_MPDU]; static volatile struct mstp_port_struct_t MSTP_Port; void dlmstp_init(char *ifname) -{ +{ (void)ifname; /* initialize buffer */ Receive_Buffer.ready = false; diff --git a/bacnet-stack/ports/win32/MAKEFILE.MAK b/bacnet-stack/ports/win32/MAKEFILE.MAK index 06287917..cd82b241 100644 --- a/bacnet-stack/ports/win32/MAKEFILE.MAK +++ b/bacnet-stack/ports/win32/MAKEFILE.MAK @@ -1,151 +1,151 @@ -# -# Simple makefile to build an RTB executable for RTOS-32 -# -# This makefile assumes Borland bcc32 development environment -# on Windows NT/9x/2000/XP -# - -!ifndef BORLAND_DIR -BORLAND_DIR_Not_Defined: - @echo . - @echo You must define environment variable BORLAND_DIR to compile. -!endif - -PRODUCT = bacnet -PRODUCT_EXE = $(PRODUCT).exe - -# Choose the Data Link Layer to Enable -DEFINES = -DBACDL_BIP=1;TSM_ENABLED=1;BIG_ENDIAN=0 - -SRCS = main.c bip-init.c \ - ..\..\bip.c \ - ..\..\demo\handler\h_iam.c \ - ..\..\demo\handler\h_whois.c \ - ..\..\demo\handler\h_wp.c \ - ..\..\demo\handler\h_rp.c \ - ..\..\demo\handler\h_rp_a.c \ - ..\..\demo\handler\noserv.c \ - ..\..\demo\handler\txbuf.c \ - ..\..\demo\handler\s_rp.c \ - ..\..\demo\handler\s_whois.c \ - ..\..\bacdcode.c \ - ..\..\bacapp.c \ - ..\..\bacstr.c \ - ..\..\bactext.c \ - ..\..\indtext.c \ - ..\..\bigend.c \ - ..\..\whois.c \ - ..\..\iam.c \ - ..\..\dcc.c \ - ..\..\rp.c \ - ..\..\wp.c \ - ..\..\arf.c \ - ..\..\awf.c \ - ..\..\demo\object\bacfile.c \ - ..\..\demo\object\device.c \ - ..\..\demo\object\ai.c \ - ..\..\demo\object\ao.c \ - ..\..\demo\object\av.c \ - ..\..\demo\object\bi.c \ - ..\..\demo\object\bo.c \ - ..\..\demo\object\bv.c \ - ..\..\demo\object\lsp.c \ - ..\..\demo\object\mso.c \ - ..\..\datalink.c \ - ..\..\tsm.c \ - ..\..\address.c \ - ..\..\abort.c \ - ..\..\reject.c \ - ..\..\bacerror.c \ - ..\..\apdu.c \ - ..\..\npdu.c - -OBJS = $(SRCS:.c=.obj) - -# Compiler definitions -# -BCC_CFG = bcc32.cfg -CC = $(BORLAND_DIR)\bin\bcc32 +$(BCC_CFG) -#LINK = $(BORLAND_DIR)\bin\tlink32 -LINK = $(BORLAND_DIR)\bin\ilink32 -TLIB = $(BORLAND_DIR)\bin\tlib - -# -# Include directories -# -CC_DIR = $(BORLAND_DIR)\BIN -INCL_DIRS = -I$(BORLAND_DIR)\include;..\..\;..\..\demo\handler\;..\..\demo\object\;. - -CFLAGS = $(INCL_DIRS) $(CS_FLAGS) $(DEFINES) - -# Libraries -# -C_LIB_DIR = $(BORLAND_DIR)\lib - -LIBS = $(C_LIB_DIR)\IMPORT32.lib \ -$(C_LIB_DIR)\CW32MT.lib - -# -# Main target -# -# This should be the first one in the makefile - -all : $(BCC_CFG) $(PRODUCT_EXE) - -# Linker specific: the link below is for BCC linker/compiler. If you link -# with a different linker - please change accordingly. -# - -# need a temp response file (@&&) because command line is too long -$(PRODUCT_EXE) : $(OBJS) - @echo Running Linker for $(PRODUCT_EXE) - $(LINK) -L$(C_LIB_DIR) -m -c -s -v @&&| # temp response file, starts with | - $(BORLAND_DIR)\lib\c0x32.obj $** # $** lists each dependency - $< - $*.map - $(LIBS) -| # end of temp response file - -# -# Utilities - -clean : - @echo Deleting obj files, $(PRODUCT_EXE) and map files. - del *.obj - del ..\..\*.obj - del ..\..\demo\handler\*.obj - del ..\..\demo\object\*.obj - del $(PRODUCT_EXE) - del *.map - del $(BCC_CFG) - -# -# Generic rules -# -.SUFFIXES: .cpp .c .sbr .obj - -# -# cc generic rule -# -.c.obj: - $(CC) -o$@ $< - -# Compiler configuration file -$(BCC_CFG) : - Copy &&| -$(CFLAGS) --c --y #include line numbers in OBJ's --v #include debug info --w+ #turn on all warnings --Od #disable all optimizations -#-a4 #32 bit data alignment -#-M # generate link map -#-ls # linker options -#-WM- #not multithread --WM #multithread --w-aus # ignore warning assigned a value that is never used --w-sig # ignore warning conversion may lose sig digits -| $@ - -# EOF: makefile +# +# Simple makefile to build an RTB executable for RTOS-32 +# +# This makefile assumes Borland bcc32 development environment +# on Windows NT/9x/2000/XP +# + +!ifndef BORLAND_DIR +BORLAND_DIR_Not_Defined: + @echo . + @echo You must define environment variable BORLAND_DIR to compile. +!endif + +PRODUCT = bacnet +PRODUCT_EXE = $(PRODUCT).exe + +# Choose the Data Link Layer to Enable +DEFINES = -DBACDL_BIP=1;TSM_ENABLED=1;BIG_ENDIAN=0 + +SRCS = main.c bip-init.c \ + ..\..\bip.c \ + ..\..\demo\handler\h_iam.c \ + ..\..\demo\handler\h_whois.c \ + ..\..\demo\handler\h_wp.c \ + ..\..\demo\handler\h_rp.c \ + ..\..\demo\handler\h_rp_a.c \ + ..\..\demo\handler\noserv.c \ + ..\..\demo\handler\txbuf.c \ + ..\..\demo\handler\s_rp.c \ + ..\..\demo\handler\s_whois.c \ + ..\..\bacdcode.c \ + ..\..\bacapp.c \ + ..\..\bacstr.c \ + ..\..\bactext.c \ + ..\..\indtext.c \ + ..\..\bigend.c \ + ..\..\whois.c \ + ..\..\iam.c \ + ..\..\dcc.c \ + ..\..\rp.c \ + ..\..\wp.c \ + ..\..\arf.c \ + ..\..\awf.c \ + ..\..\demo\object\bacfile.c \ + ..\..\demo\object\device.c \ + ..\..\demo\object\ai.c \ + ..\..\demo\object\ao.c \ + ..\..\demo\object\av.c \ + ..\..\demo\object\bi.c \ + ..\..\demo\object\bo.c \ + ..\..\demo\object\bv.c \ + ..\..\demo\object\lsp.c \ + ..\..\demo\object\mso.c \ + ..\..\datalink.c \ + ..\..\tsm.c \ + ..\..\address.c \ + ..\..\abort.c \ + ..\..\reject.c \ + ..\..\bacerror.c \ + ..\..\apdu.c \ + ..\..\npdu.c + +OBJS = $(SRCS:.c=.obj) + +# Compiler definitions +# +BCC_CFG = bcc32.cfg +CC = $(BORLAND_DIR)\bin\bcc32 +$(BCC_CFG) +#LINK = $(BORLAND_DIR)\bin\tlink32 +LINK = $(BORLAND_DIR)\bin\ilink32 +TLIB = $(BORLAND_DIR)\bin\tlib + +# +# Include directories +# +CC_DIR = $(BORLAND_DIR)\BIN +INCL_DIRS = -I$(BORLAND_DIR)\include;..\..\;..\..\demo\handler\;..\..\demo\object\;. + +CFLAGS = $(INCL_DIRS) $(CS_FLAGS) $(DEFINES) + +# Libraries +# +C_LIB_DIR = $(BORLAND_DIR)\lib + +LIBS = $(C_LIB_DIR)\IMPORT32.lib \ +$(C_LIB_DIR)\CW32MT.lib + +# +# Main target +# +# This should be the first one in the makefile + +all : $(BCC_CFG) $(PRODUCT_EXE) + +# Linker specific: the link below is for BCC linker/compiler. If you link +# with a different linker - please change accordingly. +# + +# need a temp response file (@&&) because command line is too long +$(PRODUCT_EXE) : $(OBJS) + @echo Running Linker for $(PRODUCT_EXE) + $(LINK) -L$(C_LIB_DIR) -m -c -s -v @&&| # temp response file, starts with | + $(BORLAND_DIR)\lib\c0x32.obj $** # $** lists each dependency + $< + $*.map + $(LIBS) +| # end of temp response file + +# +# Utilities + +clean : + @echo Deleting obj files, $(PRODUCT_EXE) and map files. + del *.obj + del ..\..\*.obj + del ..\..\demo\handler\*.obj + del ..\..\demo\object\*.obj + del $(PRODUCT_EXE) + del *.map + del $(BCC_CFG) + +# +# Generic rules +# +.SUFFIXES: .cpp .c .sbr .obj + +# +# cc generic rule +# +.c.obj: + $(CC) -o$@ $< + +# Compiler configuration file +$(BCC_CFG) : + Copy &&| +$(CFLAGS) +-c +-y #include line numbers in OBJ's +-v #include debug info +-w+ #turn on all warnings +-Od #disable all optimizations +#-a4 #32 bit data alignment +#-M # generate link map +#-ls # linker options +#-WM- #not multithread +-WM #multithread +-w-aus # ignore warning assigned a value that is never used +-w-sig # ignore warning conversion may lose sig digits +| $@ + +# EOF: makefile diff --git a/bacnet-stack/ports/win32/bacnet/bacnet.plg b/bacnet-stack/ports/win32/bacnet/bacnet.plg index 15a85f48..378e0134 100644 --- a/bacnet-stack/ports/win32/bacnet/bacnet.plg +++ b/bacnet-stack/ports/win32/bacnet/bacnet.plg @@ -1,232 +1,232 @@ - - -
-

Build Log

-

---------------------Configuration: bacnet - Win32 Debug-------------------- -

-

Command Lines

-Creating temporary file "C:\DOCUME~1\stk01\LOCALS~1\Temp\RSP632.tmp" with contents -[ -/nologo /MLd /W3 /Gm /GX /ZI /Od /I "..\..\.." /I ".." /I "..\..\..\demo\object\\" /I "..\..\..\demo\handler\\" /D "_DEBUG" /D BACDL_BIP=1 /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D TSM_ENABLED=1 /D PRINT_ENABLED=1 /D BIG_ENDIAN=0 /D USE_INADDR=0 /FR"Debug/" /Fo"Debug/" /Fd"Debug/" /FD /GZ /c -"C:\code\bacnet-stack\abort.c" -"C:\code\bacnet-stack\address.c" -"C:\code\bacnet-stack\demo\object\ai.c" -"C:\code\bacnet-stack\demo\object\ao.c" -"C:\code\bacnet-stack\apdu.c" -"C:\code\bacnet-stack\arf.c" -"C:\code\bacnet-stack\demo\object\av.c" -"C:\code\bacnet-stack\bacapp.c" -"C:\code\bacnet-stack\bacdcode.c" -"C:\code\bacnet-stack\bacerror.c" -"C:\code\bacnet-stack\demo\object\bacfile.c" -"C:\code\bacnet-stack\bacstr.c" -"C:\code\bacnet-stack\bactext.c" -"C:\code\bacnet-stack\demo\object\bi.c" -"C:\code\bacnet-stack\bigend.c" -"C:\code\bacnet-stack\ports\win32\bip-init.c" -"C:\code\bacnet-stack\bip.c" -"C:\code\bacnet-stack\demo\object\bo.c" -"C:\code\bacnet-stack\demo\object\bv.c" -"C:\code\bacnet-stack\crc.c" -"C:\code\bacnet-stack\datetime.c" -"C:\code\bacnet-stack\dcc.c" -"C:\code\bacnet-stack\demo\object\device.c" -"C:\code\bacnet-stack\demo\handler\h_arf.c" -"C:\code\bacnet-stack\demo\handler\h_arf_a.c" -"C:\code\bacnet-stack\demo\handler\h_iam.c" -"C:\code\bacnet-stack\demo\handler\h_rp.c" -"C:\code\bacnet-stack\demo\handler\h_rp_a.c" -"C:\code\bacnet-stack\demo\handler\h_whois.c" -"C:\code\bacnet-stack\demo\handler\h_wp.c" -"C:\code\bacnet-stack\iam.c" -"C:\code\bacnet-stack\indtext.c" -"C:\code\bacnet-stack\demo\object\lc.c" -"C:\code\bacnet-stack\demo\object\lsp.c" -"C:\code\bacnet-stack\ports\win32\main.c" -"C:\code\bacnet-stack\demo\object\mso.c" -"C:\code\bacnet-stack\demo\handler\noserv.c" -"C:\code\bacnet-stack\npdu.c" -"C:\code\bacnet-stack\reject.c" -"C:\code\bacnet-stack\ringbuf.c" -"C:\code\bacnet-stack\rp.c" -"C:\code\bacnet-stack\demo\handler\s_rp.c" -"C:\code\bacnet-stack\demo\handler\s_whois.c" -"C:\code\bacnet-stack\demo\handler\s_wp.c" -"C:\code\bacnet-stack\tsm.c" -"C:\code\bacnet-stack\demo\handler\txbuf.c" -"C:\code\bacnet-stack\whois.c" -"C:\code\bacnet-stack\wp.c" -] -Creating command line "cl.exe @C:\DOCUME~1\stk01\LOCALS~1\Temp\RSP632.tmp" -Creating temporary file "C:\DOCUME~1\stk01\LOCALS~1\Temp\RSP633.tmp" with contents -[ -kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:console /incremental:yes /pdb:"Debug/bacnet.pdb" /debug /machine:I386 /out:"Debug/bacnet.exe" /pdbtype:sept -".\Debug\abort.obj" -".\Debug\address.obj" -".\Debug\ai.obj" -".\Debug\ao.obj" -".\Debug\apdu.obj" -".\Debug\arf.obj" -".\Debug\av.obj" -".\Debug\bacapp.obj" -".\Debug\bacdcode.obj" -".\Debug\bacerror.obj" -".\Debug\bacfile.obj" -".\Debug\bacstr.obj" -".\Debug\bactext.obj" -".\Debug\bi.obj" -".\Debug\bigend.obj" -".\Debug\bip-init.obj" -".\Debug\bip.obj" -".\Debug\bo.obj" -".\Debug\bv.obj" -".\Debug\crc.obj" -".\Debug\datetime.obj" -".\Debug\dcc.obj" -".\Debug\device.obj" -".\Debug\h_arf.obj" -".\Debug\h_arf_a.obj" -".\Debug\h_iam.obj" -".\Debug\h_rp.obj" -".\Debug\h_rp_a.obj" -".\Debug\h_whois.obj" -".\Debug\h_wp.obj" -".\Debug\iam.obj" -".\Debug\indtext.obj" -".\Debug\lc.obj" -".\Debug\lsp.obj" -".\Debug\main.obj" -".\Debug\mso.obj" -".\Debug\noserv.obj" -".\Debug\npdu.obj" -".\Debug\reject.obj" -".\Debug\ringbuf.obj" -".\Debug\rp.obj" -".\Debug\s_rp.obj" -".\Debug\s_whois.obj" -".\Debug\s_wp.obj" -".\Debug\tsm.obj" -".\Debug\txbuf.obj" -".\Debug\whois.obj" -".\Debug\wp.obj" -] -Creating command line "link.exe @C:\DOCUME~1\stk01\LOCALS~1\Temp\RSP633.tmp" -

Output Window

-Compiling... -abort.c -address.c -ai.c -ao.c -apdu.c -arf.c -av.c -bacapp.c -bacdcode.c -bacerror.c -bacfile.c -bacstr.c -bactext.c -bi.c -bigend.c -bip-init.c -bip.c -bo.c -bv.c -crc.c -Generating Code... -Compiling... -datetime.c -dcc.c -device.c -h_arf.c -h_arf_a.c -h_iam.c -h_rp.c -h_rp_a.c -h_whois.c -h_wp.c -iam.c -indtext.c -lc.c -lsp.c -main.c -mso.c -noserv.c -npdu.c -reject.c -ringbuf.c -Generating Code... -Compiling... -rp.c -s_rp.c -s_whois.c -s_wp.c -tsm.c -txbuf.c -whois.c -wp.c -Generating Code... -Linking... -Creating temporary file "C:\DOCUME~1\stk01\LOCALS~1\Temp\RSP635.tmp" with contents -[ -/nologo /o"Debug/bacnet.bsc" -".\Debug\abort.sbr" -".\Debug\address.sbr" -".\Debug\ai.sbr" -".\Debug\ao.sbr" -".\Debug\apdu.sbr" -".\Debug\arf.sbr" -".\Debug\av.sbr" -".\Debug\bacapp.sbr" -".\Debug\bacdcode.sbr" -".\Debug\bacerror.sbr" -".\Debug\bacfile.sbr" -".\Debug\bacstr.sbr" -".\Debug\bactext.sbr" -".\Debug\bi.sbr" -".\Debug\bigend.sbr" -".\Debug\bip-init.sbr" -".\Debug\bip.sbr" -".\Debug\bo.sbr" -".\Debug\bv.sbr" -".\Debug\crc.sbr" -".\Debug\datetime.sbr" -".\Debug\dcc.sbr" -".\Debug\device.sbr" -".\Debug\h_arf.sbr" -".\Debug\h_arf_a.sbr" -".\Debug\h_iam.sbr" -".\Debug\h_rp.sbr" -".\Debug\h_rp_a.sbr" -".\Debug\h_whois.sbr" -".\Debug\h_wp.sbr" -".\Debug\iam.sbr" -".\Debug\indtext.sbr" -".\Debug\lc.sbr" -".\Debug\lsp.sbr" -".\Debug\main.sbr" -".\Debug\mso.sbr" -".\Debug\noserv.sbr" -".\Debug\npdu.sbr" -".\Debug\reject.sbr" -".\Debug\ringbuf.sbr" -".\Debug\rp.sbr" -".\Debug\s_rp.sbr" -".\Debug\s_whois.sbr" -".\Debug\s_wp.sbr" -".\Debug\tsm.sbr" -".\Debug\txbuf.sbr" -".\Debug\whois.sbr" -".\Debug\wp.sbr"] -Creating command line "bscmake.exe @C:\DOCUME~1\stk01\LOCALS~1\Temp\RSP635.tmp" -Creating browse info file... -

Output Window

- - - -

Results

-bacnet.exe - 0 error(s), 0 warning(s) -
- - + + +
+

Build Log

+

+--------------------Configuration: bacnet - Win32 Debug-------------------- +

+

Command Lines

+Creating temporary file "C:\DOCUME~1\stk01\LOCALS~1\Temp\RSP632.tmp" with contents +[ +/nologo /MLd /W3 /Gm /GX /ZI /Od /I "..\..\.." /I ".." /I "..\..\..\demo\object\\" /I "..\..\..\demo\handler\\" /D "_DEBUG" /D BACDL_BIP=1 /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D TSM_ENABLED=1 /D PRINT_ENABLED=1 /D BIG_ENDIAN=0 /D USE_INADDR=0 /FR"Debug/" /Fo"Debug/" /Fd"Debug/" /FD /GZ /c +"C:\code\bacnet-stack\abort.c" +"C:\code\bacnet-stack\address.c" +"C:\code\bacnet-stack\demo\object\ai.c" +"C:\code\bacnet-stack\demo\object\ao.c" +"C:\code\bacnet-stack\apdu.c" +"C:\code\bacnet-stack\arf.c" +"C:\code\bacnet-stack\demo\object\av.c" +"C:\code\bacnet-stack\bacapp.c" +"C:\code\bacnet-stack\bacdcode.c" +"C:\code\bacnet-stack\bacerror.c" +"C:\code\bacnet-stack\demo\object\bacfile.c" +"C:\code\bacnet-stack\bacstr.c" +"C:\code\bacnet-stack\bactext.c" +"C:\code\bacnet-stack\demo\object\bi.c" +"C:\code\bacnet-stack\bigend.c" +"C:\code\bacnet-stack\ports\win32\bip-init.c" +"C:\code\bacnet-stack\bip.c" +"C:\code\bacnet-stack\demo\object\bo.c" +"C:\code\bacnet-stack\demo\object\bv.c" +"C:\code\bacnet-stack\crc.c" +"C:\code\bacnet-stack\datetime.c" +"C:\code\bacnet-stack\dcc.c" +"C:\code\bacnet-stack\demo\object\device.c" +"C:\code\bacnet-stack\demo\handler\h_arf.c" +"C:\code\bacnet-stack\demo\handler\h_arf_a.c" +"C:\code\bacnet-stack\demo\handler\h_iam.c" +"C:\code\bacnet-stack\demo\handler\h_rp.c" +"C:\code\bacnet-stack\demo\handler\h_rp_a.c" +"C:\code\bacnet-stack\demo\handler\h_whois.c" +"C:\code\bacnet-stack\demo\handler\h_wp.c" +"C:\code\bacnet-stack\iam.c" +"C:\code\bacnet-stack\indtext.c" +"C:\code\bacnet-stack\demo\object\lc.c" +"C:\code\bacnet-stack\demo\object\lsp.c" +"C:\code\bacnet-stack\ports\win32\main.c" +"C:\code\bacnet-stack\demo\object\mso.c" +"C:\code\bacnet-stack\demo\handler\noserv.c" +"C:\code\bacnet-stack\npdu.c" +"C:\code\bacnet-stack\reject.c" +"C:\code\bacnet-stack\ringbuf.c" +"C:\code\bacnet-stack\rp.c" +"C:\code\bacnet-stack\demo\handler\s_rp.c" +"C:\code\bacnet-stack\demo\handler\s_whois.c" +"C:\code\bacnet-stack\demo\handler\s_wp.c" +"C:\code\bacnet-stack\tsm.c" +"C:\code\bacnet-stack\demo\handler\txbuf.c" +"C:\code\bacnet-stack\whois.c" +"C:\code\bacnet-stack\wp.c" +] +Creating command line "cl.exe @C:\DOCUME~1\stk01\LOCALS~1\Temp\RSP632.tmp" +Creating temporary file "C:\DOCUME~1\stk01\LOCALS~1\Temp\RSP633.tmp" with contents +[ +kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:console /incremental:yes /pdb:"Debug/bacnet.pdb" /debug /machine:I386 /out:"Debug/bacnet.exe" /pdbtype:sept +".\Debug\abort.obj" +".\Debug\address.obj" +".\Debug\ai.obj" +".\Debug\ao.obj" +".\Debug\apdu.obj" +".\Debug\arf.obj" +".\Debug\av.obj" +".\Debug\bacapp.obj" +".\Debug\bacdcode.obj" +".\Debug\bacerror.obj" +".\Debug\bacfile.obj" +".\Debug\bacstr.obj" +".\Debug\bactext.obj" +".\Debug\bi.obj" +".\Debug\bigend.obj" +".\Debug\bip-init.obj" +".\Debug\bip.obj" +".\Debug\bo.obj" +".\Debug\bv.obj" +".\Debug\crc.obj" +".\Debug\datetime.obj" +".\Debug\dcc.obj" +".\Debug\device.obj" +".\Debug\h_arf.obj" +".\Debug\h_arf_a.obj" +".\Debug\h_iam.obj" +".\Debug\h_rp.obj" +".\Debug\h_rp_a.obj" +".\Debug\h_whois.obj" +".\Debug\h_wp.obj" +".\Debug\iam.obj" +".\Debug\indtext.obj" +".\Debug\lc.obj" +".\Debug\lsp.obj" +".\Debug\main.obj" +".\Debug\mso.obj" +".\Debug\noserv.obj" +".\Debug\npdu.obj" +".\Debug\reject.obj" +".\Debug\ringbuf.obj" +".\Debug\rp.obj" +".\Debug\s_rp.obj" +".\Debug\s_whois.obj" +".\Debug\s_wp.obj" +".\Debug\tsm.obj" +".\Debug\txbuf.obj" +".\Debug\whois.obj" +".\Debug\wp.obj" +] +Creating command line "link.exe @C:\DOCUME~1\stk01\LOCALS~1\Temp\RSP633.tmp" +

Output Window

+Compiling... +abort.c +address.c +ai.c +ao.c +apdu.c +arf.c +av.c +bacapp.c +bacdcode.c +bacerror.c +bacfile.c +bacstr.c +bactext.c +bi.c +bigend.c +bip-init.c +bip.c +bo.c +bv.c +crc.c +Generating Code... +Compiling... +datetime.c +dcc.c +device.c +h_arf.c +h_arf_a.c +h_iam.c +h_rp.c +h_rp_a.c +h_whois.c +h_wp.c +iam.c +indtext.c +lc.c +lsp.c +main.c +mso.c +noserv.c +npdu.c +reject.c +ringbuf.c +Generating Code... +Compiling... +rp.c +s_rp.c +s_whois.c +s_wp.c +tsm.c +txbuf.c +whois.c +wp.c +Generating Code... +Linking... +Creating temporary file "C:\DOCUME~1\stk01\LOCALS~1\Temp\RSP635.tmp" with contents +[ +/nologo /o"Debug/bacnet.bsc" +".\Debug\abort.sbr" +".\Debug\address.sbr" +".\Debug\ai.sbr" +".\Debug\ao.sbr" +".\Debug\apdu.sbr" +".\Debug\arf.sbr" +".\Debug\av.sbr" +".\Debug\bacapp.sbr" +".\Debug\bacdcode.sbr" +".\Debug\bacerror.sbr" +".\Debug\bacfile.sbr" +".\Debug\bacstr.sbr" +".\Debug\bactext.sbr" +".\Debug\bi.sbr" +".\Debug\bigend.sbr" +".\Debug\bip-init.sbr" +".\Debug\bip.sbr" +".\Debug\bo.sbr" +".\Debug\bv.sbr" +".\Debug\crc.sbr" +".\Debug\datetime.sbr" +".\Debug\dcc.sbr" +".\Debug\device.sbr" +".\Debug\h_arf.sbr" +".\Debug\h_arf_a.sbr" +".\Debug\h_iam.sbr" +".\Debug\h_rp.sbr" +".\Debug\h_rp_a.sbr" +".\Debug\h_whois.sbr" +".\Debug\h_wp.sbr" +".\Debug\iam.sbr" +".\Debug\indtext.sbr" +".\Debug\lc.sbr" +".\Debug\lsp.sbr" +".\Debug\main.sbr" +".\Debug\mso.sbr" +".\Debug\noserv.sbr" +".\Debug\npdu.sbr" +".\Debug\reject.sbr" +".\Debug\ringbuf.sbr" +".\Debug\rp.sbr" +".\Debug\s_rp.sbr" +".\Debug\s_whois.sbr" +".\Debug\s_wp.sbr" +".\Debug\tsm.sbr" +".\Debug\txbuf.sbr" +".\Debug\whois.sbr" +".\Debug\wp.sbr"] +Creating command line "bscmake.exe @C:\DOCUME~1\stk01\LOCALS~1\Temp\RSP635.tmp" +Creating browse info file... +

Output Window

+ + + +

Results

+bacnet.exe - 0 error(s), 0 warning(s) +
+ + diff --git a/bacnet-stack/ports/win32/bacnet/readme.txt b/bacnet-stack/ports/win32/bacnet/readme.txt index ef74afff..0f4c86dc 100644 --- a/bacnet-stack/ports/win32/bacnet/readme.txt +++ b/bacnet-stack/ports/win32/bacnet/readme.txt @@ -1,113 +1,113 @@ -BACnet Stack - SourceForge.net -Build for Visual C++ 6.0 - -When building the BACnet stack using Visual C++ compiler, -there are some settings that are important. - -Q. Are there some global configuration options for this BACnet stack? - -A. The BACnet stack uses some preprocessor defines to configure -a number of subtle personalities. -PRINT_ENABLED=1 - enables printing to stdio -BIG_ENDIAN=0 - chooses the BACnet encoding and decoding order -BACDL_BIP=1 - chooses BACnet/IP for the datalink layer -BACDL_ETHERNET=0 - chooses BACnet Ethernet for the datalink layer -BACDL_ARCNET=0 - chooses BACnet ARCNET for the datalink layer -BACDL_MSTP=0 - chooses BACnet MS/TP for the datalink layer -USE_INADDR=1 - uses INADDR_BROADCAST for broadcast rather than CLASSx -TSM_ENABLED=1 - enables the Transaction State Machine for clients -BIP_DEBUG=1 - enables print statements for debugging -In Visual C++, add a Preprocessor Definition by: -1. Select "Project" menu -2. Select "Settings..." -3. Select the "C/C++" tab (3rd Tab) -4. Select the Category: General -5. You can see the "Preprocessor Definitions:" box -6. Type OPTION_NAME=1 or OPTION_NAME=0 in that edit box - using a comma to separate multiple options. -7. Press OK -8. Compile the entire project again... - -Q. MSVC refuses to open bacnet.dsw and bacnet.dsp. - -A. bacnet.dsw and bacnet.dsp are text files that were retrieved -from CVS on a unix client and are now in unix text file format since -they end with a "\r\n" rather than "\n". Use the unix2dos commandline -tool to convert them back to dos: -unix2dos bacnet.dsw -unix2dos bacnet.dsp - -Q. error LNK2001: unresolved external symbol _WinMain@16 - -A. The demo ports/win32/main.c was designed as a Win32 Console -Application. If you want to change it to a Windows GUI application, -you will have to add all the Windows GUI code, including WinMain(). -I recommend that you use a framework, such as WxWidgets/WxWindows, -but this has not been done yet. - -Q. error C1083: Cannot open include file: 'stdint.h': No such file - -A. The BACnet stack uses some header files, and Visual C++ needs to know -where they are: -1. Select "Project" menu -2. Select "Settings..." -3. Select the "C/C++" tab (3rd Tab) -4. Select the Category: Preprocessor -5. You can see the "Additional include directories:" box -6. Type the path to stdint.h in that edit box (using a comma if necessary) -7. Type the path to bacdcode.h in that edit box (using a comma if necessary) -In my system, the paths look like: -c:\code\bacnet-stack\,c:\code\bacnet-stack\ports\win32\, -c:\code\bacnet-stack\demo\handler\,c:\code\bacnet-stack\demo\object\ -8. Press OK -9. Compile the project again... - -Q. error C2065: 'MAX_MPDU' : undeclared identifier - -A. The BACnet stack uses a preprocessor define to configure -its datalink layer. In Visual C++, add a Preprocessor Definition by: -1. Select "Project" menu -2. Select "Settings..." -3. Select the "C/C++" tab (3rd Tab) -4. Select the Category: General -5. You can see the "Preprocessor Definitions:" box -6. Type BACDL_BIP=1 in that edit box (using a comma if necessary) -7. Press OK -8. Compile the entire project again... - -Q. error LNK2001: unresolved external symbol _bacapp_print - -A. The BACnet stack uses a preprocessor define to configure -printing to stdio. In Visual C++, add a Preprocessor Definition by: -1. Select "Project" menu -2. Select "Settings..." -3. Select the "C/C++" tab (3rd Tab) -4. Select the Category: General -5. You can see the "Preprocessor Definitions:" box -6. Type PRINT_ENABLED=1 in that edit box (using a comma if necessary) -7. Press OK -8. Compile the entire project again... - -Q. error LNK2001: unresolved external symbol __imp__closesocket@4 - -A. Visual C++ needs to have the Winsock library to be happy: -1. Select "Project" menu -2. Select "Settings..." -3. Select the "Link" tab (4th Tab) -4. You can see "Object/library modules:" edit box -5. Type Wsock32.LIB in that edit box -6. Press OK -7. Compile the entire project again... - -Q. error C2061: in file tsm.c -A. The BACnet stack uses a preprocessor define to configure -client functionality in the Transaction State Machine (TSM). -In Visual C++, add a Preprocessor Definition by: -1. Select "Project" menu -2. Select "Settings..." -3. Select the "C/C++" tab (3rd Tab) -4. Select the Category: General -5. You can see the "Preprocessor Definitions:" box -6. Type TSM_ENABLED=1 in that edit box (using a comma if necessary) -7. Press OK -8. Compile the entire project again... +BACnet Stack - SourceForge.net +Build for Visual C++ 6.0 + +When building the BACnet stack using Visual C++ compiler, +there are some settings that are important. + +Q. Are there some global configuration options for this BACnet stack? + +A. The BACnet stack uses some preprocessor defines to configure +a number of subtle personalities. +PRINT_ENABLED=1 - enables printing to stdio +BIG_ENDIAN=0 - chooses the BACnet encoding and decoding order +BACDL_BIP=1 - chooses BACnet/IP for the datalink layer +BACDL_ETHERNET=0 - chooses BACnet Ethernet for the datalink layer +BACDL_ARCNET=0 - chooses BACnet ARCNET for the datalink layer +BACDL_MSTP=0 - chooses BACnet MS/TP for the datalink layer +USE_INADDR=1 - uses INADDR_BROADCAST for broadcast rather than CLASSx +TSM_ENABLED=1 - enables the Transaction State Machine for clients +BIP_DEBUG=1 - enables print statements for debugging +In Visual C++, add a Preprocessor Definition by: +1. Select "Project" menu +2. Select "Settings..." +3. Select the "C/C++" tab (3rd Tab) +4. Select the Category: General +5. You can see the "Preprocessor Definitions:" box +6. Type OPTION_NAME=1 or OPTION_NAME=0 in that edit box + using a comma to separate multiple options. +7. Press OK +8. Compile the entire project again... + +Q. MSVC refuses to open bacnet.dsw and bacnet.dsp. + +A. bacnet.dsw and bacnet.dsp are text files that were retrieved +from CVS on a unix client and are now in unix text file format since +they end with a "\r\n" rather than "\n". Use the unix2dos commandline +tool to convert them back to dos: +unix2dos bacnet.dsw +unix2dos bacnet.dsp + +Q. error LNK2001: unresolved external symbol _WinMain@16 + +A. The demo ports/win32/main.c was designed as a Win32 Console +Application. If you want to change it to a Windows GUI application, +you will have to add all the Windows GUI code, including WinMain(). +I recommend that you use a framework, such as WxWidgets/WxWindows, +but this has not been done yet. + +Q. error C1083: Cannot open include file: 'stdint.h': No such file + +A. The BACnet stack uses some header files, and Visual C++ needs to know +where they are: +1. Select "Project" menu +2. Select "Settings..." +3. Select the "C/C++" tab (3rd Tab) +4. Select the Category: Preprocessor +5. You can see the "Additional include directories:" box +6. Type the path to stdint.h in that edit box (using a comma if necessary) +7. Type the path to bacdcode.h in that edit box (using a comma if necessary) +In my system, the paths look like: +c:\code\bacnet-stack\,c:\code\bacnet-stack\ports\win32\, +c:\code\bacnet-stack\demo\handler\,c:\code\bacnet-stack\demo\object\ +8. Press OK +9. Compile the project again... + +Q. error C2065: 'MAX_MPDU' : undeclared identifier + +A. The BACnet stack uses a preprocessor define to configure +its datalink layer. In Visual C++, add a Preprocessor Definition by: +1. Select "Project" menu +2. Select "Settings..." +3. Select the "C/C++" tab (3rd Tab) +4. Select the Category: General +5. You can see the "Preprocessor Definitions:" box +6. Type BACDL_BIP=1 in that edit box (using a comma if necessary) +7. Press OK +8. Compile the entire project again... + +Q. error LNK2001: unresolved external symbol _bacapp_print + +A. The BACnet stack uses a preprocessor define to configure +printing to stdio. In Visual C++, add a Preprocessor Definition by: +1. Select "Project" menu +2. Select "Settings..." +3. Select the "C/C++" tab (3rd Tab) +4. Select the Category: General +5. You can see the "Preprocessor Definitions:" box +6. Type PRINT_ENABLED=1 in that edit box (using a comma if necessary) +7. Press OK +8. Compile the entire project again... + +Q. error LNK2001: unresolved external symbol __imp__closesocket@4 + +A. Visual C++ needs to have the Winsock library to be happy: +1. Select "Project" menu +2. Select "Settings..." +3. Select the "Link" tab (4th Tab) +4. You can see "Object/library modules:" edit box +5. Type Wsock32.LIB in that edit box +6. Press OK +7. Compile the entire project again... + +Q. error C2061: in file tsm.c +A. The BACnet stack uses a preprocessor define to configure +client functionality in the Transaction State Machine (TSM). +In Visual C++, add a Preprocessor Definition by: +1. Select "Project" menu +2. Select "Settings..." +3. Select the "C/C++" tab (3rd Tab) +4. Select the Category: General +5. You can see the "Preprocessor Definitions:" box +6. Type TSM_ENABLED=1 in that edit box (using a comma if necessary) +7. Press OK +8. Compile the entire project again... diff --git a/bacnet-stack/ports/win32/bip-init.c b/bacnet-stack/ports/win32/bip-init.c index 972f9f25..3f4fc18a 100644 --- a/bacnet-stack/ports/win32/bip-init.c +++ b/bacnet-stack/ports/win32/bip-init.c @@ -1,358 +1,358 @@ -/*####COPYRIGHTBEGIN#### - ------------------------------------------- - Copyright (C) 2005 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####*/ - -#define WIN32_LEAN_AND_MEAN -#define STRICT 1 - -#include -#include -#include /* for standard integer types uint8_t etc. */ -#include /* for the standard bool type. */ -#include "bacdcode.h" -#include "bip.h" -#include "net.h" - -/* To fill a need, we invent the gethostaddr() function. */ -static long gethostaddr(void) -{ - struct hostent *host_ent; - char host_name[255]; - - if (gethostname(host_name, sizeof(host_name)) != 0) - return -1; - - if ((host_ent = gethostbyname(host_name)) == NULL) - return -1; -#ifdef BIP_DEBUG - printf("host: %s at %u.%u.%u.%u\n", host_name, - ((uint8_t*)host_ent->h_addr)[0], - ((uint8_t*)host_ent->h_addr)[1], - ((uint8_t*)host_ent->h_addr)[2], - ((uint8_t*)host_ent->h_addr)[3]); -#endif - /* note: network byte order */ - return *(long *) host_ent->h_addr; -} - -static void set_broadcast_address(uint32_t net_address) -{ -#if USE_INADDR - /* Note: sometimes INADDR_BROADCAST does not let me get - any unicast messages. Not sure why... */ - (void) net_address; - bip_set_broadcast_addr(INADDR_BROADCAST); -#else - long broadcast_address = 0; - long mask = 0; - - if (IN_CLASSA(ntohl(net_address))) - broadcast_address = - (ntohl(net_address) & ~IN_CLASSA_HOST) | IN_CLASSA_HOST; - else if (IN_CLASSB(ntohl(net_address))) - broadcast_address = - (ntohl(net_address) & ~IN_CLASSB_HOST) | IN_CLASSB_HOST; - else if (IN_CLASSC(ntohl(net_address))) - broadcast_address = - (ntohl(net_address) & ~IN_CLASSC_HOST) | IN_CLASSC_HOST; - else if (IN_CLASSD(ntohl(net_address))) - broadcast_address = - (ntohl(net_address) & ~IN_CLASSD_HOST) | IN_CLASSD_HOST; - else - broadcast_address = INADDR_BROADCAST; - bip_set_broadcast_addr(htonl(broadcast_address)); -#endif -} - -static void cleanup(void) -{ - WSACleanup(); -} - - -/* on Windows, ifname is the dotted ip address of the interface */ -void bip_set_interface(char *ifname) -{ - struct in_addr address; - - /* setup local address */ - if (bip_get_addr() == 0) { - bip_set_addr(inet_addr(ifname)); - } -#ifdef BIP_DEBUG - address.s_addr = htonl(bip_get_addr()); - fprintf(stderr, "Interface: %s\n", ifname); -#endif - /* setup local broadcast address */ - if (bip_get_broadcast_addr() == 0) { - address.s_addr = htonl(bip_get_addr()); - set_broadcast_address(address.s_addr); - } -} - -static char *winsock_error_code_text(int code) -{ - switch (code) { - case WSAEACCES: - return "Permission denied."; - case WSAEINTR: - return "Interrupted system call."; - case WSAEBADF: - return "Bad file number."; - case WSAEFAULT: - return "Bad address."; - case WSAEINVAL: - return "Invalid argument."; - case WSAEMFILE: - return "Too many open files."; - case WSAEWOULDBLOCK: - return "Operation would block."; - case WSAEINPROGRESS: - return "Operation now in progress. This error is returned if any Windows Sockets API function is called while a blocking function is in progress."; - case WSAENOTSOCK: - return "Socket operation on nonsocket."; - case WSAEDESTADDRREQ: - return "Destination address required."; - case WSAEMSGSIZE: - return "Message too long."; - case WSAEPROTOTYPE: - return "Protocol wrong type for socket."; - case WSAENOPROTOOPT: - return "Protocol not available."; - case WSAEPROTONOSUPPORT: - return "Protocol not supported."; - case WSAESOCKTNOSUPPORT: - return "Socket type not supported."; - case WSAEOPNOTSUPP: - return "Operation not supported on socket."; - case WSAEPFNOSUPPORT: - return "Protocol family not supported."; - case WSAEAFNOSUPPORT: - return "Address family not supported by protocol family."; - case WSAEADDRINUSE: - return "Address already in use."; - case WSAEADDRNOTAVAIL: - return "Cannot assign requested address."; - case WSAENETDOWN: - return "Network is down. This error may be reported at any time if the Windows Sockets implementation detects an underlying failure."; - case WSAENETUNREACH: - return "Network is unreachable."; - case WSAENETRESET: - return "Network dropped connection on reset."; - case WSAECONNABORTED: - return "Software caused connection abort."; - case WSAECONNRESET: - return "Connection reset by peer."; - case WSAENOBUFS: - return "No buffer space available."; - case WSAEISCONN: - return "Socket is already connected."; - case WSAENOTCONN: - return "Socket is not connected."; - case WSAESHUTDOWN: - return "Cannot send after socket shutdown."; - case WSAETOOMANYREFS: - return "Too many references: cannot splice."; - case WSAETIMEDOUT: - return "Connection timed out."; - case WSAECONNREFUSED: - return "Connection refused."; - case WSAELOOP: - return "Too many levels of symbolic links."; - case WSAENAMETOOLONG: - return "File name too long."; - case WSAEHOSTDOWN: - return "Host is down."; - case WSAEHOSTUNREACH: - return "No route to host."; - case WSASYSNOTREADY: - return "Returned by WSAStartup(), " - "indicating that the network subsystem is unusable."; - case WSAVERNOTSUPPORTED: - return "Returned by WSAStartup(), " - "indicating that the Windows Sockets DLL cannot support " - "this application."; - case WSANOTINITIALISED: - return "Winsock not initialized. " - "This message is returned by any function except WSAStartup(), " - "indicating that a successful WSAStartup() has not yet " - "been performed."; - case WSAEDISCON: - return "Disconnect."; - case WSAHOST_NOT_FOUND: - return "Host not found. " - "This message indicates that the key " - "(name, address, and so on) was not found."; - case WSATRY_AGAIN: - return "Nonauthoritative host not found. " - "This error may suggest that the name service itself " - "is not functioning."; - case WSANO_RECOVERY: - return "Nonrecoverable error. " - "This error may suggest that the name service itself " - "is not functioning."; - case WSANO_DATA: - return "Valid name, no data record of requested type. " - "This error indicates that the key " - "(name, address, and so on) was not found."; - default: return "unknown"; - } -} - -bool bip_init(char *ifname) -{ - int rv = 0; /* return from socket lib calls */ - struct sockaddr_in sin = { -1 }; - int value = 1; - int sock_fd = -1; - int Result; - int Code; - WSADATA wd; - struct in_addr address; - struct in_addr broadcast_address; - - Result = WSAStartup((1 << 8) | 1, &wd); - /*Result = WSAStartup(MAKEWORD(2,2), &wd); */ - if (Result != 0) { - Code = WSAGetLastError(); - printf("TCP/IP stack initialization failed\n" - " error code: %i %s\n", - Code, winsock_error_code_text(Code)); - exit(1); - } - atexit(cleanup); - - if (ifname) - bip_set_interface(ifname); - /* has address been set? */ - address.s_addr = htonl(bip_get_addr()); - if (address.s_addr == 0) { - address.s_addr = gethostaddr(); - if (address.s_addr == (unsigned) -1) { - Code = WSAGetLastError(); - printf("Get host address failed\n" - " error code: %i %s\n", - Code, winsock_error_code_text(Code)); - exit(1); - } - bip_set_addr(address.s_addr); - } -#ifdef BIP_DEBUG - fprintf(stderr, "IP Address: %s\n", inet_ntoa(address)); -#endif - /* has broadcast address been set? */ - if (bip_get_broadcast_addr() == 0) { - set_broadcast_address(address.s_addr); - } -#ifdef BIP_DEBUG - broadcast_address.s_addr = htonl(bip_get_broadcast_addr()); - fprintf(stderr, "IP Broadcast Address: %s\n", - inet_ntoa(broadcast_address)); - fprintf(stderr, "UDP Port: 0x%04X [%hu]\n", - bip_get_port(), - bip_get_port()); -#endif - /* assumes that the driver has already been initialized */ - sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - bip_set_socket(sock_fd); - if (sock_fd < 0) { - fprintf(stderr, "bip: failed to allocate a socket.\n"); - return false; - } - /* Allow us to use the same socket for sending and receiving */ - /* This makes sure that the src port is correct when sending */ - rv = setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, - (char *) &value, sizeof(value)); - if (rv < 0) { - fprintf(stderr, "bip: failed to set REUSEADDR socket option.\n"); - close(sock_fd); - bip_set_socket(-1); - return false; - } - /* allow us to send a broadcast */ - rv = setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, - (char *) &value, sizeof(value)); - if (rv < 0) { - fprintf(stderr, "bip: failed to set BROADCAST socket option.\n"); - close(sock_fd); - bip_set_socket(-1); - return false; - } -#if 0 - /* probably only for Apple... */ - /* rebind a port that is already in use. - Note: all users of the port must specify this flag */ - rv = setsockopt(sock_fd, SOL_SOCKET, SO_REUSEPORT, - (char *) &value, sizeof(value)); - if (rv < 0) { - fprintf(stderr, "bip: failed to set REUSEPORT socket option.\n"); - close(sock_fd); - bip_set_socket(-1); - return false; - } -#endif - /* bind the socket to the local port number and IP address */ - sin.sin_family = AF_INET; -#if USE_INADDR - /* by setting sin.sin_addr.s_addr to INADDR_ANY, - I am telling the IP stack to automatically fill - in the IP address of the machine the process - is running on. - - Some server computers have multiple IP addresses. - A socket bound to one of these will not accept - connections to another address. Frequently you prefer - to allow any one of the computer's IP addresses - to be used for connections. Use INADDR_ANY (0L) to - allow clients to connect using any one of the host's - IP addresses. */ - sin.sin_addr.s_addr = htonl(INADDR_ANY); -#else - /* or we could use the specific adapter address - note: already in network byte order */ - sin.sin_addr.s_addr = address.s_addr; -#endif - sin.sin_port = htons(bip_get_port()); - memset(&(sin.sin_zero), '\0', sizeof(sin.sin_zero)); - rv = bind(sock_fd, - (const struct sockaddr *) &sin, sizeof(struct sockaddr)); - if (rv < 0) { - fprintf(stderr, "bip: failed to bind to %s port %hd\n", - inet_ntoa(sin.sin_addr), bip_get_port()); - close(sock_fd); - bip_set_socket(-1); - return false; - } - - return true; -} +/*####COPYRIGHTBEGIN#### + ------------------------------------------- + Copyright (C) 2005 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####*/ + +#define WIN32_LEAN_AND_MEAN +#define STRICT 1 + +#include +#include +#include /* for standard integer types uint8_t etc. */ +#include /* for the standard bool type. */ +#include "bacdcode.h" +#include "bip.h" +#include "net.h" + +/* To fill a need, we invent the gethostaddr() function. */ +static long gethostaddr(void) +{ + struct hostent *host_ent; + char host_name[255]; + + if (gethostname(host_name, sizeof(host_name)) != 0) + return -1; + + if ((host_ent = gethostbyname(host_name)) == NULL) + return -1; +#ifdef BIP_DEBUG + printf("host: %s at %u.%u.%u.%u\n", host_name, + ((uint8_t*)host_ent->h_addr)[0], + ((uint8_t*)host_ent->h_addr)[1], + ((uint8_t*)host_ent->h_addr)[2], + ((uint8_t*)host_ent->h_addr)[3]); +#endif + /* note: network byte order */ + return *(long *) host_ent->h_addr; +} + +static void set_broadcast_address(uint32_t net_address) +{ +#if USE_INADDR + /* Note: sometimes INADDR_BROADCAST does not let me get + any unicast messages. Not sure why... */ + (void) net_address; + bip_set_broadcast_addr(INADDR_BROADCAST); +#else + long broadcast_address = 0; + long mask = 0; + + if (IN_CLASSA(ntohl(net_address))) + broadcast_address = + (ntohl(net_address) & ~IN_CLASSA_HOST) | IN_CLASSA_HOST; + else if (IN_CLASSB(ntohl(net_address))) + broadcast_address = + (ntohl(net_address) & ~IN_CLASSB_HOST) | IN_CLASSB_HOST; + else if (IN_CLASSC(ntohl(net_address))) + broadcast_address = + (ntohl(net_address) & ~IN_CLASSC_HOST) | IN_CLASSC_HOST; + else if (IN_CLASSD(ntohl(net_address))) + broadcast_address = + (ntohl(net_address) & ~IN_CLASSD_HOST) | IN_CLASSD_HOST; + else + broadcast_address = INADDR_BROADCAST; + bip_set_broadcast_addr(htonl(broadcast_address)); +#endif +} + +static void cleanup(void) +{ + WSACleanup(); +} + + +/* on Windows, ifname is the dotted ip address of the interface */ +void bip_set_interface(char *ifname) +{ + struct in_addr address; + + /* setup local address */ + if (bip_get_addr() == 0) { + bip_set_addr(inet_addr(ifname)); + } +#ifdef BIP_DEBUG + address.s_addr = htonl(bip_get_addr()); + fprintf(stderr, "Interface: %s\n", ifname); +#endif + /* setup local broadcast address */ + if (bip_get_broadcast_addr() == 0) { + address.s_addr = htonl(bip_get_addr()); + set_broadcast_address(address.s_addr); + } +} + +static char *winsock_error_code_text(int code) +{ + switch (code) { + case WSAEACCES: + return "Permission denied."; + case WSAEINTR: + return "Interrupted system call."; + case WSAEBADF: + return "Bad file number."; + case WSAEFAULT: + return "Bad address."; + case WSAEINVAL: + return "Invalid argument."; + case WSAEMFILE: + return "Too many open files."; + case WSAEWOULDBLOCK: + return "Operation would block."; + case WSAEINPROGRESS: + return "Operation now in progress. This error is returned if any Windows Sockets API function is called while a blocking function is in progress."; + case WSAENOTSOCK: + return "Socket operation on nonsocket."; + case WSAEDESTADDRREQ: + return "Destination address required."; + case WSAEMSGSIZE: + return "Message too long."; + case WSAEPROTOTYPE: + return "Protocol wrong type for socket."; + case WSAENOPROTOOPT: + return "Protocol not available."; + case WSAEPROTONOSUPPORT: + return "Protocol not supported."; + case WSAESOCKTNOSUPPORT: + return "Socket type not supported."; + case WSAEOPNOTSUPP: + return "Operation not supported on socket."; + case WSAEPFNOSUPPORT: + return "Protocol family not supported."; + case WSAEAFNOSUPPORT: + return "Address family not supported by protocol family."; + case WSAEADDRINUSE: + return "Address already in use."; + case WSAEADDRNOTAVAIL: + return "Cannot assign requested address."; + case WSAENETDOWN: + return "Network is down. This error may be reported at any time if the Windows Sockets implementation detects an underlying failure."; + case WSAENETUNREACH: + return "Network is unreachable."; + case WSAENETRESET: + return "Network dropped connection on reset."; + case WSAECONNABORTED: + return "Software caused connection abort."; + case WSAECONNRESET: + return "Connection reset by peer."; + case WSAENOBUFS: + return "No buffer space available."; + case WSAEISCONN: + return "Socket is already connected."; + case WSAENOTCONN: + return "Socket is not connected."; + case WSAESHUTDOWN: + return "Cannot send after socket shutdown."; + case WSAETOOMANYREFS: + return "Too many references: cannot splice."; + case WSAETIMEDOUT: + return "Connection timed out."; + case WSAECONNREFUSED: + return "Connection refused."; + case WSAELOOP: + return "Too many levels of symbolic links."; + case WSAENAMETOOLONG: + return "File name too long."; + case WSAEHOSTDOWN: + return "Host is down."; + case WSAEHOSTUNREACH: + return "No route to host."; + case WSASYSNOTREADY: + return "Returned by WSAStartup(), " + "indicating that the network subsystem is unusable."; + case WSAVERNOTSUPPORTED: + return "Returned by WSAStartup(), " + "indicating that the Windows Sockets DLL cannot support " + "this application."; + case WSANOTINITIALISED: + return "Winsock not initialized. " + "This message is returned by any function except WSAStartup(), " + "indicating that a successful WSAStartup() has not yet " + "been performed."; + case WSAEDISCON: + return "Disconnect."; + case WSAHOST_NOT_FOUND: + return "Host not found. " + "This message indicates that the key " + "(name, address, and so on) was not found."; + case WSATRY_AGAIN: + return "Nonauthoritative host not found. " + "This error may suggest that the name service itself " + "is not functioning."; + case WSANO_RECOVERY: + return "Nonrecoverable error. " + "This error may suggest that the name service itself " + "is not functioning."; + case WSANO_DATA: + return "Valid name, no data record of requested type. " + "This error indicates that the key " + "(name, address, and so on) was not found."; + default: return "unknown"; + } +} + +bool bip_init(char *ifname) +{ + int rv = 0; /* return from socket lib calls */ + struct sockaddr_in sin = { -1 }; + int value = 1; + int sock_fd = -1; + int Result; + int Code; + WSADATA wd; + struct in_addr address; + struct in_addr broadcast_address; + + Result = WSAStartup((1 << 8) | 1, &wd); + /*Result = WSAStartup(MAKEWORD(2,2), &wd); */ + if (Result != 0) { + Code = WSAGetLastError(); + printf("TCP/IP stack initialization failed\n" + " error code: %i %s\n", + Code, winsock_error_code_text(Code)); + exit(1); + } + atexit(cleanup); + + if (ifname) + bip_set_interface(ifname); + /* has address been set? */ + address.s_addr = htonl(bip_get_addr()); + if (address.s_addr == 0) { + address.s_addr = gethostaddr(); + if (address.s_addr == (unsigned) -1) { + Code = WSAGetLastError(); + printf("Get host address failed\n" + " error code: %i %s\n", + Code, winsock_error_code_text(Code)); + exit(1); + } + bip_set_addr(address.s_addr); + } +#ifdef BIP_DEBUG + fprintf(stderr, "IP Address: %s\n", inet_ntoa(address)); +#endif + /* has broadcast address been set? */ + if (bip_get_broadcast_addr() == 0) { + set_broadcast_address(address.s_addr); + } +#ifdef BIP_DEBUG + broadcast_address.s_addr = htonl(bip_get_broadcast_addr()); + fprintf(stderr, "IP Broadcast Address: %s\n", + inet_ntoa(broadcast_address)); + fprintf(stderr, "UDP Port: 0x%04X [%hu]\n", + bip_get_port(), + bip_get_port()); +#endif + /* assumes that the driver has already been initialized */ + sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + bip_set_socket(sock_fd); + if (sock_fd < 0) { + fprintf(stderr, "bip: failed to allocate a socket.\n"); + return false; + } + /* Allow us to use the same socket for sending and receiving */ + /* This makes sure that the src port is correct when sending */ + rv = setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, + (char *) &value, sizeof(value)); + if (rv < 0) { + fprintf(stderr, "bip: failed to set REUSEADDR socket option.\n"); + close(sock_fd); + bip_set_socket(-1); + return false; + } + /* allow us to send a broadcast */ + rv = setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, + (char *) &value, sizeof(value)); + if (rv < 0) { + fprintf(stderr, "bip: failed to set BROADCAST socket option.\n"); + close(sock_fd); + bip_set_socket(-1); + return false; + } +#if 0 + /* probably only for Apple... */ + /* rebind a port that is already in use. + Note: all users of the port must specify this flag */ + rv = setsockopt(sock_fd, SOL_SOCKET, SO_REUSEPORT, + (char *) &value, sizeof(value)); + if (rv < 0) { + fprintf(stderr, "bip: failed to set REUSEPORT socket option.\n"); + close(sock_fd); + bip_set_socket(-1); + return false; + } +#endif + /* bind the socket to the local port number and IP address */ + sin.sin_family = AF_INET; +#if USE_INADDR + /* by setting sin.sin_addr.s_addr to INADDR_ANY, + I am telling the IP stack to automatically fill + in the IP address of the machine the process + is running on. + + Some server computers have multiple IP addresses. + A socket bound to one of these will not accept + connections to another address. Frequently you prefer + to allow any one of the computer's IP addresses + to be used for connections. Use INADDR_ANY (0L) to + allow clients to connect using any one of the host's + IP addresses. */ + sin.sin_addr.s_addr = htonl(INADDR_ANY); +#else + /* or we could use the specific adapter address + note: already in network byte order */ + sin.sin_addr.s_addr = address.s_addr; +#endif + sin.sin_port = htons(bip_get_port()); + memset(&(sin.sin_zero), '\0', sizeof(sin.sin_zero)); + rv = bind(sock_fd, + (const struct sockaddr *) &sin, sizeof(struct sockaddr)); + if (rv < 0) { + fprintf(stderr, "bip: failed to bind to %s port %hd\n", + inet_ntoa(sin.sin_addr), bip_get_port()); + close(sock_fd); + bip_set_socket(-1); + return false; + } + + return true; +} diff --git a/bacnet-stack/ports/win32/ethernet.c b/bacnet-stack/ports/win32/ethernet.c index 972b30b3..aee013da 100644 --- a/bacnet-stack/ports/win32/ethernet.c +++ b/bacnet-stack/ports/win32/ethernet.c @@ -1,455 +1,455 @@ -/*####COPYRIGHTBEGIN#### - ------------------------------------------- - Copyright (C) 2005 Steve Karg, modified by Kevin Liao - - 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####*/ - -#include /* for standard integer types uint8_t etc. */ -#include /* for the standard bool type. */ -#include -#include -#include - -#include "bacdef.h" -#include "ethernet.h" -#include "bacdcode.h" - - -/* Uses WinPCap to access raw ethernet */ -/* Notes: */ -/* To make ethernet.c work under win32, you have to: */ -/* 1. install winpcap 3.1 development pack; */ -/* 2. install Microsoft Platform SDK Feb 2003. */ -/* 3. remove or modify functions used for log such as */ -/* "LogError()", "LogInfo()", which were implemented */ -/* as a wrapper of Log4cpp. */ -/* -- Kevin Liao */ - -/* includes for accessing ethernet by using winpcap */ -#include "pcap.h" -#include "packet32.h" -#include "ntddndis.h" -#include "remote-ext.h" - - -/* commonly used comparison address for ethernet */ -uint8_t Ethernet_Broadcast[MAX_MAC_LEN] = - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; -/* commonly used empty address for ethernet quick compare */ -uint8_t Ethernet_Empty_MAC[MAX_MAC_LEN] = { 0, 0, 0, 0, 0, 0 }; - -/* my local device data - MAC address */ -uint8_t Ethernet_MAC_Address[MAX_MAC_LEN] = { 0 }; - -/* couple of var for using winpcap */ -static char pcap_errbuf[PCAP_ERRBUF_SIZE + 1]; -static pcap_t *pcap_eth802_fp = NULL; /* 802.2 file handle, from winpcap */ -static unsigned eth_timeout = 100; - - -/* couple of external func for runtime error logging, you can simply */ -/* replace them with standard "printf(...)" */ -/* Logging extern functions: Info level */ -extern void LogInfo(const char *msg); -/* Logging extern functions: Error level*/ -extern void LogError(const char *msg); -/* Logging extern functions: Debug level*/ -extern void LogDebug(const char *msg); - - -bool ethernet_valid(void) -{ - return (pcap_eth802_fp != NULL); -} - -void ethernet_cleanup(void) -{ - if (pcap_eth802_fp) { - pcap_close(pcap_eth802_fp); - pcap_eth802_fp = NULL; - } - LogInfo("ethernet.c: ethernet_cleanup() ok.\n"); -} - -void ethernet_set_timeout(unsigned timeout) -{ - eth_timeout = timeout; -} - -/*---------------------------------------------------------------------- - Portable function to set a socket into nonblocking mode. - Calling this on a socket causes all future read() and write() calls on - that socket to do only as much as they can immediately, and return - without waiting. - If no data can be read or written, they return -1 and set errno - to EAGAIN (or EWOULDBLOCK). - Thanks to Bjorn Reese for this code. -----------------------------------------------------------------------*/ -/** - * We don't need to use this function since WinPCap has provided one - * named "pcap_setnonblock()". - * Kevin, 2006.08.15 - */ -/* -int setNonblocking(int fd) -{ - int flags; - - if (-1 == (flags = fcntl(fd, F_GETFL, 0))) - flags = 0; - return fcntl(fd, F_SETFL, flags | O_NONBLOCK); -} -*/ - -bool ethernet_init(char *if_name) -{ - PPACKET_OID_DATA pOidData; - LPADAPTER lpAdapter; - pcap_if_t *pcap_all_if; - pcap_if_t *dev; - BOOLEAN result; - CHAR str[sizeof(PACKET_OID_DATA) + 128]; - int i; - char msgBuf[200]; - - if (ethernet_valid()) - ethernet_cleanup(); - - /** - * Find the interface user specified - */ - /* Retrieve the device list */ - if (pcap_findalldevs(&pcap_all_if, pcap_errbuf) == -1) { - sprintf(msgBuf, - "ethernet.c: error in pcap_findalldevs: %s\n", pcap_errbuf); - LogError(msgBuf); - return false; - } - /* Scan the list printing every entry */ - for (dev = pcap_all_if; dev; dev = dev->next) { - if (strcmp(if_name, dev->name) == 0) - break; - } - pcap_freealldevs(pcap_all_if); /* we don't need it anymore */ - if (dev == NULL) { - sprintf(msgBuf, - "ethernet.c: specified interface not found: %s\n", if_name); - LogError(msgBuf); - return false; - } - - /** - * Get local MAC address - */ - ZeroMemory(str, sizeof(PACKET_OID_DATA) + 128); - lpAdapter = PacketOpenAdapter(if_name); - if (lpAdapter == NULL) { - ethernet_cleanup(); - sprintf(msgBuf, - "ethernet.c: error in PacketOpenAdapter(\"%s\")\n", if_name); - LogError(msgBuf); - return false; - } - pOidData = (PPACKET_OID_DATA) str; - pOidData->Oid = OID_802_3_CURRENT_ADDRESS; - pOidData->Length = 6; - result = PacketRequest(lpAdapter, FALSE, pOidData); - if (!result) { - PacketCloseAdapter(lpAdapter); - ethernet_cleanup(); - LogError("ethernet.c: error in PacketRequest()\n"); - return false; - } - for (i = 0; i < 6; ++i) - Ethernet_MAC_Address[i] = pOidData->Data[i]; - PacketCloseAdapter(lpAdapter); - - /** - * Open interface for subsequent sending and receiving - */ - /* Open the output device */ - pcap_eth802_fp = pcap_open(if_name, /* name of the device */ - MAX_MPDU, /* portion of the packet to capture */ - PCAP_OPENFLAG_PROMISCUOUS, /* promiscuous mode */ - eth_timeout, /* read timeout */ - NULL, /* authentication on the remote machine */ - pcap_errbuf /* error buffer */ - ); - if (pcap_eth802_fp == NULL) { - PacketCloseAdapter(lpAdapter); - ethernet_cleanup(); - sprintf(msgBuf, - "ethernet.c: unable to open the adapter. %s is not supported by WinPcap\n", - if_name); - LogError(msgBuf); - return false; - } - - LogInfo("ethernet.c: ethernet_init() ok.\n"); - - atexit(ethernet_cleanup); - - return ethernet_valid(); -} - -/* function to send a packet out the 802.2 socket */ -/* returns bytes sent success, negative on failure */ -int ethernet_send(BACNET_ADDRESS * dest, /* destination address */ - BACNET_ADDRESS * src, /* source address */ - uint8_t * pdu, /* any data to be sent - may be null */ - unsigned pdu_len /* number of bytes of data */ - ) -{ - int bytes = 0; - uint8_t mtu[MAX_MPDU] = { 0 }; - int mtu_len = 0; - int i = 0; - - /* don't waste time if the socket is not valid */ - if (!ethernet_valid()) { - LogError - ("ethernet.c: invalid 802.2 ethernet interface descriptor!\n"); - return -1; - } - /* load destination ethernet MAC address */ - if (dest->mac_len == 6) { - for (i = 0; i < 6; i++) { - mtu[mtu_len] = dest->mac[i]; - mtu_len++; - } - } else { - LogError("ethernet.c: invalid destination MAC address!\n"); - return -2; - } - - /* load source ethernet MAC address */ - if (src->mac_len == 6) { - for (i = 0; i < 6; i++) { - mtu[mtu_len] = src->mac[i]; - mtu_len++; - } - } else { - LogError("ethernet.c: invalid source MAC address!\n"); - return -3; - } - if ((14 + 3 + pdu_len) > MAX_MPDU) { - LogError("ethernet.c: PDU is too big to send!\n"); - return -4; - } - /* packet length */ - mtu_len += - encode_unsigned16(&mtu[12], 3 /*DSAP,SSAP,LLC */ + pdu_len); - /* Logical PDU portion */ - mtu[mtu_len++] = 0x82; /* DSAP for BACnet */ - mtu[mtu_len++] = 0x82; /* SSAP for BACnet */ - mtu[mtu_len++] = 0x03; /* Control byte in header */ - memcpy(&mtu[mtu_len], pdu, pdu_len); - mtu_len += pdu_len; - - /* Send the packet */ - if (pcap_sendpacket(pcap_eth802_fp, mtu, mtu_len) != 0) { - /* did it get sent? */ - char msgBuf[200]; - sprintf(msgBuf, - "ethernet.c: error sending packet: %s\n", - pcap_geterr(pcap_eth802_fp)); - LogError(msgBuf); - return -5; - } - - return mtu_len; -} - -/* function to send a packet out the 802.2 socket */ -/* returns number of bytes sent on success, negative on failure */ -int ethernet_send_pdu(BACNET_ADDRESS * dest, /* destination address */ - uint8_t * pdu, /* any data to be sent - may be null */ - unsigned pdu_len /* number of bytes of data */ - ) -{ - int i = 0; /* counter */ - BACNET_ADDRESS src = { 0 }; /* source address */ - - for (i = 0; i < 6; i++) { - src.mac[i] = Ethernet_MAC_Address[i]; - src.mac_len++; - } - /* function to send a packet out the 802.2 socket */ - /* returns 1 on success, 0 on failure */ - return ethernet_send(dest, /* destination address */ - &src, /* source address */ - pdu, /* any data to be sent - may be null */ - pdu_len /* number of bytes of data */ - ); -} - -/* receives an 802.2 framed packet */ -/* returns the number of octets in the PDU, or zero on failure */ -uint16_t ethernet_receive(BACNET_ADDRESS * src, /* source address */ - uint8_t * pdu, /* PDU data */ - uint16_t max_pdu, /* amount of space available in the PDU */ - unsigned timeout /* number of milliseconds to wait for a packet. we ommit it due to winpcap API. */ - ) -{ - struct pcap_pkthdr *header; - int res; - u_char *pkt_data; - uint16_t pdu_len = 0; /* return value */ - - /* Make sure the socket is open */ - if (!ethernet_valid()) { - LogError - ("ethernet.c: invalid 802.2 ethernet interface descriptor!\n"); - return 0; - } - - /* Capture a packet */ - res = pcap_next_ex(pcap_eth802_fp, &header, &pkt_data); - if (res < 0) { - char msgBuf[200]; - sprintf(msgBuf, - "ethernet.c: error in receiving packet: %s\n", - pcap_geterr(pcap_eth802_fp)); - return 0; - } else if (res == 0) - return 0; - - if (header->len == 0 || header->caplen == 0) - return 0; - - /* the signature of an 802.2 BACnet packet */ - if ((pkt_data[14] != 0x82) && (pkt_data[15] != 0x82)) { - /*eth_log_error("ethernet.c: Non-BACnet packet\n"); */ - return 0; - } - /* copy the source address */ - src->mac_len = 6; - memmove(src->mac, &pkt_data[6], 6); - - /* check destination address for when */ - /* the Ethernet card is in promiscious mode */ - if ((memcmp(&pkt_data[0], Ethernet_MAC_Address, 6) != 0) - && (memcmp(&pkt_data[0], Ethernet_Broadcast, 6) != 0)) { - /*eth_log_error( "ethernet.c: This packet isn't for us\n"); */ - return 0; - } - - (void) decode_unsigned16(&pkt_data[12], &pdu_len); - pdu_len -= 3 /* DSAP, SSAP, LLC Control */ ; - /* copy the buffer into the PDU */ - if (pdu_len < max_pdu) - memmove(&pdu[0], &pkt_data[17], pdu_len); - /* ignore packets that are too large */ - else - pdu_len = 0; - - return pdu_len; -} - -void ethernet_set_my_address(BACNET_ADDRESS * my_address) -{ - int i = 0; - - for (i = 0; i < 6; i++) { - Ethernet_MAC_Address[i] = my_address->mac[i]; - } - - return; -} - -void ethernet_get_my_address(BACNET_ADDRESS * my_address) -{ - int i = 0; - - my_address->mac_len = 0; - for (i = 0; i < 6; i++) { - my_address->mac[i] = Ethernet_MAC_Address[i]; - my_address->mac_len++; - } - my_address->net = 0; /* local only, no routing */ - my_address->len = 0; - for (i = 0; i < MAX_MAC_LEN; i++) { - my_address->adr[i] = 0; - } - - return; -} - -void ethernet_get_broadcast_address(BACNET_ADDRESS * dest) -{ /* destination address */ - int i = 0; /* counter */ - - if (dest) { - for (i = 0; i < 6; i++) { - dest->mac[i] = Ethernet_Broadcast[i]; - } - dest->mac_len = 6; - dest->net = BACNET_BROADCAST_NETWORK; - dest->len = 0; /* denotes broadcast address */ - for (i = 0; i < MAX_MAC_LEN; i++) { - dest->adr[i] = 0; - } - } - - return; -} - -void ethernet_debug_address(const char *info, BACNET_ADDRESS * dest) -{ - int i = 0; /* counter */ - char msgBuf[200]; - - if (info) { - sprintf(msgBuf, "%s", info); - LogError(msgBuf); - } - /* if */ - if (dest) { - sprintf(msgBuf, - "Address:\n MAC Length=%d\n MAC Address=", dest->mac_len); - LogInfo(msgBuf); - for (i = 0; i < MAX_MAC_LEN; i++) { - sprintf(msgBuf, "%02X ", (unsigned) dest->mac[i]); - LogInfo(msgBuf); - } /* for */ - LogInfo("\n"); - sprintf(msgBuf, - " Net=%hu\n Len=%d\n Adr=", dest->net, dest->len); - LogInfo(msgBuf); - for (i = 0; i < MAX_MAC_LEN; i++) { - sprintf(msgBuf, "%02X ", (unsigned) dest->adr[i]); - LogInfo(msgBuf); - } /* for */ - LogInfo("\n"); - } - /* if ( dest ) */ - return; -} +/*####COPYRIGHTBEGIN#### + ------------------------------------------- + Copyright (C) 2005 Steve Karg, modified by Kevin Liao + + 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####*/ + +#include /* for standard integer types uint8_t etc. */ +#include /* for the standard bool type. */ +#include +#include +#include + +#include "bacdef.h" +#include "ethernet.h" +#include "bacdcode.h" + + +/* Uses WinPCap to access raw ethernet */ +/* Notes: */ +/* To make ethernet.c work under win32, you have to: */ +/* 1. install winpcap 3.1 development pack; */ +/* 2. install Microsoft Platform SDK Feb 2003. */ +/* 3. remove or modify functions used for log such as */ +/* "LogError()", "LogInfo()", which were implemented */ +/* as a wrapper of Log4cpp. */ +/* -- Kevin Liao */ + +/* includes for accessing ethernet by using winpcap */ +#include "pcap.h" +#include "packet32.h" +#include "ntddndis.h" +#include "remote-ext.h" + + +/* commonly used comparison address for ethernet */ +uint8_t Ethernet_Broadcast[MAX_MAC_LEN] = + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +/* commonly used empty address for ethernet quick compare */ +uint8_t Ethernet_Empty_MAC[MAX_MAC_LEN] = { 0, 0, 0, 0, 0, 0 }; + +/* my local device data - MAC address */ +uint8_t Ethernet_MAC_Address[MAX_MAC_LEN] = { 0 }; + +/* couple of var for using winpcap */ +static char pcap_errbuf[PCAP_ERRBUF_SIZE + 1]; +static pcap_t *pcap_eth802_fp = NULL; /* 802.2 file handle, from winpcap */ +static unsigned eth_timeout = 100; + + +/* couple of external func for runtime error logging, you can simply */ +/* replace them with standard "printf(...)" */ +/* Logging extern functions: Info level */ +extern void LogInfo(const char *msg); +/* Logging extern functions: Error level*/ +extern void LogError(const char *msg); +/* Logging extern functions: Debug level*/ +extern void LogDebug(const char *msg); + + +bool ethernet_valid(void) +{ + return (pcap_eth802_fp != NULL); +} + +void ethernet_cleanup(void) +{ + if (pcap_eth802_fp) { + pcap_close(pcap_eth802_fp); + pcap_eth802_fp = NULL; + } + LogInfo("ethernet.c: ethernet_cleanup() ok.\n"); +} + +void ethernet_set_timeout(unsigned timeout) +{ + eth_timeout = timeout; +} + +/*---------------------------------------------------------------------- + Portable function to set a socket into nonblocking mode. + Calling this on a socket causes all future read() and write() calls on + that socket to do only as much as they can immediately, and return + without waiting. + If no data can be read or written, they return -1 and set errno + to EAGAIN (or EWOULDBLOCK). + Thanks to Bjorn Reese for this code. +----------------------------------------------------------------------*/ +/** + * We don't need to use this function since WinPCap has provided one + * named "pcap_setnonblock()". + * Kevin, 2006.08.15 + */ +/* +int setNonblocking(int fd) +{ + int flags; + + if (-1 == (flags = fcntl(fd, F_GETFL, 0))) + flags = 0; + return fcntl(fd, F_SETFL, flags | O_NONBLOCK); +} +*/ + +bool ethernet_init(char *if_name) +{ + PPACKET_OID_DATA pOidData; + LPADAPTER lpAdapter; + pcap_if_t *pcap_all_if; + pcap_if_t *dev; + BOOLEAN result; + CHAR str[sizeof(PACKET_OID_DATA) + 128]; + int i; + char msgBuf[200]; + + if (ethernet_valid()) + ethernet_cleanup(); + + /** + * Find the interface user specified + */ + /* Retrieve the device list */ + if (pcap_findalldevs(&pcap_all_if, pcap_errbuf) == -1) { + sprintf(msgBuf, + "ethernet.c: error in pcap_findalldevs: %s\n", pcap_errbuf); + LogError(msgBuf); + return false; + } + /* Scan the list printing every entry */ + for (dev = pcap_all_if; dev; dev = dev->next) { + if (strcmp(if_name, dev->name) == 0) + break; + } + pcap_freealldevs(pcap_all_if); /* we don't need it anymore */ + if (dev == NULL) { + sprintf(msgBuf, + "ethernet.c: specified interface not found: %s\n", if_name); + LogError(msgBuf); + return false; + } + + /** + * Get local MAC address + */ + ZeroMemory(str, sizeof(PACKET_OID_DATA) + 128); + lpAdapter = PacketOpenAdapter(if_name); + if (lpAdapter == NULL) { + ethernet_cleanup(); + sprintf(msgBuf, + "ethernet.c: error in PacketOpenAdapter(\"%s\")\n", if_name); + LogError(msgBuf); + return false; + } + pOidData = (PPACKET_OID_DATA) str; + pOidData->Oid = OID_802_3_CURRENT_ADDRESS; + pOidData->Length = 6; + result = PacketRequest(lpAdapter, FALSE, pOidData); + if (!result) { + PacketCloseAdapter(lpAdapter); + ethernet_cleanup(); + LogError("ethernet.c: error in PacketRequest()\n"); + return false; + } + for (i = 0; i < 6; ++i) + Ethernet_MAC_Address[i] = pOidData->Data[i]; + PacketCloseAdapter(lpAdapter); + + /** + * Open interface for subsequent sending and receiving + */ + /* Open the output device */ + pcap_eth802_fp = pcap_open(if_name, /* name of the device */ + MAX_MPDU, /* portion of the packet to capture */ + PCAP_OPENFLAG_PROMISCUOUS, /* promiscuous mode */ + eth_timeout, /* read timeout */ + NULL, /* authentication on the remote machine */ + pcap_errbuf /* error buffer */ + ); + if (pcap_eth802_fp == NULL) { + PacketCloseAdapter(lpAdapter); + ethernet_cleanup(); + sprintf(msgBuf, + "ethernet.c: unable to open the adapter. %s is not supported by WinPcap\n", + if_name); + LogError(msgBuf); + return false; + } + + LogInfo("ethernet.c: ethernet_init() ok.\n"); + + atexit(ethernet_cleanup); + + return ethernet_valid(); +} + +/* function to send a packet out the 802.2 socket */ +/* returns bytes sent success, negative on failure */ +int ethernet_send(BACNET_ADDRESS * dest, /* destination address */ + BACNET_ADDRESS * src, /* source address */ + uint8_t * pdu, /* any data to be sent - may be null */ + unsigned pdu_len /* number of bytes of data */ + ) +{ + int bytes = 0; + uint8_t mtu[MAX_MPDU] = { 0 }; + int mtu_len = 0; + int i = 0; + + /* don't waste time if the socket is not valid */ + if (!ethernet_valid()) { + LogError + ("ethernet.c: invalid 802.2 ethernet interface descriptor!\n"); + return -1; + } + /* load destination ethernet MAC address */ + if (dest->mac_len == 6) { + for (i = 0; i < 6; i++) { + mtu[mtu_len] = dest->mac[i]; + mtu_len++; + } + } else { + LogError("ethernet.c: invalid destination MAC address!\n"); + return -2; + } + + /* load source ethernet MAC address */ + if (src->mac_len == 6) { + for (i = 0; i < 6; i++) { + mtu[mtu_len] = src->mac[i]; + mtu_len++; + } + } else { + LogError("ethernet.c: invalid source MAC address!\n"); + return -3; + } + if ((14 + 3 + pdu_len) > MAX_MPDU) { + LogError("ethernet.c: PDU is too big to send!\n"); + return -4; + } + /* packet length */ + mtu_len += + encode_unsigned16(&mtu[12], 3 /*DSAP,SSAP,LLC */ + pdu_len); + /* Logical PDU portion */ + mtu[mtu_len++] = 0x82; /* DSAP for BACnet */ + mtu[mtu_len++] = 0x82; /* SSAP for BACnet */ + mtu[mtu_len++] = 0x03; /* Control byte in header */ + memcpy(&mtu[mtu_len], pdu, pdu_len); + mtu_len += pdu_len; + + /* Send the packet */ + if (pcap_sendpacket(pcap_eth802_fp, mtu, mtu_len) != 0) { + /* did it get sent? */ + char msgBuf[200]; + sprintf(msgBuf, + "ethernet.c: error sending packet: %s\n", + pcap_geterr(pcap_eth802_fp)); + LogError(msgBuf); + return -5; + } + + return mtu_len; +} + +/* function to send a packet out the 802.2 socket */ +/* returns number of bytes sent on success, negative on failure */ +int ethernet_send_pdu(BACNET_ADDRESS * dest, /* destination address */ + uint8_t * pdu, /* any data to be sent - may be null */ + unsigned pdu_len /* number of bytes of data */ + ) +{ + int i = 0; /* counter */ + BACNET_ADDRESS src = { 0 }; /* source address */ + + for (i = 0; i < 6; i++) { + src.mac[i] = Ethernet_MAC_Address[i]; + src.mac_len++; + } + /* function to send a packet out the 802.2 socket */ + /* returns 1 on success, 0 on failure */ + return ethernet_send(dest, /* destination address */ + &src, /* source address */ + pdu, /* any data to be sent - may be null */ + pdu_len /* number of bytes of data */ + ); +} + +/* receives an 802.2 framed packet */ +/* returns the number of octets in the PDU, or zero on failure */ +uint16_t ethernet_receive(BACNET_ADDRESS * src, /* source address */ + uint8_t * pdu, /* PDU data */ + uint16_t max_pdu, /* amount of space available in the PDU */ + unsigned timeout /* number of milliseconds to wait for a packet. we ommit it due to winpcap API. */ + ) +{ + struct pcap_pkthdr *header; + int res; + u_char *pkt_data; + uint16_t pdu_len = 0; /* return value */ + + /* Make sure the socket is open */ + if (!ethernet_valid()) { + LogError + ("ethernet.c: invalid 802.2 ethernet interface descriptor!\n"); + return 0; + } + + /* Capture a packet */ + res = pcap_next_ex(pcap_eth802_fp, &header, &pkt_data); + if (res < 0) { + char msgBuf[200]; + sprintf(msgBuf, + "ethernet.c: error in receiving packet: %s\n", + pcap_geterr(pcap_eth802_fp)); + return 0; + } else if (res == 0) + return 0; + + if (header->len == 0 || header->caplen == 0) + return 0; + + /* the signature of an 802.2 BACnet packet */ + if ((pkt_data[14] != 0x82) && (pkt_data[15] != 0x82)) { + /*eth_log_error("ethernet.c: Non-BACnet packet\n"); */ + return 0; + } + /* copy the source address */ + src->mac_len = 6; + memmove(src->mac, &pkt_data[6], 6); + + /* check destination address for when */ + /* the Ethernet card is in promiscious mode */ + if ((memcmp(&pkt_data[0], Ethernet_MAC_Address, 6) != 0) + && (memcmp(&pkt_data[0], Ethernet_Broadcast, 6) != 0)) { + /*eth_log_error( "ethernet.c: This packet isn't for us\n"); */ + return 0; + } + + (void) decode_unsigned16(&pkt_data[12], &pdu_len); + pdu_len -= 3 /* DSAP, SSAP, LLC Control */ ; + /* copy the buffer into the PDU */ + if (pdu_len < max_pdu) + memmove(&pdu[0], &pkt_data[17], pdu_len); + /* ignore packets that are too large */ + else + pdu_len = 0; + + return pdu_len; +} + +void ethernet_set_my_address(BACNET_ADDRESS * my_address) +{ + int i = 0; + + for (i = 0; i < 6; i++) { + Ethernet_MAC_Address[i] = my_address->mac[i]; + } + + return; +} + +void ethernet_get_my_address(BACNET_ADDRESS * my_address) +{ + int i = 0; + + my_address->mac_len = 0; + for (i = 0; i < 6; i++) { + my_address->mac[i] = Ethernet_MAC_Address[i]; + my_address->mac_len++; + } + my_address->net = 0; /* local only, no routing */ + my_address->len = 0; + for (i = 0; i < MAX_MAC_LEN; i++) { + my_address->adr[i] = 0; + } + + return; +} + +void ethernet_get_broadcast_address(BACNET_ADDRESS * dest) +{ /* destination address */ + int i = 0; /* counter */ + + if (dest) { + for (i = 0; i < 6; i++) { + dest->mac[i] = Ethernet_Broadcast[i]; + } + dest->mac_len = 6; + dest->net = BACNET_BROADCAST_NETWORK; + dest->len = 0; /* denotes broadcast address */ + for (i = 0; i < MAX_MAC_LEN; i++) { + dest->adr[i] = 0; + } + } + + return; +} + +void ethernet_debug_address(const char *info, BACNET_ADDRESS * dest) +{ + int i = 0; /* counter */ + char msgBuf[200]; + + if (info) { + sprintf(msgBuf, "%s", info); + LogError(msgBuf); + } + /* if */ + if (dest) { + sprintf(msgBuf, + "Address:\n MAC Length=%d\n MAC Address=", dest->mac_len); + LogInfo(msgBuf); + for (i = 0; i < MAX_MAC_LEN; i++) { + sprintf(msgBuf, "%02X ", (unsigned) dest->mac[i]); + LogInfo(msgBuf); + } /* for */ + LogInfo("\n"); + sprintf(msgBuf, + " Net=%hu\n Len=%d\n Adr=", dest->net, dest->len); + LogInfo(msgBuf); + for (i = 0; i < MAX_MAC_LEN; i++) { + sprintf(msgBuf, "%02X ", (unsigned) dest->adr[i]); + LogInfo(msgBuf); + } /* for */ + LogInfo("\n"); + } + /* if ( dest ) */ + return; +} diff --git a/bacnet-stack/ports/win32/main.c b/bacnet-stack/ports/win32/main.c index 7d0d76f8..ee8a84e5 100644 --- a/bacnet-stack/ports/win32/main.c +++ b/bacnet-stack/ports/win32/main.c @@ -1,257 +1,257 @@ -/************************************************************************** -* -* Copyright (C) 2005 Steve Karg -* -* Permission is hereby granted, free of charge, to any person obtaining -* a copy of this software and associated documentation files (the -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to -* permit persons to whom the Software is furnished to do so, subject to -* the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -* -*********************************************************************/ - -/* This is one way to use the embedded BACnet stack under Win32 */ -/* compiled with Borland C++ 5.02 or Visual C++ 6.0 */ -#include -#include -#include -#include -#include /* for kbhit and getch */ -#include "iam.h" -#include "address.h" -#include "config.h" -#include "bacdef.h" -#include "npdu.h" -#include "apdu.h" -#include "device.h" -#include "handlers.h" -#include "client.h" -#include "datalink.h" -#include "txbuf.h" - -/* buffer used for receive */ -static uint8_t Rx_Buf[MAX_MPDU] = { 0 }; - -/* send a whois to see who is on the network */ -static bool Who_Is_Request = true; -bool I_Am_Request = true; - -static void Read_Properties(void) -{ - uint32_t device_id = 0; - bool status = false; - unsigned max_apdu = 0; - BACNET_ADDRESS src; - bool next_device = false; - static unsigned index = 0; - static unsigned property = 0; - /* list of required (and some optional) properties in the - Device Object - note: you could just loop through - all the properties in all the objects. */ - const int object_props[] = { - PROP_OBJECT_IDENTIFIER, - PROP_OBJECT_NAME, - PROP_OBJECT_TYPE, - PROP_SYSTEM_STATUS, - PROP_VENDOR_NAME, - PROP_VENDOR_IDENTIFIER, - PROP_MODEL_NAME, - PROP_FIRMWARE_REVISION, - PROP_APPLICATION_SOFTWARE_VERSION, - PROP_PROTOCOL_VERSION, - PROP_PROTOCOL_CONFORMANCE_CLASS, - PROP_PROTOCOL_SERVICES_SUPPORTED, - PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED, - PROP_MAX_APDU_LENGTH_ACCEPTED, - PROP_SEGMENTATION_SUPPORTED, - PROP_LOCAL_TIME, - PROP_LOCAL_DATE, - PROP_UTC_OFFSET, - PROP_DAYLIGHT_SAVINGS_STATUS, - PROP_APDU_SEGMENT_TIMEOUT, - PROP_APDU_TIMEOUT, - PROP_NUMBER_OF_APDU_RETRIES, - PROP_TIME_SYNCHRONIZATION_RECIPIENTS, - PROP_MAX_MASTER, - PROP_MAX_INFO_FRAMES, - PROP_DEVICE_ADDRESS_BINDING, - /* note: PROP_OBJECT_LIST is missing cause - we need to get it with an index method since - the list could be very large */ - /* some proprietary properties */ - 514, 515, - /* end of list */ - -1 - }; - - if (address_count()) { - if (address_get_by_index(index, &device_id, &max_apdu, &src)) { - if (object_props[property] < 0) - next_device = true; - else { - status = Send_Read_Property_Request(device_id, /* destination device */ - OBJECT_DEVICE, - device_id, object_props[property], BACNET_ARRAY_ALL); - if (status) - property++; - } - } else - next_device = true; - if (next_device) { - next_device = false; - index++; - if (index >= MAX_ADDRESS_CACHE) - index = 0; - property = 0; - } - } - - return; -} - -static void LocalIAmHandler(uint8_t * service_request, - uint16_t service_len, BACNET_ADDRESS * src) -{ - int len = 0; - uint32_t device_id = 0; - unsigned max_apdu = 0; - int segmentation = 0; - uint16_t vendor_id = 0; - - (void) src; - (void) service_len; - len = iam_decode_service_request(service_request, - &device_id, &max_apdu, &segmentation, &vendor_id); - fprintf(stderr, "Received I-Am Request"); - if (len != -1) { - fprintf(stderr, " from %u!\n", device_id); - address_add(device_id, max_apdu, src); - } else - fprintf(stderr, "!\n"); - - return; -} - -static void Init_Service_Handlers(void) -{ - /* we need to handle who-is to support dynamic device binding */ - apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, - handler_who_is); - apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_I_AM, - LocalIAmHandler); - - /* set the handler for all the services we don't implement */ - /* It is required to send the proper reject message... */ - apdu_set_unrecognized_service_handler_handler - (handler_unrecognized_service); - /* we must implement read property - it's required! */ - apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY, - handler_read_property); - apdu_set_confirmed_handler(SERVICE_CONFIRMED_WRITE_PROPERTY, - handler_write_property); - /* handle the data coming back from confirmed requests */ - apdu_set_confirmed_ack_handler(SERVICE_CONFIRMED_READ_PROPERTY, - handler_read_property_ack); -} - -static void print_address(char *name, BACNET_ADDRESS * dest) -{ /* destination address */ - int i = 0; /* counter */ - - if (dest) { - printf("%s: ", name); - for (i = 0; i < dest->mac_len; i++) { - printf("%02X", dest->mac[i]); - } - printf("\n"); - } -} - -static void print_address_cache(void) -{ - int i, j; - BACNET_ADDRESS address; - uint32_t device_id = 0; - unsigned max_apdu = 0; - - fprintf(stderr, "Device\tMAC\tMaxAPDU\tNet\n"); - for (i = 0; i < MAX_ADDRESS_CACHE; i++) { - if (address_get_by_index(i, &device_id, &max_apdu, &address)) { - fprintf(stderr, "%u\t", device_id); - for (j = 0; j < address.mac_len; j++) { - fprintf(stderr, "%02X", address.mac[j]); - } - fprintf(stderr, "\t"); - fprintf(stderr, "%hu\t", max_apdu); - fprintf(stderr, "%hu\n", address.net); - } - } -} - -int main(int argc, char *argv[]) -{ - BACNET_ADDRESS src = { 0 }; /* address where message came from */ - uint16_t pdu_len = 0; - unsigned timeout = 100; /* milliseconds */ - BACNET_ADDRESS my_address, broadcast_address; - - (void) argc; - (void) argv; - Device_Set_Object_Instance_Number(124); - Init_Service_Handlers(); - /* init the data link layer */ - if (!datalink_init(NULL)) - return 1; - datalink_get_broadcast_address(&broadcast_address); - print_address("Broadcast", &broadcast_address); - datalink_get_my_address(&my_address); - print_address("Address", &my_address); - - printf("BACnet stack running...\n"); - /* loop forever */ - for (;;) { - /* input */ - - /* returns 0 bytes on timeout */ - pdu_len = datalink_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout); - /* process */ - if (pdu_len) { - npdu_handler(&src, &Rx_Buf[0], pdu_len); - } - if (I_Am_Request) { - I_Am_Request = false; - iam_send(&Handler_Transmit_Buffer[0]); - } else if (Who_Is_Request) { - Who_Is_Request = false; - Send_WhoIs(-1, -1); - } else { - Read_Properties(); - } - - /* output */ - - /* blink LEDs, Turn on or off outputs, etc */ - - /* wait for ESC from keyboard before quitting */ - if (kbhit() && (getch() == 0x1B)) - break; - } - - print_address_cache(); - - return 0; -} +/************************************************************************** +* +* Copyright (C) 2005 Steve Karg +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*********************************************************************/ + +/* This is one way to use the embedded BACnet stack under Win32 */ +/* compiled with Borland C++ 5.02 or Visual C++ 6.0 */ +#include +#include +#include +#include +#include /* for kbhit and getch */ +#include "iam.h" +#include "address.h" +#include "config.h" +#include "bacdef.h" +#include "npdu.h" +#include "apdu.h" +#include "device.h" +#include "handlers.h" +#include "client.h" +#include "datalink.h" +#include "txbuf.h" + +/* buffer used for receive */ +static uint8_t Rx_Buf[MAX_MPDU] = { 0 }; + +/* send a whois to see who is on the network */ +static bool Who_Is_Request = true; +bool I_Am_Request = true; + +static void Read_Properties(void) +{ + uint32_t device_id = 0; + bool status = false; + unsigned max_apdu = 0; + BACNET_ADDRESS src; + bool next_device = false; + static unsigned index = 0; + static unsigned property = 0; + /* list of required (and some optional) properties in the + Device Object + note: you could just loop through + all the properties in all the objects. */ + const int object_props[] = { + PROP_OBJECT_IDENTIFIER, + PROP_OBJECT_NAME, + PROP_OBJECT_TYPE, + PROP_SYSTEM_STATUS, + PROP_VENDOR_NAME, + PROP_VENDOR_IDENTIFIER, + PROP_MODEL_NAME, + PROP_FIRMWARE_REVISION, + PROP_APPLICATION_SOFTWARE_VERSION, + PROP_PROTOCOL_VERSION, + PROP_PROTOCOL_CONFORMANCE_CLASS, + PROP_PROTOCOL_SERVICES_SUPPORTED, + PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED, + PROP_MAX_APDU_LENGTH_ACCEPTED, + PROP_SEGMENTATION_SUPPORTED, + PROP_LOCAL_TIME, + PROP_LOCAL_DATE, + PROP_UTC_OFFSET, + PROP_DAYLIGHT_SAVINGS_STATUS, + PROP_APDU_SEGMENT_TIMEOUT, + PROP_APDU_TIMEOUT, + PROP_NUMBER_OF_APDU_RETRIES, + PROP_TIME_SYNCHRONIZATION_RECIPIENTS, + PROP_MAX_MASTER, + PROP_MAX_INFO_FRAMES, + PROP_DEVICE_ADDRESS_BINDING, + /* note: PROP_OBJECT_LIST is missing cause + we need to get it with an index method since + the list could be very large */ + /* some proprietary properties */ + 514, 515, + /* end of list */ + -1 + }; + + if (address_count()) { + if (address_get_by_index(index, &device_id, &max_apdu, &src)) { + if (object_props[property] < 0) + next_device = true; + else { + status = Send_Read_Property_Request(device_id, /* destination device */ + OBJECT_DEVICE, + device_id, object_props[property], BACNET_ARRAY_ALL); + if (status) + property++; + } + } else + next_device = true; + if (next_device) { + next_device = false; + index++; + if (index >= MAX_ADDRESS_CACHE) + index = 0; + property = 0; + } + } + + return; +} + +static void LocalIAmHandler(uint8_t * service_request, + uint16_t service_len, BACNET_ADDRESS * src) +{ + int len = 0; + uint32_t device_id = 0; + unsigned max_apdu = 0; + int segmentation = 0; + uint16_t vendor_id = 0; + + (void) src; + (void) service_len; + len = iam_decode_service_request(service_request, + &device_id, &max_apdu, &segmentation, &vendor_id); + fprintf(stderr, "Received I-Am Request"); + if (len != -1) { + fprintf(stderr, " from %u!\n", device_id); + address_add(device_id, max_apdu, src); + } else + fprintf(stderr, "!\n"); + + return; +} + +static void Init_Service_Handlers(void) +{ + /* we need to handle who-is to support dynamic device binding */ + apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, + handler_who_is); + apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_I_AM, + LocalIAmHandler); + + /* set the handler for all the services we don't implement */ + /* It is required to send the proper reject message... */ + apdu_set_unrecognized_service_handler_handler + (handler_unrecognized_service); + /* we must implement read property - it's required! */ + apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY, + handler_read_property); + apdu_set_confirmed_handler(SERVICE_CONFIRMED_WRITE_PROPERTY, + handler_write_property); + /* handle the data coming back from confirmed requests */ + apdu_set_confirmed_ack_handler(SERVICE_CONFIRMED_READ_PROPERTY, + handler_read_property_ack); +} + +static void print_address(char *name, BACNET_ADDRESS * dest) +{ /* destination address */ + int i = 0; /* counter */ + + if (dest) { + printf("%s: ", name); + for (i = 0; i < dest->mac_len; i++) { + printf("%02X", dest->mac[i]); + } + printf("\n"); + } +} + +static void print_address_cache(void) +{ + int i, j; + BACNET_ADDRESS address; + uint32_t device_id = 0; + unsigned max_apdu = 0; + + fprintf(stderr, "Device\tMAC\tMaxAPDU\tNet\n"); + for (i = 0; i < MAX_ADDRESS_CACHE; i++) { + if (address_get_by_index(i, &device_id, &max_apdu, &address)) { + fprintf(stderr, "%u\t", device_id); + for (j = 0; j < address.mac_len; j++) { + fprintf(stderr, "%02X", address.mac[j]); + } + fprintf(stderr, "\t"); + fprintf(stderr, "%hu\t", max_apdu); + fprintf(stderr, "%hu\n", address.net); + } + } +} + +int main(int argc, char *argv[]) +{ + BACNET_ADDRESS src = { 0 }; /* address where message came from */ + uint16_t pdu_len = 0; + unsigned timeout = 100; /* milliseconds */ + BACNET_ADDRESS my_address, broadcast_address; + + (void) argc; + (void) argv; + Device_Set_Object_Instance_Number(124); + Init_Service_Handlers(); + /* init the data link layer */ + if (!datalink_init(NULL)) + return 1; + datalink_get_broadcast_address(&broadcast_address); + print_address("Broadcast", &broadcast_address); + datalink_get_my_address(&my_address); + print_address("Address", &my_address); + + printf("BACnet stack running...\n"); + /* loop forever */ + for (;;) { + /* input */ + + /* returns 0 bytes on timeout */ + pdu_len = datalink_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout); + /* process */ + if (pdu_len) { + npdu_handler(&src, &Rx_Buf[0], pdu_len); + } + if (I_Am_Request) { + I_Am_Request = false; + iam_send(&Handler_Transmit_Buffer[0]); + } else if (Who_Is_Request) { + Who_Is_Request = false; + Send_WhoIs(-1, -1); + } else { + Read_Properties(); + } + + /* output */ + + /* blink LEDs, Turn on or off outputs, etc */ + + /* wait for ESC from keyboard before quitting */ + if (kbhit() && (getch() == 0x1B)) + break; + } + + print_address_cache(); + + return 0; +} diff --git a/bacnet-stack/ports/win32/net.h b/bacnet-stack/ports/win32/net.h index a717cf7b..58145a9b 100644 --- a/bacnet-stack/ports/win32/net.h +++ b/bacnet-stack/ports/win32/net.h @@ -1,38 +1,38 @@ -/************************************************************************** -* -* Copyright (C) 2005 Steve Karg -* -* Permission is hereby granted, free of charge, to any person obtaining -* a copy of this software and associated documentation files (the -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to -* permit persons to whom the Software is furnished to do so, subject to -* the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -* -*********************************************************************/ - -#ifndef NET_H -#define NET_H - -#define WIN32_LEAN_AND_MEAN -#define STRICT 1 - -#include - -#define close closesocket - -typedef int socklen_t; - -#endif +/************************************************************************** +* +* Copyright (C) 2005 Steve Karg +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*********************************************************************/ + +#ifndef NET_H +#define NET_H + +#define WIN32_LEAN_AND_MEAN +#define STRICT 1 + +#include + +#define close closesocket + +typedef int socklen_t; + +#endif diff --git a/bacnet-stack/ports/win32/readme.txt b/bacnet-stack/ports/win32/readme.txt index a5bd7030..90b110f0 100644 --- a/bacnet-stack/ports/win32/readme.txt +++ b/bacnet-stack/ports/win32/readme.txt @@ -1,15 +1,15 @@ -BACnet Stack - Win32 - -This directory contains a demo program that compiles with a Win32 compiler. -It was tested with the freely downloadable Borland C++ 5.5, as well as -Borland C++ 5 and Visual C++ 6.0. - -The makefile.mak file is used with the Borland command line tools. -Run setvars.bat to configure the environment for the Borland tools. -Edit it if necessary to set the correct location of your tools. - -The bacnet.ide file is used with the Borland IDE. - -The bacnet directory is used with Visual C++ 6 tools, and there is a -workspace file bacnet.dsw that is used to compile the demo program. - +BACnet Stack - Win32 + +This directory contains a demo program that compiles with a Win32 compiler. +It was tested with the freely downloadable Borland C++ 5.5, as well as +Borland C++ 5 and Visual C++ 6.0. + +The makefile.mak file is used with the Borland command line tools. +Run setvars.bat to configure the environment for the Borland tools. +Edit it if necessary to set the correct location of your tools. + +The bacnet.ide file is used with the Borland IDE. + +The bacnet directory is used with Visual C++ 6 tools, and there is a +workspace file bacnet.dsw that is used to compile the demo program. + diff --git a/bacnet-stack/ports/win32/setvars.bat b/bacnet-stack/ports/win32/setvars.bat index 6a804123..fb8fe9cc 100644 --- a/bacnet-stack/ports/win32/setvars.bat +++ b/bacnet-stack/ports/win32/setvars.bat @@ -1,2 +1,2 @@ -set BORLAND_DIR=\bcc55 - +set BORLAND_DIR=\bcc55 + diff --git a/bacnet-stack/ports/win32/stdbool.h b/bacnet-stack/ports/win32/stdbool.h index 2b7511a6..4c05de20 100644 --- a/bacnet-stack/ports/win32/stdbool.h +++ b/bacnet-stack/ports/win32/stdbool.h @@ -1,28 +1,28 @@ -#ifndef STDBOOL_H -#define STDBOOL_H - -/* C99 Boolean types for compilers without C99 support */ - -#ifndef __cplusplus -typedef int _Bool; -#ifndef bool -#define bool _Bool -#endif -#ifndef true -#define true 1 -#endif -#ifndef false -#define false 0 -#endif -#define __bool_true_false_are_defined 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -#ifndef TRUE -#define TRUE 1 -#endif - -#endif +#ifndef STDBOOL_H +#define STDBOOL_H + +/* C99 Boolean types for compilers without C99 support */ + +#ifndef __cplusplus +typedef int _Bool; +#ifndef bool +#define bool _Bool +#endif +#ifndef true +#define true 1 +#endif +#ifndef false +#define false 0 +#endif +#define __bool_true_false_are_defined 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#endif diff --git a/bacnet-stack/ports/win32/stdint.h b/bacnet-stack/ports/win32/stdint.h index 9c003d0a..3bd54ae8 100644 --- a/bacnet-stack/ports/win32/stdint.h +++ b/bacnet-stack/ports/win32/stdint.h @@ -1,19 +1,19 @@ -/* Defines the standard integer types that are used in code */ -/* for the x86 processor and Borland Compiler */ - -#ifndef STDINT_H -#define STDINT_H - -#include - -typedef unsigned char uint8_t; /* 1 byte 0 to 255 */ -typedef signed char int8_t; /* 1 byte -127 to 127 */ -typedef unsigned short uint16_t; /* 2 bytes 0 to 65535 */ -typedef signed short int16_t; /* 2 bytes -32767 to 32767 */ -/*typedef unsigned short long uint24_t; // 3 bytes 0 to 16777215 */ -typedef unsigned long uint32_t; /* 4 bytes 0 to 4294967295 */ -typedef signed long int32_t; /* 4 bytes -2147483647 to 2147483647 */ -/* typedef signed long long int64_t; */ -/* typedef unsigned long long uint64_t; */ - -#endif /* STDINT_H */ +/* Defines the standard integer types that are used in code */ +/* for the x86 processor and Borland Compiler */ + +#ifndef STDINT_H +#define STDINT_H + +#include + +typedef unsigned char uint8_t; /* 1 byte 0 to 255 */ +typedef signed char int8_t; /* 1 byte -127 to 127 */ +typedef unsigned short uint16_t; /* 2 bytes 0 to 65535 */ +typedef signed short int16_t; /* 2 bytes -32767 to 32767 */ +/*typedef unsigned short long uint24_t; // 3 bytes 0 to 16777215 */ +typedef unsigned long uint32_t; /* 4 bytes 0 to 4294967295 */ +typedef signed long int32_t; /* 4 bytes -2147483647 to 2147483647 */ +/* typedef signed long long int64_t; */ +/* typedef unsigned long long uint64_t; */ + +#endif /* STDINT_H */