pythonsocketsraw-dataescpos

interpreting individual bits from ESC/POS status code


I admit, that this project I am working on, is not exactly a textbook example on how to make first steps with Python, but here I am.

The setup

an ESC/POS printer, locally connected (ethernet, socket) with RaspberryPi, that is remotely receiving print jobs (via an AMQP).

The issue

Connecting to AMQP broker and the printer as well as printing is working fine. What I am struggling with, is dealing with the printer status codes with ctypes.

When digging the Internet through, searching for the best approach, I came across a Python wiki article (link) regarding bit manipulation, where it was stated that for usage like mine, ctypes are recommended. It indeed seemed great and clean approach, so I immediately applied that to my code (below simplified version of it).

import socket
import ctypes

class PrinterStatus_bits( ctypes.LittleEndianStructure ):
    _fields_ = [
                ("fix0",        c_uint8, 1 ),  # asByte & 1
                ("fix1",        c_uint8, 1 ),  # asByte & 2
                ("drawer",      c_uint8, 1 ),  # asByte & 4
                ("offline",     c_uint8, 1 ),  # asByte & 8
                ("fix4",        c_uint8, 1 ),  # asByte & 16
                ("recovery",    c_uint8, 1 ),  # asByte & 32
                ("feed",        c_uint8, 1 ),  # asByte & 64
                ("fix7",        c_uint8, 1 ),  # asByte & 128
               ]

class Flags( ctypes.Union ):
    _anonymous_ = ("bit",)
    _fields_ = [
                ("bit",    PrinterStatus_bits),
                ("asByte", c_uint8           )
               ]


sock            = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address  = ('123.123.123.123', 9100)
c_uint8         = ctypes.c_uint8          
flags           = Flags()
msg             = b'\x10\x04\x01'

print('connecting to %s port %s' % server_address)
sock.connect(server_address)

print('requesting printer status')
sock.sendall(msg)
data           = sock.recv(1)
flags.asByte   = ord(data)

the 1 byte receive length is set consciously, as that is the fixed length of the response. The thing is, however, that this is only the first (of four), general status code.

I'd love to have all those status codes available via flags object, just don't know how to work with unions.

If I do something like:

class PrinterStatus_bits( ctypes.LittleEndianStructure ):
class PrinterOffline_bits( ctypes.LittleEndianStructure ):
class PrinterError_bits( ctypes.LittleEndianStructure ):
class PrinterPaper_bits( ctypes.LittleEndianStructure ):

class Flags( ctypes.Union ):
    _anonymous_ = ("status",)
    _fields_ = [
                ("status",   PrinterStatus_bits),
                ("offline",  PrinterOffline_bits),
                ("error",    PrinterError_bits),
                ("paper",    PrinterPaper_bits ),
                ("asByte",   c_uint8    )
               ]

how do I even assign proper values to corresponding classes?

p.s. all 4 status codes are always exactly 1 byte long

p.p.s I'm not hell bent on using ctypes and if it's not a valid approach in this case, I'd be fine with that and I'll just loop through all the 4 responses and assign those values to a 0/1 array, but my curiosity got better of me and I'd like to find out if it's even doable this way


Solution

  • You are way over complicating this.

    flags    = ord(data)
    drawer   = (flags & 4) != 0
    offline  = (flags & 8) != 0
    recovery = (flags & 32) != 0
    feed     = (flags & 64) != 0