├── .gitignore ├── Hex2Bin.csproj ├── Hex2Bin.sln ├── Program.cs ├── Properties └── AssemblyInfo.cs ├── README.md └── bin └── Debug └── Hex2Bin.exe /.gitignore: -------------------------------------------------------------------------------- 1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs) 2 | [Oo]bj/ 3 | 4 | # mstest test results 5 | TestResults 6 | 7 | ## Ignore Visual Studio temporary files, build results, and 8 | ## files generated by popular Visual Studio add-ons. 9 | 10 | # User-specific files 11 | *.suo 12 | *.user 13 | *.sln.docstates 14 | 15 | # Build results 16 | [Rr]elease/ 17 | x64/ 18 | *_i.c 19 | *_p.c 20 | *.ilk 21 | *.meta 22 | *.obj 23 | *.pch 24 | *.pdb 25 | *.pgc 26 | *.pgd 27 | *.rsp 28 | *.sbr 29 | *.tlb 30 | *.tli 31 | *.tlh 32 | *.tmp 33 | *.log 34 | *.vspscc 35 | *.vssscc 36 | .builds 37 | 38 | # Visual C++ cache files 39 | ipch/ 40 | *.aps 41 | *.ncb 42 | *.opensdf 43 | *.sdf 44 | 45 | # Visual Studio profiler 46 | *.psess 47 | *.vsp 48 | *.vspx 49 | 50 | # Guidance Automation Toolkit 51 | *.gpState 52 | 53 | # ReSharper is a .NET coding add-in 54 | _ReSharper* 55 | 56 | # NCrunch 57 | *.ncrunch* 58 | .*crunch*.local.xml 59 | 60 | # Installshield output folder 61 | [Ee]xpress 62 | 63 | # DocProject is a documentation generator add-in 64 | DocProject/buildhelp/ 65 | DocProject/Help/*.HxT 66 | DocProject/Help/*.HxC 67 | DocProject/Help/*.hhc 68 | DocProject/Help/*.hhk 69 | DocProject/Help/*.hhp 70 | DocProject/Help/Html2 71 | DocProject/Help/html 72 | 73 | # Click-Once directory 74 | publish 75 | 76 | # Publish Web Output 77 | *.Publish.xml 78 | 79 | # NuGet Packages Directory 80 | packages 81 | 82 | # Windows Azure Build Output 83 | csx 84 | *.build.csdef 85 | 86 | # Windows Store app package directory 87 | AppPackages/ 88 | 89 | # Others 90 | [Oo]bj 91 | sql 92 | TestResults 93 | [Tt]est[Rr]esult* 94 | *.Cache 95 | ClientBin 96 | [Ss]tyle[Cc]op.* 97 | ~$* 98 | *.dbmdl 99 | Generated_Code #added for RIA/Silverlight projects 100 | 101 | # Backup & report files from converting an old project file to a newer 102 | # Visual Studio version. Backup files are not needed, because we have git ;-) 103 | _UpgradeReport_Files/ 104 | Backup*/ 105 | UpgradeLog*.XML 106 | -------------------------------------------------------------------------------- /Hex2Bin.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 9.0.30729 7 | 2.0 8 | {F2742C17-3333-4DD3-9DD7-0EE274B03728} 9 | Exe 10 | Properties 11 | Hex2Bin 12 | hex2bin 13 | v2.0 14 | 512 15 | 16 | 17 | 3.5 18 | 19 | publish\ 20 | true 21 | Disk 22 | false 23 | Foreground 24 | 7 25 | Days 26 | false 27 | false 28 | true 29 | 0 30 | 1.0.0.%2a 31 | false 32 | false 33 | true 34 | 35 | 36 | true 37 | full 38 | false 39 | bin\Debug\ 40 | DEBUG;TRACE 41 | prompt 42 | 4 43 | AllRules.ruleset 44 | false 45 | x86 46 | 47 | 48 | pdbonly 49 | true 50 | bin\Release\ 51 | TRACE 52 | prompt 53 | 4 54 | AllRules.ruleset 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | False 66 | .NET Framework 3.5 SP1 Client Profile 67 | false 68 | 69 | 70 | False 71 | .NET Framework 3.5 SP1 72 | true 73 | 74 | 75 | False 76 | Windows Installer 3.1 77 | true 78 | 79 | 80 | 81 | 88 | -------------------------------------------------------------------------------- /Hex2Bin.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hex2Bin", "Hex2Bin.csproj", "{F2742C17-3333-4DD3-9DD7-0EE274B03728}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Release|Any CPU = Release|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {F2742C17-3333-4DD3-9DD7-0EE274B03728}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {F2742C17-3333-4DD3-9DD7-0EE274B03728}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {F2742C17-3333-4DD3-9DD7-0EE274B03728}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {F2742C17-3333-4DD3-9DD7-0EE274B03728}.Release|Any CPU.Build.0 = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.IO; 5 | using System.Globalization; 6 | 7 | namespace Hex2Bin 8 | { 9 | enum FileFormat 10 | { 11 | Auto, 12 | Bin, 13 | Hex, 14 | Jam 15 | } 16 | 17 | class Program 18 | { 19 | static byte[] Memory = null; 20 | 21 | static uint MemoryLow = uint.MaxValue; 22 | static uint MemoryHigh = uint.MinValue; 23 | 24 | static uint AddressMax = 0; 25 | static uint AddressMin = uint.MaxValue; 26 | 27 | static uint BaseAddress = 0; 28 | static bool BaseAddressDefine = false; 29 | 30 | static uint MemoryStart = 0; 31 | static bool IsMemoryStart = false; 32 | 33 | static uint MemoryEnd = 0; 34 | static bool IsMemoryEnd = false; 35 | 36 | static uint MemoryLength = 0; 37 | static bool IsMemoryLength = false; 38 | 39 | static bool ScanOnly = false; 40 | static bool MakeCode = false; 41 | static bool ExtractCode = false; 42 | static byte EmptyValue = 0xFF; 43 | 44 | const uint BLOCK_SIZE = 1024; 45 | 46 | static void usageHelp() 47 | { 48 | Console.Write(@" 49 | Hex2Bin [options] in-file.hex|bin|s|jam [out-file] 50 | -h[elp] display this text 51 | -b[ase]=address set base address (0x... for hex) 52 | -ml=length set memory length (0x... for hex) 53 | -ms=address set memory start address (0x... for hex) 54 | -me=address set memory end address (0x... for hex) 55 | -s[can] scan file for min/max addresses 56 | -c[ode] convert to C text 57 | -f[ill]=value fill value for empty memory 58 | -ex[tract] extract from base (-b) to end (-e) or length (-l) 59 | -mcu=PIC24FJ256 allocate memory ones (256K) 60 | -mcu=PIC24FJ128 allocate memory ones (128K) 61 | -bin force input format to BINARY format 62 | -hex force input format to HEX format 63 | -jam force input format to JAM format 64 | Process .jam (Microchip format) file and make one image file 65 | .hex Intel hex format file 66 | .s Motorola format file 67 | .bin binary file 68 | " 69 | ); 70 | } 71 | 72 | static void Main(string[] args) 73 | { 74 | string fileIn = null; 75 | string fileOut = null; 76 | int exitCode = 0; 77 | FileFormat input_type = FileFormat.Auto; 78 | if (args.Length == 0) 79 | { 80 | usageHelp(); 81 | Environment.Exit(1); 82 | } 83 | 84 | #region Options 85 | foreach (string arg in args) 86 | { 87 | if (arg.StartsWith("-", StringComparison.InvariantCulture) || 88 | arg.StartsWith("/", StringComparison.InvariantCulture) 89 | ) 90 | { 91 | #region Process options 92 | 93 | string[] option = arg.Substring(1).Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries); 94 | string value = string.Empty; 95 | if (option.Length == 2) 96 | value = option[1].Trim(); 97 | 98 | switch (option[0].ToLowerInvariant()) 99 | { 100 | case "hex": 101 | input_type = FileFormat.Hex; 102 | break; 103 | case "bin": 104 | input_type = FileFormat.Bin; 105 | break; 106 | case "jam": 107 | input_type = FileFormat.Jam; 108 | break; 109 | case "mcu": 110 | #region Set PIC type 111 | switch (value.ToUpperInvariant()) 112 | { 113 | case "PIC24FJ256": 114 | Memory = new byte[256 * 1024]; 115 | break; 116 | case "PIC24FJ128": 117 | Memory = new byte[128 * 1024]; 118 | break; 119 | default: 120 | Console.WriteLine(string.Format("Unknown -mcu {0}", value)); 121 | exitCode = 1; 122 | break; 123 | } 124 | break; 125 | #endregion 126 | case "b": 127 | case "base": 128 | #region Set base address 129 | if (!string.IsNullOrEmpty(value)) 130 | { 131 | if (IsMemoryEnd) 132 | { 133 | Console.WriteLine("Can set Base Address only ones."); 134 | } 135 | else if (value.StartsWith("0x", StringComparison.InvariantCultureIgnoreCase)) 136 | { // Hex format 0x.... 137 | if ((BaseAddressDefine = uint.TryParse(value.Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out BaseAddress))) 138 | break; 139 | } 140 | else 141 | { 142 | if ((BaseAddressDefine = uint.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out BaseAddress))) 143 | break; 144 | } 145 | } 146 | exitCode = 1; 147 | break; 148 | #endregion 149 | case "ms": 150 | #region Set start address 151 | if (!string.IsNullOrEmpty(value)) 152 | { 153 | if (IsMemoryStart) 154 | { 155 | Console.WriteLine("Can set Start Address only ones."); 156 | } 157 | else if (value.StartsWith("0x", StringComparison.InvariantCultureIgnoreCase)) 158 | { // Hex format 0x.... 159 | if ((IsMemoryStart = uint.TryParse(value.Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out MemoryStart))) 160 | break; 161 | } 162 | else 163 | { 164 | if ((IsMemoryStart = uint.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out MemoryStart))) 165 | break; 166 | } 167 | } 168 | exitCode = 1; 169 | break; 170 | #endregion 171 | case "me": 172 | #region Set end address 173 | if (!string.IsNullOrEmpty(value)) 174 | { 175 | if (IsMemoryLength) 176 | { 177 | Console.WriteLine("Can't set both End Address and Length"); 178 | } 179 | else if (IsMemoryEnd) 180 | { 181 | Console.WriteLine("Can set End Address only ones."); 182 | } 183 | else if (value.StartsWith("0x", StringComparison.InvariantCultureIgnoreCase)) 184 | { // Hex format 0x.... 185 | if ((IsMemoryEnd = uint.TryParse(value.Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out MemoryEnd))) 186 | break; 187 | } 188 | else 189 | { 190 | if ((IsMemoryEnd = uint.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out MemoryEnd))) 191 | break; 192 | } 193 | } 194 | exitCode = 1; 195 | break; 196 | #endregion 197 | case "ml": 198 | #region Set length 199 | if (!string.IsNullOrEmpty(value)) 200 | { 201 | if (IsMemoryEnd) 202 | { 203 | Console.WriteLine("Can't set both End Address and Length"); 204 | } 205 | else if (IsMemoryLength) 206 | { 207 | Console.WriteLine("Can set Length only ones."); 208 | } 209 | else if (value.StartsWith("0x", StringComparison.InvariantCultureIgnoreCase)) 210 | { // Hex format 0x.... 211 | if ((IsMemoryLength = uint.TryParse(value.Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out MemoryLength))) 212 | break; 213 | } 214 | else 215 | { 216 | if ((IsMemoryLength = uint.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out MemoryLength))) 217 | break; 218 | } 219 | } 220 | exitCode = 1; 221 | break; 222 | #endregion 223 | case "f": 224 | case "fill": 225 | #region Set empty memory value 226 | if (!string.IsNullOrEmpty(value)) 227 | { 228 | if (value.StartsWith("0x", StringComparison.InvariantCultureIgnoreCase)) 229 | { // Hex format 0x 230 | if (byte.TryParse(value.Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out EmptyValue)) 231 | break; 232 | } 233 | else 234 | { // Decimal format 235 | if (byte.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out EmptyValue)) 236 | break; 237 | } 238 | } 239 | exitCode = 1; 240 | break; 241 | #endregion 242 | case "s": 243 | case "scan": 244 | ScanOnly = true; 245 | break; 246 | case "c": 247 | case "code": 248 | MakeCode = true; 249 | break; 250 | case "ex": 251 | case "extract": 252 | ExtractCode = true; 253 | break; 254 | default: 255 | #region Unknown option 256 | Console.WriteLine(string.Format("Unknown option {0}", arg)); 257 | exitCode = 1; 258 | break; 259 | #endregion 260 | } 261 | #endregion 262 | } 263 | else if (fileIn == null) 264 | fileIn = arg; // First paramter as input file 265 | else if (fileOut == null) 266 | fileOut = arg; // Second paramter as output file 267 | else 268 | { 269 | Console.WriteLine("Too many files define."); 270 | exitCode = 1; 271 | } 272 | if (exitCode != 0) 273 | Environment.Exit(exitCode); 274 | } 275 | #endregion 276 | 277 | if (string.IsNullOrEmpty(fileIn)) 278 | { 279 | Console.WriteLine("No input file."); 280 | Environment.Exit(1); 281 | } 282 | 283 | if (!File.Exists(fileIn)) 284 | { 285 | Console.WriteLine(string.Format("Input file {0} not found.", fileIn)); 286 | Environment.Exit(1); 287 | } 288 | 289 | #region Load file 290 | string ext = Path.GetExtension(fileIn).ToLowerInvariant(); 291 | if (input_type == FileFormat.Auto) 292 | { 293 | switch (ext) 294 | { 295 | case ".bin": 296 | input_type = FileFormat.Bin; 297 | break; 298 | case ".hex": 299 | input_type = FileFormat.Hex; 300 | break; 301 | case ".jam": 302 | input_type = FileFormat.Jam; 303 | break; 304 | default: 305 | Console.WriteLine("Unknown extension {0}", ext); 306 | Environment.Exit(1); 307 | break; 308 | } 309 | } 310 | 311 | switch (input_type) 312 | { 313 | case FileFormat.Jam: 314 | input_type = FileFormat.Hex; 315 | #region Process Microchip JAM file 316 | // Each line is HEX file name 317 | using (TextReader s = new StreamReader(fileIn)) 318 | { 319 | string filename; 320 | while ((filename = s.ReadLine()) != null) 321 | { 322 | filename = filename.Trim(); 323 | if (filename.Length == 0) 324 | continue; 325 | Console.WriteLine(string.Format("Process file:{0}", filename)); 326 | exitCode = loadHex(filename); 327 | if (exitCode != 0) 328 | break; 329 | } 330 | } 331 | break; 332 | #endregion 333 | case FileFormat.Hex: 334 | exitCode = loadHex(fileIn); 335 | break; 336 | case FileFormat.Bin: 337 | exitCode = loadBin(fileIn); 338 | break; 339 | } 340 | 341 | if ((exitCode == 0) && (Memory == null || Memory.Length == 0)) 342 | { 343 | Console.WriteLine("Empty input data."); 344 | exitCode = 1; 345 | } 346 | 347 | if (exitCode != 0) 348 | Environment.Exit(exitCode); 349 | #endregion 350 | 351 | Console.WriteLine("Memory Address range: 0x{0:X}-0x{1:X}", AddressMin, AddressMax); 352 | 353 | #region Check Addresses 354 | if (!IsMemoryStart) 355 | MemoryStart = AddressMin; 356 | if (IsMemoryLength) 357 | MemoryEnd = MemoryStart + MemoryLength - 1; 358 | else if (!IsMemoryEnd) 359 | MemoryEnd = AddressMax; 360 | 361 | if (AddressMin != 0 && MemoryStart < AddressMin) 362 | { 363 | Console.WriteLine("Start Address must be great or equal Memory Min. Address"); 364 | Environment.Exit(1); 365 | } 366 | if (MemoryEnd < MemoryStart) 367 | { 368 | Console.WriteLine("End Address must be great or equal Start Address"); 369 | Environment.Exit(1); 370 | } 371 | else if (MemoryEnd > AddressMax) 372 | { 373 | Console.WriteLine("End Address must be less than Memory Max. Address"); 374 | Environment.Exit(1); 375 | } 376 | #endregion 377 | 378 | #region Save internal memory to binary file 379 | 380 | if (MakeCode) 381 | { 382 | #region MakeCode 383 | 384 | if (fileOut == null) 385 | fileOut = string.Concat(Path.GetFileNameWithoutExtension(fileIn), ".c"); 386 | 387 | using (FileStream fs = new FileStream(fileOut, File.Exists(fileOut) ? FileMode.Truncate : FileMode.Create, FileAccess.Write)) 388 | { 389 | using (StreamWriter sw = new StreamWriter(fs, Encoding.Default)) 390 | { 391 | int row_count = 0; 392 | int length = (int)(MemoryEnd - MemoryStart + 1); 393 | sw.Write(string.Format(@" 394 | #include 395 | 396 | /* 397 | * File: {0} 398 | * Address range: 0x{1:X}-0x{2:X} 399 | */ 400 | const PROGMEM uint8_t {3}[{4}] 401 | // __attribute__((used)) 402 | // __attribute__((section("".flash_0x{1:X}""))) 403 | = {{", 404 | fileIn, 405 | BaseAddress, MemoryEnd, 406 | Path.GetFileNameWithoutExtension(fileIn).Replace("-", "_"), 407 | length 408 | ) 409 | ); 410 | 411 | int address = (int)(MemoryStart - AddressMin); 412 | while (length != 0) 413 | { 414 | length--; 415 | if (row_count == 0) 416 | { 417 | if (length != 0) 418 | sw.Write(","); 419 | sw.Write("\r\n\t"); 420 | row_count = 16; 421 | } 422 | else 423 | { 424 | sw.Write(", "); 425 | } 426 | --row_count; 427 | 428 | sw.Write(string.Format("0x{0:X2}", Memory[address++])); 429 | } 430 | sw.Write(@" 431 | }; 432 | "); 433 | sw.Close(); 434 | } 435 | } 436 | #endregion 437 | } 438 | else if (ExtractCode) 439 | { 440 | #region Extract 441 | if (fileOut == null) 442 | { 443 | Console.WriteLine("Must define output file name"); 444 | Environment.Exit(1); 445 | } 446 | exitCode = writeToBin(fileOut); 447 | #endregion 448 | } 449 | else if (!ScanOnly) 450 | { 451 | switch (input_type) 452 | { 453 | case FileFormat.Bin: 454 | if (fileOut == null) 455 | fileOut = string.Concat(Path.GetFileNameWithoutExtension(fileIn), ".hex"); 456 | exitCode = writeToHex(fileOut); 457 | break; 458 | case FileFormat.Hex: 459 | if (fileOut == null) 460 | fileOut = string.Concat(Path.GetFileNameWithoutExtension(fileIn), ".bin"); 461 | exitCode = writeToBin(fileOut); 462 | break; 463 | default: 464 | break; 465 | } 466 | } 467 | #endregion 468 | Environment.Exit(exitCode); 469 | } 470 | 471 | private static int writeToBin(string fileOut) 472 | { 473 | int exitcode = 0; 474 | try 475 | { 476 | using (Stream s = File.Open(fileOut, File.Exists(fileOut) ? FileMode.Truncate : FileMode.Create, FileAccess.Write)) 477 | { 478 | s.Write(Memory, (int)(MemoryStart - AddressMin), (int)(MemoryEnd - MemoryStart + 1)); 479 | s.Close(); 480 | } 481 | } 482 | catch(Exception ex) 483 | { 484 | Console.WriteLine(ex.Message); 485 | exitcode = -1; 486 | } 487 | return exitcode; 488 | } 489 | 490 | #region loadBin(string fileIn) 491 | /// 492 | /// Convert binary file to hex format 493 | /// 494 | /// 495 | /// 496 | private static int loadBin(string fileIn) 497 | { 498 | int exitCode = 0; 499 | 500 | try 501 | { 502 | using (FileStream fs = new FileStream(fileIn, FileMode.Open)) 503 | { 504 | using (BinaryReader b = new BinaryReader(fs)) 505 | { 506 | Memory = new byte[fs.Length]; 507 | b.Read(Memory, 0, (int)fs.Length); 508 | b.Close(); 509 | } 510 | fs.Close(); 511 | } 512 | if (Memory != null && Memory.Length > 0) 513 | { 514 | AddressMin = 0; 515 | AddressMax = (uint)Memory.Length - 1; 516 | } 517 | } 518 | catch (Exception ex) 519 | { 520 | Console.WriteLine(ex.Message); 521 | exitCode = 1; 522 | } 523 | return exitCode; 524 | } 525 | #endregion 526 | 527 | #region writeToHex(string fileOut) 528 | private static int writeToHex(string fileOut) 529 | { 530 | uint out_address = BaseAddress; 531 | uint hex_address = 0; 532 | int exitCode = 0; 533 | 534 | try 535 | { 536 | // Convert to HEX file 537 | uint byte_index = MemoryStart; 538 | StringBuilder sb = new StringBuilder(50); 539 | uint cs; 540 | 541 | using (FileStream fs = new FileStream(fileOut, FileMode.Create, FileAccess.Write)) 542 | { 543 | using (TextWriter w = new StreamWriter(fs)) 544 | { 545 | while (byte_index <= MemoryEnd) 546 | { 547 | sb.Remove(0, sb.Length); 548 | if (hex_address != (out_address & 0xFFFF0000)) 549 | { 550 | cs = 2 + (uint)INTEL_COMMAND.EXTEND_ADDR + ((out_address >> 16) & 0xFF) + ((out_address >> 24) & 0xFF); 551 | sb.AppendFormat(":020000{0:X2}{1:X4}{2:X2}", (uint)INTEL_COMMAND.EXTEND_ADDR, (out_address >> 16) & 0xFFFF, ((cs ^ 0xFF) + 1) & 0xFF); 552 | w.WriteLine(sb.ToString()); 553 | hex_address = (out_address & 0xFFFF0000); 554 | sb.Remove(0, sb.Length); 555 | } 556 | 557 | uint byte_count = Math.Min((uint)16, (uint)(MemoryEnd - byte_index + 1)); 558 | sb.AppendFormat(":{0:X2}{1:X4}{2:X2}", byte_count, out_address & 0xFFFF, (uint)INTEL_COMMAND.DATA); 559 | cs = byte_count + (out_address & 0xFF) + (out_address >> 8 & 0xFF) + (uint)INTEL_COMMAND.DATA; 560 | while (byte_count > 0) 561 | { 562 | byte data = Memory[byte_index++]; 563 | cs += data; 564 | sb.AppendFormat("{0:X2}", data); 565 | out_address++; 566 | --byte_count; 567 | } 568 | sb.AppendFormat("{0:X2}", ((cs ^ 0xFF) + 1) & 0xFF); 569 | w.WriteLine(sb.ToString()); 570 | } 571 | w.WriteLine(":00000001FF"); 572 | w.Close(); 573 | } 574 | fs.Close(); 575 | } 576 | } 577 | catch (Exception ex) 578 | { 579 | Console.WriteLine(ex.Message); 580 | exitCode = 1; 581 | } 582 | return exitCode; 583 | } 584 | #endregion 585 | 586 | #region loadHex(string fileIn) 587 | enum MOTOROLA_COMMAND : byte 588 | { 589 | CMD_00 = 0x00, 590 | CMD_01 = 0x01, 591 | CMD_02 = 0x02, 592 | CMD_03 = 0x03, 593 | CMD_04 = 0x04, 594 | CMD_05 = 0x05, 595 | CMD_06 = 0x06, 596 | CMD_07 = 0x07, 597 | CMD_08 = 0x08, 598 | CMD_09 = 0x09 599 | } 600 | enum INTEL_COMMAND : byte 601 | { 602 | UNKNOWN = 0xFF, 603 | DATA = 0x00, 604 | EOF = 0x01, 605 | EXT_SEGMENT_ADDR = 0x02, 606 | SEGMENT_ADDR = 0x03, 607 | EXTEND_ADDR = 0x04, 608 | LINEAR_ADDR = 0x05, 609 | DATA_LOOP = 0x10 610 | } 611 | 612 | /// 613 | /// Convert HEX|S file to internal byte array 614 | /// 615 | /// 616 | /// error code (0=none) 617 | private static int loadHex(string fileIn) 618 | { 619 | uint extend_address = 0, start_address = 0, segment_address = 0, linear_address = 0; 620 | string line; 621 | int lineNumber = 0; 622 | bool fail = false; 623 | uint count = 0, address = 0; 624 | byte data = 0, checksum; 625 | int idx = 0; 626 | INTEL_COMMAND command = INTEL_COMMAND.UNKNOWN; 627 | 628 | using (TextReader s = new StreamReader(fileIn)) 629 | { 630 | while ((line = s.ReadLine()) != null) 631 | { 632 | ++lineNumber; 633 | line = line.Trim(); 634 | if (line.Length == 0) 635 | continue; 636 | 637 | if (line.StartsWith("S")) 638 | { 639 | #region Motorola format 640 | // Stccaaaaaaadd...ddss 641 | if (line.Length < 9) 642 | { 643 | fail = true; 644 | } 645 | else 646 | { 647 | fail |= !byte.TryParse(line.Substring(1, 1), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out data); 648 | MOTOROLA_COMMAND m_command = (MOTOROLA_COMMAND)data; 649 | switch (m_command) 650 | { 651 | case MOTOROLA_COMMAND.CMD_01: 652 | fail |= !uint.TryParse(line.Substring(2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out count); 653 | fail |= !uint.TryParse(line.Substring(4, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out address); 654 | command = INTEL_COMMAND.DATA_LOOP; 655 | idx = 8; 656 | count -= 3; 657 | break; 658 | case MOTOROLA_COMMAND.CMD_02: 659 | if (line.Length < 11) 660 | { 661 | fail = true; 662 | } 663 | else 664 | { 665 | fail |= !uint.TryParse(line.Substring(2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out count); 666 | fail |= !uint.TryParse(line.Substring(4, 6), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out address); 667 | } 668 | command = INTEL_COMMAND.DATA_LOOP; 669 | idx = 10; 670 | count -= 4; 671 | break; 672 | case MOTOROLA_COMMAND.CMD_03: 673 | if (line.Length < 13) 674 | { 675 | fail = true; 676 | } 677 | else 678 | { 679 | fail |= !uint.TryParse(line.Substring(2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out count); 680 | fail |= !uint.TryParse(line.Substring(4, 8), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out address); 681 | } 682 | command = INTEL_COMMAND.DATA_LOOP; 683 | idx = 12; 684 | count -= 5; 685 | break; 686 | case MOTOROLA_COMMAND.CMD_00: 687 | case MOTOROLA_COMMAND.CMD_04: 688 | case MOTOROLA_COMMAND.CMD_05: 689 | case MOTOROLA_COMMAND.CMD_06: 690 | fail = true; 691 | break; 692 | case MOTOROLA_COMMAND.CMD_07: 693 | case MOTOROLA_COMMAND.CMD_08: 694 | case MOTOROLA_COMMAND.CMD_09: 695 | continue; 696 | } 697 | } 698 | #endregion 699 | } 700 | else if (line.StartsWith(":")) 701 | { 702 | #region Intel format 703 | if (line.Length < 11) 704 | { 705 | fail = true; 706 | } 707 | else 708 | { 709 | fail |= !uint.TryParse(line.Substring(1, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out count); 710 | fail |= !uint.TryParse(line.Substring(3, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out address); 711 | fail |= !byte.TryParse(line.Substring(7, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out data); 712 | command = (INTEL_COMMAND)data; 713 | fail |= !byte.TryParse(line.Substring(line.Length - 2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out checksum); 714 | } 715 | #endregion 716 | } 717 | else 718 | continue; // Ignore line 719 | 720 | if (fail) 721 | { 722 | Console.WriteLine(string.Format("Can't parse line {0}", lineNumber)); 723 | break; 724 | } 725 | 726 | switch (command) 727 | { 728 | case INTEL_COMMAND.EOF: // End of File 729 | return 0; 730 | case INTEL_COMMAND.DATA: 731 | #region Data Record 732 | idx = 9; 733 | goto data_loop; 734 | case INTEL_COMMAND.DATA_LOOP: 735 | data_loop: 736 | for (; !fail && count > 0; --count) 737 | { 738 | if (line.Length < idx + 2) 739 | { 740 | Console.WriteLine(string.Format("Data record too short at line {0}", lineNumber)); 741 | fail = true; 742 | } 743 | else 744 | fail = !byte.TryParse(line.Substring(idx, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out data); 745 | 746 | if (!fail) 747 | writeToMemory(segment_address + extend_address + address - BaseAddress, data); 748 | 749 | address++; 750 | idx += 2; 751 | } 752 | break; 753 | #endregion 754 | case INTEL_COMMAND.EXT_SEGMENT_ADDR: // Extended Segment Address Record 755 | #region Extended segment address record 756 | if (count != 2 || line.Length != 15) 757 | { 758 | Console.WriteLine(string.Format("Bad Extended segment address record line {0}.", lineNumber)); 759 | } 760 | else 761 | { 762 | fail |= !uint.TryParse(line.Substring(9, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out segment_address); 763 | if (fail) 764 | Console.WriteLine(string.Format("Bad Start Address records line {0}.", lineNumber)); 765 | else 766 | segment_address <<= 4; 767 | } 768 | break; 769 | #endregion 770 | case INTEL_COMMAND.SEGMENT_ADDR: 771 | #region Start Segment Address Record 772 | if (count != 4) 773 | { 774 | Console.WriteLine(string.Format("Bad Start Segment records line {0}.", lineNumber)); 775 | } 776 | else 777 | { 778 | fail |= !uint.TryParse(line.Substring(9, 8), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out start_address); 779 | if (fail) 780 | Console.WriteLine(string.Format("Bad Start Segment records line {0}.", lineNumber)); 781 | else 782 | Console.WriteLine(string.Format("Start Segment: {0:X}", start_address)); 783 | } 784 | break; 785 | #endregion 786 | case INTEL_COMMAND.EXTEND_ADDR: 787 | #region Extended Linear Address Record 788 | if (line.Length != 15) 789 | { 790 | Console.WriteLine(string.Format("Bad Extended Address records line {0}.", lineNumber)); 791 | fail = true; 792 | } 793 | else 794 | { 795 | fail |= !uint.TryParse(line.Substring(9, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out extend_address); 796 | if (!fail) 797 | extend_address = extend_address << 16; 798 | } 799 | break; 800 | #endregion 801 | case INTEL_COMMAND.LINEAR_ADDR: 802 | #region Start Linear Address Record 803 | if (count != 4) 804 | { 805 | Console.WriteLine(string.Format("Bad Linear Address record line {0}.", lineNumber)); 806 | } 807 | else 808 | { 809 | fail |= !uint.TryParse(line.Substring(9, 8), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out linear_address); 810 | if (fail) 811 | Console.WriteLine(string.Format("Bad Linear Address record line {0}.", lineNumber)); 812 | else 813 | Console.WriteLine(string.Format("Linear Address: 0x{0:X}", linear_address)); 814 | } 815 | break; 816 | #endregion 817 | default: 818 | Console.WriteLine(string.Format("Bad command {0} at line {1}.", command, lineNumber)); 819 | fail = true; 820 | break; 821 | } 822 | if (fail) 823 | break; 824 | } 825 | } 826 | return fail ? 1 : 0; 827 | } 828 | #endregion 829 | 830 | #region writeToMemory(uint address, byte data) 831 | private static void writeToMemory(uint address, byte data) 832 | { 833 | if (address < MemoryLow || address >= MemoryHigh) 834 | { 835 | uint block = address / BLOCK_SIZE; 836 | uint low = Math.Min(MemoryLow, block * BLOCK_SIZE); 837 | uint high = Math.Max(MemoryHigh, (block + 1) * BLOCK_SIZE); 838 | uint idx; 839 | if (Memory == null) 840 | { 841 | Memory = new byte[high - low]; 842 | MemoryLow = low; 843 | idx = MemoryLow; 844 | } 845 | else 846 | { 847 | byte[] memory = new byte[high - low]; 848 | Memory.CopyTo(memory, MemoryLow - low); 849 | Memory = memory; 850 | idx = low; 851 | while (idx < MemoryLow) 852 | Memory[idx++ - low] = EmptyValue; 853 | MemoryLow = low; 854 | idx = MemoryHigh; 855 | } 856 | while (idx < high) 857 | Memory[idx++ - low] = EmptyValue; 858 | MemoryHigh = high; 859 | } 860 | AddressMax = Math.Max(AddressMax, address); 861 | AddressMin = Math.Min(AddressMin, address); 862 | Memory[address - MemoryLow] = data; 863 | } 864 | #endregion 865 | } 866 | } 867 | -------------------------------------------------------------------------------- /Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Hex2Bin")] 9 | [assembly: AssemblyDescription("Hex <-> Bin utility")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("X893")] 12 | [assembly: AssemblyProduct("Hex2Bin")] 13 | [assembly: AssemblyCopyright("Copyright X893 © 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("a8e1f500-e5ba-4b30-8cc4-b8e322081404")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Hex2Bin 2 | ======= 3 | 4 | Hex <-> Bin conversion utility 5 | Also can process Microchip JAM file - multiple hex files. 6 | -------------------------------------------------------------------------------- /bin/Debug/Hex2Bin.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/x893/Hex2Bin/6d6631958b65cd46fad4395aa027abee4c42dc2c/bin/Debug/Hex2Bin.exe --------------------------------------------------------------------------------