Working with binary data, S-records (long)

yaipa h. yaipa at yahoo.com
Fri Mar 21 16:43:53 EST 2003


Hans-Joachim,

I amd looking at the PyTables modules for handing HDD binary sector
data.

http://groups.google.com/groups?dq=&hl=en&lr=&ie=UTF-8&group=comp.lang.python.announce&selm=mailman.1048090984.682.clpa-moderators%40python.org

Cheers,

-Alan 






"Hans-Joachim Widmaier" <hjwidmaier at web.de> wrote in message news:<pan.2003.03.20.18.58.24.448261 at web.de>...
> We have a program to download (Flash-)Eprom images to an embedded device.
> It reads the image data from a file in Motorola S-record format, augments
> the image with some device specific data and sends the thing via a serial
> port to the device, usually after downloading a small piece of software,
> a second-stage bootloader, first, in the same manner. This program is
> currently written in C and runs under Linux and in a DOS shell under older
> Windows versions. Over the years said program accumulated a lot of cruft
> and grew command line options like weed. Now my boss asked me to make a
> new version which offers a GUI and runs under Windows 2000, XP as well.
> Which is perfectly fine with me, 'cause after finding pyserial that'll be
> more like a fun job (I've already written a similar thing in Python that
> reads an ELF program file and downloads the needed section to another
> device - it worked in a few hours; a C version would have taken weeks to
> write and debug).
> 
> Time to get to the topic. Reading S-records in Python is not all that much
> fun (ok, it's neither in C). I've thought about doing it in C and
> returning a string, but that would lose the address information. And
> creating more complex python data types in C is something I've never done.
> And I don't want to compile under Windows. Thus I wrote a pure Python
> reader, which looks like (this is the whole class so far):
> --------------------------
> import operator
> 
> class SRecord:
>     def __init__(self, init=0xff, checkcs=True):
>         self.udata  = []
>         self.data   = []
>         self.tail   = {}
>         self.offset = 0
>         self.size   = 0
>         self.start  = None
>         self.comm   = []
>         self.init   = init
>         self.check  = checkcs
> 
>     def readrecord(self, line):
>         """Lese eine Zeile als S-Record und gebe Adresse, Daten und Prüfsumme zurück."""
>         type = line[:2]
>         data = [int(line[i:i + 2], 16) for i in range(2, len(line), 2)]
>         cs   = (reduce(operator.add, data) + 1) & 0xff  # Muß 0 ergeben
>         if type in ('S1', 'S9'):
>             adr = (data[1] << 8) + data[2]
>             fd  = 3
>         elif type in ('S2', 'S8'):
>             adr = (data[1] << 16) + (data[2] << 8) + data[3]
>             fd  = 4
>         elif type in ('S3', 'S7'):
>             adr = (long(data[0]) << 24) + (data[2] << 16) + (data[3] << 8) + data[4]
>             fd  = 5
>         elif type == 'S0':      # Kommentar
>             return 'C', 0, data[3:-1], cs
>         else:
>             raise ValueError, "Kein gültiger S-Record"
>         if type > 'S6':         # Startadresse
>             type = 'S'
>         else:                   # Daten
>             type = 'D'
>         return type, adr, data[fd:-1], cs
> 
>     def readrecords(self, records):
>         """Eine Liste (Zeilen) von S-Records lesen."""
>         recno = -1
>         for line in records:
>             recno += 1
>             line = line.rstrip()
>             type, adr, data, cs = self.readrecord(line)
>             if cs and self.checkcs:
>                 raise ValueError, "Prüfsummenfehler in Record %d" % recno
>             if type == 'D':
>                 self.udata.append((adr, data))
>             elif type == 'S':
>                 self.start = adr
>             else:
>                 self.comm.append("".join(map(chr, data)))
>         if not self.udata:
>             return
>         self.udata.sort()
>         loadr = self.udata[0][0]
>         hiadr = self.udata[-1][0] + len(self.udata[-1][1])
>         size  = hiadr - loadr
>         self.data = [self.init] * size
>         for adr, data in self.udata:
>             dlen  = len(data)
>             adr  -= loadr
>             self.data[adr:adr + dlen] = data
>         self.offset = loadr
>         self.size   = size
> 
> -----------------------
> On my development machine (1.7 GHz) it's reasonably fast with a file worth
> 100 KB. But I'm afraid it'll suck on our production machines, which run at
> 166 MHz (give or take some). I thought about using array, but it's lacking
> a method to create a big array without creating a list or string first.
> 
> Anyway, does anyone see a way to speed this up? I'm not going to inline
> readrecord(), as I don't care about 10 %. I'm asking if you see a real
> flaw in my algorithm.
> 
> <pipe-dreaming mode on>
> Whenever I play with binary data in Python, a dream of a mutable string
> data type crops up. Doing byte fiddling with strings is quite ok as long
> as the data is comparably small. But when the thing gets largish, the
> slicing, copying and reassembling are getting increasingly inelegant, not
> to say "un-pythonic." Even if that hypothetical mutable string type
> wouldn't be returned by read() and wouldn't be accepted by write(),
> conversion from and to normal immutable strings should be cheap.
> <pipe-dreaming mode off>
> 
> Hope you're not distracted by the german comments, and just presuming you
> know what S-records are,
> 
> Hans-Joachim




More information about the Python-list mailing list