This repository has been archived by the owner on Mar 11, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathIntelHex.cs
295 lines (260 loc) · 10.9 KB
/
IntelHex.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
/*
* IntelHex.cs
* Utility class to create, read, write, and print Intel HEX8 binary records.
*
* Original Written by Vanya A. Sergeev <vsergeev@gmail.com>
* Version 1.0.5 - February 2011
*
* Modified by Jerry G. Scherer <scherej1@hotmail.com> for C#
* Version 1.0.0 - May 2012
*/
using System;
using System.Text;
using System.IO;
namespace LibGIS.Net
{
/// <summary>
/// IntelHexStructure provides the internal data structure which will be used by the IntelHex class.
/// This class is used for internal processing and is declared public to allow the application that instantiates
/// the IntelHex class access to the internal storage.
/// </summary>
public class IntelHexStructure
{
public UInt16 address; //< The 16-bit address field.
//< The 8-bit array data field, which has a maximum size of 256 bytes.
public byte[] data = new byte[IntelHex.IHEX_MAX_DATA_LEN / 2];
public int dataLen; //< The number of bytes of data stored in this record.
public int type; //< The Intel HEX8 record type of this record.
public byte checksum; //< The checksum of this record.
}
/// <summary>
/// IntelHex is the base class to work with Intel Hex records.
/// This class will contain all necessary functions to process data using the Intel Hex record standard.
/// </summary>
public class IntelHex
{
// 768 should be plenty of space to read in a Intel HEX8 record
const int IHEX_RECORD_BUFF_SIZE = 768;
// Offsets and lengths of various fields in an Intel HEX8 record
const int IHEX_COUNT_OFFSET = 1;
const int IHEX_COUNT_LEN = 2;
const int IHEX_ADDRESS_OFFSET = 3;
const int IHEX_ADDRESS_LEN = 4;
const int IHEX_TYPE_OFFSET = 7;
const int IHEX_TYPE_LEN = 2;
const int IHEX_DATA_OFFSET = 9;
const int IHEX_CHECKSUM_LEN = 2;
public const int IHEX_MAX_DATA_LEN = 512;
// Ascii hex encoded length of a single byte
const int IHEX_ASCII_HEX_BYTE_LEN = 2;
// Start code offset and value
const int IHEX_START_CODE_OFFSET = 0;
const char IHEX_START_CODE = ':';
const int IHEX_OK = 0; //< Error code for success or no error.
const int IHEX_ERROR_FILE = -1; //< Error code for error while reading from or writing to a file. You may check errno for the exact error if this error code is encountered.
const int IHEX_ERROR_EOF = -2; //< Error code for encountering end-of-file when reading from a file.
const int IHEX_ERROR_INVALID_RECORD = -3; //< Error code for error if an invalid record was read.
const int IHEX_ERROR_INVALID_ARGUMENTS = -4; //< Error code for error from invalid arguments passed to function.
const int IHEX_ERROR_NEWLINE = -5; //< Error code for encountering a newline with no record when reading from a file.
const int IHEX_ERROR_INVALID_STRUCTURE = -6; //< Error code for not building a structure prior to calling the function.
const int IHEX_TYPE_00 = 0; //< Data Record
const int IHEX_TYPE_01 = 1; //< End of File Record
const int IHEX_TYPE_02 = 2; //< Extended Segment Address Record
const int IHEX_TYPE_03 = 3; //< Start Segment Address Record
const int IHEX_TYPE_04 = 4; //< Extended Linear Address Record
const int IHEX_TYPE_05 = 5; //< Start Linear Address Record
IntelHexStructure irec = new IntelHexStructure(); // internal structure that holds the record information.
int status = IHEX_ERROR_INVALID_ARGUMENTS; // internal variable that saves the status of the last function call.
// Accessor variable to return status of last function call.
public int Status
{
get { return status; }
}
/// <summary>
/// Initializes a new IntelHex structure that is returned upon successful completion of the function,
/// including up to 16-bit integer address, 8-bit data array, and size of 8-bit data array.
/// </summary>
/// <param name="type">The type of Intel HEX record to be defined by the record.</param>
/// <param name="address">The 16-, 24-, or 32-bit address of the record.</param>
/// <param name="data">An array of 8-bit data bytes.</param>
/// <param name="dataLen">The number of data bytes passed in the array.</param>
/// <returns>IntelHexStructure instance or null, if null then query Status class variable for the error.</returns>
public IntelHexStructure NewRecord(int type, UInt16 address, byte[] data, int dataLen)
{
// Data length size check, assertion of irec pointer
if (dataLen < 0 || dataLen > IHEX_MAX_DATA_LEN / 2 || irec == null)
{
status = IHEX_ERROR_INVALID_ARGUMENTS;
return null;
}
irec.type = type;
irec.address = address;
if(data != null)
Array.Copy(data, irec.data, (long)dataLen);
irec.dataLen = dataLen;
irec.checksum = Checksum();
status = IHEX_OK;
return irec;
}
/// <summary>
/// Utility function to read an Intel HEX8 record from a file
/// </summary>
/// <param name="inStream">An instance of the StreamReader class to allow reading the file data.</param>
/// <returns>IntelHexStructure instance or null, if null then query Status class variable for the error.</returns>
public IntelHexStructure Read(StreamReader inStream)
{
String recordBuff;
int dataCount, i;
// Check our record pointer and file pointer
if (irec == null || inStream == null)
{
status = IHEX_ERROR_INVALID_ARGUMENTS;
return null;
}
try
{
// Read Line will return a line from the file.
recordBuff = inStream.ReadLine();
}
catch (Exception)
{
status = IHEX_ERROR_FILE;
return null;
}
// Check if we hit a newline
if (recordBuff == null || recordBuff.Length == 0)
{
status = IHEX_ERROR_NEWLINE;
return null;
}
// Size check for start code, count, address, and type fields
if (recordBuff.Length < (1 + IHEX_COUNT_LEN + IHEX_ADDRESS_LEN + IHEX_TYPE_LEN))
{
status = IHEX_ERROR_INVALID_RECORD;
return null;
}
// Check the for colon start code
if (recordBuff[IHEX_START_CODE_OFFSET] != IHEX_START_CODE)
{
status = IHEX_ERROR_INVALID_RECORD;
return null;
}
// Copy the ASCII hex encoding of the count field into hexBuff, convert it to a usable integer
dataCount = Convert.ToInt16(recordBuff.Substring(IHEX_COUNT_OFFSET, IHEX_COUNT_LEN), 16);
// Copy the ASCII hex encoding of the address field into hexBuff, convert it to a usable integer
irec.address = Convert.ToUInt16(recordBuff.Substring(IHEX_ADDRESS_OFFSET, IHEX_ADDRESS_LEN), 16);
// Copy the ASCII hex encoding of the address field into hexBuff, convert it to a usable integer
irec.type = Convert.ToInt16(recordBuff.Substring(IHEX_TYPE_OFFSET, IHEX_TYPE_LEN), 16);
// Size check for start code, count, address, type, data and checksum fields
if (recordBuff.Length < (1 + IHEX_COUNT_LEN + IHEX_ADDRESS_LEN + IHEX_TYPE_LEN + dataCount * 2 + IHEX_CHECKSUM_LEN))
{
status = IHEX_ERROR_INVALID_RECORD;
return null;
}
// Loop through each ASCII hex byte of the data field, pull it out into hexBuff,
// convert it and store the result in the data buffer of the Intel HEX8 record
for (i = 0; i < dataCount; i++)
{
// Times two i because every byte is represented by two ASCII hex characters
irec.data[i] = Convert.ToByte(recordBuff.Substring(IHEX_DATA_OFFSET+2*i, IHEX_ASCII_HEX_BYTE_LEN), 16);
}
irec.dataLen = dataCount;
// Copy the ASCII hex encoding of the checksum field into hexBuff, convert it to a usable integer
irec.checksum = Convert.ToByte(recordBuff.Substring(IHEX_DATA_OFFSET+dataCount*2, IHEX_CHECKSUM_LEN), 16);
if (irec.checksum != Checksum())
{
status = IHEX_ERROR_INVALID_RECORD;
return null;
}
status = IHEX_OK;
return irec;
}
// Utility function to write an Intel HEX8 record to a file
public IntelHexStructure Write(StreamWriter outStream)
{
int i;
// Check our record pointer and file pointer
if (irec == null || outStream == null)
{
status = IHEX_ERROR_INVALID_ARGUMENTS;
return null;
}
// Check that the data length is in range
if (irec.dataLen > IHEX_MAX_DATA_LEN / 2)
{
status = IHEX_ERROR_INVALID_RECORD;
return null;
}
try
{
// Write the start code, data count, address, and type fields
outStream.Write(String.Format("{0}{1:X2}{2:X4}{3:X2}", IHEX_START_CODE, irec.dataLen, irec.address, irec.type));
// Write the data bytes
for (i = 0; i < irec.dataLen; i++)
outStream.Write(String.Format("{0:X2}", irec.data[i]));
// Last but not least, the checksum
outStream.WriteLine(String.Format("{0:X2}", Checksum()));
}
catch(Exception)
{
status = IHEX_ERROR_FILE;
return null;
}
status = IHEX_OK;
return irec;
}
/// <summary>
/// Utility function to print the information stored in an Intel HEX8 record
/// </summary>
/// <param name="verbose">A boolean set to false by default, if set to true will provide extended information.</param>
/// <returns>String which provides the output of the function, this does not write directly to the console.</returns>
public String Print(bool verbose = false)
{
int i;
String returnString;
if (verbose)
{
returnString = String.Format("Intel HEX8 Record Type: \t{0}\n", irec.type);
returnString += String.Format("Intel HEX8 Record Address: \t0x{0:X4}\n", irec.address);
returnString += String.Format("Intel HEX8 Record Data: \t[");
for (i = 0; i < irec.dataLen; i++)
{
if (i + 1 < irec.dataLen)
returnString += String.Format("0x{0:X02}, ", irec.data[i]);
else
returnString += String.Format("0x{0:X02}", irec.data[i]);
}
returnString += String.Format("]\n");
returnString += String.Format("Intel HEX8 Record Checksum: \t0x{0:X2}\n", irec.checksum);
}
else
{
returnString = String.Format("{0}{1:X2}{2:X4}{3:X2}", IHEX_START_CODE, irec.dataLen, irec.address, irec.type);
for (i = 0; i < irec.dataLen; i++)
returnString += String.Format("{0:X2}", irec.data[i]);
returnString += String.Format("{0:X2}", Checksum());
}
status = IHEX_OK;
return (returnString);
}
/// <summary>
/// An internal utility function to calculate the checksum of an Intel HEX8 record
/// </summary>
/// <returns>byte which is the checksum of IntelHexStructure.</returns>
internal byte Checksum()
{
byte checksum;
int i;
// Add the data count, type, address, and data bytes together
checksum = (byte)irec.dataLen;
checksum += (byte)irec.type;
checksum += (byte)irec.address;
checksum += (byte)((irec.address & 0xFF00)>>8);
for (i = 0; i < irec.dataLen; i++)
checksum += irec.data[i];
// Two's complement on checksum
checksum =(byte)(~checksum + 1);
return checksum;
}
}
}