diff --git a/bacnet-stack/abort.mak b/bacnet-stack/abort.mak index 64d762e1..753540ec 100644 --- a/bacnet-stack/abort.mak +++ b/bacnet-stack/abort.mak @@ -7,6 +7,7 @@ BASEDIR = . CFLAGS = -Wall -I. -Itest -DTEST -DTEST_ABORT -g SRCS = bacdcode.c \ + bacstr.c \ bigend.c \ abort.c \ test/ctest.c diff --git a/bacnet-stack/ai.c b/bacnet-stack/ai.c index 4a965aaa..1e11205f 100644 --- a/bacnet-stack/ai.c +++ b/bacnet-stack/ai.c @@ -71,6 +71,7 @@ int Analog_Input_Encode_Property_APDU( { int apdu_len = 0; // return value BACNET_BIT_STRING bit_string; + BACNET_CHARACTER_STRING char_string; char text_string[32] = {""}; float value = 3.14; @@ -84,7 +85,9 @@ int Analog_Input_Encode_Property_APDU( case PROP_OBJECT_NAME: case PROP_DESCRIPTION: sprintf(text_string,"ANALOG INPUT %u",object_instance); - apdu_len = encode_tagged_character_string(&apdu[0], text_string); + characterstring_init_ansi(&char_string, text_string); + 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); diff --git a/bacnet-stack/ai.mak b/bacnet-stack/ai.mak index 617981f9..6aef7e43 100755 --- a/bacnet-stack/ai.mak +++ b/bacnet-stack/ai.mak @@ -7,6 +7,7 @@ BASEDIR = . CFLAGS = -Wall -I. -Itest -DTEST -DTEST_ANALOG_INPUT -g SRCS = bacdcode.c \ + bacstr.c \ bigend.c \ ai.c \ test/ctest.c diff --git a/bacnet-stack/ao.c b/bacnet-stack/ao.c index 35dbceee..1e17ea24 100644 --- a/bacnet-stack/ao.c +++ b/bacnet-stack/ao.c @@ -152,6 +152,7 @@ int Analog_Output_Encode_Property_APDU( int len = 0; int apdu_len = 0; // return value BACNET_BIT_STRING bit_string; + BACNET_CHARACTER_STRING char_string; char text_string[32] = {""}; float real_value = 1.414; unsigned object_index = 0; @@ -168,7 +169,9 @@ int Analog_Output_Encode_Property_APDU( case PROP_DESCRIPTION: // note: the object name must be unique within this device sprintf(text_string,"ANALOG OUTPUT %u",object_instance); - apdu_len = encode_tagged_character_string(&apdu[0], text_string); + characterstring_init_ansi(&char_string, text_string); + apdu_len = encode_tagged_character_string(&apdu[0], + &char_string); break; case PROP_OBJECT_TYPE: apdu_len = encode_tagged_enumerated(&apdu[0], OBJECT_ANALOG_OUTPUT); diff --git a/bacnet-stack/ao.mak b/bacnet-stack/ao.mak index 6343403a..d61cb1a6 100755 --- a/bacnet-stack/ao.mak +++ b/bacnet-stack/ao.mak @@ -7,6 +7,7 @@ BASEDIR = . CFLAGS = -Wall -I. -Itest -DTEST -DTEST_ANALOG_OUTPUT -g SRCS = bacdcode.c \ + bacstr.c \ bigend.c \ ao.c \ test/ctest.c diff --git a/bacnet-stack/arf.c b/bacnet-stack/arf.c index c87d15ed..c2ab9c79 100644 --- a/bacnet-stack/arf.c +++ b/bacnet-stack/arf.c @@ -220,7 +220,7 @@ int arf_ack_encode_apdu( apdu_len += encode_tagged_signed(&apdu[apdu_len], data->type.stream.fileStartPosition); apdu_len += encode_tagged_octet_string(&apdu[apdu_len], - data->fileData, data->fileDataLength); + &data->fileData); apdu_len += encode_closing_tag(&apdu[apdu_len], 0); break; case FILE_RECORD_ACCESS: @@ -230,7 +230,7 @@ int arf_ack_encode_apdu( apdu_len += encode_tagged_unsigned(&apdu[apdu_len], data->type.record.RecordCount); apdu_len += encode_tagged_octet_string(&apdu[apdu_len], - data->fileData, data->fileDataLength); + &data->fileData); apdu_len += encode_closing_tag(&apdu[apdu_len], 1); break; default: @@ -281,9 +281,7 @@ int arf_ack_decode_service_request( return -1; len += decode_octet_string(&apdu[len], len_value_type, - data->fileData, - data->fileDataLength); - data->fileDataLength = len_value_type; + &data->fileData); if (!decode_is_closing_tag_number(&apdu[len], 0)) return -1; // a tag number is not extended so only one octet @@ -320,9 +318,7 @@ int arf_ack_decode_service_request( return -1; len += decode_octet_string(&apdu[len], len_value_type, - data->fileData, - data->fileDataLength); - data->fileDataLength = len_value_type; + &data->fileData); if (!decode_is_closing_tag_number(&apdu[len], 1)) return -1; // a tag number is not extended so only one octet @@ -380,7 +376,6 @@ void testAtomicReadFileAckAccess(Test * pTest, int apdu_len = 0; uint8_t invoke_id = 128; uint8_t test_invoke_id = 0; - uint8_t test_octet_string[128] = "bingo!"; len = arf_ack_encode_apdu( &apdu[0], @@ -389,8 +384,6 @@ void testAtomicReadFileAckAccess(Test * pTest, ct_test(pTest, len != 0); apdu_len = len; - test_data.fileData = test_octet_string; - test_data.fileDataLength = sizeof(test_octet_string); len = arf_ack_decode_apdu( &apdu[0], apdu_len, @@ -411,33 +404,35 @@ void testAtomicReadFileAckAccess(Test * pTest, ct_test(pTest, test_data.type.record.RecordCount == data->type.record.RecordCount); } - ct_test(pTest, test_data.fileDataLength == - data->fileDataLength); + ct_test(pTest, octetstring_length(&test_data.fileData) == + octetstring_length(&data->fileData)); ct_test(pTest, memcmp( - &test_data.fileData[0], - &data->fileData[0], - test_data.fileDataLength) == 0); + octetstring_value(&test_data.fileData), + octetstring_value(&data->fileData), + octetstring_length(&test_data.fileData)) == 0); } void testAtomicReadFileAck(Test * pTest) { BACNET_ATOMIC_READ_FILE_DATA data = {0}; - uint8_t *test_octet_string = "Joshua-Mary-Anna-Christopher"; + uint8_t test_octet_string[32] = "Joshua-Mary-Anna-Christopher"; data.endOfFile = true; data.access = FILE_STREAM_ACCESS; data.type.stream.fileStartPosition = 0; - data.fileData = test_octet_string; - data.fileDataLength = strlen(test_octet_string); + octetstring_init(&data.fileData, + test_octet_string, + sizeof(test_octet_string)); testAtomicReadFileAckAccess(pTest, &data); data.endOfFile = false; data.access = FILE_RECORD_ACCESS; data.type.record.fileStartRecord = 1; data.type.record.RecordCount = 2; - data.fileData = test_octet_string; - data.fileDataLength = strlen(test_octet_string); + octetstring_init(&data.fileData, + test_octet_string, + sizeof(test_octet_string)); testAtomicReadFileAckAccess(pTest, &data); return; diff --git a/bacnet-stack/arf.h b/bacnet-stack/arf.h index d47540d7..cee8e75a 100644 --- a/bacnet-stack/arf.h +++ b/bacnet-stack/arf.h @@ -37,6 +37,7 @@ #include #include #include "bacdcode.h" +#include "bacstr.h" typedef struct BACnet_Atomic_Read_File_Data { @@ -57,10 +58,7 @@ typedef struct BACnet_Atomic_Read_File_Data unsigned RecordCount; } record; } type; - // These are used for the ACK portion - // Set them to an unused buffer for the decode to fill - uint8_t *fileData; - unsigned fileDataLength; + BACNET_OCTET_STRING fileData; bool endOfFile; } BACNET_ATOMIC_READ_FILE_DATA; diff --git a/bacnet-stack/arf.mak b/bacnet-stack/arf.mak index 9047f11f..b75bf76a 100644 --- a/bacnet-stack/arf.mak +++ b/bacnet-stack/arf.mak @@ -7,6 +7,7 @@ BASEDIR = . CFLAGS = -Wall -I. -Itest -DTEST -DTEST_ATOMIC_READ_FILE -DBACDL_BIP=1 -g SRCS = bacdcode.c \ + bacstr.c \ bigend.c \ arf.c \ test/ctest.c diff --git a/bacnet-stack/awf.c b/bacnet-stack/awf.c index 0246d693..4292b826 100644 --- a/bacnet-stack/awf.c +++ b/bacnet-stack/awf.c @@ -64,7 +64,7 @@ int awf_encode_apdu( apdu_len += encode_tagged_signed(&apdu[apdu_len], data->type.stream.fileStartPosition); apdu_len += encode_tagged_octet_string(&apdu[apdu_len], - data->fileData, data->fileDataLength); + &data->fileData); apdu_len += encode_closing_tag(&apdu[apdu_len], 0); break; case FILE_RECORD_ACCESS: @@ -74,7 +74,7 @@ int awf_encode_apdu( apdu_len += encode_tagged_unsigned(&apdu[apdu_len], data->type.record.returnedRecordCount); apdu_len += encode_tagged_octet_string(&apdu[apdu_len], - data->fileData, data->fileDataLength); + &data->fileData); apdu_len += encode_closing_tag(&apdu[apdu_len], 1); break; default: @@ -127,9 +127,7 @@ int awf_decode_service_request( return -1; len += decode_octet_string(&apdu[len], len_value_type, - data->fileData, - data->fileDataLength); - data->fileDataLength = len_value_type; + &data->fileData); if (!decode_is_closing_tag_number(&apdu[len], 0)) return -1; // a tag number is not extended so only one octet @@ -166,9 +164,7 @@ int awf_decode_service_request( return -1; len += decode_octet_string(&apdu[len], len_value_type, - data->fileData, - data->fileDataLength); - data->fileDataLength = len_value_type; + &data->fileData); if (!decode_is_closing_tag_number(&apdu[len], 1)) return -1; // a tag number is not extended so only one octet @@ -322,7 +318,6 @@ void testAtomicWriteFileAccess(Test * pTest, int apdu_len = 0; uint8_t invoke_id = 128; uint8_t test_invoke_id = 0; - uint8_t test_octet_string[128] = "bingo!"; len = awf_encode_apdu( &apdu[0], @@ -331,8 +326,6 @@ void testAtomicWriteFileAccess(Test * pTest, ct_test(pTest, len != 0); apdu_len = len; - test_data.fileData = test_octet_string; - test_data.fileDataLength = sizeof(test_octet_string); len = awf_decode_apdu( &apdu[0], apdu_len, @@ -354,25 +347,26 @@ void testAtomicWriteFileAccess(Test * pTest, ct_test(pTest, test_data.type.record.returnedRecordCount == data->type.record.returnedRecordCount); } - ct_test(pTest, test_data.fileDataLength == - data->fileDataLength); + ct_test(pTest, octetstring_length(&test_data.fileData) == + octetstring_length(&data->fileData)); ct_test(pTest, memcmp( - &test_data.fileData[0], - &data->fileData[0], - test_data.fileDataLength) == 0); + octetstring_value(&test_data.fileData), + octetstring_value(&data->fileData), + octetstring_length(&test_data.fileData)) == 0); } void testAtomicWriteFile(Test * pTest) { BACNET_ATOMIC_WRITE_FILE_DATA data = {0}; - uint8_t *test_octet_string = "Joshua-Mary-Anna-Christopher"; - + uint8_t test_octet_string[32] = "Joshua-Mary-Anna-Christopher"; + data.object_type = OBJECT_FILE; data.object_instance = 1; data.access = FILE_STREAM_ACCESS; data.type.stream.fileStartPosition = 0; - data.fileData = test_octet_string; - data.fileDataLength = strlen(test_octet_string); + octetstring_init(&data.fileData, + test_octet_string, + sizeof(test_octet_string)); testAtomicWriteFileAccess(pTest, &data); data.object_type = OBJECT_FILE; @@ -380,8 +374,9 @@ void testAtomicWriteFile(Test * pTest) data.access = FILE_RECORD_ACCESS; data.type.record.fileStartRecord = 1; data.type.record.returnedRecordCount = 2; - data.fileData = test_octet_string; - data.fileDataLength = strlen(test_octet_string); + octetstring_init(&data.fileData, + test_octet_string, + sizeof(test_octet_string)); testAtomicWriteFileAccess(pTest, &data); return; diff --git a/bacnet-stack/awf.h b/bacnet-stack/awf.h index bcf1ef3d..ec9cbfc7 100644 --- a/bacnet-stack/awf.h +++ b/bacnet-stack/awf.h @@ -55,11 +55,7 @@ typedef struct BACnet_Atomic_Write_File_Data unsigned returnedRecordCount; } record; } type; - // note: set the file data to an empty buffer - // and set the DataLength to the size of the empty buffer - // before decoding the data. - uint8_t *fileData; - unsigned fileDataLength; + BACNET_OCTET_STRING fileData; } BACNET_ATOMIC_WRITE_FILE_DATA; #ifdef __cplusplus diff --git a/bacnet-stack/awf.mak b/bacnet-stack/awf.mak index 428ecf3d..76f794a6 100644 --- a/bacnet-stack/awf.mak +++ b/bacnet-stack/awf.mak @@ -7,6 +7,7 @@ BASEDIR = . CFLAGS = -Wall -I. -Itest -DTEST -DTEST_ATOMIC_WRITE_FILE -DBACDL_BIP=1 -g SRCS = bacdcode.c \ + bacstr.c \ bigend.c \ awf.c \ test/ctest.c diff --git a/bacnet-stack/bacapp.mak b/bacnet-stack/bacapp.mak index 62bf9131..c4f36538 100644 --- a/bacnet-stack/bacapp.mak +++ b/bacnet-stack/bacapp.mak @@ -7,6 +7,7 @@ BASEDIR = . CFLAGS = -Wall -I. -Itest -DTEST -DTEST_BACNET_APPLICATION_DATA -g SRCS = bacdcode.c \ + bacstr.c \ bacapp.c \ bigend.c \ test/ctest.c diff --git a/bacnet-stack/bacdcode.c b/bacnet-stack/bacdcode.c index e97ff099..5e171190 100644 --- a/bacnet-stack/bacdcode.c +++ b/bacnet-stack/bacdcode.c @@ -807,16 +807,16 @@ int encode_tagged_object_id( // from clause 20.2.8 Encoding of an Octet String Value // returns the number of apdu bytes consumed -int encode_octet_string(uint8_t * apdu, const uint8_t *octet_string, - unsigned len) +int encode_octet_string(uint8_t * apdu, BACNET_OCTET_STRING *octet_string) { - unsigned i; + int len = 0; /* return value */ - // limit - 6 octets is the most our tag and type could be - if (len > (MAX_APDU - 6)) - len = MAX_APDU - 6; - for (i = 0; i < len; i++) { - apdu[i] = octet_string[i]; + if (octet_string) + { + /* FIXME: might need to pass in the length of the APDU + to bounds check since it might not be the only data chunk */ + len = octetstring_length(octet_string); + memmove(&apdu[0], octetstring_value(octet_string), len); } return len; @@ -825,17 +825,22 @@ int encode_octet_string(uint8_t * apdu, const uint8_t *octet_string, // from clause 20.2.8 Encoding of an Octet String Value // and 20.2.1 General Rules for Encoding BACnet Tags // returns the number of apdu bytes consumed -int encode_tagged_octet_string(uint8_t * apdu, const uint8_t *octet_string, - unsigned len) +int encode_tagged_octet_string(uint8_t * apdu, + BACNET_OCTET_STRING *octet_string) { - int apdu_len; - - apdu_len = encode_tag(&apdu[0], BACNET_APPLICATION_TAG_OCTET_STRING, - false, len); - if ((apdu_len + len) < MAX_APDU) - apdu_len += encode_octet_string(&apdu[apdu_len], octet_string, len); - else - apdu_len = 0; + int apdu_len = 0; + + if (octet_string) + { + apdu_len = encode_tag(&apdu[0], BACNET_APPLICATION_TAG_OCTET_STRING, + false, octetstring_length(octet_string)); + /* FIXME: probably need to pass in the length of the APDU + to bounds check since it might not be the only data chunk */ + if ((apdu_len + octetstring_length(octet_string)) < MAX_APDU) + apdu_len += encode_octet_string(&apdu[apdu_len], octet_string); + else + apdu_len = 0; + } return apdu_len; } @@ -844,21 +849,14 @@ int encode_tagged_octet_string(uint8_t * apdu, const uint8_t *octet_string, // and 20.2.1 General Rules for Encoding BACnet Tags // returns the number of apdu bytes consumed int decode_octet_string(uint8_t * apdu, uint32_t len_value, - uint8_t *buffer, size_t buffer_len) + BACNET_OCTET_STRING *octet_string) { int len = 0; // return value - uint32_t i = 0; // counter + bool status = false; - // FIXME: issue warning? - if (len_value > buffer_len) - len_value = buffer_len; - - if (len_value) { - for (i = 0; i < len_value; i++) { - buffer[i] = apdu[i]; - } - len += len_value; - } + status = octetstring_init(octet_string,&apdu[0],len_value); + if (status) + len = len_value; return len; } @@ -883,27 +881,28 @@ int encode_bacnet_string(uint8_t * apdu, const char *char_string, int len) // from clause 20.2.9 Encoding of a Character String Value // returns the number of apdu bytes consumed -int encode_bacnet_character_string(uint8_t * apdu, const char *char_string) +int encode_bacnet_character_string(uint8_t * apdu, + BACNET_CHARACTER_STRING *char_string) { int len; - len = strlen(char_string); - len = encode_bacnet_string(&apdu[0], char_string, len); + len = characterstring_length(char_string); + apdu[0] = characterstring_encoding(char_string); + memmove(apdu, characterstring_value(char_string), len); - return len; + return len + 1 /* for encoding */; } // from clause 20.2.9 Encoding of a Character String Value // and 20.2.1 General Rules for Encoding BACnet Tags // returns the number of apdu bytes consumed -int encode_tagged_character_string(uint8_t * apdu, const char *char_string) +int encode_tagged_character_string(uint8_t * apdu, + BACNET_CHARACTER_STRING *char_string) { int len = 0; int string_len = 0; - // find the size of the apdu first - not necessarily effecient - // but reuses existing functions - string_len = encode_bacnet_character_string(&apdu[1], char_string); + string_len = characterstring_length(char_string) + 1 /* for encoding */; len = encode_tag(&apdu[0], BACNET_APPLICATION_TAG_CHARACTER_STRING, false, string_len); if ((len + string_len) < MAX_APDU) @@ -918,28 +917,15 @@ int encode_tagged_character_string(uint8_t * apdu, const char *char_string) // and 20.2.1 General Rules for Encoding BACnet Tags // returns the number of apdu bytes consumed int decode_character_string(uint8_t * apdu, uint32_t len_value, - char *char_string, size_t string_len) + BACNET_CHARACTER_STRING *char_string) { int len = 0; // return value - uint32_t i = 0; // counter + bool status = false; - // FIXME: issue warning? - if (len_value > string_len) - len_value = string_len; - - if (len_value) { - // decode ANSI X3.4 - if (apdu[len] == 0) { - len++; - len_value--; - for (i = 0; i < len_value; i++) { - char_string[i] = apdu[len + i]; - } - // terminate the c string - char_string[i] = 0; - len += len_value; - } - } + status = characterstring_init(char_string, apdu[0], (char *)&apdu[1], + len_value-1); + if (status) + len = len_value; return len; } @@ -1509,40 +1495,54 @@ void testBACDCodeOctetString(Test * pTest) { uint8_t array[MAX_APDU] = { 0 }; uint8_t encoded_array[MAX_APDU] = { 0 }; - char test_string[MAX_APDU] = { "" }; - char decoded_string[MAX_APDU] = { "" }; + BACNET_OCTET_STRING octet_string; + BACNET_OCTET_STRING test_octet_string; + uint8_t test_value[MAX_APDU] = { "" }; int i; // for loop counter int apdu_len; int len; - char *test_string0 = ""; uint8_t tag_number = 0; uint32_t len_value = 0; + bool status = false; + int diff = 0; /* for memcmp */ - apdu_len = encode_tagged_octet_string(&array[0], (uint8_t *)&test_string0[0], 0); + status = octetstring_init( + &octet_string, + NULL, + 0); + ct_test(pTest,status == true); + apdu_len = encode_tagged_octet_string(&array[0], &octet_string); len = decode_tag_number_and_value(&array[0], &tag_number, &len_value); - len += decode_octet_string(&array[len], len_value, - (uint8_t *)&decoded_string[0], sizeof(decoded_string)); + ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OCTET_STRING); + len += decode_octet_string(&array[len], len_value, &test_octet_string); ct_test(pTest, apdu_len == len); - ct_test(pTest, memcmp(&test_string0[0], &decoded_string[0], - len_value) == 0); + diff = memcmp(octetstring_value(&octet_string), &test_value[0], + octetstring_length(&octet_string)); + ct_test(pTest,diff == 0); + for (i = 0; i < (MAX_APDU - 6); i++) { - test_string[i] = '0' + (i % 10); - apdu_len = - encode_tagged_octet_string(&encoded_array[0], - (uint8_t *)&test_string[0], i); + test_value[i] = '0' + (i % 10); + status = octetstring_init( + &octet_string, + test_value, + i); + ct_test(pTest,status == true); + apdu_len = encode_tagged_octet_string(&encoded_array[0],&octet_string); len = decode_tag_number_and_value(&encoded_array[0], &tag_number, &len_value); + ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OCTET_STRING); len += decode_octet_string(&encoded_array[len], len_value, - (uint8_t *)&decoded_string[0], sizeof(decoded_string)); + &test_octet_string); if (apdu_len != len) { printf("test octet string=#%d\n", i); } ct_test(pTest, apdu_len == len); - if (memcmp(&test_string[0], &decoded_string[0], len_value) != 0) { + diff = memcmp(octetstring_value(&octet_string), &test_value[0], + octetstring_length(&octet_string)); + if (diff) { printf("test octet string=#%d\n", i); } - ct_test(pTest, memcmp(&test_string[0], &decoded_string[0], - len_value) == 0); + ct_test(pTest,diff == 0); } return; @@ -1552,39 +1552,53 @@ void testBACDCodeCharacterString(Test * pTest) { uint8_t array[MAX_APDU] = { 0 }; uint8_t encoded_array[MAX_APDU] = { 0 }; - char test_string[MAX_APDU] = { "" }; - char decoded_string[MAX_APDU] = { "" }; + BACNET_CHARACTER_STRING char_string; + BACNET_CHARACTER_STRING test_char_string; + char test_value[MAX_APDU] = { "" }; int i; // for loop counter int apdu_len; int len; - char *test_string0 = ""; uint8_t tag_number = 0; uint32_t len_value = 0; + int diff = 0; /* for comparison */ + bool status = false; - apdu_len = encode_tagged_character_string(&array[0], &test_string0[0]); + status = characterstring_init( + &char_string, + CHARACTER_ANSI, + NULL, + 0); + ct_test(pTest,status == true); + apdu_len = encode_tagged_character_string(&array[0], &char_string); len = decode_tag_number_and_value(&array[0], &tag_number, &len_value); - len += decode_character_string(&array[len], len_value, - &decoded_string[0], sizeof(decoded_string)); + ct_test(pTest,tag_number == BACNET_APPLICATION_TAG_CHARACTER_STRING); + len += decode_character_string(&array[len], len_value, &test_char_string); ct_test(pTest, apdu_len == len); - ct_test(pTest, strcmp(&test_string0[0], &decoded_string[0]) == 0); + diff = memcmp(characterstring_value(&char_string), &test_value[0], + characterstring_length(&char_string)); + ct_test(pTest, diff == 0); for (i = 0; i < (MAX_APDU - 6); i++) { - test_string[i] = 'S'; - test_string[i + 1] = '\0'; + test_value[i] = 'S'; + test_value[i + 1] = '\0'; + status = characterstring_init_ansi(&char_string, test_value); + ct_test(pTest,status == true); apdu_len = - encode_tagged_character_string(&encoded_array[0], - &test_string[0]); + encode_tagged_character_string(&encoded_array[0], &char_string); len = decode_tag_number_and_value(&encoded_array[0], &tag_number, &len_value); + ct_test(pTest,tag_number == BACNET_APPLICATION_TAG_CHARACTER_STRING); len += decode_character_string(&encoded_array[len], len_value, - &decoded_string[0], sizeof(decoded_string)); + &test_char_string); if (apdu_len != len) { - printf("test string=#%d\n", i); + printf("test string=#%d apdu_len=%d len=%d\n", i,apdu_len,len); } ct_test(pTest, apdu_len == len); - if (strcmp(&test_string[0], &decoded_string[0]) != 0) { + diff = memcmp(characterstring_value(&char_string), &test_value[0], + characterstring_length(&char_string)); + if (diff) { printf("test string=#%d\n", i); } - ct_test(pTest, strcmp(&test_string[0], &decoded_string[0]) == 0); + ct_test(pTest, diff == 0); } return; diff --git a/bacnet-stack/bacdcode.h b/bacnet-stack/bacdcode.h index 01b23813..1b1082bc 100644 --- a/bacnet-stack/bacdcode.h +++ b/bacnet-stack/bacdcode.h @@ -100,25 +100,23 @@ int encode_tagged_object_id(uint8_t * apdu, int object_type, uint32_t instance); // from clause 20.2.8 Encoding of an Octet String Value // and 20.2.1 General Rules for Encoding BACnet Tags // returns the number of apdu bytes consumed -int encode_octet_string(uint8_t * apdu, const uint8_t *octet_string, - unsigned len); -int encode_tagged_octet_string(uint8_t * apdu, const uint8_t *octet_string, - unsigned len); +int encode_octet_string(uint8_t * apdu, + BACNET_OCTET_STRING *octet_string); +int encode_tagged_octet_string(uint8_t * apdu, + BACNET_OCTET_STRING *octet_string); int decode_octet_string(uint8_t * apdu, uint32_t len_value, - uint8_t *buffer, size_t buffer_len); + BACNET_OCTET_STRING *octet_string); // from clause 20.2.9 Encoding of a Character String Value // and 20.2.1 General Rules for Encoding BACnet Tags // returns the number of apdu bytes consumed -int encode_bacnet_string(uint8_t * apdu, - const char *char_string, int string_len); int encode_bacnet_character_string(uint8_t * apdu, - const char *char_string); + BACNET_CHARACTER_STRING *char_string); int encode_tagged_character_string(uint8_t * apdu, - const char *char_string); + BACNET_CHARACTER_STRING *char_string); int decode_character_string(uint8_t * apdu, uint32_t len_value, - char *char_string, size_t string_len); + BACNET_CHARACTER_STRING *char_string); // from clause 20.2.4 Encoding of an Unsigned Integer Value // and 20.2.1 General Rules for Encoding BACnet Tags diff --git a/bacnet-stack/bacdcode.mak b/bacnet-stack/bacdcode.mak index f3012795..04e84013 100644 --- a/bacnet-stack/bacdcode.mak +++ b/bacnet-stack/bacdcode.mak @@ -6,6 +6,7 @@ CFLAGS = -Wall -I. -Itest -g -DTEST -DTEST_DECODE TARGET = bacdcode SRCS = bacdcode.c \ + bacstr.c \ bigend.c \ test/ctest.c diff --git a/bacnet-stack/bacerror.mak b/bacnet-stack/bacerror.mak index 37469ecf..a4ef15d0 100644 --- a/bacnet-stack/bacerror.mak +++ b/bacnet-stack/bacerror.mak @@ -7,6 +7,7 @@ BASEDIR = . CFLAGS = -Wall -I. -Itest -DTEST -DTEST_BACERROR -g SRCS = bacdcode.c \ + bacstr.c \ bigend.c \ bacerror.c \ test/ctest.c diff --git a/bacnet-stack/bacfile.c b/bacnet-stack/bacfile.c index 457e9a13..4f316da4 100644 --- a/bacnet-stack/bacfile.c +++ b/bacnet-stack/bacfile.c @@ -153,6 +153,7 @@ int bacfile_encode_property_apdu( { int apdu_len = 0; // return value char text_string[32] = {""}; + BACNET_CHARACTER_STRING char_string; (void)array_index; switch (property) @@ -164,17 +165,22 @@ int bacfile_encode_property_apdu( break; case PROP_OBJECT_NAME: sprintf(text_string,"FILE %d",object_instance); - apdu_len = encode_tagged_character_string(&apdu[0], text_string); + characterstring_init_ansi(&char_string, text_string); + apdu_len = encode_tagged_character_string(&apdu[0], + &char_string); break; case PROP_OBJECT_TYPE: apdu_len = encode_tagged_enumerated(&apdu[0], OBJECT_FILE); break; case PROP_DESCRIPTION: + characterstring_init_ansi(&char_string, bacfile_name(object_instance)); apdu_len = encode_tagged_character_string(&apdu[0], - bacfile_name(object_instance)); + &char_string); break; case PROP_FILE_TYPE: - apdu_len = encode_tagged_character_string(&apdu[0],"TEXT"); + characterstring_init_ansi(&char_string, "TEXT"); + apdu_len = encode_tagged_character_string(&apdu[0], + &char_string); break; case PROP_FILE_SIZE: apdu_len = encode_tagged_unsigned(&apdu[0], @@ -300,6 +306,7 @@ bool bacfile_read_data(BACNET_ATOMIC_READ_FILE_DATA *data) char *pFilename = NULL; bool found = false; FILE *pFile = NULL; + size_t len = 0; pFilename = bacfile_name(data->object_instance); if (pFilename) @@ -311,23 +318,24 @@ bool bacfile_read_data(BACNET_ATOMIC_READ_FILE_DATA *data) (void)fseek(pFile, data->type.stream.fileStartPosition, SEEK_SET); - data->fileDataLength = fread(data->fileData, 1, + len = fread(octetstring_value(&data->fileData), 1, data->type.stream.requestedOctetCount, pFile); - if (data->fileDataLength < data->type.stream.requestedOctetCount) + if (len < data->type.stream.requestedOctetCount) data->endOfFile = true; else data->endOfFile = false; + octetstring_truncate(&data->fileData,len); fclose(pFile); } else { - data->fileDataLength = 0; + octetstring_truncate(&data->fileData,0); data->endOfFile = true; } } else { - data->fileDataLength = 0; + octetstring_truncate(&data->fileData,0); data->endOfFile = true; } diff --git a/bacnet-stack/bacstr.c b/bacnet-stack/bacstr.c index a240ce01..6ed2254b 100644 --- a/bacnet-stack/bacstr.c +++ b/bacnet-stack/bacstr.c @@ -34,6 +34,7 @@ #include #include +#include /* for strlen */ #include "bacstr.h" #include "bits.h" @@ -87,10 +88,19 @@ uint8_t bitstring_bits_used(BACNET_BIT_STRING *bit_string) return bit_string->bits_used; } +uint8_t bitstring_bits_capacity(BACNET_BIT_STRING *bit_string) +{ + if (bit_string) + return (sizeof(bit_string->value) * 8); + else + return 0; +} + /* returns false if the string exceeds capacity initialize by using length=0 */ bool characterstring_init( BACNET_CHARACTER_STRING *char_string, + uint8_t encoding, char *value, size_t length) { @@ -100,6 +110,7 @@ bool characterstring_init( if (char_string) { char_string->length = 0; + char_string->encoding = encoding; if (length <= sizeof(char_string->value)) { if (value) @@ -124,6 +135,16 @@ bool characterstring_init( return status; } +bool characterstring_init_ansi( + BACNET_CHARACTER_STRING *char_string, + char *value) +{ + return characterstring_init( + char_string, + CHARACTER_ANSI, + value, value?strlen(value):0); +} + /* returns false if the string exceeds capacity */ bool characterstring_append( BACNET_CHARACTER_STRING *char_string, @@ -171,25 +192,16 @@ bool characterstring_truncate( } /* returns the length. Returns the value in parameter. */ -size_t characterstring_value(BACNET_CHARACTER_STRING *char_string, char *value) +char *characterstring_value(BACNET_CHARACTER_STRING *char_string) { - size_t i; /* counter */ - size_t length = 0; /* return value */ + char *value = NULL; if (char_string) { - /* FIXME: validate length is within bounds? */ - length = char_string->length; - if (value) - { - for (i = 0; i < sizeof(char_string->value); i++) - { - value[i] = char_string->value[i]; - } - } + value = char_string->value; } - return length; + return value; } /* returns the length. */ @@ -206,6 +218,31 @@ size_t characterstring_length(BACNET_CHARACTER_STRING *char_string) return length; } +size_t characterstring_capacity(BACNET_CHARACTER_STRING *char_string) +{ + size_t length = 0; + + if (char_string) + { + length = sizeof(char_string->value); + } + + return length; +} + +/* returns the encoding. */ +uint8_t characterstring_encoding(BACNET_CHARACTER_STRING *char_string) +{ + uint8_t encoding = 0; + + if (char_string) + { + encoding = char_string->encoding; + } + + return encoding; +} + /* returns false if the string exceeds capacity initialize by using length=0 */ bool octetstring_init( @@ -290,25 +327,16 @@ bool octetstring_truncate( } /* returns the length. Returns the value in parameter. */ -size_t octetstring_value(BACNET_OCTET_STRING *octet_string, uint8_t *value) +uint8_t *octetstring_value(BACNET_OCTET_STRING *octet_string) { - size_t i; /* counter */ - size_t length = 0; /* return value */ + uint8_t *value = NULL; if (octet_string) { - /* FIXME: validate length is within bounds? */ - length = octet_string->length; - if (value) - { - for (i = 0; i < sizeof(octet_string->value); i++) - { - value[i] = octet_string->value[i]; - } - } + value = octet_string->value; } - return length; + return value; } /* returns the length. */ @@ -325,6 +353,20 @@ size_t octetstring_length(BACNET_OCTET_STRING *octet_string) return length; } +/* returns the length. */ +size_t octetstring_capacity(BACNET_OCTET_STRING *octet_string) +{ + size_t length = 0; + + if (octet_string) + { + /* FIXME: validate length is within bounds? */ + length = sizeof(octet_string->value); + } + + return length; +} + #ifdef TEST #include #include @@ -363,7 +405,7 @@ void testBitString(Test * pTest) void testCharacterString(Test * pTest) { BACNET_CHARACTER_STRING bacnet_string; - char value[MAX_APDU] = "Joshua,Mary,Anna,Christopher"; + char *value = "Joshua,Mary,Anna,Christopher"; char test_value[MAX_APDU] = "Patricia"; char test_append_value[MAX_APDU] = " and the Kids"; char test_append_string[MAX_APDU] = ""; @@ -373,37 +415,38 @@ void testCharacterString(Test * pTest) size_t i = 0; // verify initialization - status = characterstring_init(&bacnet_string,NULL,0); + status = characterstring_init(&bacnet_string,CHARACTER_ANSI,NULL,0); ct_test(pTest, status == true); ct_test(pTest,characterstring_length(&bacnet_string) == 0); - ct_test(pTest, characterstring_value(&bacnet_string,&value[0]) == 0); - for (i = 0; i < sizeof(value); i++) - { - ct_test(pTest, value[i] == 0); - } + ct_test(pTest,characterstring_encoding(&bacnet_string) == CHARACTER_ANSI); /* bounds check */ - status = characterstring_init(&bacnet_string,NULL,sizeof(value)+1); + status = characterstring_init( + &bacnet_string, + CHARACTER_ANSI, + NULL, + characterstring_capacity(&bacnet_string)+1); ct_test(pTest, status == false); - status = characterstring_init(&bacnet_string,NULL,sizeof(value)); - ct_test(pTest, status == true); - status = characterstring_truncate(&bacnet_string,sizeof(value)+1); + status = characterstring_truncate( + &bacnet_string,characterstring_capacity(&bacnet_string)+1); ct_test(pTest, status == false); - status = characterstring_truncate(&bacnet_string,sizeof(value)); + status = characterstring_truncate( + &bacnet_string,characterstring_capacity(&bacnet_string)); ct_test(pTest, status == true); test_length = strlen(test_value); status = characterstring_init( &bacnet_string, + CHARACTER_ANSI, &test_value[0], test_length); ct_test(pTest, status == true); - length = characterstring_value(&bacnet_string,&value[0]); + value = characterstring_value(&bacnet_string); + length = characterstring_length(&bacnet_string); ct_test(pTest, length == test_length); for (i = 0; i < test_length; i++) { ct_test(pTest, value[i] == test_value[i]); } - test_length = strlen(test_append_value); status = characterstring_append( &bacnet_string, @@ -413,7 +456,8 @@ void testCharacterString(Test * pTest) strcat(test_append_string,test_append_value); test_length = strlen(test_append_string); ct_test(pTest, status == true); - length = characterstring_value(&bacnet_string,&value[0]); + length = characterstring_length(&bacnet_string); + value = characterstring_value(&bacnet_string); ct_test(pTest, length == test_length); for (i = 0; i < test_length; i++) { @@ -424,7 +468,7 @@ void testCharacterString(Test * pTest) void testOctetString(Test * pTest) { BACNET_OCTET_STRING bacnet_string; - uint8_t value[MAX_APDU] = "Joshua,Mary,Anna,Christopher"; + uint8_t *value = NULL; uint8_t test_value[MAX_APDU] = "Patricia"; uint8_t test_append_value[MAX_APDU] = " and the Kids"; uint8_t test_append_string[MAX_APDU] = ""; @@ -437,19 +481,21 @@ void testOctetString(Test * pTest) status = octetstring_init(&bacnet_string,NULL,0); ct_test(pTest, status == true); ct_test(pTest,octetstring_length(&bacnet_string) == 0); - ct_test(pTest, octetstring_value(&bacnet_string,&value[0]) == 0); - for (i = 0; i < sizeof(value); i++) + value = octetstring_value(&bacnet_string); + for (i = 0; i < octetstring_capacity(&bacnet_string); i++) { ct_test(pTest, value[i] == 0); } /* bounds check */ - status = octetstring_init(&bacnet_string,NULL,sizeof(value)+1); + status = octetstring_init(&bacnet_string,NULL, + octetstring_capacity(&bacnet_string)+1); ct_test(pTest, status == false); - status = octetstring_init(&bacnet_string,NULL,sizeof(value)); + status = octetstring_init(&bacnet_string,NULL, + octetstring_capacity(&bacnet_string)); ct_test(pTest, status == true); - status = octetstring_truncate(&bacnet_string,sizeof(value)+1); + status = octetstring_truncate(&bacnet_string,octetstring_capacity(&bacnet_string)+1); ct_test(pTest, status == false); - status = octetstring_truncate(&bacnet_string,sizeof(value)); + status = octetstring_truncate(&bacnet_string,octetstring_capacity(&bacnet_string)); ct_test(pTest, status == true); test_length = strlen((char *)test_value); @@ -458,7 +504,8 @@ void testOctetString(Test * pTest) &test_value[0], test_length); ct_test(pTest, status == true); - length = octetstring_value(&bacnet_string,&value[0]); + length = octetstring_length(&bacnet_string); + value = octetstring_value(&bacnet_string); ct_test(pTest, length == test_length); for (i = 0; i < test_length; i++) { @@ -474,7 +521,8 @@ void testOctetString(Test * pTest) strcat((char *)test_append_string,(char *)test_append_value); test_length = strlen((char *)test_append_string); ct_test(pTest, status == true); - length = octetstring_value(&bacnet_string,&value[0]); + length = octetstring_length(&bacnet_string); + value = octetstring_value(&bacnet_string); ct_test(pTest, length == test_length); for (i = 0; i < test_length; i++) { diff --git a/bacnet-stack/bacstr.h b/bacnet-stack/bacstr.h index 8f757e38..9f79d773 100644 --- a/bacnet-stack/bacstr.h +++ b/bacnet-stack/bacstr.h @@ -51,7 +51,9 @@ typedef struct BACnet_Bit_String typedef struct BACnet_Character_String { size_t length; - char value[MAX_APDU]; + uint8_t encoding; + /* limit - 6 octets is the most our tag and type could be */ + char value[MAX_APDU-6]; } BACNET_CHARACTER_STRING; /* FIXME: convert the bacdcode library to use BACNET_OCTET_STRING @@ -59,7 +61,8 @@ typedef struct BACnet_Character_String typedef struct BACnet_Octet_String { size_t length; - uint8_t value[MAX_APDU]; + /* limit - 6 octets is the most our tag and type could be */ + uint8_t value[MAX_APDU-6]; } BACNET_OCTET_STRING; #ifdef __cplusplus @@ -70,13 +73,19 @@ void bitstring_init(BACNET_BIT_STRING *bit_string); void bitstring_set_bit(BACNET_BIT_STRING *bit_string, uint8_t bit, bool value); bool bitstring_bit(BACNET_BIT_STRING *bit_string, uint8_t bit); uint8_t bitstring_bits_used(BACNET_BIT_STRING *bit_string); +uint8_t bitstring_bits_capacity(BACNET_BIT_STRING *bit_string); /* returns false if the string exceeds capacity initialize by using length=0 */ bool characterstring_init( BACNET_CHARACTER_STRING *char_string, + uint8_t encoding, char *value, size_t length); +/* used for ANSI C-Strings */ +bool characterstring_init_ansi( + BACNET_CHARACTER_STRING *char_string, + char *value); /* returns false if the string exceeds capacity */ bool characterstring_append( BACNET_CHARACTER_STRING *char_string, @@ -88,9 +97,15 @@ bool characterstring_append( bool characterstring_truncate( BACNET_CHARACTER_STRING *char_string, size_t length); -/* returns the length. Returns the value in parameter. */ -size_t characterstring_value(BACNET_CHARACTER_STRING *char_string, char *value); +bool characterstring_set_encoding( + BACNET_CHARACTER_STRING *char_string, + uint8_t encoding); +/* Returns the value */ +char *characterstring_value(BACNET_CHARACTER_STRING *char_string); +/* returns the length */ size_t characterstring_length(BACNET_CHARACTER_STRING *char_string); +uint8_t characterstring_encoding(BACNET_CHARACTER_STRING *char_string); +size_t characterstring_capacity(BACNET_CHARACTER_STRING *char_string); /* returns false if the string exceeds capacity initialize by using length=0 */ @@ -109,9 +124,11 @@ bool octetstring_append( bool octetstring_truncate( BACNET_OCTET_STRING *octet_string, size_t length); -/* returns the length. Returns the value in parameter. */ -size_t octetstring_value(BACNET_OCTET_STRING *octet_string, uint8_t *value); +/* Returns the value */ +uint8_t *octetstring_value(BACNET_OCTET_STRING *octet_string); +/* Returns the length.*/ size_t octetstring_length(BACNET_OCTET_STRING *octet_string); +size_t octetstring_capacity(BACNET_OCTET_STRING *octet_string); #ifdef __cplusplus } diff --git a/bacnet-stack/device.c b/bacnet-stack/device.c index 2456f01f..41050d9a 100644 --- a/bacnet-stack/device.c +++ b/bacnet-stack/device.c @@ -25,6 +25,7 @@ #include #include +#include /* for memmove*/ #include "bacdef.h" #include "bacdcode.h" #include "bacenum.h" @@ -39,16 +40,16 @@ static uint32_t Object_Instance_Number = 0; // FIXME: it is likely that this name is configurable, // so consider a fixed sized string -static const char *Object_Name = "SimpleServer"; +static char Object_Name[16] = "SimpleServer"; static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL; -static const char *Vendor_Name = "ASHRAE"; +static char Vendor_Name[16] = "ASHRAE"; // vendor id assigned by ASHRAE static uint16_t Vendor_Identifier = 0; -static const char *Model_Name = "GNU"; -static const char *Firmware_Revision = "1.0"; -static const char *Application_Software_Version = "1.0"; -//static char *Location = "USA"; -static const char *Description = "server"; +static char Model_Name[16] = "GNU"; +static char Firmware_Revision[16] = "1.0"; +static char Application_Software_Version[16] = "1.0"; +static char Location[16] = "USA"; +static char Description[16] = "server"; //static uint8_t Protocol_Version = 1; - constant, not settable //static uint8_t Protocol_Revision = 4; - constant, not settable //Protocol_Services_Supported @@ -88,10 +89,16 @@ uint32_t Device_Object_Instance_Number(void) return Object_Instance_Number; } -void Device_Set_Object_Instance_Number(uint32_t object_id) +bool Device_Set_Object_Instance_Number(uint32_t object_id) { - // FIXME: bounds check? - Object_Instance_Number = object_id; + bool status = true; /* return value */ + + if (object_id <= BACNET_MAX_INSTANCE) + Object_Instance_Number = object_id; + else + status = false; + + return status; } bool Device_Valid_Object_Instance_Number(uint32_t object_id) @@ -117,9 +124,18 @@ const char *Device_Vendor_Name(void) return Vendor_Name; } -void Device_Set_Vendor_Name(const char *name) +bool Device_Set_Vendor_Name(const char *name, size_t length) { - Vendor_Name = name; + bool status = false; /*return value*/ + + if (length < sizeof(Vendor_Name)) + { + memmove(Vendor_Name,name,length); + Vendor_Name[length] = 0; + status = true; + } + + return status; } uint16_t Device_Vendor_Identifier(void) @@ -137,9 +153,18 @@ const char *Device_Model_Name(void) return Model_Name; } -void Device_Set_Model_Name(const char *name) +bool Device_Set_Model_Name(const char *name, size_t length) { - Model_Name = name; + bool status = false; /*return value*/ + + if (length < sizeof(Model_Name)) + { + memmove(Model_Name,name,length); + Model_Name[length] = 0; + status = true; + } + + return status; } const char *Device_Firmware_Revision(void) @@ -147,9 +172,18 @@ const char *Device_Firmware_Revision(void) return Firmware_Revision; } -void Device_Set_Firmware_Revision(const char *name) +bool Device_Set_Firmware_Revision(const char *name, size_t length) { - Firmware_Revision = name; + bool status = false; /*return value*/ + + if (length < sizeof(Firmware_Revision)) + { + memmove(Firmware_Revision,name,length); + Firmware_Revision[length] = 0; + status = true; + } + + return status; } const char *Device_Application_Software_Version(void) @@ -157,9 +191,18 @@ const char *Device_Application_Software_Version(void) return Application_Software_Version; } -void Device_Set_Application_Software_Version(const char *name) +bool Device_Set_Application_Software_Version(const char *name, size_t length) { - Application_Software_Version = name; + bool status = false; /*return value*/ + + if (length < sizeof(Application_Software_Version)) + { + memmove(Application_Software_Version,name,length); + Application_Software_Version[length] = 0; + status = true; + } + + return status; } const char *Device_Description(void) @@ -167,9 +210,37 @@ const char *Device_Description(void) return Description; } -void Device_Set_Description(const char *name) +bool Device_Set_Description(const char *name, size_t length) { - Description = name; + bool status = false; /*return value*/ + + if (length < sizeof(Description)) + { + memmove(Description,name,length); + Description[length] = 0; + status = true; + } + + return status; +} + +const char *Device_Location(void) +{ + return Location; +} + +bool Device_Set_Location(const char *name, size_t length) +{ + bool status = false; /*return value*/ + + if (length < sizeof(Location)) + { + memmove(Location,name,length); + Location[length] = 0; + status = true; + } + + return status; } uint8_t Device_Protocol_Version(void) @@ -301,6 +372,7 @@ int Device_Encode_Property_APDU( int apdu_len = 0; // return value int len = 0; // apdu len intermediate value BACNET_BIT_STRING bit_string; + BACNET_CHARACTER_STRING char_string; unsigned i = 0; int object_type = 0; uint32_t instance = 0; @@ -313,32 +385,44 @@ int Device_Encode_Property_APDU( Object_Instance_Number); break; case PROP_OBJECT_NAME: - apdu_len = encode_tagged_character_string(&apdu[0], Object_Name); + characterstring_init(&char_string,CHARACTER_ANSI, + Object_Name,strlen(Object_Name)); + apdu_len = encode_tagged_character_string(&apdu[0], &char_string); break; case PROP_OBJECT_TYPE: apdu_len = encode_tagged_enumerated(&apdu[0], OBJECT_DEVICE); break; case PROP_DESCRIPTION: - apdu_len = encode_tagged_character_string(&apdu[0], Description); + characterstring_init(&char_string,CHARACTER_ANSI, + Description,strlen(Description)); + apdu_len = encode_tagged_character_string(&apdu[0], &char_string); break; case PROP_SYSTEM_STATUS: apdu_len = encode_tagged_enumerated(&apdu[0], System_Status); break; case PROP_VENDOR_NAME: - apdu_len = encode_tagged_character_string(&apdu[0], Vendor_Name); + characterstring_init(&char_string,CHARACTER_ANSI, + Vendor_Name,strlen(Vendor_Name)); + apdu_len = encode_tagged_character_string(&apdu[0], &char_string); break; case PROP_VENDOR_IDENTIFIER: apdu_len = encode_tagged_unsigned(&apdu[0], Vendor_Identifier); break; case PROP_MODEL_NAME: - apdu_len = encode_tagged_character_string(&apdu[0], Model_Name); + characterstring_init(&char_string,CHARACTER_ANSI, + Model_Name,strlen(Model_Name)); + apdu_len = encode_tagged_character_string(&apdu[0], &char_string); break; case PROP_FIRMWARE_REVISION: - apdu_len = encode_tagged_character_string(&apdu[0], Firmware_Revision); + characterstring_init(&char_string,CHARACTER_ANSI, + Firmware_Revision,strlen(Firmware_Revision)); + apdu_len = encode_tagged_character_string(&apdu[0], &char_string); break; case PROP_APPLICATION_SOFTWARE_VERSION: - apdu_len = encode_tagged_character_string(&apdu[0], - Application_Software_Version); + characterstring_init(&char_string,CHARACTER_ANSI, + Application_Software_Version, + strlen(Application_Software_Version)); + apdu_len = encode_tagged_character_string(&apdu[0], &char_string); break; // if you support time //case PROP_LOCAL_TIME: @@ -376,7 +460,7 @@ int Device_Encode_Property_APDU( // initialize all the services to not-supported bitstring_set_bit(&bit_string, (uint8_t)i, false); } - // initialize those we support + /* FIXME: set the services that YOUR device executes */ bitstring_set_bit(&bit_string, SERVICE_SUPPORTED_WHO_IS, true); bitstring_set_bit(&bit_string, SERVICE_SUPPORTED_I_AM, true); bitstring_set_bit(&bit_string, SERVICE_SUPPORTED_READ_PROPERTY, true); @@ -389,8 +473,10 @@ int Device_Encode_Property_APDU( // initialize all the object types to not-supported bitstring_set_bit(&bit_string, (uint8_t)i, false); } + /* FIXME: indicate the objects that YOU support */ bitstring_set_bit(&bit_string, OBJECT_DEVICE, true); bitstring_set_bit(&bit_string, OBJECT_ANALOG_INPUT, true); + bitstring_set_bit(&bit_string, OBJECT_ANALOG_OUTPUT, true); apdu_len = encode_tagged_bitstring(&apdu[0], &bit_string); break; case PROP_OBJECT_LIST: @@ -490,10 +576,9 @@ bool Device_Write_Property( if (wp_data->value.tag == BACNET_APPLICATION_TAG_OBJECT_ID) { if ((wp_data->value.type.Object_Id.type == OBJECT_DEVICE) && - (wp_data->value.type.Object_Id.instance <= BACNET_MAX_INSTANCE)) + (Device_Set_Object_Instance_Number( + wp_data->value.type.Object_Id.instance))) { - Device_Set_Object_Instance_Number( - wp_data->value.type.Object_Id.instance); I_Am_Request = true; status = true; } @@ -561,18 +646,18 @@ bool Device_Write_Property( *error_code = ERROR_CODE_INVALID_DATA_TYPE; } break; - + case PROP_OBJECT_NAME: if (wp_data->value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) { - BACNET_CHARACTER_STRING Character_String = wp_data->value.type.Character_String; - - char decoded_string[MAX_APDU] = { "" }; - int decoded = 0; - //decoded = decode_character_string(&data->application_data[tag_len], len_value_type, &decoded_string[0], sizeof(decoded_string)); - - //Device_Set_Vendor_Name(const char *name); - status = true; + status = Device_Set_Vendor_Name( + characterstring_value(&wp_data->value.type.Character_String), + characterstring_length(&wp_data->value.type.Character_String)); + if (!status) + { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY; + } } else { @@ -580,7 +665,7 @@ bool Device_Write_Property( *error_code = ERROR_CODE_INVALID_DATA_TYPE; } break; - + default: *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; @@ -597,20 +682,34 @@ bool Device_Write_Property( void testDevice(Test * pTest) { - Device_Set_Object_Instance_Number(111); - ct_test(pTest, Device_Object_Instance_Number() == 111); - + bool status = false; + const char *name = "Patricia"; + + status = Device_Set_Object_Instance_Number(0); + ct_test(pTest, Device_Object_Instance_Number() == 0); + ct_test(pTest, status == true); + status = Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE); + ct_test(pTest, Device_Object_Instance_Number() == BACNET_MAX_INSTANCE); + ct_test(pTest, status == true); + status = Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE/2); + ct_test(pTest, Device_Object_Instance_Number() == (BACNET_MAX_INSTANCE/2)); + ct_test(pTest, status == true); + status = Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE+1); + ct_test(pTest, Device_Object_Instance_Number() != (BACNET_MAX_INSTANCE+1)); + ct_test(pTest, status == false); + + Device_Set_System_Status(STATUS_NON_OPERATIONAL); ct_test(pTest, Device_System_Status() == STATUS_NON_OPERATIONAL); - Device_Set_Vendor_Name("MyName"); - ct_test(pTest, strcmp(Device_Vendor_Name(),"MyName") == 0); + Device_Set_Vendor_Name(name,strlen(name)); + ct_test(pTest, strcmp(Device_Vendor_Name(),name) == 0); Device_Set_Vendor_Identifier(42); ct_test(pTest, Device_Vendor_Identifier() == 42); - Device_Set_Model_Name("MyModel"); - ct_test(pTest, strcmp(Device_Model_Name(),"MyModel") == 0); + Device_Set_Model_Name(name,strlen(name)); + ct_test(pTest, strcmp(Device_Model_Name(),name) == 0); return; } diff --git a/bacnet-stack/device.h b/bacnet-stack/device.h index ce1c3a1f..66919708 100644 --- a/bacnet-stack/device.h +++ b/bacnet-stack/device.h @@ -45,7 +45,7 @@ extern "C" { #endif /* __cplusplus */ uint32_t Device_Object_Instance_Number(void); -void Device_Set_Object_Instance_Number(uint32_t object_id); +bool Device_Set_Object_Instance_Number(uint32_t object_id); bool Device_Valid_Object_Instance_Number(uint32_t object_id); unsigned Device_Object_List_Count(void); bool Device_Object_List_Identifier(unsigned array_index, @@ -56,22 +56,25 @@ BACNET_DEVICE_STATUS Device_System_Status(void); void Device_Set_System_Status(BACNET_DEVICE_STATUS status); const char *Device_Vendor_Name(void); -void Device_Set_Vendor_Name(const char *name); +bool Device_Set_Vendor_Name(const char *name, size_t length); uint16_t Device_Vendor_Identifier(void); void Device_Set_Vendor_Identifier(uint16_t vendor_id); const char *Device_Model_Name(void); -void Device_Set_Model_Name(const char *name); +bool Device_Set_Model_Name(const char *name, size_t length); const char *Device_Firmware_Revision(void); -void Device_Set_Firmware_Revision(const char *name); +bool Device_Set_Firmware_Revision(const char *name, size_t length); const char *Device_Application_Software_Version(void); -void Device_Set_Application_Software_Version(const char *name); +bool Device_Set_Application_Software_Version(const char *name, size_t length); const char *Device_Description(void); -void Device_Set_Description(const char *name); +bool Device_Set_Description(const char *name, size_t length); + +const char *Device_Location(void); +bool Device_Set_Location(const char *name, size_t length); // some stack-centric constant values - no set methods uint8_t Device_Protocol_Version(void); diff --git a/bacnet-stack/device.mak b/bacnet-stack/device.mak index 05b426d5..098c6638 100644 --- a/bacnet-stack/device.mak +++ b/bacnet-stack/device.mak @@ -8,6 +8,7 @@ CFLAGS = -Wall -I. -Itest -DTEST -DTEST_DEVICE -g SRCS = bacdcode.c \ bigend.c \ + bacstr.c \ device.c \ test/ctest.c diff --git a/bacnet-stack/handlers.c b/bacnet-stack/handlers.c index 62555f14..564a52dc 100644 --- a/bacnet-stack/handlers.c +++ b/bacnet-stack/handlers.c @@ -713,7 +713,6 @@ void AtomicReadFileHandler( int bytes_sent = 0; BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT; BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT; - char buffer[MAX_APDU - 16] = ""; // for reply data, less apdu overhead fprintf(stderr,"Received Atomic-Read-File Request!\n"); len = arf_decode_service_request( @@ -754,9 +753,8 @@ void AtomicReadFileHandler( { if (data.access == FILE_STREAM_ACCESS) { - data.fileData = (uint8_t *)&buffer[0]; - data.fileDataLength = sizeof(buffer); - if (data.type.stream.requestedOctetCount < data.fileDataLength) + if (data.type.stream.requestedOctetCount < + octetstring_capacity(&data.fileData)) { if (bacfile_read_data(&data)) { @@ -855,12 +853,13 @@ void AtomicReadFileAckHandler( (void)fseek(pFile, data.type.stream.fileStartPosition, SEEK_SET); - if (fwrite(data.fileData,data.fileDataLength,1,pFile) != 1) + if (fwrite(octetstring_value(&data.fileData), + octetstring_length(&data.fileData),1,pFile) != 1) fprintf(stderr,"Failed to write to %s (%u)!\n", pFilename, instance); fclose(pFile); } - } + } } else if (data.access == FILE_RECORD_ACCESS) { diff --git a/bacnet-stack/iam.mak b/bacnet-stack/iam.mak index b560b00c..97dc37dd 100755 --- a/bacnet-stack/iam.mak +++ b/bacnet-stack/iam.mak @@ -7,6 +7,7 @@ BASEDIR = . CFLAGS = -Wall -I. -Itest -DTEST -DTEST_IAM -g SRCS = bacdcode.c \ + bacstr.c \ bigend.c \ npdu.c \ apdu.c \ diff --git a/bacnet-stack/npdu.mak b/bacnet-stack/npdu.mak index b8f2b4ab..38c38a49 100644 --- a/bacnet-stack/npdu.mak +++ b/bacnet-stack/npdu.mak @@ -7,6 +7,7 @@ BASEDIR = . CFLAGS = -Wall -I. -Itest -DTEST -DTEST_NPDU -g SRCS = bacdcode.c \ + bacstr.c \ bigend.c \ npdu.c \ apdu.c \ diff --git a/bacnet-stack/ports/linux/main.c b/bacnet-stack/ports/linux/main.c index c3e2f054..97f995a4 100644 --- a/bacnet-stack/ports/linux/main.c +++ b/bacnet-stack/ports/linux/main.c @@ -47,20 +47,6 @@ // buffers used for receiving static uint8_t Rx_Buf[MAX_MPDU] = {0}; -static void Init_Device_Parameters(void) -{ - // configure my initial values - Device_Set_Object_Instance_Number(111); - Device_Set_Vendor_Name("Lithonia Lighting"); - Device_Set_Vendor_Identifier(42); - Device_Set_Model_Name("Simple BACnet Server"); - Device_Set_Firmware_Revision("1.00"); - Device_Set_Application_Software_Version("none"); - Device_Set_Description("Example of a simple BACnet server"); - - return; -} - static void LocalIAmHandler( uint8_t *service_request, uint16_t service_len, @@ -275,8 +261,8 @@ int main(int argc, char *argv[]) signal(SIGINT, sig_handler); signal(SIGHUP, sig_handler); signal(SIGTERM, sig_handler); - // setup this BACnet Server - Init_Device_Parameters(); + // setup this BACnet Server device + Device_Set_Object_Instance_Number(111); Init_Service_Handlers(); #ifdef BACDL_ETHERNET // init the physical layer diff --git a/bacnet-stack/ports/rtos32/main.c b/bacnet-stack/ports/rtos32/main.c index bb7b4fde..34154c67 100644 --- a/bacnet-stack/ports/rtos32/main.c +++ b/bacnet-stack/ports/rtos32/main.c @@ -67,20 +67,6 @@ volatile struct mstp_port_struct_t MSTP_Port; // port data static uint8_t MSTP_MAC_Address = 0x05; // local MAC address #endif -static void Init_Device_Parameters(void) -{ - // configure my initial values - Device_Set_Object_Instance_Number(126); - Device_Set_Vendor_Name("Lithonia Lighting"); - Device_Set_Vendor_Identifier(42); - Device_Set_Model_Name("Simple BACnet Server"); - Device_Set_Firmware_Revision("1.00"); - Device_Set_Application_Software_Version("none"); - Device_Set_Description("Example of a simple BACnet server"); - - return; -} - static void Init_Service_Handlers(void) { // we need to handle who-is to support dynamic device binding @@ -264,7 +250,7 @@ int main(int argc, char *argv[]) (void)argc; (void)argv; - Init_Device_Parameters(); + Device_Set_Object_Instance_Number(126); Init_Service_Handlers(); // init the physical layer #ifdef BACDL_BIP diff --git a/bacnet-stack/reject.mak b/bacnet-stack/reject.mak index b9b81247..a59f6daf 100644 --- a/bacnet-stack/reject.mak +++ b/bacnet-stack/reject.mak @@ -7,6 +7,7 @@ BASEDIR = . CFLAGS = -Wall -I. -Itest -DTEST -DTEST_REJECT -g SRCS = bacdcode.c \ + bacstr.c \ bigend.c \ reject.c \ test/ctest.c diff --git a/bacnet-stack/rp.mak b/bacnet-stack/rp.mak index 9d2dcf8a..5a336e46 100644 --- a/bacnet-stack/rp.mak +++ b/bacnet-stack/rp.mak @@ -7,6 +7,7 @@ BASEDIR = . CFLAGS = -Wall -I. -Itest -DTEST -DTEST_READ_PROPERTY -g SRCS = bacdcode.c \ + bacstr.c \ bigend.c \ rp.c \ test/ctest.c diff --git a/bacnet-stack/rpm.mak b/bacnet-stack/rpm.mak index 1fd30546..b4d52166 100644 --- a/bacnet-stack/rpm.mak +++ b/bacnet-stack/rpm.mak @@ -9,6 +9,7 @@ CFLAGS = -Wall -I. -Itest -DTEST -DTEST_READ_PROPERTY_MULTIPLE -g SRCS = bacdcode.c \ bacerror.c \ bacapp.c \ + bacstr.c \ bigend.c \ rpm.c \ test/ctest.c diff --git a/bacnet-stack/test.sh b/bacnet-stack/test.sh index f6277ff0..d9baeb00 100755 --- a/bacnet-stack/test.sh +++ b/bacnet-stack/test.sh @@ -4,70 +4,15 @@ rm test.log touch test.log -make -f crc.mak clean -make -f crc.mak -./crc >> test.log -make -f crc.mak clean - -make -f ringbuf.mak clean -make -f ringbuf.mak -./ringbuf >> test.log -make -f ringbuf.mak clean - -make -f mstp.mak clean -make -f mstp.mak -./mstp >> test.log -make -f mstp.mak clean - -make -f iam.mak clean -make -f iam.mak -./iam >> test.log -make -f iam.mak clean - -make -f whois.mak clean -make -f whois.mak -./whois >> test.log -make -f whois.mak clean - -make -f bacdcode.mak clean -make -f bacdcode.mak -./bacdcode >> test.log -make -f bacdcode.mak clean - -make -f iam.mak clean -make -f iam.mak -./iam >> test.log -make -f iam.mak clean - -make -f whois.mak clean -make -f whois.mak -./whois >> test.log -make -f whois.mak clean - -make -f npdu.mak clean -make -f npdu.mak -./npdu >> test.log -make -f npdu.mak clean - -make -f reject.mak clean -make -f reject.mak -./reject >> test.log -make -f reject.mak clean - make -f abort.mak clean make -f abort.mak ./abort >> test.log make -f abort.mak clean -make -f bacerror.mak clean -make -f bacerror.mak -./bacerror >> test.log -make -f bacerror.mak clean - -make -f device.mak clean -make -f device.mak -./device >> test.log -make -f device.mak clean +make -f address.mak clean +make -f address.mak +./address >> test.log +make -f address.mak clean make -f ai.mak clean make -f ai.mak @@ -79,17 +24,102 @@ make -f ao.mak ./analog_output >> test.log make -f ao.mak clean -make -f wp.mak clean -make -f wp.mak -./writeproperty >> test.log -make -f wp.mak clean +make -f arf.mak clean +make -f arf.mak +./atomicreadfile >> test.log +make -f arf.mak clean -make -f address.mak clean -make -f address.mak -./address >> test.log -make -f address.mak clean +make -f awf.mak clean +make -f awf.mak +./atomicwritefile >> test.log +make -f awf.mak clean + +make -f bacapp.mak clean +make -f bacapp.mak +./bacapp >> test.log +make -f bacapp.mak clean + +make -f bacdcode.mak clean +make -f bacdcode.mak +./bacdcode >> test.log +make -f bacdcode.mak clean + +make -f bacerror.mak clean +make -f bacerror.mak +./bacerror >> test.log +make -f bacerror.mak clean + +make -f bacstr.mak clean +make -f bacstr.mak +./bacstr >> test.log +make -f bacstr.mak clean + +make -f crc.mak clean +make -f crc.mak +./crc >> test.log +make -f crc.mak clean + +make -f device.mak clean +make -f device.mak +./device >> test.log +make -f device.mak clean + +make -f iam.mak clean +make -f iam.mak +./iam >> test.log +make -f iam.mak clean make -f indtext.mak clean make -f indtext.mak ./indtext >> test.log make -f indtext.mak clean + +make -f mstp.mak clean +make -f mstp.mak +./mstp >> test.log +make -f mstp.mak clean + +make -f npdu.mak clean +make -f npdu.mak +./npdu >> test.log +make -f npdu.mak clean + +make -f reject.mak clean +make -f reject.mak +./reject >> test.log +make -f reject.mak clean + +make -f ringbuf.mak clean +make -f ringbuf.mak +./ringbuf >> test.log +make -f ringbuf.mak clean + +make -f rp.mak clean +make -f rp.mak +./readproperty >> test.log +make -f rp.mak clean + +make -f rpm.mak clean +make -f rpm.mak +./rpm >> test.log +make -f rpm.mak clean + +make -f sbuf.mak clean +make -f sbuf.mak +./sbuf >> test.log +make -f sbuf.mak clean + +make -f tsm.mak clean +make -f tsm.mak +./tsm >> test.log +make -f tsm.mak clean + +make -f whois.mak clean +make -f whois.mak +./whois >> test.log +make -f whois.mak clean + +make -f wp.mak clean +make -f wp.mak +./writeproperty >> test.log +make -f wp.mak clean diff --git a/bacnet-stack/tsm.c b/bacnet-stack/tsm.c index 1b7aedd6..30692167 100644 --- a/bacnet-stack/tsm.c +++ b/bacnet-stack/tsm.c @@ -250,23 +250,12 @@ void tsm_free_invoke_id(uint8_t invokeID) #include #include "ctest.h" +// flag to send an I-Am +bool I_Am_Request = true; + void testTSM(Test * pTest) { - //unsigned i; - uint8_t invokeID = 0; - BACNET_ADDRESS dest = {0}; - uint8_t pdu[MAX_PDU] = {0}; - uint16_t pdu_len = 0; - - memset(pdu,0xa5,sizeof(pdu)); - pdu_len = sizeof(pdu); - - invokeID = tsm_request_confirmed_unsegmented_transaction( - &dest, - &pdu[0], - pdu_len); - ct_test(pTest, invokeID != 0); - + /* FIXME: add some unit testing...*/ return; } diff --git a/bacnet-stack/tsm.mak b/bacnet-stack/tsm.mak index c3d60d8b..cf5111ca 100644 --- a/bacnet-stack/tsm.mak +++ b/bacnet-stack/tsm.mak @@ -6,9 +6,17 @@ BASEDIR = . #CFLAGS = -Wall -I. -g CFLAGS = -Wall -I. -Itest -DTEST -DTEST_TSM -g -SRCS = bacdcode.c \ +SRCS = address.c \ + bacdcode.c \ + bacstr.c \ bigend.c \ device.c \ + ai.c \ + ao.c \ + iam.c \ + npdu.c \ + apdu.c \ + datalink.c \ tsm.c \ test/ctest.c diff --git a/bacnet-stack/whois.mak b/bacnet-stack/whois.mak index 856b30de..7a962b4c 100644 --- a/bacnet-stack/whois.mak +++ b/bacnet-stack/whois.mak @@ -7,6 +7,7 @@ BASEDIR = . CFLAGS = -Wall -I. -Itest -DTEST -DTEST_WHOIS -g SRCS = bacdcode.c \ + bacstr.c \ bigend.c \ whois.c \ test/ctest.c diff --git a/bacnet-stack/wp.mak b/bacnet-stack/wp.mak index a915d1b1..7c8bf9d0 100644 --- a/bacnet-stack/wp.mak +++ b/bacnet-stack/wp.mak @@ -7,6 +7,7 @@ BASEDIR = . CFLAGS = -Wall -I. -Itest -DTEST -DTEST_WRITE_PROPERTY -DBACDL_BIP=1 -g SRCS = bacdcode.c \ + bacstr.c \ bigend.c \ bacapp.c \ wp.c \