Axiohm A758 helper library for Python
Jacek Kowalski
2016-05-03 bd81c147c5fcdcbddc70d2e768df6f19d781ad58
commit | author | age
bd2ed9 1 from __future__ import division
JK 2
3 import serial
4
5 class Axiohm:
6     CODEPAGE_437 = 0
7     CODEPAGE_850 = 1
8     CODEPAGE_852 = 2
9     CODEPAGE_860 = 3
10     CODEPAGE_863 = 4
11     CODEPAGE_865 = 5
12     CODEPAGE_858 = 6
13     CODEPAGE_866 = 7
14     
15     codepage_mapping = {
16         CODEPAGE_437: 'cp437',
17         CODEPAGE_850: 'cp850',
18         CODEPAGE_852: 'cp852',
19         CODEPAGE_860: 'cp860',
20         CODEPAGE_863: 'cp863',
21         CODEPAGE_865: 'cp865',
22         CODEPAGE_866: 'cp866',
23     }
24     
25     CUT_MODE_PARTIAL = 0
26     CUT_MODE_PARTIAL_FEED = 66
27     CUT_MODE_FULL = 1
28     CUT_MODE_FULL_FEED = 65
29     
30     BARCODE_TEXT_NONE = 0
31     BARCODE_TEXT_ABOVE = 1
32     BARCODE_TEXT_BELOW = 2
33     BARCODE_TEXT_BOTH = 3
34     
35     BARCODE_UPCA = 65
36     BARCODE_UPCE = 66
37     BARCODE_EAN13 = 67
38     BARCODE_EAN8 = 68
39     BARCODE_CODE39 = 69
40     BARCODE_INT2OF5 = 70
41     BARCODE_CODABAR = 71
42     BARCODE_CODE93 = 72
43     BARCODE_CODE128 = 73
44     BARCODE_PDF417 = 75
45     
46     STATION_RECEIPT = 1
47     STATION_SLIP = 4
48     
49     ALIGN_LEFT = 0
50     ALIGN_CENTER = 1
51     ALIGN_RIGHT = 2
52     
53     PITCH_STANDARD = 0
54     PITCH_COMPRESSED = 1
55     
56     def __init__(self, **kwargs):
57         self.serial = serial.Serial(**kwargs)
58         self.currentStation = self.STATION_RECEIPT
59         self.currentCodepage = self.CODEPAGE_437
60     
61     # CONTROL
62     
63     def beep(self):
64         self.serial.write("\x1b\x07")
65
66     def reset(self):
67         self.currentStation = self.STATION_RECEIPT
68         self.currentCodepage = self.CODEPAGE_437
69         self.serial.write("\x1b\x40")
70     
71     def selectReceipt(self):
72         self.currentStation = self.STATION_RECEIPT
73         self.serial.write("\x1e")
74     
75     def selectSlip(self):
76         self.currentStation = self.STATION_SLIP
77         self.serial.write("\x1c")
78
79     def getStatus(self):
80         self.serial.write("\x1b\x76")
81         data = ord(self.serial.read(1))
82         return {
83             'receiptPaperLow':  ((data & 0x01) != 0),
84             'receiptCoverOpen': ((data & 0x02) != 0),
85             'receiptPaperOut':  ((data & 0x04) != 0),
86             'jam':              ((data & 0x08) != 0),
87             'leadingEdge':      ((data & 0x20) != 0),
88             'trailingEdge':     ((data & 0x40) != 0),
89             'headOverheat':     ((data & 0x80) != 0),
90         }
91     
92     def getModel(self):
93         self.serial.write("\x1d\x49\x01")
94         model = ord(self.serial.read(1))
95         self.serial.write("\x1d\x49\x02")
96         type = ord(self.serial.read(1))
97         
98         knownModels = {
99             28: "Axiohm A758",
100             26: "Axiohm A756",
101         }
102         modelName = "Unknown"
103         if model in knownModels:
104             modelName = knownModels[model]
105         
106         return {
107             'model':       model,
108             'modelName':   modelName,
109             'twoByteCode': ((type & 0x01) != 0),
110             'knife':       ((type & 0x02) != 0),
111             'micr':        ((type & 0x08) != 0),
112         }
113     
114     # CUTTING
115     
116     def cutMode(self, mode, offset=0):
117         self.serial.write("\x1d\x56" + chr(mode))
118         if mode == 65 or mode == 66:
119             self.serial.write(chr(offset))
120     
121     def cutFeedFull(self):
122         self.cutMode(Axiohm.CUT_MODE_FULL_FEED)
123     
124     def cutFeedPartial(self):
125         self.cutMode(Axiohm.CUT_MODE_PARTIAL_FEED)
126     
127     def cutFull(self):
128         self.serial.write("\x1b\x69")
129     
130     def cutPartial(self):
131         self.serial.write("\x1b\x6d")
132     
133     def cut(self):
134         self.cutFeedFull()
135     
136     # FORMATTING
137     
138     def clear(self):
139         self.serial.write("\x10")
140     
141     def setDoubleWide(self):
142         self.serial.write("\x12")
143     
144     def setSingleWide(self):
145         self.serial.write("\x13")
146     
147     def setPitch(self, pitch = PITCH_STANDARD):
148         self.serial.write("\x1b\x16" + chr(pitch))
149     
150     def setCodePage(self, codepage):
151         self.currentCodepage = codepage
152         self.serial.write("\x1b\x52" + chr(codepage))
153     
154     def rotateCCW(self):
155         self.serial.write("\x1b\x12")
156     
157     def rotateCW(self):
158         self.serial.write("\x1b\x56\x01")
159     
160     def upsideDown(self):
161         self.serial.write("\x1b\x7b\x01")
162     
163     def align(self, alignment):
164         assert self.currentStation != self.STATION_SLIP, 'Slip station prints cannot be aligned'
165         self.serial.write("\x1b\x61" + chr(alignment))
166     
167     def alignLeft(self):
168         self.align(self.ALIGN_LEFT)
169     
170     def alignCenter(self):
171         self.align(self.ALIGN_CENTER)
172     
173     def alignRight(self):
174         self.align(self.ALIGN_RIGHT)
175     
176     def setBarcodeTextLocation(self, location = BARCODE_TEXT_NONE):
177         self.serial.write("\x1d\x48" + chr(location))
178     
179     def setBarcodeTextPitch(self, pitch = PITCH_STANDARD):
180         self.serial.write("\x1d\x66" + chr(pitch))
181     
a242be 182     def setBarcodeHeight(self, height):
JK 183         self.serial.write("\x1d\x68" + chr(height))
bd2ed9 184     
JK 185     def setBarcodeHeightInches(self, inches = 1):
186         if self.currentStation == self.STATION_SLIP:
187             self.setBarcodeHeight(int(inches * 216))
188         else:
189             self.setBarcodeHeight(int(inches * 203))
190     
191     def setBarcodeHeightMilimeters(self, milimeters = 8.5):
192         if self.currentStation == self.STATION_SLIP:
193             self.setBarcodeHeight(int(milimeters / 8.5))
194         else:
195             self.setBarcodeHeight(int(milimeters / 8))
a242be 196     
JK 197     def setBarcodeWidth(self, width):
198         self.serial.write("\x1d\x77" + chr(width))
bd2ed9 199     
JK 200     # FEEDING
201     
202     def feedLines(self, lines = 1):
203         if lines < 0:
204             assert self.currentStation != self.STATION_SLIP, 'Receipt station cannot be reverse feed'
205             lines = -lines
206             self.serial.write("\x1d")
207         self.serial.write("\x14" + chr(lines))
208     
209     def feedDots(self, dots = 1):
210         if dots < 0:
211             assert self.currentStation != self.STATION_SLIP, 'Receipt station cannot be reverse feed'
212             dots = -dots
213             self.serial.write("\x1d")
214         
215         while(dots > 255):
216             self.serial.write("\x15\xff")
217             dots -= 255
218         
219         self.serial.write("\x15" + chr(dots))
220     
221     def feedInches(self, inches = 0.1):
222         if self.currentStation == self.STATION_SLIP:
223             self.feedDots(int(inches * 72))
224         else:
225             self.feedDots(int(inches * 203))
226     
227     def feedMilimeters(self, milimeters = 10):
228         if self.currentStation == self.STATION_SLIP:
229             self.feedDots(int(milimeters * 19 / 2.388))
230         else:
231             self.feedDots(int(milimeters * 7 / 2.47))
232     
233     # PRINT POSITION
234     
bd81c1 235     def moveAbsolute(self, dots = 0):
bd2ed9 236         self.serial.write("\x1b\x24" + chr(dots % 256) + chr(int(dots/256)))
JK 237     
238     def moveAbsoluteInches(self, inches):
239         if self.currentStation == self.STATION_SLIP:
240             self.moveAbsolute(int(inches * 660 / 4.752))
241         else:
242             self.moveAbsolute(int(inches * 576 / 2.835))
243     
244     def moveAbsoluteMilimeters(self, milimeters):
245         if self.currentStation == self.STATION_SLIP:
246             self.moveAbsolute(int(milimeters * 660 / 120.7))
247         else:
248             self.moveAbsolute(int(milimeters * 576 / 72))
249     
250     def moveRelative(self, dots):
251         if dots < 0:
252             dots = 65536 + dots
bd81c1 253         
bd2ed9 254         self.serial.write("\x1b\x5c" + chr(dots % 256) + chr(int(dots/256)))
JK 255     
256     def moveRelativeInches(self, inches):
257         if self.currentStation == self.STATION_SLIP:
258             self.moveRelative(int(inches * 660 / 4.752))
259         else:
260             self.moveRelative(int(inches * 576 / 2.835))
261     
262     def moveRelativeMilimeters(self, milimeters):
263         if self.currentStation == self.STATION_SLIP:
264             self.moveRelative(int(milimeters * 660 / 120.7))
265         else:
266             self.moveRelative(int(milimeters * 576 / 72))
267     
bd81c1 268     def marginLeft(self, dots = 0):
JK 269         self.serial.write("\x1d\x4c" + chr(dots % 256) + chr(int(dots/256)))
270     
bd2ed9 271     # PRINTING
JK 272     
273     def printUnicode(self, line=""):
274         printData = ""
275         for char in line:
276             try:
277                 printData += char.encode(self.codepage_mapping[self.currentCodepage])
278             except ValueError:
279                 for codepage, encoding in self.codepage_mapping.iteritems():
280                     try:
281                         charEncoded = char.encode(encoding)
282                         self.currentCodepage = codepage
283                         printData += "\x1b\x52" + chr(codepage) + charEncoded
284                         break
285                     except ValueError:
286                         pass
287                 else:
288                     raise
289         self.printText(printData)
290     
291     def printText(self, lines):
292         self.serial.write(lines)
293     
294     def printLine(self, line=""):
295         self.printText(line + "\r\n")
296     
297     def printLineUnicode(self, line=""):
298         self.printUnicode(line + "\r\n")
299     
300     def printBarcode(self, type, data):
301         assert(type > 64)
302         self.serial.write("\x1d\x6b" + chr(type) + chr(len(data)) + data)
303     
a242be 304     def printCode128(self, bytelist):
JK 305         assert 103 <= bytelist[0] <= 105
306         assert bytelist[1] < 103
307         
308         checksum = bytelist[0]
309         for i, item in enumerate(bytelist):
310             checksum = (checksum + i*item) % 103
311         
312         bytelist.append(checksum)
313         self.printBarcode(self.BARCODE_CODE128, str(bytearray(bytelist)))
314     
bd2ed9 315     def printLinesRotatedCCW(self, lines, startingPosition = 0):
JK 316         maxLineLength = max([len(line) for line in lines])
317         lines = [line.ljust(maxLineLength, ' ') for line in lines]
318         
319         self.rotateCCW()
320         for column in xrange(maxLineLength-1, -1, -1):
321             if startingPosition != 0:
322                 self.moveAbsolute(startingPosition)
323             self.printLineUnicode(''.join([line[column] for line in lines]))
324     
325     # SLIP
326     
327     def waitForSlip(self):
328         self.serial.write("\x1b\x63\x30\x04")
329     
330     def ejectSlip(self):
331         self.serial.write("\x0c")