本文首发于微信公众号“嵌入式软件实战派”。
这是《玩转Hex文件》的姊妹篇。
如果你还不了解S19或者SREC文件格式,请戳《SREC、Hex、Bin等烧录文件格式完全解读》。
本文与其说是《玩转S19文件》,还不如说是《玩转S19、Hex、Bin文件》,因为接下来讲的神器是可以玩转S19、Hex、Bin的。下面是基于Python的BinCopy库来讲解的。
写数据
方法有很多:
add(data, overwrite=False)
add_binary(data, address=0, overwrite=False)
add_binary_file(filename, address=0, overwrite=False)
add_file(filename, overwrite=False)
add_ihex(records, overwrite=False)
add_ihex_file(filename, overwrite=False)
add_srec(records, overwrite=False)
add_srec_file(filename, overwrite=False)
add_ti_txt(lines, overwrite=False)
add_ti_txt_file(filename, overwrite=False)
使用也很简单,可以自行查找其使用手册来看看,以下挑几个来讲解下。
import bincopy
bf=bincopy.BinFile()
bf.add_binary("embedded_sw".encode(),0x00)
那么得到的内容是
00000000 65 6d 62 65 64 64 65 64 5f 73 77 |embedded_sw |
假设,我有另一个bin
文件is_great.bin
,我想加载到这个bf里面来,可以这样:
bf.add_binary_file("is_great.bin",0x10)
可得到像这样的结果:
00000000 65 6d 62 65 64 64 65 64 5f 73 77 |embedded_sw |
00000010 69 73 20 67 72 65 61 74 21 |is great! |
同样的道理,
对于intel hex内容可以用方法add_ihex(records, overwrite=False)
;
对于intel hex文件内容可以用方法add_ihex_file(filename, overwrite=False)
;
对于SREC(S19)内容可以用方法add_srec(records, overwrite=False)
;
对于SREC(S19)文件可以用方法add_srec_file(filename, overwrite=False)
;
……
读数据
读的方法有很多:
as_array(minimum_address=None, padding=None, separator=’, ')
as_binary()
as_ihex(number_of_data_bytes=32, address_length_bits=32)
as_srec(number_of_data_bytes=32, address_length_bits=32)
as_ti_txt()
就针对上面的例子,我试下这些方法
bf.as_array()
0x65, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x73, 0x77, 0xff, 0xff, 0xff, 0xff, 0xff, 0x69, 0x73, 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, 0x21
把padding参数加上
bf.as_array(padding=b'x\ff')
0x65, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x73, 0x77, 0x78, 0x0c, 0x66, 0x78, 0x0c, 0x66, 0x78, 0x0c, 0x66, 0x78, 0x0c, 0x66, 0x78, 0x0c, 0x66, 0x69, 0x73, 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, 0x21
从上面这个padding参数得出的结果可以看出,如果不用padding(即padding=None)的话,得出的结果是不管空白地方的,这个要注意。
bf.as_ihex()
:0B000000656D6265646465645F737782
:09001000697320677265617421B7
:00000001FF
bf.as_srec()
S31000000000656D6265646465645F73777C
S30E00000010697320677265617421B1
S5030002FA
bf.as_ti_txt()
@0000
65 6D 62 65 64 64 65 64 5F 73 77
@0010
69 73 20 67 72 65 61 74 21
q
格式转换
从上面的读数据的例子,很容易得到想要的格式内容,那么将这些格式内容保存成文档,不就是相当于格式转换了吗!
下面以ihex格式为例,其他格式类同:
with open("embedded_sw_ihex.hex", 'w') as f:for l in s19.as_ihex():f.write(l)
但这里要注意,写入的文档最后面会多一个空行,看看这个空行是否会影响你项目上用到的解析软件。当然,你可以用rstrip()
删掉最后面的空行(换行符),像这样:
with open("embedded_sw_ihex.hex", 'w') as f:for l in s19.as_ihex().rstrip():f.write(l)
文件裁剪
对于一个文件,我只想其中的一部分,怎么办?可以试试以下两个方法:
crop(minimum_address, maximum_address)
exclude(minimum_address, maximum_address)
解释一下,这个crop
就是保留minimum_address
~ maximum_address
之间的内容;而exclude
就是保留minimum_address
~ maximum_address
之间的内容砍掉不要。
下面来实验下这个
bf.crop(0x00, 0x09)
bf.as_hexdump()
00000000 65 6d 62 65 64 64 65 64 5f |embedded_ |
数一下这个内容字节数,只有9个字节,其实是不包含最大地址maximum_address
的内容的,那么这个maximum_address
是什么意思呢?
我们看看官方文档的说明:
crop(minimum_address, maximum_address)
Keep given range and discard the rest.
minimum_address is the first word address to keep (including).
maximum_address is the last word address to keep (excluding).
maximum_address
的内容是excluding的。也就是说crop后保留的内容是minimum_address
到maximum_address-1
的内容,即[minimum_address, maximun_address)
或者[minimum_address, maximun_address-1]
。这个跟IntelHex库的.maxaddr()
是不一样的。
同样地,接着上面的例子:
bf.exclude(0x03, 0x07)
bf.as_hexdump()
00000000 65 6d 62 64 5f |emb d_ |
其他
查看文件信息,可以用info()
方法
bf.info()
Data ranges:0x00000000 - 0x00000003 (3 bytes)0x00000007 - 0x00000009 (2 bytes)
用segments
可以查看里面的每个数据段内容
for seg in bf.segments: print(seg)
Segment(address=0, data=bytearray(b'emb'))
Segment(address=7, data=bytearray(b'd_'))
所有的segment又可以切割成很小的chunks(size=32, alignment=1)
for chunk in bf.segments.chunks(1): print(chunk)
Chunk(address=0, data=bytearray(b'e'))
Chunk(address=1, data=bytearray(b'm'))
Chunk(address=2, data=bytearray(b'b'))
Chunk(address=7, data=bytearray(b'd'))
Chunk(address=8, data=bytearray(b'_'))