diff --git a/bacnet-stack/demo/handler/h_arf.c b/bacnet-stack/demo/handler/h_arf.c index a35d36ce..9d01f8f4 100644 --- a/bacnet-stack/demo/handler/h_arf.c +++ b/bacnet-stack/demo/handler/h_arf.c @@ -107,6 +107,7 @@ void handler_atomic_read_file( int pdu_len = 0; bool error = false; int bytes_sent = 0; + uint32_t offset = 0; BACNET_NPDU_DATA npdu_data; BACNET_ADDRESS my_address; BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT; @@ -147,8 +148,8 @@ void handler_atomic_read_file( error = true; } else if (data.access == FILE_STREAM_ACCESS) { if (data.type.stream.requestedOctetCount < - octetstring_capacity(&data.fileData)) { - if (bacfile_read_data(&data)) { + octetstring_capacity(&data.fileData[0])) { + if (bacfile_read_stream_data(&data)) { #if PRINT_ENABLED fprintf(stderr, "ARF: Stream offset %d, %d octets.\n", data.type.stream.fileStartPosition, @@ -170,9 +171,30 @@ void handler_atomic_read_file( #if PRINT_ENABLED fprintf(stderr, "Too Big To Send (%d >= %d). Sending Abort!\n", data.type.stream.requestedOctetCount, - octetstring_capacity(&data.fileData)); + octetstring_capacity(&data.fileData[0])); #endif } + } else if (data.access == FILE_RECORD_ACCESS) { + if (data.type.record.fileStartRecord >= + BACNET_READ_FILE_RECORD_COUNT) { + error_class = ERROR_CLASS_SERVICES; + error_code = ERROR_CODE_INVALID_FILE_START_POSITION; + error = true; + } else if (bacfile_read_stream_data(&data)) { +#if PRINT_ENABLED + fprintf(stderr, + "ARF: fileStartRecord %d, %u RecordCount.\n", + data.type.record.fileStartRecord, + data.type.record.RecordCount); +#endif + len = + arf_ack_encode_apdu(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, &data); + } else { + error = true; + error_class = ERROR_CLASS_OBJECT; + error_code = ERROR_CODE_FILE_ACCESS_DENIED; + } } else { error = true; error_class = ERROR_CLASS_SERVICES; @@ -184,7 +206,7 @@ void handler_atomic_read_file( } else { error = true; error_class = ERROR_CLASS_SERVICES; - error_code = ERROR_CODE_FILE_ACCESS_DENIED; + error_code = ERROR_CODE_INCONSISTENT_OBJECT_TYPE; } if (error) { len = diff --git a/bacnet-stack/demo/handler/h_arf_a.c b/bacnet-stack/demo/handler/h_arf_a.c index 63a52bb4..bfcebf25 100644 --- a/bacnet-stack/demo/handler/h_arf_a.c +++ b/bacnet-stack/demo/handler/h_arf_a.c @@ -72,7 +72,7 @@ void handler_atomic_read_file_ack( if (data.access == FILE_STREAM_ACCESS) { bacfile_read_ack_stream_data(instance, &data); } else if (data.access == FILE_RECORD_ACCESS) { - /* FIXME: add handling for Record Access */ + bacfile_read_ack_record_data(instance, &data); } } } diff --git a/bacnet-stack/demo/handler/h_awf.c b/bacnet-stack/demo/handler/h_awf.c index 8f5285ef..bc1acf38 100644 --- a/bacnet-stack/demo/handler/h_awf.c +++ b/bacnet-stack/demo/handler/h_awf.c @@ -130,7 +130,22 @@ void handler_atomic_write_file( #if PRINT_ENABLED fprintf(stderr, "AWF: Stream offset %d, %d bytes\n", data.type.stream.fileStartPosition, - octetstring_length(&data.fileData)); + octetstring_length(&data.fileData[0])); +#endif + len = + awf_ack_encode_apdu(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, &data); + } else { + error = true; + error_class = ERROR_CLASS_OBJECT; + error_code = ERROR_CODE_FILE_ACCESS_DENIED; + } + } else if (data.access == FILE_RECORD_ACCESS) { + if (bacfile_write_record_data(&data)) { +#if PRINT_ENABLED + fprintf(stderr, "AWF: StartRecord %d, RecordCount %u\n", + data.type.record.fileStartRecord, + data.type.record.returnedRecordCount); #endif len = awf_ack_encode_apdu(&Handler_Transmit_Buffer[pdu_len], @@ -151,7 +166,7 @@ void handler_atomic_write_file( } else { error = true; error_class = ERROR_CLASS_SERVICES; - error_code = ERROR_CODE_FILE_ACCESS_DENIED; + error_code = ERROR_CODE_INCONSISTENT_OBJECT_TYPE; } if (error) { len = diff --git a/bacnet-stack/demo/handler/s_awfs.c b/bacnet-stack/demo/handler/s_awfs.c index b0aef8bb..eade7275 100644 --- a/bacnet-stack/demo/handler/s_awfs.c +++ b/bacnet-stack/demo/handler/s_awfs.c @@ -45,89 +45,86 @@ /** @file s_awfs.c Send part of an Atomic Write File Stream request. */ -uint8_t Send_Atomic_Write_File_Stream( - uint32_t device_id, - uint32_t file_instance, - int fileStartPosition, - BACNET_OCTET_STRING * fileData) -{ - BACNET_ADDRESS dest; - BACNET_ADDRESS my_address; - BACNET_NPDU_DATA npdu_data; - unsigned max_apdu = 0; - uint8_t invoke_id = 0; - bool status = false; - int len = 0; - int pdu_len = 0; - int bytes_sent = 0; - BACNET_ATOMIC_WRITE_FILE_DATA data; +uint8_t Send_Atomic_Write_File_Stream (uint32_t device_id, + uint32_t file_instance, + int fileStartPosition, + BACNET_OCTET_STRING * fileData) { + BACNET_ADDRESS dest; + BACNET_ADDRESS my_address; + BACNET_NPDU_DATA npdu_data; + unsigned max_apdu = 0; + uint8_t invoke_id = 0; + bool status = false; + int len = 0; + int pdu_len = 0; + int bytes_sent = 0; + BACNET_ATOMIC_WRITE_FILE_DATA data; - /* if we are forbidden to send, don't send! */ - if (!dcc_communication_enabled()) - return 0; + /* if we are forbidden to send, don't send! */ + if (!dcc_communication_enabled ()) + return 0; - /* is the device bound? */ - status = address_get_by_device(device_id, &max_apdu, &dest); - /* is there a tsm available? */ - if (status) - invoke_id = tsm_next_free_invokeID(); - if (invoke_id) { - /* load the data for the encoding */ - data.object_type = OBJECT_FILE; - data.object_instance = file_instance; - data.access = FILE_STREAM_ACCESS; - data.type.stream.fileStartPosition = fileStartPosition; - status = octetstring_copy(&data.fileData, fileData); - if (status) { - /* encode the NPDU portion of the packet */ - datalink_get_my_address(&my_address); - npdu_encode_npdu_data(&npdu_data, true, MESSAGE_PRIORITY_NORMAL); - pdu_len = - npdu_encode_pdu(&Handler_Transmit_Buffer[0], &dest, - &my_address, &npdu_data); - /* encode the APDU portion of the packet */ - len = - awf_encode_apdu(&Handler_Transmit_Buffer[pdu_len], invoke_id, - &data); - pdu_len += len; - /* will the APDU fit the target device? - note: if there is a bottleneck router in between - us and the destination, we won't know unless - we have a way to check for that and update the - max_apdu in the address binding table. */ - if ((unsigned) pdu_len <= max_apdu) { - tsm_set_confirmed_unsegmented_transaction(invoke_id, &dest, - &npdu_data, &Handler_Transmit_Buffer[0], - (uint16_t) pdu_len); - bytes_sent = - datalink_send_pdu(&dest, &npdu_data, - &Handler_Transmit_Buffer[0], pdu_len); + /* is the device bound? */ + status = address_get_by_device (device_id, &max_apdu, &dest); + /* is there a tsm available? */ + if (status) + invoke_id = tsm_next_free_invokeID (); + if (invoke_id) { + /* load the data for the encoding */ + data.object_type = OBJECT_FILE; + data.object_instance = file_instance; + data.access = FILE_STREAM_ACCESS; + data.type.stream.fileStartPosition = fileStartPosition; + status = octetstring_copy (&data.fileData[0], fileData); + if (status) { + /* encode the NPDU portion of the packet */ + datalink_get_my_address (&my_address); + npdu_encode_npdu_data (&npdu_data, true, MESSAGE_PRIORITY_NORMAL); + pdu_len = + npdu_encode_pdu (&Handler_Transmit_Buffer[0], &dest, &my_address, + &npdu_data); + /* encode the APDU portion of the packet */ + len = + awf_encode_apdu (&Handler_Transmit_Buffer[pdu_len], invoke_id, &data); + pdu_len += len; + /* will the APDU fit the target device? + note: if there is a bottleneck router in between + us and the destination, we won't know unless + we have a way to check for that and update the + max_apdu in the address binding table. */ + if ((unsigned) pdu_len <= max_apdu) { + tsm_set_confirmed_unsegmented_transaction (invoke_id, &dest, + &npdu_data, + &Handler_Transmit_Buffer + [0], (uint16_t) pdu_len); + bytes_sent = + datalink_send_pdu (&dest, &npdu_data, &Handler_Transmit_Buffer[0], + pdu_len); #if PRINT_ENABLED - if (bytes_sent <= 0) - fprintf(stderr, - "Failed to Send AtomicWriteFile Request (%s)!\n", - strerror(errno)); + if (bytes_sent <= 0) + fprintf (stderr, "Failed to Send AtomicWriteFile Request (%s)!\n", + strerror (errno)); #endif - } else { - tsm_free_invoke_id(invoke_id); - invoke_id = 0; + } else { + tsm_free_invoke_id (invoke_id); + invoke_id = 0; #if PRINT_ENABLED - fprintf(stderr, - "Failed to Send AtomicWriteFile Request " - "(payload [%d] exceeds destination maximum APDU [%u])!\n", - pdu_len, max_apdu); + fprintf (stderr, + "Failed to Send AtomicWriteFile Request " + "(payload [%d] exceeds destination maximum APDU [%u])!\n", + pdu_len, max_apdu); #endif - } - } else { - tsm_free_invoke_id(invoke_id); - invoke_id = 0; + } + } else { + tsm_free_invoke_id (invoke_id); + invoke_id = 0; #if PRINT_ENABLED - fprintf(stderr, - "Failed to Send AtomicWriteFile Request " - "(payload [%d] exceeds octet string capacity)!\n", pdu_len); + fprintf (stderr, + "Failed to Send AtomicWriteFile Request " + "(payload [%d] exceeds octet string capacity)!\n", pdu_len); #endif - } } + } - return invoke_id; + return invoke_id; } diff --git a/bacnet-stack/demo/object/bacfile.c b/bacnet-stack/demo/object/bacfile.c index 9f458607..ae3492fd 100644 --- a/bacnet-stack/demo/object/bacfile.c +++ b/bacnet-stack/demo/object/bacfile.c @@ -49,6 +49,10 @@ typedef struct { char *filename; } BACNET_FILE_LISTING; +#ifndef FILE_RECORD_SIZE +#define FILE_RECORD_SIZE MAX_OCTET_STRING_BYTES +#endif + static BACNET_FILE_LISTING BACnet_File_Listing[] = { {0, "temp_0.txt"}, {1, "temp_1.txt"}, @@ -277,7 +281,8 @@ int bacfile_read_property( break; case PROP_FILE_ACCESS_METHOD: apdu_len = - encode_application_enumerated(&apdu[0], FILE_STREAM_ACCESS); + encode_application_enumerated(&apdu[0], + FILE_RECORD_AND_STREAM_ACCESS); break; default: rpdata->error_class = ERROR_CLASS_PROPERTY; @@ -436,7 +441,7 @@ uint32_t bacfile_instance_from_tsm( } #endif -bool bacfile_read_data( +bool bacfile_read_stream_data( BACNET_ATOMIC_READ_FILE_DATA * data) { char *pFilename = NULL; @@ -451,20 +456,20 @@ bool bacfile_read_data( if (pFile) { (void) fseek(pFile, data->type.stream.fileStartPosition, SEEK_SET); len = - fread(octetstring_value(&data->fileData), 1, + fread(octetstring_value(&data->fileData[0]), 1, data->type.stream.requestedOctetCount, pFile); if (len < data->type.stream.requestedOctetCount) data->endOfFile = true; else data->endOfFile = false; - octetstring_truncate(&data->fileData, len); + octetstring_truncate(&data->fileData[0], len); fclose(pFile); } else { - octetstring_truncate(&data->fileData, 0); + octetstring_truncate(&data->fileData[0], 0); data->endOfFile = true; } } else { - octetstring_truncate(&data->fileData, 0); + octetstring_truncate(&data->fileData[0], 0); data->endOfFile = true; } @@ -498,8 +503,8 @@ bool bacfile_write_stream_data( (void) fseek(pFile, data->type.stream.fileStartPosition, SEEK_SET); } - if (fwrite(octetstring_value(&data->fileData), - octetstring_length(&data->fileData), 1, pFile) != 1) { + if (fwrite(octetstring_value(&data->fileData[0]), + octetstring_length(&data->fileData[0]), 1, pFile) != 1) { /* do something if it fails? */ } fclose(pFile); @@ -509,6 +514,53 @@ bool bacfile_write_stream_data( return found; } +bool bacfile_write_record_data( + BACNET_ATOMIC_WRITE_FILE_DATA * data) +{ + char *pFilename = NULL; + bool found = false; + FILE *pFile = NULL; + uint32_t i = 0; + char dummy_data[FILE_RECORD_SIZE]; + + pFilename = bacfile_name(data->object_instance); + if (pFilename) { + found = true; + if (data->type.record.fileStartRecord == 0) { + /* open the file as a clean slate when starting at 0 */ + pFile = fopen(pFilename, "wb"); + } else if (data->type.record.fileStartRecord == -1) { + /* If 'File Start Record' parameter has the special + value -1, then the write operation shall be treated + as an append to the current end of file. */ + pFile = fopen(pFilename, "ab+"); + } else { + /* open for update */ + pFile = fopen(pFilename, "rb+"); + } + if (pFile) { + if ((data->type.record.fileStartRecord != -1) && + (data->type.record.fileStartRecord > 0)) { + for (i = 0; i < data->type.record.fileStartRecord; i++) { + fgets(&dummy_data[0], sizeof(dummy_data), pFile); + if (feof(pFile)) { + break; + } + } + } + for (i = 0; i < data->type.record.returnedRecordCount; i++) { + if (fwrite(octetstring_value(&data->fileData[i]), + octetstring_length(&data->fileData[i]), 1, pFile) != 1) { + /* do something if it fails? */ + } + } + fclose(pFile); + } + } + + return found; +} + bool bacfile_read_ack_stream_data( uint32_t instance, BACNET_ATOMIC_READ_FILE_DATA * data) @@ -523,8 +575,8 @@ bool bacfile_read_ack_stream_data( pFile = fopen(pFilename, "rb"); if (pFile) { (void) fseek(pFile, data->type.stream.fileStartPosition, SEEK_SET); - if (fwrite(octetstring_value(&data->fileData), - octetstring_length(&data->fileData), 1, pFile) != 1) { + if (fwrite(octetstring_value(&data->fileData[0]), + octetstring_length(&data->fileData[0]), 1, pFile) != 1) { #if PRINT_ENABLED fprintf(stderr, "Failed to write to %s (%lu)!\n", pFilename, (unsigned long) instance); @@ -537,6 +589,45 @@ bool bacfile_read_ack_stream_data( return found; } +bool bacfile_read_ack_record_data( + uint32_t instance, + BACNET_ATOMIC_READ_FILE_DATA * data) +{ + bool found = false; + FILE *pFile = NULL; + char *pFilename = NULL; + uint32_t i = 0; + char dummy_data[MAX_OCTET_STRING_BYTES] = {0}; + + pFilename = bacfile_name(instance); + if (pFilename) { + found = true; + pFile = fopen(pFilename, "rb"); + if (pFile) { + if (data->type.record.fileStartRecord > 0) { + for (i = 0; i < data->type.record.fileStartRecord; i++) { + fgets(&dummy_data[0], sizeof(dummy_data), pFile); + if (feof(pFile)) { + break; + } + } + } + for (i = 0; i < data->type.record.RecordCount; i++) { + if (fwrite(octetstring_value(&data->fileData[i]), + octetstring_length(&data->fileData[i]), 1, pFile) != 1) { +#if PRINT_ENABLED + fprintf(stderr, "Failed to write to %s (%lu)!\n", pFilename, + (unsigned long) instance); +#endif + } + } + fclose(pFile); + } + } + + return found; +} + void bacfile_init( void) { diff --git a/bacnet-stack/demo/object/bacfile.h b/bacnet-stack/demo/object/bacfile.h index f934f86b..6248acb9 100644 --- a/bacnet-stack/demo/object/bacfile.h +++ b/bacnet-stack/demo/object/bacfile.h @@ -74,13 +74,20 @@ extern "C" { uint8_t invokeID); /* handler ACK helper */ - bool bacfile_read_data( + bool bacfile_read_stream_data( BACNET_ATOMIC_READ_FILE_DATA * data); bool bacfile_read_ack_stream_data( uint32_t instance, BACNET_ATOMIC_READ_FILE_DATA * data); bool bacfile_write_stream_data( BACNET_ATOMIC_WRITE_FILE_DATA * data); + bool bacfile_read_record_data( + BACNET_ATOMIC_READ_FILE_DATA * data); + bool bacfile_read_ack_record_data( + uint32_t instance, + BACNET_ATOMIC_READ_FILE_DATA * data); + bool bacfile_write_record_data( + BACNET_ATOMIC_WRITE_FILE_DATA * data); void bacfile_init( void); diff --git a/bacnet-stack/include/arf.h b/bacnet-stack/include/arf.h index 49ff6794..01d1122c 100644 --- a/bacnet-stack/include/arf.h +++ b/bacnet-stack/include/arf.h @@ -29,6 +29,10 @@ #include "bacdcode.h" #include "bacstr.h" +#ifndef BACNET_READ_FILE_RECORD_COUNT +#define BACNET_READ_FILE_RECORD_COUNT 1 +#endif + typedef struct BACnet_Atomic_Read_File_Data { BACNET_OBJECT_TYPE object_type; uint32_t object_instance; @@ -44,7 +48,7 @@ typedef struct BACnet_Atomic_Read_File_Data { uint32_t RecordCount; } record; } type; - BACNET_OCTET_STRING fileData; + BACNET_OCTET_STRING fileData[BACNET_READ_FILE_RECORD_COUNT]; bool endOfFile; } BACNET_ATOMIC_READ_FILE_DATA; diff --git a/bacnet-stack/include/awf.h b/bacnet-stack/include/awf.h index df9d7b73..971e9fa0 100644 --- a/bacnet-stack/include/awf.h +++ b/bacnet-stack/include/awf.h @@ -28,6 +28,10 @@ #include #include "bacdcode.h" +#ifndef BACNET_WRITE_FILE_RECORD_COUNT +#define BACNET_WRITE_FILE_RECORD_COUNT 1 +#endif + typedef struct BACnet_Atomic_Write_File_Data { BACNET_OBJECT_TYPE object_type; uint32_t object_instance; @@ -41,7 +45,7 @@ typedef struct BACnet_Atomic_Write_File_Data { uint32_t returnedRecordCount; } record; } type; - BACNET_OCTET_STRING fileData; + BACNET_OCTET_STRING fileData[BACNET_WRITE_FILE_RECORD_COUNT]; } BACNET_ATOMIC_WRITE_FILE_DATA; #ifdef __cplusplus diff --git a/bacnet-stack/src/arf.c b/bacnet-stack/src/arf.c index 66ad7fce..28c13f2e 100644 --- a/bacnet-stack/src/arf.c +++ b/bacnet-stack/src/arf.c @@ -204,6 +204,7 @@ int arf_ack_encode_apdu( BACNET_ATOMIC_READ_FILE_DATA * data) { int apdu_len = 0; /* total length of the apdu, return value */ + uint32_t i = 0; if (apdu) { apdu[0] = PDU_TYPE_COMPLEX_ACK; @@ -221,7 +222,7 @@ int arf_ack_encode_apdu( data->type.stream.fileStartPosition); apdu_len += encode_application_octet_string(&apdu[apdu_len], - &data->fileData); + &data->fileData[0]); apdu_len += encode_closing_tag(&apdu[apdu_len], 0); break; case FILE_RECORD_ACCESS: @@ -232,9 +233,11 @@ int arf_ack_encode_apdu( apdu_len += encode_application_unsigned(&apdu[apdu_len], data->type.record.RecordCount); - apdu_len += - encode_application_octet_string(&apdu[apdu_len], - &data->fileData); + for (i = 0; i < data->type.record.RecordCount; i++) { + apdu_len += + encode_application_octet_string(&apdu[apdu_len], + &data->fileData[i]); + } apdu_len += encode_closing_tag(&apdu[apdu_len], 1); break; default: @@ -255,6 +258,7 @@ int arf_ack_decode_service_request( int tag_len = 0; uint8_t tag_number = 0; uint32_t len_value_type = 0; + uint32_t i = 0; /* check for value pointers */ if (apdu_len && data) { @@ -287,7 +291,7 @@ int arf_ack_decode_service_request( return -1; len += decode_octet_string(&apdu[len], len_value_type, - &data->fileData); + &data->fileData[0]); if (!decode_is_closing_tag_number(&apdu[len], 0)) return -1; /* a tag number is not extended so only one octet */ @@ -316,16 +320,18 @@ int arf_ack_decode_service_request( len += decode_unsigned(&apdu[len], len_value_type, &data->type.record.RecordCount); - /* fileData */ - tag_len = - decode_tag_number_and_value(&apdu[len], &tag_number, - &len_value_type); - len += tag_len; - if (tag_number != BACNET_APPLICATION_TAG_OCTET_STRING) - return -1; - len += - decode_octet_string(&apdu[len], len_value_type, - &data->fileData); + for (i = 0; i < data->type.record.RecordCount; i++) { + /* fileData */ + tag_len = + decode_tag_number_and_value(&apdu[len], &tag_number, + &len_value_type); + len += tag_len; + if (tag_number != BACNET_APPLICATION_TAG_OCTET_STRING) + return -1; + len += + decode_octet_string(&apdu[len], len_value_type, + &data->fileData[i]); + } if (!decode_is_closing_tag_number(&apdu[len], 1)) return -1; /* a tag number is not extended so only one octet */ @@ -403,11 +409,11 @@ void testAtomicReadFileAckAccess( data->type.record.RecordCount); } ct_test(pTest, - octetstring_length(&test_data.fileData) == - octetstring_length(&data->fileData)); - ct_test(pTest, memcmp(octetstring_value(&test_data.fileData), - octetstring_value(&data->fileData), - octetstring_length(&test_data.fileData)) == 0); + octetstring_length(&test_data.fileData[0]) == + octetstring_length(&data->fileData[0])); + ct_test(pTest, memcmp(octetstring_value(&test_data.fileData[0]), + octetstring_value(&data->fileData[0]), + octetstring_length(&test_data.fileData[0])) == 0); } void testAtomicReadFileAck( @@ -420,7 +426,7 @@ void testAtomicReadFileAck( data.endOfFile = true; data.access = FILE_STREAM_ACCESS; data.type.stream.fileStartPosition = 0; - octetstring_init(&data.fileData, test_octet_string, + octetstring_init(&data.fileData[0], test_octet_string, sizeof(test_octet_string)); testAtomicReadFileAckAccess(pTest, &data); @@ -428,7 +434,7 @@ void testAtomicReadFileAck( data.access = FILE_RECORD_ACCESS; data.type.record.fileStartRecord = 1; data.type.record.RecordCount = 2; - octetstring_init(&data.fileData, test_octet_string, + octetstring_init(&data.fileData[0], test_octet_string, sizeof(test_octet_string)); testAtomicReadFileAckAccess(pTest, &data); diff --git a/bacnet-stack/src/awf.c b/bacnet-stack/src/awf.c index 4fbcd5c1..88f1a913 100644 --- a/bacnet-stack/src/awf.c +++ b/bacnet-stack/src/awf.c @@ -46,6 +46,7 @@ int awf_encode_apdu( BACNET_ATOMIC_WRITE_FILE_DATA * data) { int apdu_len = 0; /* total length of the apdu, return value */ + uint32_t i = 0; if (apdu) { apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST; @@ -64,7 +65,7 @@ int awf_encode_apdu( data->type.stream.fileStartPosition); apdu_len += encode_application_octet_string(&apdu[apdu_len], - &data->fileData); + &data->fileData[0]); apdu_len += encode_closing_tag(&apdu[apdu_len], 0); break; case FILE_RECORD_ACCESS: @@ -75,9 +76,11 @@ int awf_encode_apdu( apdu_len += encode_application_unsigned(&apdu[apdu_len], data->type.record.returnedRecordCount); - apdu_len += - encode_application_octet_string(&apdu[apdu_len], - &data->fileData); + for (i = 0; i < data->type.record.returnedRecordCount; i++) { + apdu_len += + encode_application_octet_string(&apdu[apdu_len], + &data->fileData[i]); + } apdu_len += encode_closing_tag(&apdu[apdu_len], 1); break; default: @@ -101,6 +104,7 @@ int awf_decode_service_request( int32_t signed_value = 0; uint32_t unsigned_value = 0; uint16_t type = 0; /* for decoding */ + uint32_t i = 0; /* check for value pointers */ if (apdu_len && data) { @@ -133,7 +137,7 @@ int awf_decode_service_request( return -1; len += decode_octet_string(&apdu[len], len_value_type, - &data->fileData); + &data->fileData[0]); if (!decode_is_closing_tag_number(&apdu[len], 0)) return -1; /* a tag number is not extended so only one octet */ @@ -162,15 +166,17 @@ int awf_decode_service_request( decode_unsigned(&apdu[len], len_value_type, &unsigned_value); data->type.record.returnedRecordCount = unsigned_value; /* fileData */ - tag_len = - decode_tag_number_and_value(&apdu[len], &tag_number, - &len_value_type); - len += tag_len; - if (tag_number != BACNET_APPLICATION_TAG_OCTET_STRING) - return -1; - len += - decode_octet_string(&apdu[len], len_value_type, - &data->fileData); + for (i = 0; i < data->type.record.returnedRecordCount; i++) { + tag_len = + decode_tag_number_and_value(&apdu[len], &tag_number, + &len_value_type); + len += tag_len; + if (tag_number != BACNET_APPLICATION_TAG_OCTET_STRING) + return -1; + len += + decode_octet_string(&apdu[len], len_value_type, + &data->fileData[i]); + } if (!decode_is_closing_tag_number(&apdu[len], 1)) return -1; /* a tag number is not extended so only one octet */ @@ -294,7 +300,8 @@ int awf_ack_decode_apdu( if (apdu_len > offset) { len = - awf_decode_service_request(&apdu[offset], apdu_len - offset, data); + awf_ack_decode_service_request(&apdu[offset], apdu_len - offset, + data); } return len; @@ -338,11 +345,11 @@ void testAtomicWriteFileAccess( data->type.record.returnedRecordCount); } ct_test(pTest, - octetstring_length(&test_data.fileData) == - octetstring_length(&data->fileData)); - ct_test(pTest, memcmp(octetstring_value(&test_data.fileData), - octetstring_value(&data->fileData), - octetstring_length(&test_data.fileData)) == 0); + octetstring_length(&test_data.fileData[0]) == + octetstring_length(&data->fileData[0])); + ct_test(pTest, memcmp(octetstring_value(&test_data.fileData[0]), + octetstring_value(&data->fileData[0]), + octetstring_length(&test_data.fileData[0])) == 0); } void testAtomicWriteFile( @@ -355,7 +362,7 @@ void testAtomicWriteFile( data.object_instance = 1; data.access = FILE_STREAM_ACCESS; data.type.stream.fileStartPosition = 0; - octetstring_init(&data.fileData, test_octet_string, + octetstring_init(&data.fileData[0], test_octet_string, sizeof(test_octet_string)); testAtomicWriteFileAccess(pTest, &data); @@ -364,7 +371,7 @@ void testAtomicWriteFile( data.access = FILE_RECORD_ACCESS; data.type.record.fileStartRecord = 1; data.type.record.returnedRecordCount = 2; - octetstring_init(&data.fileData, test_octet_string, + octetstring_init(&data.fileData[0], test_octet_string, sizeof(test_octet_string)); testAtomicWriteFileAccess(pTest, &data);