4

I have a class with all sorts of data in it, like:

class UARTMessage:
    Identification1 = int(0) #byte 0
    Timestamp1 = int(0) #bytes [1:5]
    Voltage1 = int(0) #bytes [6:7]
    Current1 = int(0) #bytes [8:9]
    Signal1= int(0) #bytes [10:11]
    Identification2 = int(0) #byte 12
    Timestamp2 = int(0) #bytes [13:17]
    Voltage2 = int(0) #bytes [18:19]
    Current2 = int(0) #bytes [20:21]
    Signal = int(0) #bytes [22:23]
    Identification3 = int(0) #byte 24   

The data to fill this structure up will come from a serial. I need to deserialize the data coming from the serial in the shape of this structure. I am reading from serial 40 bytes data chunks and I need to split itit. I tried pickle library but it seems that it's not fitted exactly for deserializing this type of data. I found struct but I cannot understand how to use it proprely in this case.
As the comments in the struct, I need to desearilize the chunks of data like: first byte is Identificator, bytes from 1 to 5 included is the timestamp and so on....
DO you have any ideea how can I achieve this?
Thanks

1
  • Are you sure that timestamp is 5 bytes long? It's easy to do with struct module, but 5 bytes doesn't correspond to any C data type. Commented Aug 8, 2016 at 15:49

1 Answer 1

7

First of all, we need to declare format of incoming bytes according to this list: https://docs.python.org/3/library/struct.html?highlight=struct#format-characters.

import struct
import sys


class UARTMessage:

    fmt = '@B5shhhB5shhhB'

    def __init__(self, data_bytes):
        fields = struct.unpack(self.fmt, data_bytes)
        (self.Identification1,
         self.Timestamp1,
         self.Voltage1,
         self.Current1,
         self.Signal1,
         self.Identification2,
         self.Timestamp2,
         self.Voltage2,
         self.Current2,
         self.Signal2,
         self.Identification3) = fields
        self.Timestamp1 = int.from_bytes(self.Timestamp1, sys.byteorder)
        self.Timestamp2 = int.from_bytes(self.Timestamp2, sys.byteorder)
        self.Timestamp3 = int.from_bytes(self.Timestamp3, sys.byteorder)

First character of the fmt is byte order. @ is python default (usually little endian), if you need to use network big-endian put !. Each subsequent character represents a data type which comes from the bytes stream.

Next, in the initializer, I unpack bytes according to the recipe in fmt into a fields tuple. Next, I assign the values of the tuple to object attributes. Timestamp has unusual length of 5 bytes, so it requires special treatment. It is fetched as 5-bytes string (5s in fmt) and converted to int using int.from_bytes function with system default bytes order (if you need a different bytes order enter 'big' or 'little' as a second argument).

When you want to create your structure, pass the sequence of bytes to the constructor.

Sign up to request clarification or add additional context in comments.

2 Comments

As described in docs.python.org/3/library/stdtypes.html int.from_bytes is only available in python 3.2. I am working with 2.7.
python 2 alternative to from_bytes is int(codecs.encode(b'\x00\x01', 'hex'), 16) (it's equivalent to little-endian order) stackoverflow.com/questions/30402743/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.