bool bacfile_read_ack_stream_data( uint32_t instance, BACNET_ATOMIC_READ_FILE_DATA * data) { bool found = false; FILE *pFile = NULL; char *pFilename = NULL; pFilename = bacfile_name(instance); if (pFilename) { found = true; 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 PRINT_ENABLED fprintf(stderr, "Failed to write to %s (%lu)!\n", pFilename, (unsigned long) instance); #endif } fclose(pFile); } } return found; }
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) { found = true; pFile = fopen(pFilename, "rb"); if (pFile) { (void) fseek(pFile, data->type.stream.fileStartPosition, SEEK_SET); len = fread(octetstring_value(&data->fileData), 1, data->type.stream.requestedOctetCount, pFile); if (len < data->type.stream.requestedOctetCount) data->endOfFile = true; else data->endOfFile = false; octetstring_truncate(&data->fileData, len); fclose(pFile); } else { octetstring_truncate(&data->fileData, 0); data->endOfFile = true; } } else { octetstring_truncate(&data->fileData, 0); data->endOfFile = true; } return found; }
void testAtomicReadFileAckAccess( Test * pTest, BACNET_ATOMIC_READ_FILE_DATA * data) { BACNET_ATOMIC_READ_FILE_DATA test_data = { 0 }; uint8_t apdu[480] = { 0 }; int len = 0; int apdu_len = 0; uint8_t invoke_id = 128; uint8_t test_invoke_id = 0; unsigned int i = 0; len = arf_ack_encode_apdu(&apdu[0], invoke_id, data); ct_test(pTest, len != 0); apdu_len = len; len = arf_ack_decode_apdu(&apdu[0], apdu_len, &test_invoke_id, &test_data); ct_test(pTest, len != -1); ct_test(pTest, test_data.endOfFile == data->endOfFile); ct_test(pTest, test_data.access == data->access); if (test_data.access == FILE_STREAM_ACCESS) { ct_test(pTest, test_data.type.stream.fileStartPosition == data->type.stream.fileStartPosition); ct_test(pTest, 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); } else if (test_data.access == FILE_RECORD_ACCESS) { ct_test(pTest, test_data.type.record.fileStartRecord == data->type.record.fileStartRecord); ct_test(pTest, test_data.type.record.RecordCount == data->type.record.RecordCount); for (i = 0; i < data->type.record.RecordCount; i++) { ct_test(pTest, octetstring_length(&test_data.fileData[i]) == octetstring_length(&data->fileData[i])); ct_test(pTest, memcmp(octetstring_value(&test_data.fileData[i]), octetstring_value(&data->fileData[i]), octetstring_length(&test_data.fileData[i])) == 0); } } }
void testAtomicWriteFileAccess( Test * pTest, BACNET_ATOMIC_WRITE_FILE_DATA * data) { BACNET_ATOMIC_WRITE_FILE_DATA test_data = { 0 }; uint8_t apdu[480] = { 0 }; int len = 0; int apdu_len = 0; uint8_t invoke_id = 128; uint8_t test_invoke_id = 0; len = awf_encode_apdu(&apdu[0], invoke_id, data); ct_test(pTest, len != 0); apdu_len = len; len = awf_decode_apdu(&apdu[0], apdu_len, &test_invoke_id, &test_data); ct_test(pTest, len != -1); ct_test(pTest, test_data.object_type == data->object_type); ct_test(pTest, test_data.object_instance == data->object_instance); ct_test(pTest, test_data.access == data->access); if (test_data.access == FILE_STREAM_ACCESS) { ct_test(pTest, test_data.type.stream.fileStartPosition == data->type.stream.fileStartPosition); } else if (test_data.access == FILE_RECORD_ACCESS) { ct_test(pTest, test_data.type.record.fileStartRecord == data->type.record.fileStartRecord); ct_test(pTest, test_data.type.record.returnedRecordCount == 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); }
static void AtomicReadFileAckHandler( uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_ACK_DATA * service_data) { int len = 0; BACNET_ATOMIC_READ_FILE_DATA data; FILE *pFile = NULL; /* stream pointer */ size_t octets_written = 0; (void) src; /* FIXME: validate the source address matches */ len = arf_ack_decode_service_request(service_request, service_len, &data); if (len > 0) { /* validate the parameters before storing data */ if ((data.access == FILE_STREAM_ACCESS) && (service_data->invoke_id == Current_Invoke_ID)) { if (data.type.stream.fileStartPosition == 0) pFile = fopen(Local_File_Name, "wb"); else pFile = fopen(Local_File_Name, "rb+"); if (pFile) { /* is there anything to do with this? data.stream.requestedOctetCount */ (void) fseek(pFile, data.type.stream.fileStartPosition, SEEK_SET); octets_written = fwrite(octetstring_value(&data.fileData), 1, /* unit to write in bytes - in our case, an octet is one byte */ octetstring_length(&data.fileData), pFile); if (octets_written != octetstring_length(&data.fileData)) { fprintf(stderr, "Unable to write data to file \"%s\".\n", Local_File_Name); } else if (octets_written == 0) { fprintf(stderr, "Received 0 byte octet string!.\n"); } else { printf("\r%d bytes", (data.type.stream.fileStartPosition + octets_written)); } fflush(pFile); fclose(pFile); } if (data.endOfFile) { End_Of_File_Detected = true; printf("\r\n"); } } } }
static void AtomicReadFileAckHandler( uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_ACK_DATA * service_data) { int len = 0; BACNET_ATOMIC_READ_FILE_DATA data; if (address_match(&Target_Address, src) && (service_data->invoke_id == Request_Invoke_ID)) { len = arf_ack_decode_service_request(service_request, service_len, &data); if (len > 0) { /* validate the parameters before storing data */ if ((data.access == FILE_STREAM_ACCESS) && (service_data->invoke_id == Request_Invoke_ID)) { char msg[32]; uint8_t *pFileData; int i; sprintf(msg, "EOF=%d,start=%d,", data.endOfFile, data.type.stream.fileStartPosition); __LogAnswer(msg, 0); pFileData = octetstring_value(&data.fileData); for (i = 0; i < octetstring_length(&data.fileData); i++) { sprintf(msg, "%02x ", *pFileData); __LogAnswer(msg, 1); pFileData++; } } else { LogError("Bad stream access reported"); } } } }
bool bacfile_write_stream_data( BACNET_ATOMIC_WRITE_FILE_DATA * data) { char *pFilename = NULL; bool found = false; FILE *pFile = NULL; pFilename = bacfile_name(data->object_instance); if (pFilename) { found = true; if (data->type.stream.fileStartPosition == 0) { /* open the file as a clean slate when starting at 0 */ pFile = fopen(pFilename, "wb"); } else if (data->type.stream.fileStartPosition == -1) { /* If 'File Start Position' 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.stream.fileStartPosition != -1) { (void) fseek(pFile, data->type.stream.fileStartPosition, SEEK_SET); } if (fwrite(octetstring_value(&data->fileData), octetstring_length(&data->fileData), 1, pFile) != 1) { /* do something if it fails? */ } fclose(pFile); } } return found; }
int main( int argc, char *argv[]) { BACNET_ADDRESS src = { 0 }; /* address where message came from */ uint16_t pdu_len = 0; unsigned timeout = 100; /* milliseconds */ unsigned max_apdu = 0; time_t elapsed_seconds = 0; time_t last_seconds = 0; time_t current_seconds = 0; time_t timeout_seconds = 0; int fileStartPosition = 0; unsigned requestedOctetCount = 0; uint8_t invoke_id = 0; bool found = false; uint16_t my_max_apdu = 0; FILE *pFile = NULL; static BACNET_OCTET_STRING fileData; size_t len = 0; bool pad_byte = false; if (argc < 4) { /* FIXME: what about access method - record or stream? */ printf ("%s device-instance file-instance local-name [octet count] [pad value]\r\n", filename_remove_path(argv[0])); return 0; } /* decode the command line parameters */ Target_Device_Object_Instance = strtol(argv[1], NULL, 0); Target_File_Object_Instance = strtol(argv[2], NULL, 0); Local_File_Name = argv[3]; if (Target_Device_Object_Instance >= BACNET_MAX_INSTANCE) { fprintf(stderr, "device-instance=%u - it must be less than %u\r\n", Target_Device_Object_Instance, BACNET_MAX_INSTANCE); return 1; } if (Target_File_Object_Instance >= BACNET_MAX_INSTANCE) { fprintf(stderr, "file-instance=%u - it must be less than %u\r\n", Target_File_Object_Instance, BACNET_MAX_INSTANCE + 1); return 1; } if (argc > 4) { Target_File_Requested_Octet_Count = strtol(argv[4], NULL, 0); } if (argc > 5) { Target_File_Requested_Octet_Pad_Byte = strtol(argv[5], NULL, 0); pad_byte = true; } /* setup my info */ Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE); address_init(); Init_Service_Handlers(); dlenv_init(); atexit(datalink_cleanup); /* configure the timeout values */ last_seconds = time(NULL); timeout_seconds = (apdu_timeout() / 1000) * apdu_retries(); /* try to bind with the device */ Send_WhoIs(Target_Device_Object_Instance, Target_Device_Object_Instance); /* loop forever */ for (;;) { /* increment timer - exit if timed out */ current_seconds = time(NULL); /* returns 0 bytes on timeout */ pdu_len = datalink_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout); /* process */ if (pdu_len) { npdu_handler(&src, &Rx_Buf[0], pdu_len); } /* at least one second has passed */ if (current_seconds != last_seconds) { tsm_timer_milliseconds(((current_seconds - last_seconds) * 1000)); } /* wait until the device is bound, or timeout and quit */ found = address_bind_request(Target_Device_Object_Instance, &max_apdu, &Target_Address); if (found) { if (Target_File_Requested_Octet_Count) { requestedOctetCount = Target_File_Requested_Octet_Count; } else { /* calculate the smaller of our APDU size or theirs and remove the overhead of the APDU (varies depending on size). note: we could fail if there is a bottle neck (router) and smaller MPDU in betweeen. */ if (max_apdu < MAX_APDU) { my_max_apdu = max_apdu; } else { my_max_apdu = MAX_APDU; } /* Typical sizes are 50, 128, 206, 480, 1024, and 1476 octets */ if (my_max_apdu <= 50) { requestedOctetCount = my_max_apdu - 19; } else if (my_max_apdu <= 480) { requestedOctetCount = my_max_apdu - 32; } else if (my_max_apdu <= 1476) { requestedOctetCount = my_max_apdu - 64; } else { requestedOctetCount = my_max_apdu / 2; } } /* has the previous invoke id expired or returned? note: invoke ID = 0 is invalid, so it will be idle */ if ((invoke_id == 0) || tsm_invoke_id_free(invoke_id)) { if (End_Of_File_Detected || Error_Detected) { printf("\r\n"); break; } if (invoke_id != 0) { fileStartPosition += requestedOctetCount; } /* we'll read the file in chunks less than max_apdu to keep unsegmented */ pFile = fopen(Local_File_Name, "rb"); if (pFile) { (void) fseek(pFile, fileStartPosition, SEEK_SET); len = fread(octetstring_value(&fileData), 1, requestedOctetCount, pFile); if (len < requestedOctetCount) { End_Of_File_Detected = true; if (pad_byte) { memset(octetstring_value(&fileData) + len + 1, (int) Target_File_Requested_Octet_Pad_Byte, requestedOctetCount - len); len = requestedOctetCount; } } octetstring_truncate(&fileData, len); fclose(pFile); } else { End_Of_File_Detected = true; } printf("\rSending %d bytes", (fileStartPosition + len)); invoke_id = Send_Atomic_Write_File_Stream (Target_Device_Object_Instance, Target_File_Object_Instance, fileStartPosition, &fileData); Current_Invoke_ID = invoke_id; } else if (tsm_invoke_id_failed(invoke_id)) { fprintf(stderr, "\rError: TSM Timeout!\r\n"); tsm_free_invoke_id(invoke_id); Error_Detected = true; /* try again or abort? */ break; } } else { /* increment timer - exit if timed out */ elapsed_seconds += (current_seconds - last_seconds); if (elapsed_seconds > timeout_seconds) { fprintf(stderr, "\rError: APDU Timeout!\r\n"); Error_Detected = true; break; } } /* keep track of time for next check */ last_seconds = current_seconds; } if (Error_Detected) { return 1; } return 0; }