Axiohm A758 helper library for Python
Jacek Kowalski
2015-03-15 bd2ed9ce64cd942409e7e4b8ef415f7e58f4391e
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     
182     def setBarcodeHeight(self, width):
183         self.serial.write("\x1d\x68" + chr(width))
184     
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))
196     
197     # FEEDING
198     
199     def feedLines(self, lines = 1):
200         if lines < 0:
201             assert self.currentStation != self.STATION_SLIP, 'Receipt station cannot be reverse feed'
202             lines = -lines
203             self.serial.write("\x1d")
204         self.serial.write("\x14" + chr(lines))
205     
206     def feedDots(self, dots = 1):
207         if dots < 0:
208             assert self.currentStation != self.STATION_SLIP, 'Receipt station cannot be reverse feed'
209             dots = -dots
210             self.serial.write("\x1d")
211         
212         while(dots > 255):
213             self.serial.write("\x15\xff")
214             dots -= 255
215         
216         self.serial.write("\x15" + chr(dots))
217     
218     def feedInches(self, inches = 0.1):
219         if self.currentStation == self.STATION_SLIP:
220             self.feedDots(int(inches * 72))
221         else:
222             self.feedDots(int(inches * 203))
223     
224     def feedMilimeters(self, milimeters = 10):
225         if self.currentStation == self.STATION_SLIP:
226             self.feedDots(int(milimeters * 19 / 2.388))
227         else:
228             self.feedDots(int(milimeters * 7 / 2.47))
229     
230     # PRINT POSITION
231     
232     def moveAbsolute(self, dots):
233         self.serial.write("\x1b\x24" + chr(dots % 256) + chr(int(dots/256)))
234     
235     def moveAbsoluteInches(self, inches):
236         if self.currentStation == self.STATION_SLIP:
237             self.moveAbsolute(int(inches * 660 / 4.752))
238         else:
239             self.moveAbsolute(int(inches * 576 / 2.835))
240     
241     def moveAbsoluteMilimeters(self, milimeters):
242         if self.currentStation == self.STATION_SLIP:
243             self.moveAbsolute(int(milimeters * 660 / 120.7))
244         else:
245             self.moveAbsolute(int(milimeters * 576 / 72))
246     
247     def moveRelative(self, dots):
248         if dots < 0:
249             dots = 65536 + dots
250         self.serial.write("\x1b\x5c" + chr(dots % 256) + chr(int(dots/256)))
251     
252     def moveRelativeInches(self, inches):
253         if self.currentStation == self.STATION_SLIP:
254             self.moveRelative(int(inches * 660 / 4.752))
255         else:
256             self.moveRelative(int(inches * 576 / 2.835))
257     
258     def moveRelativeMilimeters(self, milimeters):
259         if self.currentStation == self.STATION_SLIP:
260             self.moveRelative(int(milimeters * 660 / 120.7))
261         else:
262             self.moveRelative(int(milimeters * 576 / 72))
263     
264     # PRINTING
265     
266     def printUnicode(self, line=""):
267         printData = ""
268         for char in line:
269             try:
270                 printData += char.encode(self.codepage_mapping[self.currentCodepage])
271             except ValueError:
272                 for codepage, encoding in self.codepage_mapping.iteritems():
273                     try:
274                         charEncoded = char.encode(encoding)
275                         self.currentCodepage = codepage
276                         printData += "\x1b\x52" + chr(codepage) + charEncoded
277                         break
278                     except ValueError:
279                         pass
280                 else:
281                     raise
282         self.printText(printData)
283     
284     def printText(self, lines):
285         self.serial.write(lines)
286     
287     def printLine(self, line=""):
288         self.printText(line + "\r\n")
289     
290     def printLineUnicode(self, line=""):
291         self.printUnicode(line + "\r\n")
292     
293     def printBarcode(self, type, data):
294         assert(type > 64)
295         self.serial.write("\x1d\x6b" + chr(type) + chr(len(data)) + data)
296     
297     def printLinesRotatedCCW(self, lines, startingPosition = 0):
298         maxLineLength = max([len(line) for line in lines])
299         lines = [line.ljust(maxLineLength, ' ') for line in lines]
300         
301         self.rotateCCW()
302         for column in xrange(maxLineLength-1, -1, -1):
303             if startingPosition != 0:
304                 self.moveAbsolute(startingPosition)
305             self.printLineUnicode(''.join([line[column] for line in lines]))
306     
307     # SLIP
308     
309     def waitForSlip(self):
310         self.serial.write("\x1b\x63\x30\x04")
311     
312     def ejectSlip(self):
313         self.serial.write("\x0c")