Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
intelhex.c
00001 /** 00002 * @file intelhex.c 00003 * @brief Implementation of intelhex.h 00004 * 00005 * DAPLink Interface Firmware 00006 * Copyright (c) 2009-2016, ARM Limited, All Rights Reserved 00007 * SPDX-License-Identifier: Apache-2.0 00008 * 00009 * Licensed under the Apache License, Version 2.0 (the "License"); you may 00010 * not use this file except in compliance with the License. 00011 * You may obtain a copy of the License at 00012 * 00013 * http://www.apache.org/licenses/LICENSE-2.0 00014 * 00015 * Unless required by applicable law or agreed to in writing, software 00016 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 00017 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00018 * See the License for the specific language governing permissions and 00019 * limitations under the License. 00020 */ 00021 00022 #include <string.h> 00023 00024 #include "intelhex.h" 00025 00026 typedef enum hex_record_t hex_record_t; 00027 enum hex_record_t { 00028 DATA_RECORD = 0, 00029 EOF_RECORD = 1, 00030 EXT_SEG_ADDR_RECORD = 2, 00031 START_SEG_ADDR_RECORD = 3, 00032 EXT_LINEAR_ADDR_RECORD = 4, 00033 START_LINEAR_ADDR_RECORD = 5 00034 }; 00035 00036 typedef union hex_line_t hex_line_t; 00037 union __attribute__((packed)) hex_line_t { 00038 uint8_t buf[0x25]; 00039 struct __attribute__((packed)) { 00040 uint8_t byte_count; 00041 uint16_t address; 00042 uint8_t record_type; 00043 uint8_t data[0x25 - 0x5]; 00044 uint8_t checksum; 00045 }; 00046 }; 00047 00048 /** Swap 16bit value - let compiler figure out the best way 00049 * @param val a variable of size uint16_t to be swapped 00050 * @return the swapped value 00051 */ 00052 static uint16_t swap16(uint16_t a) 00053 { 00054 return ((a & 0x00ff) << 8) | ((a & 0xff00) >> 8); 00055 } 00056 00057 /** Converts a character representation of a hex to real value. 00058 * @param c is the hex value in char format 00059 * @return the value of the hex 00060 */ 00061 static uint8_t ctoh(char c) 00062 { 00063 return (c & 0x10) ? /*0-9*/ c & 0xf : /*A-F, a-f*/ (c & 0xf) + 9; 00064 } 00065 00066 /** Calculate checksum on a hex record 00067 * @param data is the line of hex record 00068 * @param size is the length of the data array 00069 * @return 1 if the data provided is a valid hex record otherwise 0 00070 */ 00071 static uint8_t validate_checksum(hex_line_t *record) 00072 { 00073 uint8_t result = 0, i = 0; 00074 00075 for (; i < (record->byte_count + 5); i++) { 00076 result += record->buf[i]; 00077 } 00078 00079 return (result == 0); 00080 } 00081 00082 static hex_line_t line = {0}, shadow_line = {0}; 00083 static uint32_t next_address_to_write = 0; 00084 static uint8_t low_nibble = 0, idx = 0, record_processed = 0, load_unaligned_record = 0; 00085 00086 void reset_hex_parser(void) 00087 { 00088 memset(line.buf, 0, sizeof(hex_line_t)); 00089 memset(shadow_line.buf, 0, sizeof(hex_line_t)); 00090 next_address_to_write = 0; 00091 low_nibble = 0; 00092 idx = 0; 00093 record_processed = 0; 00094 load_unaligned_record = 0; 00095 } 00096 00097 hexfile_parse_status_t parse_hex_blob(const uint8_t *hex_blob, const uint32_t hex_blob_size, uint32_t *hex_parse_cnt, uint8_t *bin_buf, const uint32_t bin_buf_size, uint32_t *bin_buf_address, uint32_t *bin_buf_cnt) 00098 { 00099 uint8_t *end = (uint8_t *)hex_blob + hex_blob_size; 00100 hexfile_parse_status_t status = HEX_PARSE_UNINIT ; 00101 // reset the amount of data that is being return'd 00102 *bin_buf_cnt = (uint32_t)0; 00103 00104 // we had an exit state where the address was unaligned to the previous record and data count. 00105 // Need to pop the last record into the buffer before decoding anthing else since it was 00106 // already decoded. 00107 if (load_unaligned_record) { 00108 // need some help... 00109 load_unaligned_record = 0; 00110 // move from line buffer back to input buffer 00111 memcpy((uint8_t *)bin_buf, (uint8_t *)line.data, line.byte_count); 00112 bin_buf += line.byte_count; 00113 *bin_buf_cnt = (uint32_t)(*bin_buf_cnt) + line.byte_count; 00114 // Store next address to write 00115 next_address_to_write = ((next_address_to_write & 0xffff0000) | line.address) + line.byte_count; 00116 } 00117 00118 while (hex_blob != end) { 00119 switch ((uint8_t)(*hex_blob)) { 00120 // we've hit the end of an ascii line 00121 // junk we dont care about could also just run the validate_checksum on &line 00122 case '\r': 00123 case '\n': 00124 //ignore new lines 00125 break; 00126 00127 // found start of a new record. reset state variables 00128 case ':': 00129 memset(line.buf, 0, sizeof(hex_line_t)); 00130 low_nibble = 0; 00131 idx = 0; 00132 record_processed = 0; 00133 break; 00134 00135 // decoding lines 00136 default: 00137 if (low_nibble) { 00138 line.buf[idx] |= ctoh((uint8_t)(*hex_blob)) & 0xf; 00139 if (++idx >= (line.byte_count + 5)) { //all data in 00140 if (0 == validate_checksum(&line)) { 00141 status = HEX_PARSE_CKSUM_FAIL ; 00142 goto hex_parser_exit; 00143 } else { 00144 if (!record_processed) { 00145 record_processed = 1; 00146 // address byteswap... 00147 line.address = swap16(line.address); 00148 00149 switch (line.record_type) { 00150 case DATA_RECORD: 00151 // keeping a record of the last hex record 00152 memcpy(shadow_line.buf, line.buf, sizeof(hex_line_t)); 00153 00154 // verify this is a continous block of memory or need to exit and dump 00155 if (((next_address_to_write & 0xffff0000) | line.address) != next_address_to_write) { 00156 load_unaligned_record = 1; 00157 status = HEX_PARSE_UNALIGNED ; 00158 goto hex_parser_exit; 00159 } 00160 00161 // move from line buffer back to input buffer 00162 memcpy(bin_buf, line.data, line.byte_count); 00163 bin_buf += line.byte_count; 00164 *bin_buf_cnt = (uint32_t)(*bin_buf_cnt) + line.byte_count; 00165 // Save next address to write 00166 next_address_to_write = ((next_address_to_write & 0xffff0000) | line.address) + line.byte_count; 00167 break; 00168 00169 case EOF_RECORD: 00170 status = HEX_PARSE_EOF ; 00171 goto hex_parser_exit; 00172 00173 case EXT_SEG_ADDR_RECORD: 00174 // Could have had data in the buffer so must exit and try to program 00175 // before updating bin_buf_address with next_address_to_write 00176 memset(bin_buf, 0xff, (bin_buf_size - (uint32_t)(*bin_buf_cnt))); 00177 // figure the start address for the buffer before returning 00178 *bin_buf_address = next_address_to_write - (uint32_t)(*bin_buf_cnt); 00179 *hex_parse_cnt = (uint32_t)(hex_blob_size - (end - hex_blob)); 00180 // update the address msb's 00181 next_address_to_write = (next_address_to_write & 0x00000000) | ((line.data[0] << 12) | (line.data[1] << 4)); 00182 // Need to exit and program if buffer has been filled 00183 status = HEX_PARSE_UNALIGNED ; 00184 return status; 00185 00186 case EXT_LINEAR_ADDR_RECORD: 00187 // Could have had data in the buffer so must exit and try to program 00188 // before updating bin_buf_address with next_address_to_write 00189 // Good catch Gaute!! 00190 memset(bin_buf, 0xff, (bin_buf_size - (uint32_t)(*bin_buf_cnt))); 00191 // figure the start address for the buffer before returning 00192 *bin_buf_address = next_address_to_write - (uint32_t)(*bin_buf_cnt); 00193 *hex_parse_cnt = (uint32_t)(hex_blob_size - (end - hex_blob)); 00194 // update the address msb's 00195 next_address_to_write = (next_address_to_write & 0x00000000) | ((line.data[0] << 24) | (line.data[1] << 16)); 00196 // Need to exit and program if buffer has been filled 00197 status = HEX_PARSE_UNALIGNED ; 00198 return status; 00199 00200 default: 00201 break; 00202 } 00203 } 00204 } 00205 } 00206 } else { 00207 if (idx < sizeof(hex_line_t)) { 00208 line.buf[idx] = ctoh((uint8_t)(*hex_blob)) << 4; 00209 } 00210 } 00211 00212 low_nibble = !low_nibble; 00213 break; 00214 } 00215 00216 hex_blob++; 00217 } 00218 00219 // decoded an entire hex block - verify (cant do this hex_parse_cnt is figured below) 00220 //status = (hex_blob_size == (uint32_t)(*hex_parse_cnt)) ? HEX_PARSE_OK : HEX_PARSE_FAILURE; 00221 status = HEX_PARSE_OK ; 00222 hex_parser_exit: 00223 memset(bin_buf, 0xff, (bin_buf_size - (uint32_t)(*bin_buf_cnt))); 00224 // figure the start address for the buffer before returning 00225 *bin_buf_address = next_address_to_write - (uint32_t)(*bin_buf_cnt); 00226 *hex_parse_cnt = (uint32_t)(hex_blob_size - (end - hex_blob)); 00227 return status; 00228 }
Generated on Tue Jul 12 2022 15:37:19 by
