from __future__ import division import serial class Axiohm: CODEPAGE_437 = 0 CODEPAGE_850 = 1 CODEPAGE_852 = 2 CODEPAGE_860 = 3 CODEPAGE_863 = 4 CODEPAGE_865 = 5 CODEPAGE_858 = 6 CODEPAGE_866 = 7 codepage_mapping = { CODEPAGE_437: 'cp437', CODEPAGE_850: 'cp850', CODEPAGE_852: 'cp852', CODEPAGE_860: 'cp860', CODEPAGE_863: 'cp863', CODEPAGE_865: 'cp865', CODEPAGE_866: 'cp866', } CUT_MODE_PARTIAL = 0 CUT_MODE_PARTIAL_FEED = 66 CUT_MODE_FULL = 1 CUT_MODE_FULL_FEED = 65 BARCODE_TEXT_NONE = 0 BARCODE_TEXT_ABOVE = 1 BARCODE_TEXT_BELOW = 2 BARCODE_TEXT_BOTH = 3 BARCODE_UPCA = 65 BARCODE_UPCE = 66 BARCODE_EAN13 = 67 BARCODE_EAN8 = 68 BARCODE_CODE39 = 69 BARCODE_INT2OF5 = 70 BARCODE_CODABAR = 71 BARCODE_CODE93 = 72 BARCODE_CODE128 = 73 BARCODE_PDF417 = 75 STATION_RECEIPT = 1 STATION_SLIP = 4 ALIGN_LEFT = 0 ALIGN_CENTER = 1 ALIGN_RIGHT = 2 PITCH_STANDARD = 0 PITCH_COMPRESSED = 1 def __init__(self, **kwargs): self.serial = serial.Serial(**kwargs) self.currentStation = self.STATION_RECEIPT self.currentCodepage = self.CODEPAGE_437 # CONTROL def beep(self): self.serial.write("\x1b\x07") def reset(self): self.currentStation = self.STATION_RECEIPT self.currentCodepage = self.CODEPAGE_437 self.serial.write("\x1b\x40") def selectReceipt(self): self.currentStation = self.STATION_RECEIPT self.serial.write("\x1e") def selectSlip(self): self.currentStation = self.STATION_SLIP self.serial.write("\x1c") def getStatus(self): self.serial.write("\x1b\x76") data = ord(self.serial.read(1)) return { 'receiptPaperLow': ((data & 0x01) != 0), 'receiptCoverOpen': ((data & 0x02) != 0), 'receiptPaperOut': ((data & 0x04) != 0), 'jam': ((data & 0x08) != 0), 'leadingEdge': ((data & 0x20) != 0), 'trailingEdge': ((data & 0x40) != 0), 'headOverheat': ((data & 0x80) != 0), } def getModel(self): self.serial.write("\x1d\x49\x01") model = ord(self.serial.read(1)) self.serial.write("\x1d\x49\x02") type = ord(self.serial.read(1)) knownModels = { 28: "Axiohm A758", 26: "Axiohm A756", } modelName = "Unknown" if model in knownModels: modelName = knownModels[model] return { 'model': model, 'modelName': modelName, 'twoByteCode': ((type & 0x01) != 0), 'knife': ((type & 0x02) != 0), 'micr': ((type & 0x08) != 0), } # CUTTING def cutMode(self, mode, offset=0): self.serial.write("\x1d\x56" + chr(mode)) if mode == 65 or mode == 66: self.serial.write(chr(offset)) def cutFeedFull(self): self.cutMode(Axiohm.CUT_MODE_FULL_FEED) def cutFeedPartial(self): self.cutMode(Axiohm.CUT_MODE_PARTIAL_FEED) def cutFull(self): self.serial.write("\x1b\x69") def cutPartial(self): self.serial.write("\x1b\x6d") def cut(self): self.cutFeedFull() # FORMATTING def clear(self): self.serial.write("\x10") def setDoubleWide(self): self.serial.write("\x12") def setSingleWide(self): self.serial.write("\x13") def setPitch(self, pitch = PITCH_STANDARD): self.serial.write("\x1b\x16" + chr(pitch)) def setCodePage(self, codepage): self.currentCodepage = codepage self.serial.write("\x1b\x52" + chr(codepage)) def rotateCCW(self): self.serial.write("\x1b\x12") def rotateCW(self): self.serial.write("\x1b\x56\x01") def upsideDown(self): self.serial.write("\x1b\x7b\x01") def align(self, alignment): assert self.currentStation != self.STATION_SLIP, 'Slip station prints cannot be aligned' self.serial.write("\x1b\x61" + chr(alignment)) def alignLeft(self): self.align(self.ALIGN_LEFT) def alignCenter(self): self.align(self.ALIGN_CENTER) def alignRight(self): self.align(self.ALIGN_RIGHT) def setBarcodeTextLocation(self, location = BARCODE_TEXT_NONE): self.serial.write("\x1d\x48" + chr(location)) def setBarcodeTextPitch(self, pitch = PITCH_STANDARD): self.serial.write("\x1d\x66" + chr(pitch)) def setBarcodeHeight(self, height): self.serial.write("\x1d\x68" + chr(height)) def setBarcodeHeightInches(self, inches = 1): if self.currentStation == self.STATION_SLIP: self.setBarcodeHeight(int(inches * 216)) else: self.setBarcodeHeight(int(inches * 203)) def setBarcodeHeightMilimeters(self, milimeters = 8.5): if self.currentStation == self.STATION_SLIP: self.setBarcodeHeight(int(milimeters / 8.5)) else: self.setBarcodeHeight(int(milimeters / 8)) def setBarcodeWidth(self, width): self.serial.write("\x1d\x77" + chr(width)) # FEEDING def feedLines(self, lines = 1): if lines < 0: assert self.currentStation != self.STATION_SLIP, 'Receipt station cannot be reverse feed' lines = -lines self.serial.write("\x1d") self.serial.write("\x14" + chr(lines)) def feedDots(self, dots = 1): if dots < 0: assert self.currentStation != self.STATION_SLIP, 'Receipt station cannot be reverse feed' dots = -dots self.serial.write("\x1d") while(dots > 255): self.serial.write("\x15\xff") dots -= 255 self.serial.write("\x15" + chr(dots)) def feedInches(self, inches = 0.1): if self.currentStation == self.STATION_SLIP: self.feedDots(int(inches * 72)) else: self.feedDots(int(inches * 203)) def feedMilimeters(self, milimeters = 10): if self.currentStation == self.STATION_SLIP: self.feedDots(int(milimeters * 19 / 2.388)) else: self.feedDots(int(milimeters * 7 / 2.47)) # PRINT POSITION def moveAbsolute(self, dots): self.serial.write("\x1b\x24" + chr(dots % 256) + chr(int(dots/256))) def moveAbsoluteInches(self, inches): if self.currentStation == self.STATION_SLIP: self.moveAbsolute(int(inches * 660 / 4.752)) else: self.moveAbsolute(int(inches * 576 / 2.835)) def moveAbsoluteMilimeters(self, milimeters): if self.currentStation == self.STATION_SLIP: self.moveAbsolute(int(milimeters * 660 / 120.7)) else: self.moveAbsolute(int(milimeters * 576 / 72)) def moveRelative(self, dots): if dots < 0: dots = 65536 + dots self.serial.write("\x1b\x5c" + chr(dots % 256) + chr(int(dots/256))) def moveRelativeInches(self, inches): if self.currentStation == self.STATION_SLIP: self.moveRelative(int(inches * 660 / 4.752)) else: self.moveRelative(int(inches * 576 / 2.835)) def moveRelativeMilimeters(self, milimeters): if self.currentStation == self.STATION_SLIP: self.moveRelative(int(milimeters * 660 / 120.7)) else: self.moveRelative(int(milimeters * 576 / 72)) # PRINTING def printUnicode(self, line=""): printData = "" for char in line: try: printData += char.encode(self.codepage_mapping[self.currentCodepage]) except ValueError: for codepage, encoding in self.codepage_mapping.iteritems(): try: charEncoded = char.encode(encoding) self.currentCodepage = codepage printData += "\x1b\x52" + chr(codepage) + charEncoded break except ValueError: pass else: raise self.printText(printData) def printText(self, lines): self.serial.write(lines) def printLine(self, line=""): self.printText(line + "\r\n") def printLineUnicode(self, line=""): self.printUnicode(line + "\r\n") def printBarcode(self, type, data): assert(type > 64) self.serial.write("\x1d\x6b" + chr(type) + chr(len(data)) + data) def printCode128(self, bytelist): assert 103 <= bytelist[0] <= 105 assert bytelist[1] < 103 checksum = bytelist[0] for i, item in enumerate(bytelist): checksum = (checksum + i*item) % 103 bytelist.append(checksum) self.printBarcode(self.BARCODE_CODE128, str(bytearray(bytelist))) def printLinesRotatedCCW(self, lines, startingPosition = 0): maxLineLength = max([len(line) for line in lines]) lines = [line.ljust(maxLineLength, ' ') for line in lines] self.rotateCCW() for column in xrange(maxLineLength-1, -1, -1): if startingPosition != 0: self.moveAbsolute(startingPosition) self.printLineUnicode(''.join([line[column] for line in lines])) # SLIP def waitForSlip(self): self.serial.write("\x1b\x63\x30\x04") def ejectSlip(self): self.serial.write("\x0c")