diff --git a/bacnet-stack/bacdcode.c b/bacnet-stack/bacdcode.c index e87f4177..acca3ac0 100644 --- a/bacnet-stack/bacdcode.c +++ b/bacnet-stack/bacdcode.c @@ -471,7 +471,7 @@ int encode_tagged_real(uint8_t * apdu, float value) // from clause 20.2.14 Encoding of an Object Identifier Value // returns the number of apdu bytes consumed -int decode_object_id(uint8_t * apdu, int *object_type, int *instance) +int decode_object_id(uint8_t * apdu, int *object_type, uint32_t *instance) { union { uint8_t byte[4]; @@ -498,7 +498,7 @@ int decode_object_id(uint8_t * apdu, int *object_type, int *instance) // from clause 20.2.14 Encoding of an Object Identifier Value // returns the number of apdu bytes consumed -int encode_bacnet_object_id(uint8_t * apdu, int object_type, int instance) +int encode_bacnet_object_id(uint8_t * apdu, int object_type, uint32_t instance) { union { uint8_t byte[4]; @@ -526,7 +526,7 @@ int encode_bacnet_object_id(uint8_t * apdu, int object_type, int instance) // and 20.2.1 General Rules for Encoding BACnet Tags // returns the number of apdu bytes consumed int encode_context_object_id(uint8_t * apdu, int tag_number, - int object_type, int instance) + int object_type, uint32_t instance) { int len = 0; @@ -540,7 +540,7 @@ int encode_context_object_id(uint8_t * apdu, int tag_number, // from clause 20.2.14 Encoding of an Object Identifier Value // and 20.2.1 General Rules for Encoding BACnet Tags // returns the number of apdu bytes consumed -int encode_tagged_object_id(uint8_t * apdu, int object_type, int instance) +int encode_tagged_object_id(uint8_t * apdu, int object_type, uint32_t instance) { int len = 0; @@ -1231,7 +1231,7 @@ void testBACDCodeObject(Test * pTest) BACNET_OBJECT_TYPE type = OBJECT_BINARY_INPUT; BACNET_OBJECT_TYPE decoded_type = OBJECT_ANALOG_OUTPUT; int instance = 123; - int decoded_instance = 0; + uint32_t decoded_instance = 0; encode_bacnet_object_id(&encoded_array[0], type, instance); decode_object_id(&encoded_array[0], diff --git a/bacnet-stack/bacdcode.h b/bacnet-stack/bacdcode.h index 73230ca0..659c534d 100644 --- a/bacnet-stack/bacdcode.h +++ b/bacnet-stack/bacdcode.h @@ -67,11 +67,11 @@ int encode_tagged_real(uint8_t * apdu, float value); // from clause 20.2.14 Encoding of an Object Identifier Value // and 20.2.1 General Rules for Encoding BACnet Tags // returns the number of apdu bytes consumed -int decode_object_id(uint8_t * apdu, int *object_type, int *instance); -int encode_bacnet_object_id(uint8_t * apdu, int object_type, int instance); +int decode_object_id(uint8_t * apdu, int *object_type, uint32_t *instance); +int encode_bacnet_object_id(uint8_t * apdu, int object_type, uint32_t instance); int encode_context_object_id(uint8_t * apdu, int tag_number, - int object_type, int instance); -int encode_tagged_object_id(uint8_t * apdu, int object_type, int instance); + int object_type, uint32_t instance); +int encode_tagged_object_id(uint8_t * apdu, int object_type, uint32_t instance); // from clause 20.2.9 Encoding of a Character String Value // and 20.2.1 General Rules for Encoding BACnet Tags diff --git a/bacnet-stack/bacenum.h b/bacnet-stack/bacenum.h index 8623115b..2ad7761e 100644 --- a/bacnet-stack/bacenum.h +++ b/bacnet-stack/bacenum.h @@ -579,6 +579,7 @@ typedef enum SEGMENTATION_TRANSMIT = 1, SEGMENTATION_RECEIVE = 2, SEGMENTATION_NONE = 3, + MAX_BACNET_SEGMENTATION = 4, } BACNET_SEGMENTATION; typedef enum diff --git a/bacnet-stack/iam.c b/bacnet-stack/iam.c new file mode 100755 index 00000000..b26a74ba --- /dev/null +++ b/bacnet-stack/iam.c @@ -0,0 +1,191 @@ +/*####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####*/ +#include +#include "bacenum.h" +#include "bacdcode.h" + +// encode I-Am service +int iam_encode_apdu( + uint8_t *apdu, + uint32_t device_id, + unsigned max_apdu, + int segmentation, + uint16_t vendor_id) +{ + int len = 0; // length of each encoding + int apdu_len = 0; // total length of the apdu, return value + + if (apdu) { + apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST; + apdu[1] = SERVICE_UNCONFIRMED_I_AM; // service choice + apdu_len = 2; + len = encode_tagged_object_id( + &apdu[apdu_len], + OBJECT_DEVICE, + device_id); + apdu_len += len; + len = encode_tagged_unsigned( + &apdu[apdu_len], + max_apdu); + apdu_len += len; + len = encode_tagged_enumerated( + &apdu[apdu_len], + segmentation); + apdu_len += len; + len = encode_tagged_unsigned( + &apdu[apdu_len], + vendor_id); + apdu_len += len; + } + + return apdu_len; +} + +int iam_decode_apdu( + uint8_t *apdu, + uint32_t *pDevice_id, + unsigned *pMax_apdu, + int *pSegmentation, + uint16_t *pVendor_id) +{ + int len = 0; + int object_type = 0; // should be a Device Object + uint32_t object_instance = 0; + uint8_t tag_number = 0; + uint32_t len_value = 0; + unsigned int decoded_value = 0; + + // optional checking - most likely was already done prior to this call + if (apdu[0] != PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST) + return -1; + if (apdu[1] != SERVICE_UNCONFIRMED_I_AM) + return -1; + // OBJECT ID - object id + len = 2; + len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); + if (tag_number != BACNET_APPLICATION_TAG_OBJECT_ID) + return -1; + len += decode_object_id(&apdu[len], &object_type, &object_instance); + if (object_type != OBJECT_DEVICE) + return -1; + *pDevice_id = object_instance; + // MAX APDU - unsigned + len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); + if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT) + return -1; + len += decode_unsigned(&apdu[len], len_value, &decoded_value); + *pMax_apdu = decoded_value; + // Segmentation - enumerated + len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); + if (tag_number != BACNET_APPLICATION_TAG_ENUMERATED) + return -1; + len += decode_enumerated(&apdu[len],len_value, &decoded_value); + if (decoded_value >= MAX_BACNET_SEGMENTATION) + return -1; + *pSegmentation = decoded_value; + // Vendor ID - unsigned16 + len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); + if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT) + return -1; + len += decode_unsigned(&apdu[len], len_value, &decoded_value); + if (decoded_value > 0xFFFF) + return -1; + *pVendor_id = decoded_value; + + return len; +} + +#ifdef TEST +#include +#include +#include "ctest.h" + +void testIAm(Test * pTest) +{ + uint8_t apdu[480] = {0}; + int len = 0; + uint32_t device_id = 42; + unsigned max_apdu = 480; + int segmentation = SEGMENTATION_NONE; + uint16_t vendor_id = 42; + uint32_t test_device_id = 0; + unsigned test_max_apdu = 0; + int test_segmentation = 0; + uint16_t test_vendor_id = 0; + + len = iam_encode_apdu( + &apdu[0], + device_id, + max_apdu, + segmentation, + vendor_id); + ct_test(pTest, len != 0); + + len = iam_decode_apdu( + &apdu[0], + &test_device_id, + &test_max_apdu, + &test_segmentation, + &test_vendor_id); + ct_test(pTest, len != -1); + ct_test(pTest, test_device_id == device_id); + ct_test(pTest, test_vendor_id == vendor_id); + ct_test(pTest, test_max_apdu == max_apdu); + ct_test(pTest, test_segmentation == segmentation); + + // check the error conditions + + +} + +#ifdef TEST_IAM +int main(void) +{ + Test *pTest; + bool rc; + + pTest = ct_create("BACnet I-Am", NULL); + /* individual tests */ + rc = ct_addTestFunction(pTest, testIAm); + assert(rc); + + 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/iam.h b/bacnet-stack/iam.h new file mode 100644 index 00000000..d12d64d0 --- /dev/null +++ b/bacnet-stack/iam.h @@ -0,0 +1,58 @@ +/*####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####*/ +#ifndef IAM_H +#define IAM_H + +#include +#include + +int iam_encode_apdu( + uint8_t *apdu, + uint32_t device_id, + unsigned max_apdu, + int segmentation, + uint16_t vendor_id); + +int iam_decode_apdu( + uint8_t *apdu, + uint32_t *pDevice_id, + unsigned *pMax_apdu, + int *pSegmentation, + uint16_t *pVendor_id); + +#ifdef TEST +void testIAm(Test * pTest); +#endif + +#endif \ No newline at end of file diff --git a/bacnet-stack/iam.mak b/bacnet-stack/iam.mak new file mode 100755 index 00000000..828823d1 --- /dev/null +++ b/bacnet-stack/iam.mak @@ -0,0 +1,33 @@ +#Makefile to build test case +CC = gcc +BASEDIR = . +#CFLAGS = -Wall -I. +# -g for debugging with gdb +#CFLAGS = -Wall -I. -g +CFLAGS = -Wall -I. -Itest -DTEST -DTEST_IAM -g + +SRCS = bacdcode.c \ + bigend.c \ + iam.c \ + test/ctest.c + +OBJS = ${SRCS:.c=.o} + +TARGET = iam + +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 *.1 *.ini + +include: .depend