| 1 |
4 |
ja_rd |
/*
|
| 2 |
|
|
* ihex.c
|
| 3 |
|
|
* Utility functions to create, read, write, and print Intel HEX8 binary records.
|
| 4 |
|
|
*
|
| 5 |
|
|
* Written by Vanya A. Sergeev <vsergeev@gmail.com>
|
| 6 |
|
|
* Version 1.0.5 - February 2011
|
| 7 |
|
|
*
|
| 8 |
|
|
*/
|
| 9 |
|
|
|
| 10 |
|
|
#include "ihex.h"
|
| 11 |
|
|
|
| 12 |
|
|
/* Initializes a new IHexRecord structure that the paramater ihexRecord points to with the passed
|
| 13 |
|
|
* record type, 16-bit integer address, 8-bit data array, and size of 8-bit data array. */
|
| 14 |
|
|
int New_IHexRecord(int type, uint16_t address, const uint8_t *data, int dataLen, IHexRecord *ihexRecord) {
|
| 15 |
|
|
/* Data length size check, assertion of ihexRecord pointer */
|
| 16 |
|
|
if (dataLen < 0 || dataLen > IHEX_MAX_DATA_LEN/2 || ihexRecord == NULL)
|
| 17 |
|
|
return IHEX_ERROR_INVALID_ARGUMENTS;
|
| 18 |
|
|
|
| 19 |
|
|
ihexRecord->type = type;
|
| 20 |
|
|
ihexRecord->address = address;
|
| 21 |
|
|
memcpy(ihexRecord->data, data, dataLen);
|
| 22 |
|
|
ihexRecord->dataLen = dataLen;
|
| 23 |
|
|
ihexRecord->checksum = Checksum_IHexRecord(ihexRecord);
|
| 24 |
|
|
|
| 25 |
|
|
return IHEX_OK;
|
| 26 |
|
|
}
|
| 27 |
|
|
|
| 28 |
|
|
/* Utility function to read an Intel HEX8 record from a file */
|
| 29 |
|
|
int Read_IHexRecord(IHexRecord *ihexRecord, FILE *in) {
|
| 30 |
|
|
char recordBuff[IHEX_RECORD_BUFF_SIZE];
|
| 31 |
|
|
/* A temporary buffer to hold ASCII hex encoded data, set to the maximum length we would ever need */
|
| 32 |
|
|
char hexBuff[IHEX_ADDRESS_LEN+1];
|
| 33 |
|
|
int dataCount, i;
|
| 34 |
|
|
|
| 35 |
|
|
/* Check our record pointer and file pointer */
|
| 36 |
|
|
if (ihexRecord == NULL || in == NULL)
|
| 37 |
|
|
return IHEX_ERROR_INVALID_ARGUMENTS;
|
| 38 |
|
|
|
| 39 |
|
|
if (fgets(recordBuff, IHEX_RECORD_BUFF_SIZE, in) == NULL) {
|
| 40 |
|
|
/* In case we hit EOF, don't report a file error */
|
| 41 |
|
|
if (feof(in) != 0)
|
| 42 |
|
|
return IHEX_ERROR_EOF;
|
| 43 |
|
|
else
|
| 44 |
|
|
return IHEX_ERROR_FILE;
|
| 45 |
|
|
}
|
| 46 |
|
|
/* Null-terminate the string at the first sign of a \r or \n */
|
| 47 |
|
|
for (i = 0; i < (int)strlen(recordBuff); i++) {
|
| 48 |
|
|
if (recordBuff[i] == '\r' || recordBuff[i] == '\n') {
|
| 49 |
|
|
recordBuff[i] = 0;
|
| 50 |
|
|
break;
|
| 51 |
|
|
}
|
| 52 |
|
|
}
|
| 53 |
|
|
|
| 54 |
|
|
|
| 55 |
|
|
/* Check if we hit a newline */
|
| 56 |
|
|
if (strlen(recordBuff) == 0)
|
| 57 |
|
|
return IHEX_ERROR_NEWLINE;
|
| 58 |
|
|
|
| 59 |
|
|
/* Size check for start code, count, addess, and type fields */
|
| 60 |
|
|
if (strlen(recordBuff) < (unsigned int)(1+IHEX_COUNT_LEN+IHEX_ADDRESS_LEN+IHEX_TYPE_LEN))
|
| 61 |
|
|
return IHEX_ERROR_INVALID_RECORD;
|
| 62 |
|
|
|
| 63 |
|
|
/* Check the for colon start code */
|
| 64 |
|
|
if (recordBuff[IHEX_START_CODE_OFFSET] != IHEX_START_CODE)
|
| 65 |
|
|
return IHEX_ERROR_INVALID_RECORD;
|
| 66 |
|
|
|
| 67 |
|
|
/* Copy the ASCII hex encoding of the count field into hexBuff, convert it to a usable integer */
|
| 68 |
|
|
strncpy(hexBuff, recordBuff+IHEX_COUNT_OFFSET, IHEX_COUNT_LEN);
|
| 69 |
|
|
hexBuff[IHEX_COUNT_LEN] = 0;
|
| 70 |
|
|
dataCount = strtol(hexBuff, (char **)NULL, 16);
|
| 71 |
|
|
|
| 72 |
|
|
/* Copy the ASCII hex encoding of the address field into hexBuff, convert it to a usable integer */
|
| 73 |
|
|
strncpy(hexBuff, recordBuff+IHEX_ADDRESS_OFFSET, IHEX_ADDRESS_LEN);
|
| 74 |
|
|
hexBuff[IHEX_ADDRESS_LEN] = 0;
|
| 75 |
|
|
ihexRecord->address = strtol(hexBuff, (char **)NULL, 16);
|
| 76 |
|
|
|
| 77 |
|
|
/* Copy the ASCII hex encoding of the address field into hexBuff, convert it to a usable integer */
|
| 78 |
|
|
strncpy(hexBuff, recordBuff+IHEX_TYPE_OFFSET, IHEX_TYPE_LEN);
|
| 79 |
|
|
hexBuff[IHEX_TYPE_LEN] = 0;
|
| 80 |
|
|
ihexRecord->type = strtol(hexBuff, (char **)NULL, 16);
|
| 81 |
|
|
|
| 82 |
|
|
/* Size check for start code, count, address, type, data and checksum fields */
|
| 83 |
|
|
if (strlen(recordBuff) < (unsigned int)(1+IHEX_COUNT_LEN+IHEX_ADDRESS_LEN+IHEX_TYPE_LEN+dataCount*2+IHEX_CHECKSUM_LEN))
|
| 84 |
|
|
return IHEX_ERROR_INVALID_RECORD;
|
| 85 |
|
|
|
| 86 |
|
|
/* Loop through each ASCII hex byte of the data field, pull it out into hexBuff,
|
| 87 |
|
|
* convert it and store the result in the data buffer of the Intel HEX8 record */
|
| 88 |
|
|
for (i = 0; i < dataCount; i++) {
|
| 89 |
|
|
/* Times two i because every byte is represented by two ASCII hex characters */
|
| 90 |
|
|
strncpy(hexBuff, recordBuff+IHEX_DATA_OFFSET+2*i, IHEX_ASCII_HEX_BYTE_LEN);
|
| 91 |
|
|
hexBuff[IHEX_ASCII_HEX_BYTE_LEN] = 0;
|
| 92 |
|
|
ihexRecord->data[i] = strtol(hexBuff, (char **)NULL, 16);
|
| 93 |
|
|
}
|
| 94 |
|
|
ihexRecord->dataLen = dataCount;
|
| 95 |
|
|
|
| 96 |
|
|
/* Copy the ASCII hex encoding of the checksum field into hexBuff, convert it to a usable integer */
|
| 97 |
|
|
strncpy(hexBuff, recordBuff+IHEX_DATA_OFFSET+dataCount*2, IHEX_CHECKSUM_LEN);
|
| 98 |
|
|
hexBuff[IHEX_CHECKSUM_LEN] = 0;
|
| 99 |
|
|
ihexRecord->checksum = strtol(hexBuff, (char **)NULL, 16);
|
| 100 |
|
|
|
| 101 |
|
|
if (ihexRecord->checksum != Checksum_IHexRecord(ihexRecord))
|
| 102 |
|
|
return IHEX_ERROR_INVALID_RECORD;
|
| 103 |
|
|
|
| 104 |
|
|
return IHEX_OK;
|
| 105 |
|
|
}
|
| 106 |
|
|
|
| 107 |
|
|
/* Utility function to write an Intel HEX8 record to a file */
|
| 108 |
|
|
int Write_IHexRecord(const IHexRecord *ihexRecord, FILE *out) {
|
| 109 |
|
|
int i;
|
| 110 |
|
|
|
| 111 |
|
|
/* Check our record pointer and file pointer */
|
| 112 |
|
|
if (ihexRecord == NULL || out == NULL)
|
| 113 |
|
|
return IHEX_ERROR_INVALID_ARGUMENTS;
|
| 114 |
|
|
|
| 115 |
|
|
/* Check that the data length is in range */
|
| 116 |
|
|
if (ihexRecord->dataLen > IHEX_MAX_DATA_LEN/2)
|
| 117 |
|
|
return IHEX_ERROR_INVALID_RECORD;
|
| 118 |
|
|
|
| 119 |
|
|
/* Write the start code, data count, address, and type fields */
|
| 120 |
|
|
if (fprintf(out, "%c%2.2X%2.4X%2.2X", IHEX_START_CODE, ihexRecord->dataLen, ihexRecord->address, ihexRecord->type) < 0)
|
| 121 |
|
|
return IHEX_ERROR_FILE;
|
| 122 |
|
|
|
| 123 |
|
|
/* Write the data bytes */
|
| 124 |
|
|
for (i = 0; i < ihexRecord->dataLen; i++) {
|
| 125 |
|
|
if (fprintf(out, "%2.2X", ihexRecord->data[i]) < 0)
|
| 126 |
|
|
return IHEX_ERROR_FILE;
|
| 127 |
|
|
}
|
| 128 |
|
|
|
| 129 |
|
|
/* Calculate and write the checksum field */
|
| 130 |
|
|
if (fprintf(out, "%2.2X\r\n", Checksum_IHexRecord(ihexRecord)) < 0)
|
| 131 |
|
|
return IHEX_ERROR_FILE;
|
| 132 |
|
|
|
| 133 |
|
|
return IHEX_OK;
|
| 134 |
|
|
}
|
| 135 |
|
|
|
| 136 |
|
|
/* Utility function to print the information stored in an Intel HEX8 record */
|
| 137 |
|
|
void Print_IHexRecord(const IHexRecord *ihexRecord) {
|
| 138 |
|
|
int i;
|
| 139 |
|
|
printf("Intel HEX8 Record Type: \t%d\n", ihexRecord->type);
|
| 140 |
|
|
printf("Intel HEX8 Record Address: \t0x%2.4X\n", ihexRecord->address);
|
| 141 |
|
|
printf("Intel HEX8 Record Data: \t{");
|
| 142 |
|
|
for (i = 0; i < ihexRecord->dataLen; i++) {
|
| 143 |
|
|
if (i+1 < ihexRecord->dataLen)
|
| 144 |
|
|
printf("0x%02X, ", ihexRecord->data[i]);
|
| 145 |
|
|
else
|
| 146 |
|
|
printf("0x%02X", ihexRecord->data[i]);
|
| 147 |
|
|
}
|
| 148 |
|
|
printf("}\n");
|
| 149 |
|
|
printf("Intel HEX8 Record Checksum: \t0x%2.2X\n", ihexRecord->checksum);
|
| 150 |
|
|
}
|
| 151 |
|
|
|
| 152 |
|
|
/* Utility function to calculate the checksum of an Intel HEX8 record */
|
| 153 |
|
|
uint8_t Checksum_IHexRecord(const IHexRecord *ihexRecord) {
|
| 154 |
|
|
uint8_t checksum;
|
| 155 |
|
|
int i;
|
| 156 |
|
|
|
| 157 |
|
|
/* Add the data count, type, address, and data bytes together */
|
| 158 |
|
|
checksum = ihexRecord->dataLen;
|
| 159 |
|
|
checksum += ihexRecord->type;
|
| 160 |
|
|
checksum += (uint8_t)ihexRecord->address;
|
| 161 |
|
|
checksum += (uint8_t)((ihexRecord->address & 0xFF00)>>8);
|
| 162 |
|
|
for (i = 0; i < ihexRecord->dataLen; i++)
|
| 163 |
|
|
checksum += ihexRecord->data[i];
|
| 164 |
|
|
|
| 165 |
|
|
/* Two's complement on checksum */
|
| 166 |
|
|
checksum = ~checksum + 1;
|
| 167 |
|
|
|
| 168 |
|
|
return checksum;
|
| 169 |
|
|
}
|
| 170 |
|
|
|