├── BIN2HS.sln
├── README.md
├── hex2bin
├── IntelHex.c
├── IntelHex.h
├── ReadMe.txt
├── Srecord.c
├── Srecord.h
├── binstr_conv.c
├── hex2bin.vcxproj
├── hex2bin.vcxproj.filters
├── hex2bin.vcxproj.user
└── main.c
├── ref
├── LICENSE-mit
├── LICENSE-public-domain
├── Makefile
├── README.md
├── atmel_generic.c
├── atmel_generic.h
├── ihex.c
├── ihex.h
├── srecord.c
├── srecord.h
└── testGIS.c
└── si
└── hex2bin.si4project
├── hex2bin.bookmarks.xml
├── hex2bin.sip_sym
├── hex2bin.sip_xab
├── hex2bin.sip_xad
├── hex2bin.sip_xc
├── hex2bin.sip_xf
├── hex2bin.sip_xm
├── hex2bin.sip_xr
├── hex2bin.sip_xsb
├── hex2bin.sip_xsd
├── hex2bin.siproj
├── hex2bin.siproj_settings.xml
├── hex2bin.siwork
└── hex2bin.snippets.xml
/BIN2HS.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hex2bin", "hex2bin\hex2bin.vcxproj", "{D669C4AE-AF2C-4018-9F68-A3786D309753}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {D669C4AE-AF2C-4018-9F68-A3786D309753}.Debug|x64.ActiveCfg = Debug|x64
17 | {D669C4AE-AF2C-4018-9F68-A3786D309753}.Debug|x64.Build.0 = Debug|x64
18 | {D669C4AE-AF2C-4018-9F68-A3786D309753}.Debug|x86.ActiveCfg = Debug|Win32
19 | {D669C4AE-AF2C-4018-9F68-A3786D309753}.Debug|x86.Build.0 = Debug|Win32
20 | {D669C4AE-AF2C-4018-9F68-A3786D309753}.Release|x64.ActiveCfg = Release|x64
21 | {D669C4AE-AF2C-4018-9F68-A3786D309753}.Release|x64.Build.0 = Release|x64
22 | {D669C4AE-AF2C-4018-9F68-A3786D309753}.Release|x86.ActiveCfg = Release|Win32
23 | {D669C4AE-AF2C-4018-9F68-A3786D309753}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## BIN2HS库
2 |
3 | ### 概述
4 | `BIN2HS`是支持Intel Hex、Motorola S格式与bin镜像格式之间进行转换。其支持文件信息快速查看、分段数据处理。
5 |
6 | ### 镜像文件格式
7 | 嵌入式系统中各种系统镜像常用已下几种文件格式来保存:
8 | - hex格式:包含地址信息,由多行纪录条目组成的文本格式文件,每行都由校验和来保证数据完整性。
9 | - srecord格式:为motorola常用的镜像格式,与hex类似,也是由多个记录条目组成的文本格式文件
10 | - bin格式:二进制镜像格式,不包含任何地址信息,也不包含校验和数据。只是数据的二进制集合。
11 |
12 | ### 文件
13 |
14 | - IntelHex.c:包括hex解析及与bin文件相互转换的核心函数
15 | - IntelHex.h:包括hex文件相关的各种类型定义与函数原型
16 | - Srecord.c:包括srecord解析及与bin文件相互转换的核心函数
17 | - Srecord.h:包括srecord文件相关的各种类型定义与函数原型
18 | - binstr_conv.c:数据与字符串的相互转换支持
19 |
20 | ### hex记录
21 |
22 | hex文件的记录行都由`:`字符开始,之后为字节数量、起始地址和数据组成的16进制字符串。
23 | `[:] [字节数:1字节] [起始地址:2字节] [数据] [校验字段:1字节]`
24 | > 示例: `:104000005829002049AE0008DD4F0008DF4F0008A6`
25 | - **:** 每个记录行都由`:`开头
26 | - **10** 记录行包含的数据字节数(不包括起始地址和校验字段)
27 | - **4000** 当前记录的起始地址
28 | - **00** 记录类型,00-数据记录,01-记录结束,04-扩展线性记录
29 | - **5829-0008** 记录行中包含的0x10长度的数据记录
30 | - **A6** 校验和为`:`之后所有数据字段的代数和的补码(所有数据累加和为0)
31 |
32 | 每条hex记录有1字节数据用以表示当前记录条目的类型:
33 | - **00** 数据记录,表示当前记录行内包含实际的映像数据
34 | - **01** 记录结束,为hex的最后一个条目,其他字段都为0
35 | - **02** 扩展段地址,数据项包含2字节扩展地址字段,左移4位作为偏移地址
36 | - **03** 起始段地址,保存到8086 CS:IP中的地址
37 | - **04** 扩展线性地址, 数据项包含2字节扩展地址字段,左移16位作为偏移地址
38 | - **05** 起始线性地址,保存到8086 CS:IP中的地址
39 |
40 | ### srecord记录
41 |
42 | srecord记录(已下简称S格式)与hex记录相似。也是由16进制字符组成的记录行构成。每个记录由`S`字符作为开始。
43 | > 示例:`S1137AF00A0A0D0000000000000000000000000061`
44 | - **S** 记录起始标志
45 | - **1** 记录类型,1-16位地址的数据记录
46 | - **13** 当前记录的字节数,位起始地址字段+数据+校验和
47 | - **7AF0** 当前记录起始地址
48 | - **0A0A-0000** 记录中包含的数据字段
49 | - **61** 校验和字段,为字节数、起始地址和数据字段累加和的反码(所有数据累加和为0xff)
50 |
51 | ### 对象
52 |
53 | ```C
54 | //HEX记录结构
55 | typedef struct eHexRecord
56 | {
57 | uint8_t count; /* 数据字节数 */
58 | uint16_t rcdAddr; /* 当前记录数据起始地址 */
59 | HexRecordType type; /* 当前记录类型 */
60 | uint32_t fileAddr; /* 文件地址=当前记录地址+扩展地址 */
61 | uint32_t extAddr; /* 用于保存记录中的扩展地址 */
62 | uint8_t *pbuff; /* 转换数据缓存内存指针 */
63 |
64 | uint32_t minAddr; /* 记录中最小地址 */
65 | uint32_t maxAddr; /* 记录中最大地址 */
66 | }IHexRecord;
67 | ```
68 |
69 | ```C
70 | //写HEX描述结构体
71 | typedef struct eHexWirteInfo
72 | {
73 | uint8_t* pbuff; /* bin内存区 */
74 | uint32_t size; /* bin文件大小 */
75 | uint32_t startAddr; /* bin起始偏移地址 */
76 | uint16_t linewidth; /* 每行数据字节数量 */
77 |
78 | uint32_t offset; /* 当前索引 */
79 | }IHexWriteDescribe;
80 | ```
81 |
82 | ### 使用方法
83 |
84 | 获取hex文件信息:
85 | > 1. 声明`IHexRecord`hex记录对象。
86 | > 2. 调用`IHex_InitRecordData`初始化记录对象
87 | > 3. 对于每个hex记录字符串行,都调用`IHex_GetNextHeadInfo`函数来解析字符串,直到`IHexRecord`中解析的记录类型为`IHEX_TYPE_ENDFILE`为止。
88 | > 4. 由`IHexRecord`结构体可得到hex文件的最小数据地址和最大数据地址
89 |
90 | 转换hex数据到bin:
91 | > 1. 声明`IHexRecord`,并声明一个数据转换的内存缓冲区,其最大缓冲区大小为`IHEX_MAX_BINDATA_NUM`
92 | > 2. 调用`IHex_InitRecordData`来初始化记录对象
93 | > 3. 对于每个hex记录行,都调用`IHex_GetNextBindata`函数来解析记录行,直到`IHexRecord`中解析的记录类型为`IHEX_TYPE_ENDFILE`为止。
94 | > 4. 当记录类型为`IHEX_TYPE_DATARECORD`时,保存对象内的转换数据
95 |
96 | 转换bin到hex:
97 | > 1. 声明`IHexWriteDescribe`,并对各个成员进行赋值
98 | > 2. 调用`IHex_InitWriteDesc`来初始化记录对象
99 | > 3. 循环调用`IHex_GetNextHexlinestr`,并将得到的记录字符串保存到需要的位置,知道其返回为0为止
100 |
101 |
102 | ## Srecord
103 |
104 | srecerd对象的使用方法与hex类似,请参考hex的使用方法。
105 |
--------------------------------------------------------------------------------
/hex2bin/IntelHex.c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangjinxing/BIN2HS/d2260ac54b19387d894b01db422f125a8ef2e9d8/hex2bin/IntelHex.c
--------------------------------------------------------------------------------
/hex2bin/IntelHex.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangjinxing/BIN2HS/d2260ac54b19387d894b01db422f125a8ef2e9d8/hex2bin/IntelHex.h
--------------------------------------------------------------------------------
/hex2bin/ReadMe.txt:
--------------------------------------------------------------------------------
1 | ========================================================================
2 | 控制台应用程序:hex2bin 项目概述
3 | ========================================================================
4 |
5 | 应用程序向导已为您创建了此 hex2bin 应用程序。
6 |
7 | 本文件概要介绍组成 hex2bin 应用程序的每个文件的内容。
8 |
9 |
10 | hex2bin.vcxproj
11 | 这是使用应用程序向导生成的 VC++ 项目的主项目文件,其中包含生成该文件的 Visual C++ 的版本信息,以及有关使用应用程序向导选择的平台、配置和项目功能的信息。
12 |
13 | hex2bin.vcxproj.filters
14 | 这是使用“应用程序向导”生成的 VC++ 项目筛选器文件。它包含有关项目文件与筛选器之间的关联信息。在 IDE 中,通过这种关联,在特定节点下以分组形式显示具有相似扩展名的文件。例如,“.cpp”文件与“源文件”筛选器关联。
15 |
16 | hex2bin.cpp
17 | 这是主应用程序源文件。
18 |
19 | /////////////////////////////////////////////////////////////////////////////
20 | 其他标准文件:
21 |
22 | StdAfx.h, StdAfx.cpp
23 | 这些文件用于生成名为 hex2bin.pch 的预编译头 (PCH) 文件和名为 StdAfx.obj 的预编译类型文件。
24 |
25 | /////////////////////////////////////////////////////////////////////////////
26 | 其他注释:
27 |
28 | 应用程序向导使用“TODO:”注释来指示应添加或自定义的源代码部分。
29 |
30 | /////////////////////////////////////////////////////////////////////////////
31 |
--------------------------------------------------------------------------------
/hex2bin/Srecord.c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangjinxing/BIN2HS/d2260ac54b19387d894b01db422f125a8ef2e9d8/hex2bin/Srecord.c
--------------------------------------------------------------------------------
/hex2bin/Srecord.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangjinxing/BIN2HS/d2260ac54b19387d894b01db422f125a8ef2e9d8/hex2bin/Srecord.h
--------------------------------------------------------------------------------
/hex2bin/binstr_conv.c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangjinxing/BIN2HS/d2260ac54b19387d894b01db422f125a8ef2e9d8/hex2bin/binstr_conv.c
--------------------------------------------------------------------------------
/hex2bin/hex2bin.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | {D669C4AE-AF2C-4018-9F68-A3786D309753}
23 | Win32Proj
24 | hex2bin
25 | 8.1
26 | BIN2HS
27 |
28 |
29 |
30 | Application
31 | true
32 | v140
33 | Unicode
34 |
35 |
36 | Application
37 | false
38 | v140
39 | true
40 | Unicode
41 |
42 |
43 | Application
44 | true
45 | v140
46 | Unicode
47 |
48 |
49 | Application
50 | false
51 | v140
52 | true
53 | Unicode
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | true
75 |
76 |
77 | true
78 |
79 |
80 | false
81 |
82 |
83 | false
84 |
85 |
86 |
87 | NotUsing
88 | Level4
89 | Disabled
90 | WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
91 | true
92 | ProgramDatabase
93 | MultiThreadedDebug
94 |
95 |
96 | Console
97 | true
98 |
99 |
100 |
101 |
102 | Use
103 | EnableAllWarnings
104 | Disabled
105 | _DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
106 | true
107 |
108 |
109 | Console
110 | true
111 |
112 |
113 |
114 |
115 | Level3
116 | Use
117 | MaxSpeed
118 | true
119 | true
120 | WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
121 | true
122 | MultiThreaded
123 |
124 |
125 | Console
126 | true
127 | true
128 | true
129 |
130 |
131 |
132 |
133 | Level3
134 | Use
135 | MaxSpeed
136 | true
137 | true
138 | NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
139 | true
140 |
141 |
142 | Console
143 | true
144 | true
145 | true
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 | NotUsing
160 | NotUsing
161 | NotUsing
162 |
163 |
164 | NotUsing
165 | NotUsing
166 | NotUsing
167 | NotUsing
168 |
169 |
170 |
171 | NotUsing
172 | NotUsing
173 | NotUsing
174 |
175 |
176 |
177 |
178 |
179 |
--------------------------------------------------------------------------------
/hex2bin/hex2bin.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
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 |
--------------------------------------------------------------------------------
/hex2bin/hex2bin.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -hb D:/test.hex D:/test1.bin 0x80004027
5 | WindowsLocalDebugger
6 |
7 |
--------------------------------------------------------------------------------
/hex2bin/main.c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangjinxing/BIN2HS/d2260ac54b19387d894b01db422f125a8ef2e9d8/hex2bin/main.c
--------------------------------------------------------------------------------
/ref/LICENSE-mit:
--------------------------------------------------------------------------------
1 | Copyright (c) 2010 Ivan A. Sergeev
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/ref/LICENSE-public-domain:
--------------------------------------------------------------------------------
1 | This copy of libGIS is licensed as Public Domain, which is free for any kind of use (personal or commercial), without warranty of any kind, and no requirement for attribution.
2 |
3 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
5 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
7 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
8 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
9 | THE SOFTWARE.
10 |
11 |
--------------------------------------------------------------------------------
/ref/Makefile:
--------------------------------------------------------------------------------
1 | CC = gcc
2 | CFLAGS = -Wall -Wextra -O3
3 | LDFLAGS=
4 | OBJECTS = atmel_generic.o ihex.o srecord.o testGIS.o
5 | PROGNAME = testGIS
6 |
7 | all: $(PROGNAME)
8 |
9 | $(PROGNAME): $(OBJECTS)
10 | $(CC) $(LDFLAGS) -o $@ $(OBJECTS)
11 |
12 | clean:
13 | rm -rf $(PROGNAME) $(OBJECTS)
14 |
15 |
--------------------------------------------------------------------------------
/ref/README.md:
--------------------------------------------------------------------------------
1 | # libGIS - Atmel Generic, Intel HEX, and Motorola S-Record Parser Routines
2 |
3 | **ChangeLog**
4 |
5 | * Release 1.0.5 - 02/05/2011
6 | * Interface change!: write, print, and checksum functions now take a pointer to the record structure instead of a copy, for more efficient use of memory.
7 | * Prettier debug printing of Intel HEX8 and Motorola S-Record records
8 | * Clean up of some of the source code comments and doxygen descriptions
9 | * Release 1.0.4 - 07/08/2010
10 | * No source code changes since version 1.0.3, but I've released libGIS as two packages, one that is licensed as purely public domain, for locations where that applies, and one that is licensed as MIT/X11, for locations where "public domain" has no legal standing.
11 | * Release 1.0.3 - 10/10/2009
12 | * Small bug fix: record reader functions handle newlines in data record lines better, and support for the carriage return character for Windows.
13 | * Bug fix: s-record write function no longer writes an inaccurate space between the record start and record type.
14 | * testGIS.c: a redefine of strcasecmp to stricmp for Windows support.
15 | * Cleaned up some compiler warnings from signed/unsigned comparisons.
16 | * Thanks to Brendan McDonnell for the above four fixes.
17 | * Minor documentation clean up.
18 | * Release 1.0.2 - 06/27/2009
19 | * Small bug fix: record reader functions will now return a newline return code when a lone newline in the file (sometimes found at the end) is encountered instead of erroring out with an invalid record error code.
20 | * Release 1.0.0 - 12/24/2006
21 | * Initial Release
22 |
23 | ----
24 |
25 | **libGIS README**
26 |
27 | libGIS is a collection of utility functions to create, read, and write Atmel Generic, Intel HEX8, and Motorola S-Record formatted files. libGIS is typically not compiled into a library, since the file formats it supports are so specific, and the source code for each file format is contained in only two files.
28 |
29 | I wrote libGIS was because I wanted a clean, flexible, and easy-to-use set of functions to deal with the nasty parsing of these formatted binary files. libGIS supports Intel HEX8 and Motorola S-Record formatted files, which are undoubtedly the most popular in use with embedded systems. libGIS also supports the Atmel Generic binary format, which may be applicable in projects targetting the Atmel AVR.
30 |
31 | libGIS is very convenient for disassembler, assembler, binary file converter, and other related projects. It is written in C (tested with gcc), but can also be compiled with a C++ compiler (such as g++), which means it can be implemented in any C/C++ projects requiring parsing of such formatted files. libGIS uses the standard C library in its backend.
32 |
33 | libGIS is clean and tiny. Each file format is supported with two files, one is the C source code and the other is the C header file, which makes compiling whichever format you need to support very easy. The interface to the utility functions is very straight forward, as demonstrated by the included testGIS.c program.
34 |
35 | The code of each file format parser has a structure to store record information, and 4-5 basic functions to create, read, write, print, and checksum (for Intel HEX8 and Motorola S-Record) records. The error handling in libGIS will never leave you out of the dark, as the possible error codes and what they mean are clearly defined in the header file of the format parser you're using.
36 |
37 | Remember that libGIS is a low-level interface to formatted binary files, and it will not automatically generate, for example, extended addresses in the Intel HEX8 format, or the header record in the S-Record format. libGIS helps in the actual writing and reading of the raw records, not dealing with the content going into them (but still adhering to the record and field size specifications).
38 |
39 | libGIS is offered with two licensing options. The first is Public Domain, which is free for any kind of use (personal or commercial), without warranty of any kind, and no requirement for attribution. The second is MIT/X11.
40 |
41 | The following function prototypes summarize the interface of libGIS:
42 |
43 | Atmel Generic format:
44 | int New_AtmelGenericRecord(uint32_t address, uint16_t data, AtmelGenericRecord *genericRecord);
45 | int Read_AtmelGenericRecord(AtmelGenericRecord *genericRecord, FILE *in);
46 | int Write_AtmelGenericRecord(const AtmelGenericRecord *genericRecord, FILE *out);
47 | void Print_AtmelGenericRecord(const AtmelGenericRecord *genericRecord);
48 |
49 | Intel HEX8 format:
50 | int New_IHexRecord(int type, uint16_t address, const uint8_t *data, int dataLen, IHexRecord *ihexRecord);
51 | int Read_IHexRecord(IHexRecord *ihexRecord, FILE *in);
52 | int Write_IHexRecord(const IHexRecord *ihexRecord, FILE *out);
53 | void Print_IHexRecord(const IHexRecord *ihexRecord);
54 | uint8_t Checksum_IHexRecord(const IHexRecord *ihexRecord);
55 |
56 | Motorola S-Record format:
57 | int New_SRecord(int type, uint32_t address, const uint8_t *data, int dataLen, SRecord *srec);
58 | int Read_SRecord(SRecord *srec, FILE *in);
59 | int Write_SRecord(const SRecord *srec, FILE *out);
60 | void Print_SRecord(const SRecord *srec);
61 | uint8_t Checksum_SRecord(const SRecord *srec);
62 |
63 | This package includes the parsing for the following formats:
64 |
65 | **Atmel Generic format:** atmel_generic.c and atmel_generic.h
66 |
67 | **Intel HEX8 format:** ihex.c and ihex.h
68 |
69 | **Motorola S-Record format:** srecord.c and srecord.h
70 |
71 | Also included is a test program (testGIS.c, with a Makefile to compile it) that prints all of the records contained in a Atmel Generic, Intel HEX8 or Motorola S-Record formatted file, documentation in PDF and html formats, and the README containing all of this.
72 |
73 | Please email me (vsergeev at gmail dot com) any bugs, problems, or suggestions you encounter with using libGIS, they are highly appreciated.
74 |
75 |
--------------------------------------------------------------------------------
/ref/atmel_generic.c:
--------------------------------------------------------------------------------
1 | /*
2 | * atmel_generic.c
3 | * Utility functions to create, read, write, and print Atmel Generic binary records.
4 | *
5 | * Written by Vanya A. Sergeev
6 | * Version 1.0.5 - February 2011
7 | *
8 | */
9 |
10 | #include "atmel_generic.h"
11 |
12 | /* Initializes a new AtmelGenericRecord structure that the paramater genericRecord points to with the passed
13 | * 24-bit integer address, and 16-bit data word. */
14 | int New_AtmelGenericRecord(uint32_t address, uint16_t data, AtmelGenericRecord *genericRecord) {
15 | /* Assert genericRecord pointer */
16 | if (genericRecord == NULL)
17 | return ATMEL_GENERIC_ERROR_INVALID_ARGUMENTS;
18 |
19 | genericRecord->address = address;
20 | genericRecord->data = data;
21 | return ATMEL_GENERIC_OK;
22 | }
23 |
24 |
25 | /* Utility function to read an Atmel Generic record from a file */
26 | int Read_AtmelGenericRecord(AtmelGenericRecord *genericRecord, FILE *in) {
27 | char recordBuff[ATMEL_GENERIC_RECORD_BUFF_SIZE];
28 | int i;
29 |
30 | /* Check our record pointer and file pointer */
31 | if (genericRecord == NULL || in == NULL)
32 | return ATMEL_GENERIC_ERROR_INVALID_ARGUMENTS;
33 |
34 | if (fgets(recordBuff, ATMEL_GENERIC_RECORD_BUFF_SIZE, in) == NULL) {
35 | /* In case we hit EOF, don't report a file error */
36 | if (feof(in) != 0)
37 | return ATMEL_GENERIC_ERROR_EOF;
38 | else
39 | return ATMEL_GENERIC_ERROR_FILE;
40 | }
41 | /* Null-terminate the string at the first sign of a \r or \n */
42 | for (i = 0; i < (int)strlen(recordBuff); i++) {
43 | if (recordBuff[i] == '\r' || recordBuff[i] == '\n') {
44 | recordBuff[i] = 0;
45 | break;
46 | }
47 | }
48 |
49 | /* Check if we hit a newline */
50 | if (strlen(recordBuff) == 0)
51 | return ATMEL_GENERIC_ERROR_NEWLINE;
52 |
53 | /* Size check that the record has the address, data, and start code */
54 | if (strlen(recordBuff) < ATMEL_GENERIC_ADDRESS_LEN + ATMEL_GENERIC_DATA_LEN + 1)
55 | return ATMEL_GENERIC_ERROR_INVALID_RECORD;
56 |
57 | /* Check for the record "start code" (the colon that separates the address and data */
58 | if (recordBuff[ATMEL_GENERIC_SEPARATOR_OFFSET] != ATMEL_GENERIC_SEPARATOR)
59 | return ATMEL_GENERIC_ERROR_INVALID_RECORD;
60 |
61 | /* Replace the colon "start code" with a 0 so we can convert the ascii hex encoded
62 | * address up to this point */
63 | recordBuff[ATMEL_GENERIC_SEPARATOR_OFFSET] = 0;
64 | genericRecord->address = strtol(recordBuff, (char **)NULL, 16);
65 |
66 | /* Convert the rest of the data past the colon, this string has been null terminated at
67 | * the end already */
68 | genericRecord->data = strtol(recordBuff+ATMEL_GENERIC_SEPARATOR_OFFSET+1, (char **)NULL, 16);
69 |
70 | return ATMEL_GENERIC_OK;
71 | }
72 |
73 | /* Utility function to write an Atmel Generic record to a file */
74 | int Write_AtmelGenericRecord(const AtmelGenericRecord *genericRecord, FILE *out) {
75 | /* Check our record pointer and file pointer */
76 | if (genericRecord == NULL || out == NULL)
77 | return ATMEL_GENERIC_ERROR_INVALID_ARGUMENTS;
78 |
79 | if (fprintf(out, "%2.6X%c%2.4X\r\n", genericRecord->address, ATMEL_GENERIC_SEPARATOR, genericRecord->data) < 0)
80 | return ATMEL_GENERIC_ERROR_FILE;
81 |
82 | return ATMEL_GENERIC_OK;
83 | }
84 |
85 | /* Utility function to print the information stored in an Atmel Generic record */
86 | void Print_AtmelGenericRecord(const AtmelGenericRecord *genericRecord) {
87 | printf("Atmel Generic Address: \t0x%2.6X\n", genericRecord->address);
88 | printf("Atmel Generic Data: \t0x%2.4X\n", genericRecord->data);
89 | }
90 |
91 |
--------------------------------------------------------------------------------
/ref/atmel_generic.h:
--------------------------------------------------------------------------------
1 | #ifndef ATMEL_GENERIC_H
2 | #define ATMEL_GENERIC_H
3 | /**
4 | * \file atmel_generic.h
5 | * \brief Low-level utility functions to create, read, write, and print Atmel Generic binary records.
6 | * \author Vanya A. Sergeev
7 | * \date February 2011
8 | * \version 1.0.5
9 | */
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | /* General definition of the Atmel Generic record specifications. */
17 | enum _AtmelGenericDefinitions {
18 | /* 16 should be plenty of space to read in an Atmel Generic record (11 bytes in reality) */
19 | ATMEL_GENERIC_RECORD_BUFF_SIZE = 16,
20 | /* Offsets and lengths of various fields in an Atmel Generic record */
21 | ATMEL_GENERIC_ADDRESS_LEN = 6,
22 | ATMEL_GENERIC_DATA_LEN = 4,
23 | /* The separator character, a colon, that separates the data and address fields in the Atmel Generic records */
24 | ATMEL_GENERIC_SEPARATOR_OFFSET = 6,
25 | ATMEL_GENERIC_SEPARATOR = ':',
26 | };
27 |
28 | /**
29 | * All of the possible error codes the Atmel Generic record utility functions may return.
30 | */
31 | enum AtmelGenericErrors {
32 | ATMEL_GENERIC_OK = 0, /**< Error code for success or no error. */
33 | ATMEL_GENERIC_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. */
34 | ATMEL_GENERIC_ERROR_EOF = -2, /**< Error code for encountering end-of-file when reading from a file. */
35 | ATMEL_GENERIC_ERROR_INVALID_RECORD = -3, /**< Error code for error if an invalid record was read. */
36 | ATMEL_GENERIC_ERROR_INVALID_ARGUMENTS = -4, /**< Error code for error from invalid arguments passed to function. */
37 | ATMEL_GENERIC_ERROR_NEWLINE = -5, /**< Error code for encountering a newline with no record when reading from a file. */
38 | };
39 |
40 | /**
41 | * Structure to hold the fields of an Atmel Generic record.
42 | */
43 | typedef struct {
44 | uint32_t address; /**< The 24-bit address field of the record. */
45 | uint16_t data; /**< The 16-bit data field of the record. */
46 | } AtmelGenericRecord;
47 |
48 | /**
49 | * Sets all of the record fields of an Atmel Generic record structure.
50 | * Note that the Atmel Generic record only supports 24-bit addresses.
51 | * \param address The 24-bit address of the data.
52 | * \param data The 16-bit word of data.
53 | * \param genericRecord A pointer to the target Atmel Generic record structure where these fields will be set.
54 | * \return ATMEL_GENERIC_OK on success, otherwise one of the ATMEL_GENERIC_ERROR_ error codes.
55 | * \retval ATMEL_GENERIC_OK on success.
56 | * \retval ATMEL_GENERIC_ERROR_INVALID_ARGUMENTS if the record pointer is NULL.
57 | */
58 | int New_AtmelGenericRecord(uint32_t address, uint16_t data, AtmelGenericRecord *genericRecord);
59 |
60 | /**
61 | * Reads an Atmel Generic record from an opened file.
62 | * \param genericRecord A pointer to the Atmel Generic record structure that will store the read record.
63 | * \param in A file pointer to an opened file that can be read.
64 | * \return ATMEL_GENERIC_OK on success, otherwise one of the ATMEL_GENERIC_ERROR_ error codes.
65 | * \retval ATMEL_GENERIC_OK on success.
66 | * \retval ATMEL_GENERIC_ERROR_INVALID_ARGUMENTS if the record pointer or file pointer is NULL.
67 | * \retval ATMEL_GENERIC_ERROR_EOF if end-of-file has been reached.
68 | * \retval ATMEL_GENERIC_ERROR_FILE if a file reading error has occured.
69 | * \retval ATMEL_GENERIC_INVALID_RECORD if the record read is invalid (record did not match specifications).
70 | */
71 | int Read_AtmelGenericRecord(AtmelGenericRecord *genericRecord, FILE *in);
72 |
73 | /**
74 | * Writes an Atmel Generic record to an opened file.
75 | * Note that the Atmel Generic record only supports 24-bit addresses, so only 24-bits of the address stored in the Atmel Generic record structure that genericRecord points to will be written.
76 | * \param genericRecord A pointer to the Atmel Generic record structure.
77 | * \param out A file pointer to an opened file that can be written to.
78 | * \return ATMEL_GENERIC_OK on success, otherwise one of the ATMEL_GENERIC_ERROR_ error codes.
79 | * \retval ATMEL_GENERIC_OK on success.
80 | * \retval ATMEL_GENERIC_ERROR_INVALID_ARGUMENTS if the record pointer or file pointer is NULL.
81 | * \retval ATMEL_GENERIC_ERROR_FILE if a file writing error has occured.
82 | */
83 | int Write_AtmelGenericRecord(const AtmelGenericRecord *genericRecord, FILE *out);
84 |
85 | /**
86 | * Prints the contents of an Atmel Generic record structure to stdout.
87 | * The record dump consists of the address and data fields of the record.
88 | * \param genericRecord A pointer to the Atmel Generic record structure.
89 | * \return Always returns ATMEL_GENERIC_OK (success).
90 | * \retval ATMEL_GENERIC_OK on success.
91 | */
92 | void Print_AtmelGenericRecord(const AtmelGenericRecord *genericRecord);
93 |
94 | #endif
95 |
--------------------------------------------------------------------------------
/ref/ihex.c:
--------------------------------------------------------------------------------
1 | /*
2 | * ihex.c
3 | * Utility functions to create, read, write, and print Intel HEX8 binary records.
4 | *
5 | * Written by Vanya A. Sergeev
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 = (uint16_t)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] = (uint8_t)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 = (uint8_t)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 |
171 |
--------------------------------------------------------------------------------
/ref/ihex.h:
--------------------------------------------------------------------------------
1 | #ifndef INTEL_HEX_H
2 | #define INTEL_HEX_H
3 | /**
4 | * \file ihex.h
5 | * \brief Low-level utility functions to create, read, write, and print Intel HEX8 binary records.
6 | * \author Vanya A. Sergeev
7 | * \date February 2011
8 | * \version 1.0.5
9 | */
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | /* General definition of the Intel HEX8 specification */
17 | enum _IHexDefinitions {
18 | /* 768 should be plenty of space to read in a Intel HEX8 record */
19 | IHEX_RECORD_BUFF_SIZE = 768,
20 | /* Offsets and lengths of various fields in an Intel HEX8 record */
21 | IHEX_COUNT_OFFSET = 1,
22 | IHEX_COUNT_LEN = 2,
23 | IHEX_ADDRESS_OFFSET = 3,
24 | IHEX_ADDRESS_LEN = 4,
25 | IHEX_TYPE_OFFSET = 7,
26 | IHEX_TYPE_LEN = 2,
27 | IHEX_DATA_OFFSET = 9,
28 | IHEX_CHECKSUM_LEN = 2,
29 | IHEX_MAX_DATA_LEN = 512,
30 | /* Ascii hex encoded length of a single byte */
31 | IHEX_ASCII_HEX_BYTE_LEN = 2,
32 | /* Start code offset and value */
33 | IHEX_START_CODE_OFFSET = 0,
34 | IHEX_START_CODE = ':',
35 | };
36 |
37 | /**
38 | * All possible error codes the Intel HEX8 record utility functions may return.
39 | */
40 | enum IHexErrors {
41 | IHEX_OK = 0, /**< Error code for success or no error. */
42 | 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. */
43 | IHEX_ERROR_EOF = -2, /**< Error code for encountering end-of-file when reading from a file. */
44 | IHEX_ERROR_INVALID_RECORD = -3, /**< Error code for error if an invalid record was read. */
45 | IHEX_ERROR_INVALID_ARGUMENTS = -4, /**< Error code for error from invalid arguments passed to function. */
46 | IHEX_ERROR_NEWLINE = -5, /**< Error code for encountering a newline with no record when reading from a file. */
47 | };
48 |
49 | /**
50 | * Intel HEX8 Record Types 00-05
51 | */
52 | enum IHexRecordTypes {
53 | IHEX_TYPE_00 = 0, /**< Data Record */
54 | IHEX_TYPE_01, /**< End of File Record */
55 | IHEX_TYPE_02, /**< Extended Segment Address Record */
56 | IHEX_TYPE_03, /**< Start Segment Address Record */
57 | IHEX_TYPE_04, /**< Extended Linear Address Record */
58 | IHEX_TYPE_05, /**< Start Linear Address Record */
59 | };
60 |
61 | /**
62 | * Structure to hold the fields of an Intel HEX8 record.
63 | */
64 | typedef struct {
65 | uint16_t address; /**< The 16-bit address field. */
66 | uint8_t data[IHEX_MAX_DATA_LEN/2]; /**< The 8-bit array data field, which has a maximum size of 256 bytes. */
67 | int dataLen; /**< The number of bytes of data stored in this record. */
68 | int type; /**< The Intel HEX8 record type of this record. */
69 | uint8_t checksum; /**< The checksum of this record. */
70 | } IHexRecord;
71 |
72 | /**
73 | * Sets all of the record fields of an Intel HEX8 record structure.
74 | * \param type The Intel HEX8 record type (integer value of 0 through 5).
75 | * \param address The 16-bit address of the data.
76 | * \param data A point to the 8-bit array of data.
77 | * \param dataLen The size of the 8-bit data array.
78 | * \param ihexRecord A pointer to the target Intel HEX8 record structure where these fields will be set.
79 | * \return IHEX_OK on success, otherwise one of the IHEX_ERROR_ error codes.
80 | * \retval IHEX_OK on success.
81 | * \retval IHEX_ERROR_INVALID_ARGUMENTS if the record pointer is NULL, or if the length of the 8-bit data array is out of range (less than zero or greater than the maximum data length allowed by record specifications, see IHexRecord.data).
82 | */
83 | int New_IHexRecord(int type, uint16_t address, const uint8_t *data, int dataLen, IHexRecord *ihexRecord);
84 |
85 | /**
86 | * Reads an Intel HEX8 record from an opened file.
87 | * \param ihexRecord A pointer to the Intel HEX8 record structure that will store the read record.
88 | * \param in A file pointer to an opened file that can be read.
89 | * \return IHEX_OK on success, otherwise one of the IHEX_ERROR_ error codes.
90 | * \retval IHEX_OK on success.
91 | * \retval IHEX_ERROR_INVALID_ARGUMENTS if the record pointer or file pointer is NULL.
92 | * \retval IHEX_ERROR_EOF if end-of-file has been reached.
93 | * \retval IHEX_ERROR_FILE if a file reading error has occured.
94 | * \retval IHEX_INVALID_RECORD if the record read is invalid (record did not match specifications or record checksum was invalid).
95 | */
96 | int Read_IHexRecord(IHexRecord *ihexRecord, FILE *in);
97 |
98 | /**
99 | * Writes an Intel HEX8 record to an opened file.
100 | * \param ihexRecord A pointer to the Intel HEX8 record structure.
101 | * \param out A file pointer to an opened file that can be written to.
102 | * \return IHEX_OK on success, otherwise one of the IHEX_ERROR_ error codes.
103 | * \retval IHEX_OK on success.
104 | * \retval IHEX_ERROR_INVALID_ARGUMENTS if the record pointer or file pointer is NULL.
105 | * \retval IHEX_ERROR_INVALID_RECORD if the record's data length is out of range (greater than the maximum data length allowed by record specifications, see IHexRecord.data).
106 | * \retval IHEX_ERROR_FILE if a file writing error has occured.
107 | */
108 | int Write_IHexRecord(const IHexRecord *ihexRecord, FILE *out);
109 |
110 | /**
111 | * Prints the contents of an Intel HEX8 record structure to stdout.
112 | * The record dump consists of the type, address, entire data array, and checksum fields of the record.
113 | * \param ihexRecord A pointer to the Intel HEX8 record structure.
114 | * \return Always returns IHEX_OK (success).
115 | * \retval IHEX_OK on success.
116 | */
117 | void Print_IHexRecord(const IHexRecord *ihexRecord);
118 |
119 | /**
120 | * Calculates the checksum of an Intel HEX8 IHexRecord structure.
121 | * See the Intel HEX8 specifications for more details on the checksum calculation.
122 | * \param ihexRecord A pointer to the Intel HEX8 record structure.
123 | * \return The 8-bit checksum.
124 | */
125 | uint8_t Checksum_IHexRecord(const IHexRecord *ihexRecord);
126 |
127 | #endif
128 |
--------------------------------------------------------------------------------
/ref/srecord.c:
--------------------------------------------------------------------------------
1 | /*
2 | * srecord.h
3 | * Utility functions to create, read, write, and print Motorola S-Record binary records.
4 | *
5 | * Written by Vanya A. Sergeev
6 | * Version 1.0.5 - February 2011
7 | *
8 | */
9 |
10 | #include "srecord.h"
11 |
12 | /* Lengths of the ASCII hex encoded address fields of different SRecord types */
13 | static int SRecord_Address_Lengths[] = {
14 | 4, // S0
15 | 4, // S1
16 | 6, // S2
17 | 8, // S3
18 | 8, // S4
19 | 4, // S5
20 | 6, // S6
21 | 8, // S7
22 | 6, // S8
23 | 4, // S9
24 | };
25 |
26 | /* Initializes a new SRecord structure that the paramater srec points to with the passed
27 | * S-Record type, up to 32-bit integer address, 8-bit data array, and size of 8-bit data array. */
28 | int New_SRecord(int type, uint32_t address, const uint8_t *data, int dataLen, SRecord *srec) {
29 | /* Data length size check, assertion of srec pointer */
30 | if (dataLen < 0 || dataLen > SRECORD_MAX_DATA_LEN/2 || srec == NULL)
31 | return SRECORD_ERROR_INVALID_ARGUMENTS;
32 |
33 | srec->type = type;
34 | srec->address = address;
35 | memcpy(srec->data, data, dataLen);
36 | srec->dataLen = dataLen;
37 | srec->checksum = Checksum_SRecord(srec);
38 |
39 | return SRECORD_OK;
40 | }
41 |
42 |
43 | /* Utility function to read an S-Record from a file */
44 | int Read_SRecord(SRecord *srec, FILE *in) {
45 | char recordBuff[SRECORD_RECORD_BUFF_SIZE];
46 | /* A temporary buffer to hold ASCII hex encoded data, set to the maximum length we would ever need */
47 | char hexBuff[SRECORD_MAX_ADDRESS_LEN+1];
48 | int asciiAddressLen, asciiDataLen, dataOffset, fieldDataCount, i;
49 |
50 | /* Check our record pointer and file pointer */
51 | if (srec == NULL || in == NULL)
52 | return SRECORD_ERROR_INVALID_ARGUMENTS;
53 |
54 | if (fgets(recordBuff, SRECORD_RECORD_BUFF_SIZE, in) == NULL) {
55 | /* In case we hit EOF, don't report a file error */
56 | if (feof(in) != 0)
57 | return SRECORD_ERROR_EOF;
58 | else
59 | return SRECORD_ERROR_FILE;
60 | }
61 | /* Null-terminate the string at the first sign of a \r or \n */
62 | for (i = 0; i < (int)strlen(recordBuff); i++) {
63 | if (recordBuff[i] == '\r' || recordBuff[i] == '\n') {
64 | recordBuff[i] = 0;
65 | break;
66 | }
67 | }
68 |
69 | /* Check if we hit a newline */
70 | if (strlen(recordBuff) == 0)
71 | return SRECORD_ERROR_NEWLINE;
72 |
73 | /* Size check for type and count fields */
74 | if (strlen(recordBuff) < SRECORD_TYPE_LEN + SRECORD_COUNT_LEN)
75 | return SRECORD_ERROR_INVALID_RECORD;
76 |
77 | /* Check for the S-Record start code at the beginning of every record */
78 | if (recordBuff[SRECORD_START_CODE_OFFSET] != SRECORD_START_CODE)
79 | return SRECORD_ERROR_INVALID_RECORD;
80 |
81 | /* Copy the ASCII hex encoding of the type field into hexBuff, convert it into a usable integer */
82 | strncpy(hexBuff, recordBuff+SRECORD_TYPE_OFFSET, SRECORD_TYPE_LEN);
83 | hexBuff[SRECORD_TYPE_LEN] = 0;
84 | srec->type = strtol(hexBuff, (char **)NULL, 16);
85 |
86 | /* Copy the ASCII hex encoding of the count field into hexBuff, convert it to a usable integer */
87 | strncpy(hexBuff, recordBuff+SRECORD_COUNT_OFFSET, SRECORD_COUNT_LEN);
88 | hexBuff[SRECORD_COUNT_LEN] = 0;
89 | fieldDataCount = strtol(hexBuff, (char **)NULL, 16);
90 |
91 | /* Check that our S-Record type is valid */
92 | if (srec->type < SRECORD_TYPE_S0 || srec->type > SRECORD_TYPE_S9)
93 | return SRECORD_ERROR_INVALID_RECORD;
94 | /* Get the ASCII hex address length of this particular S-Record type */
95 | asciiAddressLen = SRecord_Address_Lengths[srec->type];
96 |
97 | /* Size check for address field */
98 | if (strlen(recordBuff) < (unsigned int)(SRECORD_ADDRESS_OFFSET+asciiAddressLen))
99 | return SRECORD_ERROR_INVALID_RECORD;
100 |
101 | /* Copy the ASCII hex encoding of the count field into hexBuff, convert it to a usable integer */
102 | strncpy(hexBuff, recordBuff+SRECORD_ADDRESS_OFFSET, asciiAddressLen);
103 | hexBuff[asciiAddressLen] = 0;
104 | srec->address = strtol(hexBuff, (char **)NULL, 16);
105 |
106 | /* Compute the ASCII hex data length by subtracting the remaining field lengths from the S-Record
107 | * count field (times 2 to account for the number of characters used in ASCII hex encoding) */
108 | asciiDataLen = (fieldDataCount*2) - asciiAddressLen - SRECORD_CHECKSUM_LEN;
109 | /* Bailout if we get an invalid data length */
110 | if (asciiDataLen < 0 || asciiDataLen > SRECORD_MAX_DATA_LEN)
111 | return SRECORD_ERROR_INVALID_RECORD;
112 |
113 | /* Size check for final data field and checksum field */
114 | if (strlen(recordBuff) < (unsigned int)(SRECORD_ADDRESS_OFFSET+asciiAddressLen+asciiDataLen+SRECORD_CHECKSUM_LEN))
115 | return SRECORD_ERROR_INVALID_RECORD;
116 |
117 | dataOffset = SRECORD_ADDRESS_OFFSET+asciiAddressLen;
118 |
119 | /* Loop through each ASCII hex byte of the data field, pull it out into hexBuff,
120 | * convert it and store the result in the data buffer of the S-Record */
121 | for (i = 0; i < asciiDataLen/2; i++) {
122 | /* Times two i because every byte is represented by two ASCII hex characters */
123 | strncpy(hexBuff, recordBuff+dataOffset+2*i, SRECORD_ASCII_HEX_BYTE_LEN);
124 | hexBuff[SRECORD_ASCII_HEX_BYTE_LEN] = 0;
125 | srec->data[i] = strtol(hexBuff, (char **)NULL, 16);
126 | }
127 | /* Real data len is divided by two because every byte is represented by two ASCII hex characters */
128 | srec->dataLen = asciiDataLen/2;
129 |
130 | /* Copy out the checksum ASCII hex encoded byte, and convert it back to a usable integer */
131 | strncpy(hexBuff, recordBuff+dataOffset+asciiDataLen, SRECORD_CHECKSUM_LEN);
132 | hexBuff[SRECORD_CHECKSUM_LEN] = 0;
133 | srec->checksum = strtol(hexBuff, (char **)NULL, 16);
134 |
135 | if (srec->checksum != Checksum_SRecord(srec))
136 | return SRECORD_ERROR_INVALID_RECORD;
137 |
138 | return SRECORD_OK;
139 | }
140 |
141 | /* Utility function to write an S-Record to a file */
142 | int Write_SRecord(const SRecord *srec, FILE *out) {
143 | char strAddress[SRECORD_MAX_ADDRESS_LEN+1];
144 | int asciiAddressLen, asciiAddressOffset, fieldDataCount, i;
145 |
146 | /* Check our record pointer and file pointer */
147 | if (srec == NULL || out == NULL)
148 | return SRECORD_ERROR_INVALID_ARGUMENTS;
149 |
150 | /* Check that the type and data length is within range */
151 | if (srec->type < SRECORD_TYPE_S0 || srec->type > SRECORD_TYPE_S9 || srec->dataLen > SRECORD_MAX_DATA_LEN/2)
152 | return SRECORD_ERROR_INVALID_RECORD;
153 |
154 | /* Compute the record count, address and checksum lengths are halved because record count
155 | * is the number of bytes left in the record, not the length of the ASCII hex representation */
156 | fieldDataCount = SRecord_Address_Lengths[srec->type]/2 + srec->dataLen + SRECORD_CHECKSUM_LEN/2;
157 |
158 | asciiAddressLen = SRecord_Address_Lengths[srec->type];
159 | /* The offset of the ASCII hex encoded address from zero, this is used so we only write as
160 | * many bytes of the address as permitted by the S-Record type. */
161 | asciiAddressOffset = SRECORD_MAX_ADDRESS_LEN-asciiAddressLen;
162 |
163 | if (fprintf(out, "%c%1.1X%2.2X", SRECORD_START_CODE, srec->type, fieldDataCount) < 0)
164 | return SRECORD_ERROR_FILE;
165 |
166 | /* Write the ASCII hex representation of the address, starting from the offset to only
167 | * write as much of the address as permitted by the S-Record type (calculated above). */
168 | /* Fix the hex to be 8 hex digits of precision, to fit all 32-bits, including zeros */
169 | snprintf(strAddress, sizeof(strAddress), "%2.8X", srec->address);
170 | if (fprintf(out, "%s", strAddress+asciiAddressOffset) < 0)
171 | return SRECORD_ERROR_FILE;
172 |
173 | /* Write each byte of the data, guaranteed to be two hex ASCII characters each since
174 | * srec->data[i] has the type of uint8_t */
175 | for (i = 0; i < srec->dataLen; i++) {
176 | if (fprintf(out, "%2.2X", srec->data[i]) < 0)
177 | return SRECORD_ERROR_FILE;
178 | }
179 |
180 | /* Last but not least, the checksum */
181 | if (fprintf(out, "%2.2X\r\n", Checksum_SRecord(srec)) < 0)
182 | return SRECORD_ERROR_FILE;
183 |
184 | return SRECORD_OK;
185 | }
186 |
187 | /* Utility function to print the information stored in an S-Record */
188 | void Print_SRecord(const SRecord *srec) {
189 | int i;
190 | printf("S-Record Type: \t\tS%d\n", srec->type);
191 | printf("S-Record Address: \t0x%2.8X\n", srec->address);
192 | printf("S-Record Data: \t\t{");
193 | for (i = 0; i < srec->dataLen; i++) {
194 | if (i+1 < srec->dataLen)
195 | printf("0x%02X, ", srec->data[i]);
196 | else
197 | printf("0x%02X", srec->data[i]);
198 | }
199 | printf("}\n");
200 | printf("S-Record Checksum: \t0x%2.2X\n", srec->checksum);
201 | }
202 |
203 | /* Utility function to calculate the checksum of an S-Record */
204 | uint8_t Checksum_SRecord(const SRecord *srec) {
205 | uint8_t checksum;
206 | int fieldDataCount, i;
207 |
208 | /* Compute the record count, address and checksum lengths are halved because record count
209 | * is the number of bytes left in the record, not the length of the ASCII hex representation */
210 | fieldDataCount = SRecord_Address_Lengths[srec->type]/2 + srec->dataLen + SRECORD_CHECKSUM_LEN/2;
211 |
212 | /* Add the count, address, and data fields together */
213 | checksum = fieldDataCount;
214 | /* Add each byte of the address individually */
215 | checksum += (uint8_t)(srec->address & 0x000000FF);
216 | checksum += (uint8_t)((srec->address & 0x0000FF00) >> 8);
217 | checksum += (uint8_t)((srec->address & 0x00FF0000) >> 16);
218 | checksum += (uint8_t)((srec->address & 0xFF000000) >> 24);
219 | for (i = 0; i < srec->dataLen; i++)
220 | checksum += srec->data[i];
221 |
222 | /* One's complement the checksum */
223 | checksum = ~checksum;
224 |
225 | return checksum;
226 | }
227 |
228 |
--------------------------------------------------------------------------------
/ref/srecord.h:
--------------------------------------------------------------------------------
1 | #ifndef SRECORD_H
2 | #define SRECORD_H
3 | /**
4 | * \file srecord.h
5 | * \brief Low-level utility functions to create, read, write, and print Motorola S-Record binary records.
6 | * \author Vanya A. Sergeev
7 | * \date February 2011
8 | * \version 1.0.5
9 | */
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | /* General definition of the S-Record specification */
17 | enum _SRecordDefinitions {
18 | /* 768 should be plenty of space to read in an S-Record */
19 | SRECORD_RECORD_BUFF_SIZE = 768,
20 | /* Offsets and lengths of various fields in an S-Record record */
21 | SRECORD_TYPE_OFFSET = 1,
22 | SRECORD_TYPE_LEN = 1,
23 | SRECORD_COUNT_OFFSET = 2,
24 | SRECORD_COUNT_LEN = 2,
25 | SRECORD_ADDRESS_OFFSET = 4,
26 | SRECORD_CHECKSUM_LEN = 2,
27 | /* Maximum ascii hex length of the S-Record data field */
28 | SRECORD_MAX_DATA_LEN = 64,
29 | /* Maximum ascii hex length of the S-Record address field */
30 | SRECORD_MAX_ADDRESS_LEN = 8,
31 | /* Ascii hex length of a single byte */
32 | SRECORD_ASCII_HEX_BYTE_LEN = 2,
33 | /* Start code offset and value */
34 | SRECORD_START_CODE_OFFSET = 0,
35 | SRECORD_START_CODE = 'S',
36 | };
37 |
38 | /**
39 | * All possible error codes the Motorola S-Record utility functions may return.
40 | */
41 | enum SRecordErrors {
42 | SRECORD_OK = 0, /**< Error code for success or no error. */
43 | SRECORD_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. */
44 | SRECORD_ERROR_EOF = -2, /**< Error code for encountering end-of-file when reading from a file. */
45 | SRECORD_ERROR_INVALID_RECORD = -3, /**< Error code for error if an invalid record was read. */
46 | SRECORD_ERROR_INVALID_ARGUMENTS = -4, /**< Error code for error from invalid arguments passed to function. */
47 | SRECORD_ERROR_NEWLINE = -5, /**< Error code for encountering a newline with no record when reading from a file. */
48 | };
49 |
50 | /**
51 | * Motorola S-Record Types S0-S9
52 | */
53 | enum SRecordTypes {
54 | SRECORD_TYPE_S0 = 0, /**< Header record, although there is an official format it is often made proprietary by third-parties. 16-bit address normally set to 0x0000 and header information is stored in the data field. This record is unnecessary and commonly not used. */
55 | SRECORD_TYPE_S1, /**< Data record with 16-bit address */
56 | SRECORD_TYPE_S2, /**< Data record with 24-bit address */
57 | SRECORD_TYPE_S3, /**< Data record with 32-bit address */
58 | SRECORD_TYPE_S4, /**< Extension by LSI Logic, Inc. See their specification for more details. */
59 | SRECORD_TYPE_S5, /**< 16-bit address field that contains the number of S1, S2, and S3 (all data) records transmitted. No data field. */
60 | SRECORD_TYPE_S6, /**< 24-bit address field that contains the number of S1, S2, and S3 (all data) records transmitted. No data field. */
61 | SRECORD_TYPE_S7, /**< Termination record for S3 data records. 32-bit address field contains address of the entry point after the S-Record file has been processed. No data field. */
62 | SRECORD_TYPE_S8, /**< Termination record for S2 data records. 24-bit address field contains address of the entry point after the S-Record file has been processed. No data field. */
63 | SRECORD_TYPE_S9, /**< Termination record for S1 data records. 16-bit address field contains address of the entry point after the S-Record file has been processed. No data field. */
64 | };
65 |
66 | /**
67 | * Structure to hold the fields of a Motorola S-Record record.
68 | */
69 | typedef struct {
70 | uint32_t address; /**< The address field. This can be 16, 24, or 32 bits depending on the record type. */
71 | uint8_t data[SRECORD_MAX_DATA_LEN/2]; /**< The 8-bit array data field, which has a maximum size of 32 bytes. */
72 | int dataLen; /**< The number of bytes of data stored in this record. */
73 | int type; /**< The Motorola S-Record type of this record (S0-S9). */
74 | uint8_t checksum; /**< The checksum of this record. */
75 | } SRecord;
76 |
77 | /**
78 | * Sets all of the record fields of a Motorola S-Record structure.
79 | * \param type The Motorola S-Record type (integer value of 0 through 9).
80 | * \param address The 32-bit address of the data. The actual size of the address (16-,24-, or 32-bits) when written to a file depends on the S-Record type.
81 | * \param data A pointer to the 8-bit array of data.
82 | * \param dataLen The size of the 8-bit data array.
83 | * \param srec A pointer to the target Motorola S-Record structure where these fields will be set.
84 | * \return SRECORD_OK on success, otherwise one of the SRECORD_ERROR_ error codes.
85 | * \retval SRECORD_OK on success.
86 | * \retval SRECORD_ERROR_INVALID_ARGUMENTS if the record pointer is NULL, or if the length of the 8-bit data array is out of range (less than zero or greater than the maximum data length allowed by record specifications, see SRecord.data).
87 | */
88 | int New_SRecord(int type, uint32_t address, const uint8_t *data, int dataLen, SRecord *srec);
89 |
90 | /**
91 | * Reads a Motorola S-Record record from an opened file.
92 | * \param srec A pointer to the Motorola S-Record structure that will store the read record.
93 | * \param in A file pointer to an opened file that can be read.
94 | * \return SRECORD_OK on success, otherwise one of the SRECORD_ERROR_ error codes.
95 | * \retval SRECORD_OK on success.
96 | * \retval SRECORD_ERROR_INVALID_ARGUMENTS if the record pointer or file pointer is NULL.
97 | * \retval SRECORD_ERROR_EOF if end-of-file has been reached.
98 | * \retval SRECORD_ERROR_FILE if a file reading error has occured.
99 | * \retval SRECORD_INVALID_RECORD if the record read is invalid (record did not match specifications or record checksum was invalid).
100 | */
101 | int Read_SRecord(SRecord *srec, FILE *in);
102 |
103 | /**
104 | * Writes a Motorola S-Record to an opened file.
105 | * \param srec A pointer to the Motorola S-Record structure.
106 | * \param out A file pointer to an opened file that can be written to.
107 | * \return SRECORD_OK on success, otherwise one of the SRECORD_ERROR_ error codes.
108 | * \retval SRECORD_OK on success.
109 | * \retval SRECORD_ERROR_INVALID_ARGUMENTS if the record pointer or file pointer is NULL.
110 | * \retval SRECORD_ERROR_INVALID_RECORD if the record's data length (the SRecord.dataLen variable of the record) is out of range (greater than the maximum data length allowed by record specifications, see SRecord.data).
111 | * \retval SRECORD_ERROR_FILE if a file writing error has occured.
112 | */
113 | int Write_SRecord(const SRecord *srec, FILE *out);
114 |
115 | /**
116 | * Prints the contents of a Motorola S-Record structure to stdout.
117 | * The record dump consists of the type, address, entire data array, and checksum fields of the record.
118 | * \param srec A pointer to the Motorola S-Record structure.
119 | * \return Always returns SRECORD_OK (success).
120 | * \retval SRECORD_OK on success.
121 | */
122 | void Print_SRecord(const SRecord *srec);
123 |
124 | /**
125 | * Calculates the checksum of a Motorola S-Record SRecord structure.
126 | * See the Motorola S-Record specifications for more details on the checksum calculation.
127 | * \param srec A pointer to the Motorola S-Record structure.
128 | * \return The 8-bit checksum.
129 | */
130 | uint8_t Checksum_SRecord(const SRecord *srec);
131 |
132 | #endif
133 |
--------------------------------------------------------------------------------
/ref/testGIS.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This program prints all of the records stored in an Atmel Generic, Intel HEX, or Motorola S-Record formatted file.
3 | * Author: Vanya A. Sergeev
4 | */
5 |
6 | #include
7 | #include
8 | #include "srecord.h"
9 | #include "atmel_generic.h"
10 | #include "ihex.h"
11 |
12 | /* Windows doesn't have 'strcasecmp' but does have stricmp */
13 | #ifdef _WIN32
14 | #define strcasecmp stricmp
15 | #endif
16 |
17 | int main (int argc, const char * argv[]) {
18 | FILE *fp;
19 | AtmelGenericRecord arec;
20 | IHexRecord irec;
21 | SRecord srec;
22 |
23 | if (argc < 3) {
24 | fprintf(stderr, "Usage: %s \n", argv[0]);
25 | fprintf(stderr, "This program will print the records saved in a generic,\nIntel HEX, or Motorola S-Record formatted file.\n\n");
26 | fprintf(stderr, " can be generic, ihex, or srecord.\n");
27 | fprintf(stderr, " is the path to the file containing the records.\n");
28 | return -1;
29 | }
30 |
31 | fp = fopen(argv[2], "r");
32 | if (fp == NULL) {
33 | perror("Error opening file!");
34 | return -1;
35 | }
36 |
37 | if (strcasecmp(argv[1], "generic") == 0) {
38 | while (Read_AtmelGenericRecord(&arec, fp) == ATMEL_GENERIC_OK) {
39 | Print_AtmelGenericRecord(&arec);
40 | printf("\n");
41 | }
42 | } else if (strcasecmp(argv[1], "ihex") == 0) {
43 | while (Read_IHexRecord(&irec, fp) == IHEX_OK) {
44 | Print_IHexRecord(&irec);
45 | printf("\n");
46 | }
47 | } else if (strcasecmp(argv[1], "srecord") == 0) {
48 | while (Read_SRecord(&srec, fp) == SRECORD_OK) {
49 | Print_SRecord(&srec);
50 | printf("\n");
51 | }
52 | } else {
53 | fprintf(stderr, "Invalid file format specified!\n");
54 | fclose(fp);
55 | return -1;
56 | }
57 |
58 | fclose(fp);
59 | return 0;
60 | }
61 |
62 |
--------------------------------------------------------------------------------
/si/hex2bin.si4project/hex2bin.bookmarks.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/si/hex2bin.si4project/hex2bin.sip_sym:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangjinxing/BIN2HS/d2260ac54b19387d894b01db422f125a8ef2e9d8/si/hex2bin.si4project/hex2bin.sip_sym
--------------------------------------------------------------------------------
/si/hex2bin.si4project/hex2bin.sip_xab:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangjinxing/BIN2HS/d2260ac54b19387d894b01db422f125a8ef2e9d8/si/hex2bin.si4project/hex2bin.sip_xab
--------------------------------------------------------------------------------
/si/hex2bin.si4project/hex2bin.sip_xad:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangjinxing/BIN2HS/d2260ac54b19387d894b01db422f125a8ef2e9d8/si/hex2bin.si4project/hex2bin.sip_xad
--------------------------------------------------------------------------------
/si/hex2bin.si4project/hex2bin.sip_xc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangjinxing/BIN2HS/d2260ac54b19387d894b01db422f125a8ef2e9d8/si/hex2bin.si4project/hex2bin.sip_xc
--------------------------------------------------------------------------------
/si/hex2bin.si4project/hex2bin.sip_xf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangjinxing/BIN2HS/d2260ac54b19387d894b01db422f125a8ef2e9d8/si/hex2bin.si4project/hex2bin.sip_xf
--------------------------------------------------------------------------------
/si/hex2bin.si4project/hex2bin.sip_xm:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/si/hex2bin.si4project/hex2bin.sip_xr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangjinxing/BIN2HS/d2260ac54b19387d894b01db422f125a8ef2e9d8/si/hex2bin.si4project/hex2bin.sip_xr
--------------------------------------------------------------------------------
/si/hex2bin.si4project/hex2bin.sip_xsb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangjinxing/BIN2HS/d2260ac54b19387d894b01db422f125a8ef2e9d8/si/hex2bin.si4project/hex2bin.sip_xsb
--------------------------------------------------------------------------------
/si/hex2bin.si4project/hex2bin.sip_xsd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangjinxing/BIN2HS/d2260ac54b19387d894b01db422f125a8ef2e9d8/si/hex2bin.si4project/hex2bin.sip_xsd
--------------------------------------------------------------------------------
/si/hex2bin.si4project/hex2bin.siproj:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangjinxing/BIN2HS/d2260ac54b19387d894b01db422f125a8ef2e9d8/si/hex2bin.si4project/hex2bin.siproj
--------------------------------------------------------------------------------
/si/hex2bin.si4project/hex2bin.siproj_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/si/hex2bin.si4project/hex2bin.siwork:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangjinxing/BIN2HS/d2260ac54b19387d894b01db422f125a8ef2e9d8/si/hex2bin.si4project/hex2bin.siwork
--------------------------------------------------------------------------------
/si/hex2bin.si4project/hex2bin.snippets.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------