Coverage for pyilper/pilhp82162a.py: 86%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1#!/usr/bin/python3
2# -*- coding: utf-8 -*-
3# pyILPER 1.2.4 for Linux
4#
5# An emulator for virtual HP-IL devices for the PIL-Box
6# derived from ILPER 1.4.5 for Windows
7# Copyright (c) 2008-2013 Jean-Francois Garnier
8# C++ version (c) 2013 Christoph Gießelink
9# Python Version (c) 2015 Joachim Siebold
10# HP82162a printer emulation derived from the nonpareil emulator
11# (C) 1995, 2003, 2004, 2005, 2006, 2008 Eric Smith
12#
13# This program is free software; you can redistribute it and/or
14# modify it under the terms of the GNU General Public License
15# as published by the Free Software Foundation; either version 2
16# of the License, or (at your option) any later version.
17#
18# This program is distributed in the hope that it will be useful,
19# but WITHOUT ANY WARRANTY; without even the implied warranty of
20# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21# GNU General Public License for more details.
22#
23# You should have received a copy of the GNU General Public License
24# along with this program; if not, write to the Free Software
25# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26#
27# HP82162A virtual device classes ---------------------------------------------
28#
29# Changelog
30# 05.08.2017 jsi:
31# - initial version
32# 20.08.2017 jsi:
33# - fixed: papersize for pdf output not configurable
34# 21.08.2017 jsi:
35# - refactoring: new pdf printer class used
36# - store number of pdf columns in system configuration
37# - disable gui if device not enabled
38# 27.08.2017 jsi:
39# - removed redraw timer: not needed
40# - resize of printer tab now repositions everything correctly
41# 28.08.2017 jsi:
42# - remove alignments from GUI
43# - get papersize config parameter in constructor of tab widget
44# 03.09.2017 jsi
45# - register pildevice is now method of commobject
46# 16.09.2017 jsi
47# - added missing entries in ASCII character table
48# 19.09.2017 jsi
49# - use raw strings in re.findall
50# 19.09.2017 jsi
51# - use raw strings in re.findall
52# 24.09.2016 jsi
53# - added mouse wheel scrolling support
54# 02.12.2017 jsi
55# - on the fly reconfiguration of the pixelsize
56# - fix: keep scroll position on resize
57# 04.01.2018 jsi
58# - reconfigure log check box object
59# - flush log buffer
60# 16.01.2018 jsi
61# - adapt to cls_tabgeneric, implemented cascading config menu
62# 20.01.2018 jsi
63# - the pixel size is now a dual parameter
64# 28.01.2018 jsi
65# - set AutoDefault property of buttons to false
66# 29.01.2018 jsi
67# - shrink all parent widgets if the pixel size was changed
68# 22.02.2018 jsi
69# - disabled shrinking parent widgets becaus of errors on reconfiguration
70#
71import copy
72import queue
73import threading
74import re
75from PySide6 import QtCore, QtWidgets
76from .pilcore import UPDATE_TIMER, PDF_ORIENTATION_PORTRAIT
77from .pilconfig import PILCONFIG
78from .pilcharconv import charconv, CHARSET_HP41, CHARSET_ROMAN8
79from .pildevbase import cls_pildevbase
80from .pilwidgets import cls_tabgeneric, LogCheckboxWidget, T_INTEGER, O_DEFAULT
81from .pilpdf import cls_pdfprinter
82from .pilcore import HP82162A_LINEBUFFERSIZE
84#
85# constants --------------------------------------------------------------
86#
87PRINTER_CHARACTER_WIDTH_PIXELS= 7
88PRINTER_WIDTH_CHARS= 24
89PRINTER_WIDTH= (PRINTER_WIDTH_CHARS * PRINTER_CHARACTER_WIDTH_PIXELS)
90PRINTER_CHARACTER_HEIGHT_PIXELS= 13
91DISPLAY_LINE_SPACING=0
93PDF_LINES=70 # number of lines in pdf output
94PDF_MARGINS=50 # margins (top,bot,left,right) of pdf output
95PDF_MAX_COLS=3 # max number of columns in pdf output
96PDF_COLUMN_SPACING=80 # spacing between columns
97PDF_LINE_SPACING=0 # linespacing in (relative) pixel
99#
100# printer modeswitch
101#
102MODESWITCH_MAN=0
103MODESWITCH_TRACE=1
104MODESWITCH_NORM=2
106# HP-IL Status bits
107STA_SR= 64
108STA_MB= 32
109STA_MA= 16
110STA_ER= 8
111STA_PA= 4
112STA_PR= 2
113STA_LA= 1
115STA_EL= 128 << 8
116STA_ID= 64 << 8
117STA_BE= 32 << 8
118STA_EB= 16 << 8
119STA_RJ= 8 << 8
120STA_DW= 4 << 8
121STA_CO= 2 << 8
122STA_LC= 1 << 8
124# Printer status bits
125mode_8bit= 1
126mode_lowercase= 2
127mode_doublewide= 4
128mode_column= 8
129mode_rjust= 16
130mode_parse= 32
131mode_barcode= 64
132mode_inhibit_advance= 128
134#
135# printer buffer data types
136#
137type_char= 1
138type_column= 2
139type_barcode= 3
140type_format= 4
141type_skip= 5
143# GUI commands
144CMD_MAN= 0
145CMD_NORM= 1
146CMD_TRACE= 2
147CMD_PRINT_PRESSED= 3
148CMD_ADV_PRESSED= 4
149CMD_CLEAR= 5
150CMD_PRINT_RELEASED= 6
151CMD_ADV_RELEASED= 7
153# HPIL-Thread commands
154REMOTECMD_CLEAR=0
155REMOTECMD_PRINT=1
156REMOTECMD_LOG=2
158#
159# charsets
160#
161CHARSET_ASCII=0
162CHARSET_ALTERNATE=1
163#
164# hp82162a character generator -------------------------------------------------
165# character codes taken from the nonpareil calculator simulator
166# (C) Eric Smith
167#
169class hp82162a_char(object):
171 def __init__(self):
172 super().__init__()
173#
174# ASCII charset
175#
176 self.ac= { }
177 self.ac[0x00] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
178 self.ac[0x01] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
179 self.ac[0x02] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
180 self.ac[0x03] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
181 self.ac[0x04] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
182 self.ac[0x05] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
183 self.ac[0x06] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
184 self.ac[0x07] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
185 self.ac[0x08] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
186 self.ac[0x09] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
187 self.ac[0x0a] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
188 self.ac[0x0b] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
189 self.ac[0x0c] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
190 self.ac[0x0d] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
191 self.ac[0x0e] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
192 self.ac[0x0f] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
193 self.ac[0x10] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
194 self.ac[0x11] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
195 self.ac[0x12] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
196 self.ac[0x13] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
197 self.ac[0x14] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
198 self.ac[0x15] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
199 self.ac[0x16] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
200 self.ac[0x17] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
201 self.ac[0x18] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
202 self.ac[0x19] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
203 self.ac[0x1A] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
204 self.ac[0x1B] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
205 self.ac[0x1C] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
206 self.ac[0x1D] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
207 self.ac[0x1E] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
208 self.ac[0x1F] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ])
209 self.ac[0x20] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ]) # space
210 self.ac[0x21] = bytes([ 0x00, 0x00, 0x5f, 0x00, 0x00 ]) # bang
211 self.ac[0x22] = bytes([ 0x00, 0x03, 0x00, 0x03, 0x00 ]) # double quote
212 self.ac[0x23] = bytes([ 0x14, 0x7f, 0x14, 0x7f, 0x14 ]) # hash (pound, octothorpe)
213 self.ac[0x24] = bytes([ 0x24, 0x2a, 0x7f, 0x2a, 0x12 ]) # dollar
214 self.ac[0x25] = bytes([ 0x23, 0x13, 0x08, 0x64, 0x62 ]) # percent
215 self.ac[0x26] = bytes([ 0x36, 0x49, 0x56, 0x20, 0x50 ]) # ampersand
216 self.ac[0x27] = bytes([ 0x00, 0x00, 0x03, 0x00, 0x00 ]) # single quote
217 self.ac[0x28] = bytes([ 0x00, 0x1c, 0x22, 0x41, 0x00 ]) # left parenthesis
218 self.ac[0x29] = bytes([ 0x00, 0x41, 0x22, 0x1c, 0x00 ]) # right parenthesis
219 self.ac[0x2a] = bytes([ 0x14, 0x08, 0x3e, 0x08, 0x14 ]) # asterisk
220 self.ac[0x2b] = bytes([ 0x08, 0x08, 0x3e, 0x08, 0x08 ]) # plus
221 self.ac[0x2c] = bytes([ 0x00, 0x40, 0x30, 0x00, 0x00 ]) # comma
222 self.ac[0x2d] = bytes([ 0x08, 0x08, 0x08, 0x08, 0x08 ]) # hyphen
223 self.ac[0x2e] = bytes([ 0x00, 0x60, 0x60, 0x00, 0x00 ]) # period
224 self.ac[0x2f] = bytes([ 0x20, 0x10, 0x08, 0x04, 0x02 ]) # slash
225 self.ac[0x30] = bytes([ 0x3e, 0x51, 0x49, 0x45, 0x3e ]) # zero
226 self.ac[0x31] = bytes([ 0x00, 0x42, 0x7f, 0x40, 0x00 ]) # one
227 self.ac[0x32] = bytes([ 0x62, 0x51, 0x49, 0x49, 0x46 ]) # two
228 self.ac[0x33] = bytes([ 0x21, 0x41, 0x49, 0x4d, 0x33 ]) # three
229 self.ac[0x34] = bytes([ 0x18, 0x14, 0x12, 0x7f, 0x10 ]) # four
230 self.ac[0x35] = bytes([ 0x27, 0x45, 0x45, 0x45, 0x39 ]) # five
231 self.ac[0x36] = bytes([ 0x3c, 0x4a, 0x49, 0x48, 0x30 ]) # six
232 self.ac[0x37] = bytes([ 0x01, 0x71, 0x09, 0x05, 0x03 ]) # seven
233 self.ac[0x38] = bytes([ 0x36, 0x49, 0x49, 0x49, 0x36 ]) # eight
234 self.ac[0x39] = bytes([ 0x06, 0x49, 0x49, 0x29, 0x1e ]) # nine
235 self.ac[0x3a] = bytes([ 0x00, 0x00, 0x24, 0x00, 0x00 ]) # colon
236 self.ac[0x3b] = bytes([ 0x00, 0x40, 0x34, 0x00, 0x00 ]) # semicolon
237 self.ac[0x3c] = bytes([ 0x08, 0x14, 0x22, 0x41, 0x00 ]) # less than
238 self.ac[0x3d] = bytes([ 0x14, 0x14, 0x14, 0x14, 0x14 ]) # equal
239 self.ac[0x3e] = bytes([ 0x00, 0x41, 0x22, 0x14, 0x08 ]) # greater than
240 self.ac[0x3f] = bytes([ 0x02, 0x01, 0x51, 0x09, 0x06 ]) # question mark
241 self.ac[0x40] = bytes([ 0x3e, 0x41, 0x5d, 0x5d, 0x1e ]) # at
242 self.ac[0x41] = bytes([ 0x7e, 0x11, 0x11, 0x11, 0x7e ]) # UC A
243 self.ac[0x42] = bytes([ 0x7f, 0x49, 0x49, 0x49, 0x36 ]) # UC B
244 self.ac[0x43] = bytes([ 0x3e, 0x41, 0x41, 0x41, 0x22 ]) # UC C
245 self.ac[0x44] = bytes([ 0x41, 0x7f, 0x41, 0x41, 0x3e ]) # UC D
246 self.ac[0x45] = bytes([ 0x7f, 0x49, 0x49, 0x49, 0x41 ]) # UC E
247 self.ac[0x46] = bytes([ 0x7f, 0x09, 0x09, 0x09, 0x01 ]) # UC F
248 self.ac[0x47] = bytes([ 0x3e, 0x41, 0x41, 0x51, 0x72 ]) # UC G
249 self.ac[0x48] = bytes([ 0x7f, 0x08, 0x08, 0x08, 0x7f ]) # UC H
250 self.ac[0x49] = bytes([ 0x00, 0x41, 0x7f, 0x41, 0x00 ]) # UC I
251 self.ac[0x4a] = bytes([ 0x20, 0x40, 0x40, 0x40, 0x3f ]) # UC J
252 self.ac[0x4b] = bytes([ 0x7f, 0x08, 0x14, 0x22, 0x41 ]) # UC K
253 self.ac[0x4c] = bytes([ 0x7f, 0x40, 0x40, 0x40, 0x40 ]) # UC L
254 self.ac[0x4d] = bytes([ 0x7f, 0x02, 0x0c, 0x02, 0x7f ]) # UC M
255 self.ac[0x4e] = bytes([ 0x7f, 0x04, 0x08, 0x10, 0x7f ]) # UC N
256 self.ac[0x4f] = bytes([ 0x3e, 0x41, 0x41, 0x41, 0x3e ]) # UC O
257 self.ac[0x50] = bytes([ 0x7f, 0x09, 0x09, 0x09, 0x06 ]) # UC P
258 self.ac[0x51] = bytes([ 0x3e, 0x41, 0x51, 0x21, 0x5e ]) # UC Q
259 self.ac[0x52] = bytes([ 0x7f, 0x09, 0x19, 0x29, 0x46 ]) # UC R
260 self.ac[0x53] = bytes([ 0x26, 0x49, 0x49, 0x49, 0x32 ]) # UC S
261 self.ac[0x54] = bytes([ 0x01, 0x01, 0x7f, 0x01, 0x01 ]) # UC T
262 self.ac[0x55] = bytes([ 0x3f, 0x40, 0x40, 0x40, 0x3f ]) # UC U
263 self.ac[0x56] = bytes([ 0x07, 0x18, 0x60, 0x18, 0x07 ]) # UC V
264 self.ac[0x57] = bytes([ 0x7f, 0x20, 0x18, 0x20, 0x7f ]) # UC W
265 self.ac[0x58] = bytes([ 0x63, 0x14, 0x08, 0x14, 0x63 ]) # UC X
266 self.ac[0x59] = bytes([ 0x03, 0x04, 0x78, 0x04, 0x03 ]) # UC Y
267 self.ac[0x5a] = bytes([ 0x61, 0x51, 0x49, 0x45, 0x43 ]) # UC Z
268 self.ac[0x5b] = bytes([ 0x00, 0x7f, 0x41, 0x41, 0x00 ]) # left bracket
269 self.ac[0x5c] = bytes([ 0x02, 0x04, 0x08, 0x10, 0x20 ]) # backslash
270 self.ac[0x5d] = bytes([ 0x00, 0x41, 0x41, 0x7f, 0x00 ]) # right bracket
271 self.ac[0x5e] = bytes([ 0x04, 0x02, 0x01, 0x02, 0x04 ]) # ^
272 self.ac[0x5f] = bytes([ 0x40, 0x40, 0x40, 0x40, 0x40 ]) # underscore
273 self.ac[0x60] = bytes([ 0x00, 0x01, 0x02, 0x04, 0x00 ]) # `
274 self.ac[0x61] = bytes([ 0x20, 0x54, 0x54, 0x54, 0x78 ]) # LC a
275 self.ac[0x62] = bytes([ 0x7f, 0x48, 0x44, 0x44, 0x38 ]) # LC b
276 self.ac[0x63] = bytes([ 0x38, 0x44, 0x44, 0x44, 0x20 ]) # LC c
277 self.ac[0x64] = bytes([ 0x38, 0x44, 0x44, 0x48, 0x7f ]) # LC d
278 self.ac[0x65] = bytes([ 0x38, 0x54, 0x54, 0x54, 0x08 ]) # LC e
279 self.ac[0x66] = bytes([ 0x08, 0x7c, 0x0a, 0x01, 0x02 ]) # LC f
280 self.ac[0x67] = bytes([ 0x08, 0x14, 0x54, 0x54, 0x38 ]) # LC g
281 self.ac[0x68] = bytes([ 0x7f, 0x10, 0x08, 0x08, 0x70 ]) # LC h
282 self.ac[0x69] = bytes([ 0x00, 0x44, 0x7d, 0x40, 0x00 ]) # LC i
283 self.ac[0x6a] = bytes([ 0x20, 0x40, 0x40, 0x3d, 0x00 ]) # LC j
284 self.ac[0x6b] = bytes([ 0x00, 0x7f, 0x28, 0x44, 0x00 ]) # LC k
285 self.ac[0x6c] = bytes([ 0x00, 0x41, 0x7f, 0x40, 0x00 ]) # LC l
286 self.ac[0x6d] = bytes([ 0x78, 0x04, 0x18, 0x04, 0x78 ]) # LC m
287 self.ac[0x6e] = bytes([ 0x7c, 0x08, 0x04, 0x04, 0x78 ]) # LC n
288 self.ac[0x6f] = bytes([ 0x38, 0x44, 0x44, 0x44, 0x38 ]) # LC o
289 self.ac[0x70] = bytes([ 0x7c, 0x14, 0x24, 0x24, 0x18 ]) # LC p
290 self.ac[0x71] = bytes([ 0x18, 0x24, 0x24, 0x7c, 0x40 ]) # LC q
291 self.ac[0x72] = bytes([ 0x7c, 0x08, 0x04, 0x04, 0x08 ]) # LC r
292 self.ac[0x73] = bytes([ 0x48, 0x54, 0x54, 0x54, 0x24 ]) # LC s
293 self.ac[0x74] = bytes([ 0x04, 0x3e, 0x44, 0x20, 0x00 ]) # LC t
294 self.ac[0x75] = bytes([ 0x3c, 0x40, 0x40, 0x20, 0x7c ]) # LC u
295 self.ac[0x76] = bytes([ 0x1c, 0x20, 0x40, 0x20, 0x1c ]) # LC v
296 self.ac[0x77] = bytes([ 0x3c, 0x40, 0x30, 0x40, 0x3c ]) # LC w
297 self.ac[0x78] = bytes([ 0x44, 0x28, 0x10, 0x28, 0x44 ]) # LC x
298 self.ac[0x79] = bytes([ 0x44, 0x28, 0x10, 0x08, 0x04 ]) # LC y
299 self.ac[0x7a] = bytes([ 0x44, 0x64, 0x54, 0x4c, 0x44 ]) # LC z
300 self.ac[0x7b] = bytes([ 0x00, 0x08, 0x36, 0x41, 0x00 ]) # {
301 self.ac[0x7c] = bytes([ 0x00, 0x00, 0x7f, 0x00, 0x00 ]) # |
302 self.ac[0x7d] = bytes([ 0x00, 0x41, 0x36, 0x08, 0x00 ]) #
303 self.ac[0x7e] = bytes([ 0x02, 0x01, 0x02, 0x04, 0x02 ]) # ~
304 self.ac[0x7f] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ]) #
306#
307# alternate characterset
308#
309 self.hc= { }
310 self.hc[0x00] = bytes([ 0x08, 0x1c, 0x3e, 0x1c, 0x08 ]) # diamond
311 self.hc[0x01] = bytes([ 0x00, 0x14, 0x08, 0x14, 0x00 ]) # small x
312 self.hc[0x02] = bytes([ 0x44, 0x29, 0x11, 0x29, 0x44 ]) # x-bar
313 self.hc[0x03] = bytes([ 0x08, 0x1c, 0x2a, 0x08, 0x08 ]) # left arrow
314 self.hc[0x04] = bytes([ 0x38, 0x44, 0x44, 0x38, 0x44 ]) # LC alpha
315 self.hc[0x05] = bytes([ 0x7e, 0x15, 0x25, 0x25, 0x1a ]) # UC beta
316 self.hc[0x06] = bytes([ 0x7f, 0x01, 0x01, 0x01, 0x03 ]) # UC gamma
317 self.hc[0x07] = bytes([ 0x10, 0x30, 0x7f, 0x30, 0x10 ]) # down arrow
318 self.hc[0x08] = bytes([ 0x60, 0x18, 0x06, 0x18, 0x60 ]) # UC delta
319 self.hc[0x09] = bytes([ 0x38, 0x44, 0x44, 0x3c, 0x04 ]) # LC sigma
320 self.hc[0x0a] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ]) # nothing (LF)
321 self.hc[0x0b] = bytes([ 0x62, 0x14, 0x08, 0x10, 0x60 ]) # LC lambda
322 self.hc[0x0c] = bytes([ 0x40, 0x3c, 0x20, 0x20, 0x1c ]) # LC mu
323 self.hc[0x0d] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ]) # nothing (CR)
324 self.hc[0x0e] = bytes([ 0x10, 0x18, 0x78, 0x04, 0x02 ]) # LC tau
325 self.hc[0x0f] = bytes([ 0x08, 0x55, 0x77, 0x55, 0x08 ]) # UC phi
326 self.hc[0x10] = bytes([ 0x3e, 0x49, 0x49, 0x49, 0x3e ]) # UC theta
327 self.hc[0x11] = bytes([ 0x5e, 0x61, 0x01, 0x61, 0x5e ]) # UC omega
328 self.hc[0x12] = bytes([ 0x30, 0x4a, 0x4d, 0x49, 0x30 ]) # LC delta
329 self.hc[0x13] = bytes([ 0x78, 0x14, 0x15, 0x14, 0x78 ]) # UC A dot
330 self.hc[0x14] = bytes([ 0x38, 0x44, 0x45, 0x3e, 0x44 ]) # LC a dot
331 self.hc[0x15] = bytes([ 0x78, 0x15, 0x14, 0x15, 0x78 ]) # UC A umlaut
332 self.hc[0x16] = bytes([ 0x38, 0x45, 0x44, 0x7d, 0x40 ]) # LC a umlaut
333 self.hc[0x17] = bytes([ 0x3c, 0x43, 0x42, 0x43, 0x3c ]) # UC O umlaut
334 self.hc[0x18] = bytes([ 0x38, 0x45, 0x44, 0x45, 0x38 ]) # LC o umlaut
335 self.hc[0x19] = bytes([ 0x3e, 0x41, 0x40, 0x41, 0x3e ]) # UC U umlaut
336 self.hc[0x1a] = bytes([ 0x3c, 0x41, 0x40, 0x41, 0x3c ]) # LC u umlaut
337 self.hc[0x1b] = bytes([ 0x7e, 0x09, 0x7f, 0x49, 0x49 ]) # UC AE
338 self.hc[0x1c] = bytes([ 0x38, 0x44, 0x38, 0x54, 0x58 ]) # LC ae
339 self.hc[0x1d] = bytes([ 0x14, 0x34, 0x1c, 0x16, 0x14 ]) # not equal
340 self.hc[0x1e] = bytes([ 0x48, 0x7e, 0x49, 0x41, 0x22 ]) # pound sterling
341 self.hc[0x1f] = bytes([ 0x55, 0x2a, 0x55, 0x2a, 0x55 ]) # ?
342 self.hc[0x20] = bytes([ 0x00, 0x00, 0x00, 0x00, 0x00 ]) # space
343 self.hc[0x21] = bytes([ 0x00, 0x00, 0x5f, 0x00, 0x00 ]) # bang
344 self.hc[0x22] = bytes([ 0x00, 0x03, 0x00, 0x03, 0x00 ]) # double quote
345 self.hc[0x23] = bytes([ 0x14, 0x7f, 0x14, 0x7f, 0x14 ]) # hash (pound, octothorpe)
346 self.hc[0x24] = bytes([ 0x24, 0x2a, 0x7f, 0x2a, 0x12 ]) # dollar
347 self.hc[0x25] = bytes([ 0x23, 0x13, 0x08, 0x64, 0x62 ]) # percent
348 self.hc[0x26] = bytes([ 0x36, 0x49, 0x56, 0x20, 0x50 ]) # ampersand
349 self.hc[0x27] = bytes([ 0x00, 0x00, 0x03, 0x00, 0x00 ]) # single quote
350 self.hc[0x28] = bytes([ 0x00, 0x1c, 0x22, 0x41, 0x00 ]) # left parenthesis
351 self.hc[0x29] = bytes([ 0x00, 0x41, 0x22, 0x1c, 0x00 ]) # right parenthesis
352 self.hc[0x2a] = bytes([ 0x14, 0x08, 0x3e, 0x08, 0x14 ]) # asterisk
353 self.hc[0x2b] = bytes([ 0x08, 0x08, 0x3e, 0x08, 0x08 ]) # plus
354 self.hc[0x2c] = bytes([ 0x00, 0x40, 0x30, 0x00, 0x00 ]) # comma
355 self.hc[0x2d] = bytes([ 0x08, 0x08, 0x08, 0x08, 0x08 ]) # hyphen
356 self.hc[0x2e] = bytes([ 0x00, 0x60, 0x60, 0x00, 0x00 ]) # period
357 self.hc[0x2f] = bytes([ 0x20, 0x10, 0x08, 0x04, 0x02 ]) # slash
358 self.hc[0x30] = bytes([ 0x3e, 0x51, 0x49, 0x45, 0x3e ]) # zero
359 self.hc[0x31] = bytes([ 0x00, 0x42, 0x7f, 0x40, 0x00 ]) # one
360 self.hc[0x32] = bytes([ 0x62, 0x51, 0x49, 0x49, 0x46 ]) # two
361 self.hc[0x33] = bytes([ 0x21, 0x41, 0x49, 0x4d, 0x33 ]) # three
362 self.hc[0x34] = bytes([ 0x18, 0x14, 0x12, 0x7f, 0x10 ]) # four
363 self.hc[0x35] = bytes([ 0x27, 0x45, 0x45, 0x45, 0x39 ]) # five
364 self.hc[0x36] = bytes([ 0x3c, 0x4a, 0x49, 0x48, 0x30 ]) # six
365 self.hc[0x37] = bytes([ 0x01, 0x71, 0x09, 0x05, 0x03 ]) # seven
366 self.hc[0x38] = bytes([ 0x36, 0x49, 0x49, 0x49, 0x36 ]) # eight
367 self.hc[0x39] = bytes([ 0x06, 0x49, 0x49, 0x29, 0x1e ]) # nine
368 self.hc[0x3a] = bytes([ 0x00, 0x00, 0x24, 0x00, 0x00 ]) # colon
369 self.hc[0x3b] = bytes([ 0x00, 0x40, 0x34, 0x00, 0x00 ]) # semicolon
370 self.hc[0x3c] = bytes([ 0x08, 0x14, 0x22, 0x41, 0x00 ]) # less than
371 self.hc[0x3d] = bytes([ 0x14, 0x14, 0x14, 0x14, 0x14 ]) # equal
372 self.hc[0x3e] = bytes([ 0x00, 0x41, 0x22, 0x14, 0x08 ]) # greater than
373 self.hc[0x3f] = bytes([ 0x02, 0x01, 0x51, 0x09, 0x06 ]) # question mark
374 self.hc[0x40] = bytes([ 0x3e, 0x41, 0x5d, 0x5d, 0x1e ]) # at
375 self.hc[0x41] = bytes([ 0x7e, 0x11, 0x11, 0x11, 0x7e ]) # UC A
376 self.hc[0x42] = bytes([ 0x7f, 0x49, 0x49, 0x49, 0x36 ]) # UC B
377 self.hc[0x43] = bytes([ 0x3e, 0x41, 0x41, 0x41, 0x22 ]) # UC C
378 self.hc[0x44] = bytes([ 0x41, 0x7f, 0x41, 0x41, 0x3e ]) # UC D
379 self.hc[0x45] = bytes([ 0x7f, 0x49, 0x49, 0x49, 0x41 ]) # UC E
380 self.hc[0x46] = bytes([ 0x7f, 0x09, 0x09, 0x09, 0x01 ]) # UC F
381 self.hc[0x47] = bytes([ 0x3e, 0x41, 0x41, 0x51, 0x72 ]) # UC G
382 self.hc[0x48] = bytes([ 0x7f, 0x08, 0x08, 0x08, 0x7f ]) # UC H
383 self.hc[0x49] = bytes([ 0x00, 0x41, 0x7f, 0x41, 0x00 ]) # UC I
384 self.hc[0x4a] = bytes([ 0x20, 0x40, 0x40, 0x40, 0x3f ]) # UC J
385 self.hc[0x4b] = bytes([ 0x7f, 0x08, 0x14, 0x22, 0x41 ]) # UC K
386 self.hc[0x4c] = bytes([ 0x7f, 0x40, 0x40, 0x40, 0x40 ]) # UC L
387 self.hc[0x4d] = bytes([ 0x7f, 0x02, 0x0c, 0x02, 0x7f ]) # UC M
388 self.hc[0x4e] = bytes([ 0x7f, 0x04, 0x08, 0x10, 0x7f ]) # UC N
389 self.hc[0x4f] = bytes([ 0x3e, 0x41, 0x41, 0x41, 0x3e ]) # UC O
390 self.hc[0x50] = bytes([ 0x7f, 0x09, 0x09, 0x09, 0x06 ]) # UC P
391 self.hc[0x51] = bytes([ 0x3e, 0x41, 0x51, 0x21, 0x5e ]) # UC Q
392 self.hc[0x52] = bytes([ 0x7f, 0x09, 0x19, 0x29, 0x46 ]) # UC R
393 self.hc[0x53] = bytes([ 0x26, 0x49, 0x49, 0x49, 0x32 ]) # UC S
394 self.hc[0x54] = bytes([ 0x01, 0x01, 0x7f, 0x01, 0x01 ]) # UC T
395 self.hc[0x55] = bytes([ 0x3f, 0x40, 0x40, 0x40, 0x3f ]) # UC U
396 self.hc[0x56] = bytes([ 0x07, 0x18, 0x60, 0x18, 0x07 ]) # UC V
397 self.hc[0x57] = bytes([ 0x7f, 0x20, 0x18, 0x20, 0x7f ]) # UC W
398 self.hc[0x58] = bytes([ 0x63, 0x14, 0x08, 0x14, 0x63 ]) # UC X
399 self.hc[0x59] = bytes([ 0x03, 0x04, 0x78, 0x04, 0x03 ]) # UC Y
400 self.hc[0x5a] = bytes([ 0x61, 0x51, 0x49, 0x45, 0x43 ]) # UC Z
401 self.hc[0x5b] = bytes([ 0x00, 0x7f, 0x41, 0x41, 0x00 ]) # left bracket
402 self.hc[0x5c] = bytes([ 0x02, 0x04, 0x08, 0x10, 0x20 ]) # backslash
403 self.hc[0x5d] = bytes([ 0x00, 0x41, 0x41, 0x7f, 0x00 ]) # right bracket
404 self.hc[0x5e] = bytes([ 0x04, 0x02, 0x7f, 0x02, 0x04 ]) # up arrow
405 self.hc[0x5f] = bytes([ 0x40, 0x40, 0x40, 0x40, 0x40 ]) # underscore
406 self.hc[0x60] = bytes([ 0x00, 0x01, 0x07, 0x01, 0x00 ]) # superscript T
407 self.hc[0x61] = bytes([ 0x20, 0x54, 0x54, 0x54, 0x78 ]) # LC a
408 self.hc[0x62] = bytes([ 0x7f, 0x48, 0x44, 0x44, 0x38 ]) # LC b
409 self.hc[0x63] = bytes([ 0x38, 0x44, 0x44, 0x44, 0x20 ]) # LC c
410 self.hc[0x64] = bytes([ 0x38, 0x44, 0x44, 0x48, 0x7f ]) # LC d
411 self.hc[0x65] = bytes([ 0x38, 0x54, 0x54, 0x54, 0x08 ]) # LC e
412 self.hc[0x66] = bytes([ 0x08, 0x7c, 0x0a, 0x01, 0x02 ]) # LC f
413 self.hc[0x67] = bytes([ 0x08, 0x14, 0x54, 0x54, 0x38 ]) # LC g
414 self.hc[0x68] = bytes([ 0x7f, 0x10, 0x08, 0x08, 0x70 ]) # LC h
415 self.hc[0x69] = bytes([ 0x00, 0x44, 0x7d, 0x40, 0x00 ]) # LC i
416 self.hc[0x6a] = bytes([ 0x20, 0x40, 0x40, 0x3d, 0x00 ]) # LC j
417 self.hc[0x6b] = bytes([ 0x00, 0x7f, 0x28, 0x44, 0x00 ]) # LC k
418 self.hc[0x6c] = bytes([ 0x00, 0x41, 0x7f, 0x40, 0x00 ]) # LC l
419 self.hc[0x6d] = bytes([ 0x78, 0x04, 0x18, 0x04, 0x78 ]) # LC m
420 self.hc[0x6e] = bytes([ 0x7c, 0x08, 0x04, 0x04, 0x78 ]) # LC n
421 self.hc[0x6f] = bytes([ 0x38, 0x44, 0x44, 0x44, 0x38 ]) # LC o
422 self.hc[0x70] = bytes([ 0x7c, 0x14, 0x24, 0x24, 0x18 ]) # LC p
423 self.hc[0x71] = bytes([ 0x18, 0x24, 0x24, 0x7c, 0x40 ]) # LC q
424 self.hc[0x72] = bytes([ 0x7c, 0x08, 0x04, 0x04, 0x08 ]) # LC r
425 self.hc[0x73] = bytes([ 0x48, 0x54, 0x54, 0x54, 0x24 ]) # LC s
426 self.hc[0x74] = bytes([ 0x04, 0x3e, 0x44, 0x20, 0x00 ]) # LC t
427 self.hc[0x75] = bytes([ 0x3c, 0x40, 0x40, 0x20, 0x7c ]) # LC u
428 self.hc[0x76] = bytes([ 0x1c, 0x20, 0x40, 0x20, 0x1c ]) # LC v
429 self.hc[0x77] = bytes([ 0x3c, 0x40, 0x30, 0x40, 0x3c ]) # LC w
430 self.hc[0x78] = bytes([ 0x44, 0x28, 0x10, 0x28, 0x44 ]) # LC x
431 self.hc[0x79] = bytes([ 0x44, 0x28, 0x10, 0x08, 0x04 ]) # LC y
432 self.hc[0x7a] = bytes([ 0x44, 0x64, 0x54, 0x4c, 0x44 ]) # LC z
433 self.hc[0x7b] = bytes([ 0x08, 0x78, 0x08, 0x78, 0x04 ]) # LC pi
434 self.hc[0x7c] = bytes([ 0x60, 0x50, 0x58, 0x64, 0x42 ]) # angle
435 self.hc[0x7d] = bytes([ 0x08, 0x08, 0x2a, 0x1c, 0x08 ]) # right arrow
436 self.hc[0x7e] = bytes([ 0x63, 0x55, 0x49, 0x41, 0x63 ]) # UC sigma
437 self.hc[0x7f] = bytes([ 0x7f, 0x08, 0x08, 0x08, 0x08 ]) # lazy T
438 self.charset= CHARSET_ASCII
440 def set_charset(self,c):
441 self.charset=c
443 def get(self,c,i):
444 if self.charset== CHARSET_ASCII:
445 return self.ac[c][i]
446 else:
447 return self.hc[c][i]
448#
449# HP82162A tab widget ---------------------------------------------------------
450#
451class cls_tabhp82162a(cls_tabgeneric):
454 def __init__(self,parent,name):
455 super().__init__(parent,name)
456 self.name=name
457#
458# this parameter is global
459#
460 self.papersize=PILCONFIG.get("pyilper","papersize")
461#
462# init local parameter
463#
464 self.pixelsize=PILCONFIG.get(self.name,"hp82162a_pixelsize",-1)
465#
466# create Printer GUI object
467#
468 self.guiobject=cls_HP82162AWidget(self,self.name,self.papersize)
469#
470# add gui object
471#
472 self.add_guiobject(self.guiobject)
473#
474# add cascading config menu
475#
476 self.add_configwidget()
477#
478# add local config option
479#
480 self.cBut.add_option("Pixel size","hp82162a_pixelsize",T_INTEGER,[O_DEFAULT,1,2])
481#
482# add logging control widget
483#
484 self.add_logging()
485#
486# create IL-Interface object, notify printer processor object
487#
488 self.pildevice= cls_pilhp82162a(self.guiobject)
489 self.guiobject.set_pildevice(self.pildevice)
490 self.cBut.config_changed_signal.connect(self.do_tabconfig_changed)
491#
492# handle changes of tab config options
493#
494 def do_tabconfig_changed(self):
495 self.loglevel= PILCONFIG.get(self.name,"loglevel",0)
496 self.guiobject.reconfigure()
497 super().do_tabconfig_changed()
498#
499# reconfigure: reconfigure the gui object
500#
501 def reconfigure(self):
502 self.guiobject.reconfigure()
503#
504# enable pildevice and gui object
505#
506 def enable(self):
507 super().enable()
508 self.parent.commthread.register(self.pildevice,self.name)
509 self.pildevice.setactive(self.active)
510 self.pildevice.enable()
511 self.guiobject.enable()
512#
513# disable pildevice and gui object
514#
515 def disable(self):
516 self.pildevice.disable()
517 self.guiobject.disable()
518 super().disable()
519#
520# active/inactive: enable/disable GUI controls
521#
522 def toggle_active(self):
523 super().toggle_active()
524 self.guiobject.toggle_active()
525#
526# becomes visible, refresh content, activate update
527#
528 def becomes_visible(self):
529 self.guiobject.becomes_visible()
530 return
531#
532# becomes invisible, deactivate update
533#
534 def becomes_invisible(self):
535 self.guiobject.becomes_invisible()
536 return
537#
538#
539# HP82162A widget classes - GUI component of the HP82162A HP-IL printer
540#
541class cls_HP82162AWidget(QtWidgets.QWidget):
543 def __init__(self,parent,name,papersize):
544 super().__init__()
545 self.name= name
546 self.parent= parent
547 self.papersize= papersize
548 self.pildevice= None
549#
550# configuration
551#
552 self.pdfpixelsize=3
553 self.pixelsize=PILCONFIG.get_dual(self.name,"hp82162a_pixelsize")
554 self.linebuffersize=HP82162A_LINEBUFFERSIZE
555 self.printer_modeswitch= PILCONFIG.get(self.name,"modeswitch",MODESWITCH_MAN)
556#
557# create user interface of printer widget
558#
559 self.hbox=QtWidgets.QHBoxLayout()
560 self.hbox.addStretch(1)
561#
562# scrolled printer view
563#
564 self.printview=cls_ScrolledHP82162AView(self,self.name,self.pixelsize, self.pdfpixelsize,self.papersize,self.linebuffersize)
565 self.hbox.addWidget(self.printview)
566 self.vbox=QtWidgets.QVBoxLayout()
567#
568# radio buttons Man, Norm, Trace
569#
570 self.gbox= QtWidgets.QGroupBox()
571 self.gbox.setFlat(True)
572 self.gbox.setTitle("Printer mode")
573 self.vboxgbox= QtWidgets.QVBoxLayout()
574 self.gbox.setLayout(self.vboxgbox)
575#
576# Man Mode
577#
578 self.radbutMan= QtWidgets.QRadioButton(self.gbox)
579 self.radbutMan.setEnabled(False)
580 self.radbutMan.setText("Man")
581 self.radbutMan.toggled.connect(self.toggledCheckBoxes)
582 self.vboxgbox.addWidget(self.radbutMan)
583#
584# Trace Mode
585#
586 self.radbutTrace= QtWidgets.QRadioButton(self.gbox)
587 self.radbutTrace.setEnabled(False)
588 self.radbutTrace.setText("Trace")
589 self.radbutTrace.toggled.connect(self.toggledCheckBoxes)
590 self.vboxgbox.addWidget(self.radbutTrace)
591#
592# Norm Mode
593#
594 self.radbutNorm= QtWidgets.QRadioButton(self.gbox)
595 self.radbutNorm.setEnabled(False)
596 self.radbutNorm.setText("Norm")
597 self.radbutNorm.toggled.connect(self.toggledCheckBoxes)
598 self.vboxgbox.addWidget(self.radbutNorm)
600 self.vbox.addWidget(self.gbox)
601#
602# Clear Button
603#
604 self.clearButton= QtWidgets.QPushButton("Clear")
605 self.clearButton.setEnabled(False)
606 self.clearButton.setAutoDefault(False)
607 self.vbox.addWidget(self.clearButton)
608 self.clearButton.clicked.connect(self.do_clear)
609#
610# Print Button
611#
612 self.printButton= QtWidgets.QPushButton("Print")
613 self.printButton.setEnabled(False)
614 self.printButton.setAutoDefault(False)
615 self.vbox.addWidget(self.printButton)
616 self.printButton.pressed.connect(self.do_print_pressed)
617 self.printButton.released.connect(self.do_print_released)
618#
619# Paper Advance Button
620#
621 self.advanceButton= QtWidgets.QPushButton("Advance")
622 self.advanceButton.setEnabled(False)
623 self.advanceButton.setAutoDefault(False)
624 self.vbox.addWidget(self.advanceButton)
625 self.advanceButton.pressed.connect(self.do_advance_pressed)
626 self.advanceButton.released.connect(self.do_advance_released)
627#
628# PDF Button
629#
630 self.pdfButton= QtWidgets.QPushButton("PDF")
631 self.pdfButton.setEnabled(False)
632 self.pdfButton.setAutoDefault(False)
633 self.vbox.addWidget(self.pdfButton)
634 self.pdfButton.clicked.connect(self.do_pdf)
636 self.vbox.addStretch(1)
637 self.hbox.addLayout(self.vbox)
638 self.hbox.addStretch(1)
639 self.setLayout(self.hbox)
640#
641# initialize GUI command queue and lock
642#
643 self.gui_queue= queue.Queue()
644 self.gui_queue_lock= threading.Lock()
645#
646# initialize refresh timer
647#
648 self.UpdateTimer=QtCore.QTimer()
649 self.UpdateTimer.setSingleShot(True)
650 self.UpdateTimer.timeout.connect(self.process_queue)
651#
652# initialize timer for the repeated pressed advance button action
653#
654 self.repeatedAdvpressedTimer=QtCore.QTimer()
655 self.repeatedAdvpressedTimer.timeout.connect(self.repeated_advpressed)
656 self.repeatedAdvpressedTimer.setInterval(1500)
657#
658# set HP-IL device object
659#
660 def set_pildevice(self,pildevice):
661 self.pildevice=pildevice
662#
663# enable: start timer, send mode to virtual device, update check boxes
664#
665 def enable(self):
666 self.UpdateTimer.start(UPDATE_TIMER)
667 self.setCheckBoxes()
668 if self.printer_modeswitch== MODESWITCH_MAN:
669 self.pildevice.put_cmd(CMD_MAN)
670 if self.printer_modeswitch== MODESWITCH_TRACE:
671 self.pildevice.put_cmd(CMD_TRACE)
672 if self.printer_modeswitch== MODESWITCH_NORM:
673 self.pildevice.put_cmd(CMD_NORM)
674 self.toggle_active()
675 return
676#
677# disable, clear the GUI queue, stop the timer
678#
679 def disable(self):
680 self.gui_queue_lock.acquire()
681 while True:
682 try:
683 self.gui_queue.get_nowait()
684 self.gui_queue.task_done()
685 except queue.Empty:
686 break
687 self.gui_queue_lock.release()
688 self.UpdateTimer.stop()
689 return
690#
691# becomes visible
692#
693 def becomes_visible(self):
694 self.printview.becomes_visible()
695#
696# becomes invisible, do nothing
697#
698 def becomes_invisible(self):
699 pass
700#
701# active/inactive: enable/disable GUI controls
702#
703 def toggle_active(self):
704 if self.parent.active:
705 self.radbutMan.setEnabled(True)
706 self.radbutTrace.setEnabled(True)
707 self.radbutNorm.setEnabled(True)
708 self.clearButton.setEnabled(True)
709 self.printButton.setEnabled(True)
710 self.advanceButton.setEnabled(True)
711 self.pdfButton.setEnabled(True)
712 else:
713 self.radbutMan.setEnabled(False)
714 self.radbutTrace.setEnabled(False)
715 self.radbutNorm.setEnabled(False)
716 self.clearButton.setEnabled(False)
717 self.printButton.setEnabled(False)
718 self.advanceButton.setEnabled(False)
719 self.pdfButton.setEnabled(False)
720#
721# reconfigure
722#
723 def reconfigure(self):
724 self.printview.reconfigure()
725 return
726#
727# action scripts
728#
729 def do_clear(self):
730 self.printview.reset()
731 self.pildevice.put_cmd(CMD_CLEAR)
732 return
734 def do_print_pressed(self):
735 self.pildevice.put_cmd(CMD_PRINT_PRESSED)
736 return
738 def do_advance_pressed(self):
739 self.pildevice.put_cmd(CMD_ADV_PRESSED)
740 self.repeatedAdvpressedTimer.start()
741 return
743 def do_print_released(self):
744 self.pildevice.put_cmd(CMD_PRINT_RELEASED)
745 return
747 def do_advance_released(self):
748 self.pildevice.put_cmd(CMD_ADV_RELEASED)
749 self.repeatedAdvpressedTimer.stop()
750 return
752 def do_pdf(self):
753 self.pdf_columns=PILCONFIG.get(self.name,"pdfcolumns",3)
754 options=cls_PdfOptions.getPdfOptions(self.pdf_columns,"")
755 if options== "":
756 return
757 PILCONFIG.put(self.name,"pdfcolumns",options[1])
758 self.printview.pdf(options[0],options[1],options[2])
759 return
760#
761# handle change of check boxes
762#
763 def toggledCheckBoxes(self):
764 if self.radbutMan.isChecked():
765 self.pildevice.put_cmd(CMD_MAN)
766 self.printer_modeswitch= MODESWITCH_MAN
767 self.setCheckBoxes()
768 if self.radbutTrace.isChecked():
769 self.pildevice.put_cmd(CMD_TRACE)
770 self.printer_modeswitch= MODESWITCH_TRACE
771 self.setCheckBoxes()
772 if self.radbutNorm.isChecked():
773 self.pildevice.put_cmd(CMD_NORM)
774 self.printer_modeswitch= MODESWITCH_NORM
775 self.setCheckBoxes()
776 PILCONFIG.put(self.name,"modeswitch",self.printer_modeswitch)
777#
778# set check box according to self.printer_modeswitch
779#
780 def setCheckBoxes(self):
781 if self.printer_modeswitch== MODESWITCH_NORM:
782 self.radbutNorm.setChecked(True)
783 self.radbutMan.setChecked(False)
784 self.radbutTrace.setChecked(False)
785 if self.printer_modeswitch== MODESWITCH_MAN:
786 self.radbutNorm.setChecked(False)
787 self.radbutMan.setChecked(True)
788 self.radbutTrace.setChecked(False)
789 if self.printer_modeswitch== MODESWITCH_TRACE:
790 self.radbutNorm.setChecked(False)
791 self.radbutMan.setChecked(False)
792 self.radbutTrace.setChecked(True)
793 return
794#
795# put command into the GUI-command queue, this is called by the thread component
796#
797 def put_cmd(self,item):
798 self.gui_queue_lock.acquire()
799 self.gui_queue.put(item)
800 self.gui_queue_lock.release()
801#
802# repeated adv pressed action
803#
804 def repeated_advpressed(self):
805 b=bytes(0)
806 self.put_cmd([REMOTECMD_PRINT,b,1])
807#
808# process commands in the GUI command queue, this is called by a timer event
809#
810 def process_queue(self):
811 items=[]
812 self.gui_queue_lock.acquire()
813 while True:
814 try:
815 i=self.gui_queue.get_nowait()
816 items.append(i)
817 self.gui_queue.task_done()
818 except queue.Empty:
819 break
820 self.gui_queue_lock.release()
821 if len(items):
822 for c in items:
823 self.process(c)
824 self.UpdateTimer.start(UPDATE_TIMER)
825 return
826#
827# GUI command processing, commands issued by the HP-IL thread
828#
829 def process(self,item):
830 cmd= item[0]
831#
832# clear graphhics views
833#
834 if cmd== REMOTECMD_CLEAR:
835 self.printview.reset()
836#
837# output line
838#
839 elif cmd== REMOTECMD_PRINT:
840 line= item[1]
841 col_idx= item[2]
842 self.printview.add_line(line,col_idx)
843#
844# log line
845#
846 elif cmd== REMOTECMD_LOG:
847 self.parent.cbLogging.logWrite(item[1])
848 self.parent.cbLogging.logFlush()
849#
850# custom class for scrolled hp82162a output widget ----------------------------
851#
852class cls_ScrolledHP82162AView(QtWidgets.QWidget):
854 def __init__(self,parent,name,pixelsize,pdfpixelsize,papersize,linebuffersize):
855 super().__init__(parent)
856 self.parent=parent
857 self.name=name
858#
859# create window and scrollbars
860#
862 self.hbox= QtWidgets.QHBoxLayout()
863 self.scrollbar= QtWidgets.QScrollBar()
864 self.hp82162awidget= cls_HP82162aView(self,self.name,pixelsize,pdfpixelsize,papersize,linebuffersize)
865 self.hp82162awidget.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
866 self.hp82162awidget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
867 self.hbox.addWidget(self.hp82162awidget)
868 self.hbox.addWidget(self.scrollbar)
869 self.setLayout(self.hbox)
870#
871# Initialize scrollbar
872#
873 self.scrollbar.valueChanged.connect(self.do_scrollbar)
874 self.scrollbar.setEnabled(True)
875 self.reset()
876#
877# scrollbar value changed action
878#
879 def do_scrollbar(self):
880 self.hp82162awidget.do_scroll(self.scrollbar.value())
881#
882# add line to printer output window
883#
884 def add_line(self,line,col_idx):
885 self.hp82162awidget.add_line(line,col_idx)
886#
887# reset output window
888#
889 def reset(self):
890 self.hp82162awidget.reset()
891 self.scrollbar.setMinimum(0)
892 self.scrollbar.setMaximum(0)
893 self.scrollbar.setSingleStep(1)
894#
895# generate pdf output
896#
897 def pdf(self,filename,columns,title):
898 self.hp82162awidget.pdf(filename,columns,title)
899#
900# becomes visible/invisible: nothing to do
901#
902 def becomes_visible(self):
903 return
905 def becomes_invisible(self):
906 return
907#
908# reconfigure
909#
910 def reconfigure(self):
911 self.hp82162awidget.reconfigure()
912 return
914#
915# custom class for hp82162a output -----------------------------------------
916#
917class cls_HP82162aView(QtWidgets.QGraphicsView):
919 def __init__(self,parent,name,pixelsize,pdfpixelsize,papersize,linebuffersize):
920 super().__init__()
921 self.parent=parent
922 self.name= name
923#
924# initial output window in reconfigure
925#
926 self.pixelsize= -1
927 self.w=-1
928 self.h=-1
929 self.pdfpixelsize= pdfpixelsize
930 self.pdfw=PRINTER_WIDTH_CHARS*PRINTER_CHARACTER_WIDTH_PIXELS*pdfpixelsize
931 self.pdfh=PRINTER_CHARACTER_HEIGHT_PIXELS*pdfpixelsize
932 self.rows= 0
933 self.linebuffersize= linebuffersize
934 self.papersize= papersize
935#
936# initialize line bitmap buffer
937#
938 self.lb= [None] * linebuffersize
939 self.lb_current= -1
940 self.lb_anz=0
941 self.lb_position=0
943 self.printscene=None
944 self.pdfprinter=None
945 self.reconfigure()
946#
947# configure/reconfigure the printview widget, scene and its content
948#
949 def reconfigure(self):
950 tmp=PILCONFIG.get_dual(self.name,"hp82162a_pixelsize")
951#
952# re/configure the printview widget
953#
954 if tmp != self.pixelsize:
955 self.pixelsize=tmp
956 self.w=PRINTER_WIDTH_CHARS*PRINTER_CHARACTER_WIDTH_PIXELS*self.pixelsize
957 self.h=PRINTER_CHARACTER_HEIGHT_PIXELS*self.pixelsize
958#
959# set fixed width
960#
961 self.setFixedWidth(self.w+2*self.pixelsize)
962#
963# initialize scene if not existing
964#
965 if self.printscene is None:
966 self.printscene= cls_hp82162a_scene(self,self.pixelsize)
967 self.setScene(self.printscene)
968 self.reset()
969#
970# otherwise reconfigure scene and its content
971#
972 else:
973 self.printscene.reconfigure(self.pixelsize)
974 for i in range(0,self.linebuffersize):
975 if self.lb[i] is not None:
976 self.lb[i].reconfigure(self.pixelsize)
977 self.do_resize()
978#
979# now shrink all parent windows to minimum size
980#
981# w=self.parentWidget()
982# while w is not None:
983# w.adjustSize()
984# w=w.parentWidget()
985 return
986#
987# reset output window
988#
989 def reset(self):
990 for i in range(0,self.linebuffersize):
991 if self.lb[i] is not None:
992 self.lb[i]= None
993 self.lb_current= -1
994 self.lb_anz=0
995 self.lb_position=0
996 self.printscene.reset()
997#
998# overwrite standard events
999#
1000# resize event, adjust the scene size, reposition everything and redraw
1001#
1002 def resizeEvent(self,event):
1003 self.do_resize()
1005 def do_resize(self):
1006 h=self.height()
1007 self.rows=h // (PRINTER_CHARACTER_HEIGHT_PIXELS*self.pixelsize)
1008 self.printscene.set_scenesize(self.rows)
1009 scroll_max=self.lb_current- self.rows+1
1010 if scroll_max < 0:
1011 scroll_max=0
1012 self.parent.scrollbar.setMaximum(scroll_max)
1013 self.parent.scrollbar.setPageStep(self.rows)
1014 self.printscene.update_scene()
1015 return
1016#
1017# Mouse wheel event
1018#
1019 def wheelEvent(self,event):
1020 numDegrees= event.angleDelta()/8
1021 delta=0
1022 if numDegrees.y() is not None:
1023 if numDegrees.y() < 0:
1024 delta=1
1025 if numDegrees.y() > 0:
1026 delta=-1
1027 event.accept()
1028 if self.lb_current < self.rows:
1029 return
1030 if self.lb_position+delta <0 or self.lb_position+delta+self.rows-1 > self.lb_current:
1031 return
1032 self.lb_position+=delta
1033 self.parent.scrollbar.setValue(self.lb_position)
1034 self.printscene.update_scene()
1035 return
1036#
1037# external methods
1038#
1039 def add_line(self,line,col_idx):
1040#
1041# add line bitmap to line bitmap buffer
1042#
1043 if self.lb_anz < self.linebuffersize:
1044 self.lb_anz+=1
1045 self.lb_current+=1
1046 self.lb[self.lb_current]=cls_hp82162a_line(line,col_idx,self.pixelsize,)
1047 else:
1048 self.lb= self.lb[1:] + self.lb[:1]
1049 self.lb[self.lb_current]=cls_hp82162a_line(line,col_idx,self.pixelsize,)
1050 self.lb_position=self.lb_current- self.rows+1
1051 if self.lb_position < 0:
1052 self.lb_position=0
1053 self.parent.scrollbar.setMaximum(self.lb_position)
1054 self.parent.scrollbar.setValue(self.lb_position)
1056 self.printscene.update_scene()
1057#
1058# scroll bar action
1059#
1060 def do_scroll(self,value):
1061 self.lb_position=value
1062 self.printscene.update_scene()
1063#
1064# PDF output of lb buffer content, prints with page number and optional
1065# header. Output is formatted in 1-3 columns
1066#
1067 def pdf(self,filename,columns,title):
1069 self.pdfprinter= cls_pdfprinter(self.papersize,PDF_ORIENTATION_PORTRAIT,filename, title, True, columns)
1070 self.pdfprinter.begin()
1071#
1072# process lines
1073#
1074 k=0
1075 while True:
1076#
1077# end of output
1078#
1079 if k == self.lb_anz:
1080 break
1081 item_args= cls_hp82162a_line.from_hp82162a_line(self.lb[k])
1082 item= cls_hp82162a_line(item_args[0],item_args[1],self.pdfpixelsize)
1083 self.pdfprinter.print_item(item)
1084 k+=1
1085 self.pdfprinter.end()
1087#
1088# custom class for line bitmap ----------------------------------------------
1089#
1090class cls_hp82162a_line(QtWidgets.QGraphicsItem):
1092 def __init__(self,line, col_idx, pixelsize):
1093 super().__init__()
1094 self.pixelsize=-1
1095 self.w=-1
1096 self.h=-1
1097 self.rect= QtCore.QRectF(0,0,1,1)
1098 self.col_idx=col_idx
1099 self.line=bytes(line[:col_idx])
1100 self.reconfigure(pixelsize)
1102 def reconfigure(self,pixelsize):
1103 self.pixelsize=pixelsize
1104 self.w=PRINTER_WIDTH_CHARS*PRINTER_CHARACTER_WIDTH_PIXELS*pixelsize
1105 self.h=PRINTER_CHARACTER_HEIGHT_PIXELS*pixelsize
1106 self.rect= QtCore.QRectF(0,0,self.w,self.h)
1108 def setPos(self,x,y):
1109 super().setPos(x,y-self.h)
1112 def boundingRect(self):
1113 return self.rect
1114#
1115# paint bitmap
1116#
1117 def paint(self,painter,option,widget):
1119 posx=0
1120 for b in self.line:
1121 posy=0
1122 for i in range(0,8):
1123 if b & 0x01:
1124 painter.fillRect(posx,posy,self.pixelsize,self.pixelsize,QtCore.Qt.black)
1125 b= b>>1
1126 posy+= self.pixelsize
1127 posx+= self.pixelsize
1128#
1129# get a copy of the constructor parameters
1130#
1131 @classmethod
1132 def from_hp82162a_line(cls, class_instance):
1133 line= copy.deepcopy(class_instance.line)
1134 return(line,class_instance.col_idx)
1136#
1137# custom class for hp82162a graphics scene
1138#
1139class cls_hp82162a_scene(QtWidgets.QGraphicsScene):
1141 def __init__(self,parent,pixelsize):
1142 super().__init__()
1143 self.rows= 0
1144 self.w=0
1145 self.h=0
1146 self.parent=parent
1147 self.si= None
1148 self.reconfigure(pixelsize)
1149 return
1150#
1151# re/configure graphics scene
1152#
1153 def reconfigure(self,pixelsize):
1154 self.pixelsize=pixelsize
1155 self.w=PRINTER_WIDTH_CHARS*PRINTER_CHARACTER_WIDTH_PIXELS*pixelsize
1156 self.h=PRINTER_CHARACTER_HEIGHT_PIXELS*pixelsize
1157 return
1158#
1159# set or change the size of the scene
1160#
1161 def set_scenesize(self,rows):
1162 self.reset()
1163 self.rows= rows
1164 self.si= [None] * rows
1165 self.setSceneRect(0,0,self.w,self.h*self.rows)
1166#
1167# clear window and reset
1168#
1169 def reset(self):
1170 for i in range(0,self.rows):
1171 if self.si[i] is not None:
1172 self.removeItem(self.si[i])
1173 self.si[i]=None
1174#
1175# update graphics scene
1176#
1177 def update_scene(self):
1178 for i in range(0,self.rows):
1179 if self.si[i] is not None:
1180 self.removeItem(self.si[i])
1181 self.si[i]=None
1182 start= self.parent.lb_position
1183 end= start+self.rows
1185 if end >= self.parent.lb_anz:
1186 end=self.parent.lb_anz
1187 y=self.h
1188 j=0
1189 for i in range(start,end):
1190 self.si[j]=self.parent.lb[i]
1191 self.addItem(self.si[j])
1192 self.si[j].setPos(0,y)
1193 y+=self.h+DISPLAY_LINE_SPACING*self.pixelsize
1194 j+=1
1195#
1196# custom class open pdf output file and set options
1197#
1199class cls_PdfOptions(QtWidgets.QDialog):
1201 def __init__(self,columns,title):
1202 super().__init__()
1203 self.columns=columns
1204 self.title=title
1205 self.filename="hp82162a.pdf"
1206 self.setWindowTitle('HP82162A PDF output')
1207 self.vlayout = QtWidgets.QVBoxLayout()
1208 self.setLayout(self.vlayout)
1209 self.glayout = QtWidgets.QGridLayout()
1210 self.vlayout.addLayout(self.glayout)
1212 self.glayout.addWidget(QtWidgets.QLabel("PDF Output Options"),0,0,1,3)
1213 self.glayout.addWidget(QtWidgets.QLabel("Output file:"),1,0)
1214 self.filename="hp82162a.pdf"
1215 self.lfilename=QtWidgets.QLabel(self.filename)
1216 self.glayout.addWidget(self.lfilename,1,1)
1217 self.butchange=QtWidgets.QPushButton("Change")
1218 self.butchange.setFixedWidth(60)
1219 self.glayout.addWidget(self.butchange,1,2)
1220 self.glayout.addWidget(QtWidgets.QLabel("Title:"),2,0)
1221 self.edttitle=QtWidgets.QLineEdit()
1222 self.edttitle.setText(self.title)
1223 self.edttitle.setFixedWidth(200)
1224 self.glayout.addWidget(self.edttitle,2,1,1,2)
1225 self.glayout.addWidget(QtWidgets.QLabel("Columns:"),3,0)
1226 self.spincolumns=QtWidgets.QSpinBox()
1227 self.spincolumns.setMinimum(1)
1228 self.spincolumns.setMaximum(PDF_MAX_COLS)
1229 self.spincolumns.setValue(self.columns)
1230 self.glayout.addWidget(self.spincolumns,3,1,1,2)
1232 self.buttonBox = QtWidgets.QDialogButtonBox()
1233 self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
1234 self.buttonBox.setCenterButtons(True)
1235 self.buttonBox.accepted.connect(self.do_ok)
1236 self.buttonBox.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(False)
1237 self.buttonBox.rejected.connect(self.do_cancel)
1238 self.hlayout = QtWidgets.QHBoxLayout()
1239 self.hlayout.addWidget(self.buttonBox)
1240 self.vlayout.addLayout(self.hlayout)
1241 self.butchange.clicked.connect(self.change_pdffile)
1243 def get_pdfFilename(self):
1244 dialog=QtWidgets.QFileDialog()
1245 dialog.setWindowTitle("Enter PDF file name")
1246 dialog.setAcceptMode(QtWidgets.QFileDialog.AcceptSave)
1247 dialog.setFileMode(QtWidgets.QFileDialog.AnyFile)
1248 dialog.setDefaultSuffix("pdf")
1249 dialog.setNameFilters( ["PDF (*.pdf )", "All Files (*)"] )
1250 dialog.setOptions(QtWidgets.QFileDialog.DontUseNativeDialog)
1251 if dialog.exec():
1252 return dialog.selectedFiles()
1254 def change_pdffile(self):
1255 flist= self.get_pdfFilename()
1256 if flist is None:
1257 return
1258 self.filename= flist [0]
1259 self.lfilename.setText(self.filename)
1260 self.buttonBox.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(True)
1263 def do_ok(self):
1264 super().accept()
1266 def do_cancel(self):
1267 super().reject()
1269 @staticmethod
1270 def getPdfOptions(columns,title):
1271 dialog= cls_PdfOptions(columns,title)
1272 result= dialog.exec()
1273 if result== QtWidgets.QDialog.Accepted:
1274 return dialog.lfilename.text(), dialog.spincolumns.value(), dialog.edttitle.text()
1275 else:
1276 return ""
1277#
1278# Printer buffer object each entry has the following information:
1279# value: value of entry
1280# types: character, column data, barcode data
1281# mode: current printer mode (we need double wide and lowercase mode)
1282# width: pixel width of information
1283#
1284class cls_printer_buffer(object):
1286 def __init__(self):
1287 self.buffer= []
1288 self.buffer_pxlen=0 # total length of buffer entries in pixel
1289 self.buffer_fmtpos=-1 # position of first fmt specifier
1291 def add(self,v,t,m):
1292 s=0
1293 if t== type_column:
1294 if m & mode_doublewide:
1295 s=2
1296 else:
1297 s=1
1298 if t== type_char:
1299 if m & mode_doublewide:
1300 s=14
1301 else:
1302 s=7
1303 if t== type_skip:
1304 if v >= 0xa0 and v <= 0xb7:
1305 n= v - 0xa0
1306 if m & mode_doublewide:
1307 s= 14 * n
1308 else:
1309 s= 7 * n
1310 if v >= 0xb8 and v <= 0xbf:
1311 n= v- 0xb8
1312 if m & mode_doublewide:
1313 s= 2 * n
1314 else:
1315 s= n
1316 if t== type_format and self.buffer_fmtpos<0:
1317 self.buffer_fmtpos=len(self.buffer)
1318 self.buffer.append([v,t,m,s])
1319 self.buffer_pxlen+=s
1320 return
1322 def get(self,idx):
1323 if idx >= len(self.buffer):
1324 return None
1325 return self.buffer[idx]
1327 def clear(self):
1328 self.buffer_pxlen=0
1329 self.buffer_fmtpos= -1
1330 del self.buffer[:]
1332 def length(self):
1333 return len(self.buffer)
1335 def pxlen(self):
1336 return (self.buffer_pxlen)
1338 def fmtpos(self):
1339 return(self.buffer_fmtpos)
1340#
1341# line buffer object -------------------------------------------------------
1342#
1343class cls_line_buffer(object):
1345 def __init__(self,guiobject):
1346 self.guiobject= guiobject # reference to GUI object
1347 self.linebuffer= bytearray(PRINTER_WIDTH) # the line buffer
1348 self.linebuffer_index=0 # current index in line buffer
1349 self.wrap_position=-1 # pointer to wrap line position
1350#
1351# clear line buffer
1352#
1353 def clear(self):
1354 self.linebuffer_index=0
1355 self.wrap_position= -1
1356#
1357# print whole content of line buffer (end of line condition)
1358#
1359 def prt(self):
1360 linebuffer_copy=copy.deepcopy(self.linebuffer)
1361 self.guiobject.put_cmd([REMOTECMD_PRINT,linebuffer_copy,self.linebuffer_index])
1362 self.linebuffer_index=0
1363 self.wrap_position= -1
1364#
1365# add column to line buffer, if we have an overflow then print it. If we are in
1366# parse mode then break line at self.wrap_position
1367#
1368 def add(self,c,mode,wrap):
1369 if wrap:
1370 self.wrap_position=self.linebuffer_index
1371 if self.linebuffer_index== PRINTER_WIDTH:
1372 if mode & mode_parse and self.wrap_position>0:
1373 linebuffer_copy=copy.deepcopy(self.linebuffer[:self.wrap_position-1])
1374 self.guiobject.put_cmd([REMOTECMD_PRINT,linebuffer_copy,self.wrap_position-1])
1375# next data
1376 do_copy=False
1377 j=1
1378 self.linebuffer[0]=0
1379 for i in range (PRINTER_WIDTH- self.wrap_position):
1380 k=i+self.wrap_position
1381 if self.linebuffer[k]!= 0 and not do_copy:
1382 do_copy= True
1383 if do_copy:
1384 self.linebuffer[j]= self.linebuffer[k]
1385 self.linebuffer[k]= 0
1386 j+=1
1388 self.linebuffer_index= j
1389 self.wrap_positon= -1
1390 else:
1391 linebuffer_copy=copy.deepcopy(self.linebuffer)
1392 self.guiobject.put_cmd([REMOTECMD_PRINT,linebuffer_copy,self.linebuffer_index])
1393 self.linebuffer_index=0
1394 self.wrap_position= -1
1396 self.linebuffer[self.linebuffer_index]=c
1397 self.linebuffer_index+=1
1398#
1399# HP82162A emulator (thread component) --------------------------------------
1400#
1402class cls_special_k(QtCore.QObject):
1404 def __init__(self,parent,guiobject):
1405 super().__init__()
1406 self.pildevice=parent
1407 self.guiobject= guiobject
1408 self.printer_buffer= cls_printer_buffer() # printer buffer
1409 self.line_buffer= cls_line_buffer(self.guiobject) # line buffer
1410 self.char_gen= hp82162a_char() # character generator
1411 self.esc= False # escape mode
1412 self.esc_seq="" # escape sequence
1413 self.esc_prefix="" # prefix of combined esc sequence
1414 self.printer_mode=0 # printer mode bits
1415 self.num_barcode=0 # number of barcodes to read
1416 self.num_graphics=0 # number of graphics codes to read
1417 self.bclist= { }
1418 self.bcline= { }
1419#
1420# device clear, carriage positioned to right, print buffer cleared modes set
1421# to Escape, Single Wide, Left-Justify and Nonparse
1422#
1423 def reset(self):
1424 self.printer_buffer.clear()
1425 self.line_buffer.clear()
1426 self.esc= False
1427 self.esc_seq=""
1428 self.esc_prefix=""
1429 self.printer_mode=0
1430 self.char_gen.set_charset(CHARSET_ASCII)
1431 self.num_barcode=0
1432 self.num_graphics=0
1433#
1434# issue clear to GUI
1435#
1436 self.guiobject.put_cmd([REMOTECMD_CLEAR])
1437#
1438# we are idle and buffer is empty
1439#
1440 self.set_status(STA_BE)
1441 self.set_status(STA_ID)
1442#
1443# set, clear, query printer mode
1444#
1445 def setMode(self,mode_bit):
1446 self.printer_mode= self.printer_mode | mode_bit
1448 def clearMode(self,mode_bit):
1449 mask= ~ mode_bit
1450 self.printer_mode= self.printer_mode & mask
1452 def isMode(self,mode_bit):
1453 if (self.printer_mode & mode_bit):
1454 return True
1455 else:
1456 return False
1457#
1458# process barcodes
1459#
1460 def add_bar(self,length,fill):
1461 for i in range(length):
1462 if len(self.bcline)== PRINTER_CHARACTER_HEIGHT_PIXELS:
1463 self.bclist.append(self.bcline)
1464 self.bcline= []
1465 if fill:
1466 self.bcline.append(1)
1467 else:
1468 self.bcline.append(0)
1470 def process_barcodes(self):
1472 self.bclist= []
1473 self.bcline= []
1474 self.add_bar(3,True)
1475 self.add_bar(3,False)
1476 self.add_bar(3,True)
1477 self.add_bar(3,False)
1478 for i in range (self.printer_buffer.length()):
1479 ret= self.printer_buffer.get(i)
1480 code=ret[0]
1481 b= 128
1482 for j in range(8):
1483 if b & code:
1484 self.add_bar(6,True)
1485 else:
1486 self.add_bar(3,True)
1487 self.add_bar(3,False)
1488 b= b // 2
1489 self.add_bar(6,True)
1490 self.add_bar(3,False)
1491 self.add_bar(3,True)
1492 while len(self.bcline)< PRINTER_CHARACTER_HEIGHT_PIXELS:
1493 self.add_bar(1,False)
1494 self.bclist.append(self.bcline)
1495 return
1496#
1497# add column to line buffer
1498#
1499 def add_column(self,c,mode):
1500#
1501# put column data into line buffer
1502#
1503 self.line_buffer.add(c,mode,False)
1504 if mode & mode_doublewide:
1505 self.line_buffer.add(c,mode,False)
1507#
1508# generate character in line buffer
1509#
1510 def add_char(self,c,mode):
1511#
1512# blank is wrap position
1513#
1514 wrap=False
1515 if c== 0x20:
1516 wrap=True
1517#
1518# in lowercase mode convert uppercase chars
1519#
1520 if (mode & mode_lowercase) and (c >=0x41 and c <= 0x5A):
1521 c+=0x20
1522#
1523# leading space
1524#
1525 self.line_buffer.add(0,mode,wrap)
1526 if mode & mode_doublewide:
1527 self.line_buffer.add(0,mode,False)
1528#
1529# get bitmap, handle double wide
1530#
1531 for col in range(0,5):
1532 col_data=self.char_gen.get(c, col)
1533 self.line_buffer.add(col_data,mode,False)
1534 if mode & mode_doublewide:
1535 self.line_buffer.add(col_data,mode,False)
1536#
1537# trailing space
1538#
1539 self.line_buffer.add(0,mode,False)
1540 if mode & mode_doublewide:
1541 self.line_buffer.add(0,mode,False)
1542 return True
1544#
1545# end of line, process buffer
1546#
1547 def process_line(self):
1549 buffer_idx=0
1550 fmtpos= self.printer_buffer.fmtpos()
1551 log_line=""
1552#
1553# right justify buffer if we do not have a format specifier
1554#
1555 if (self.isMode(mode_rjust) and fmtpos<0):
1556 shift= PRINTER_WIDTH - self.printer_buffer.pxlen()
1557 for i in range(shift):
1558 self.add_column(0,0)
1559#
1560# center, if format specifier is at the beginning or the end of the buffer
1561#
1562 if fmtpos >=0:
1563 if fmtpos==0 or fmtpos== self.printer_buffer.length()-2:
1564 freecols=PRINTER_WIDTH - self.printer_buffer.pxlen()
1565 shift= freecols//2
1566 if freecols % 2 == 1:
1567 shift+=1
1568 for i in range(shift):
1569 self.add_column(0,0)
1570 fmtpos= -1
1571#
1572# output content
1573#
1574 while buffer_idx < self.printer_buffer.length():
1575 ret= self.printer_buffer.get(buffer_idx)
1576 v= ret[0]
1577 t= ret[1]
1578 m= ret[2]
1579#
1580# check if we have spacing format specifier right in the middle
1581#
1582 if fmtpos >=0:
1583 if buffer_idx== fmtpos:
1584 freecols=PRINTER_WIDTH - self.printer_buffer.pxlen()
1585 for i in range(freecols):
1586 self.add_column(0,0)
1587 fmtpos= -1
1588#
1589# add character to line buffer
1590#
1591 if t== type_char:
1592 self.add_char(v,m)
1593 if self.isMode(mode_8bit):
1594 log_line+= charconv(chr(v),CHARSET_HP41)
1595 else:
1596 log_line+= charconv(chr(v),CHARSET_ROMAN8)
1597#
1598# add column to line buffer
1599#
1600 if t== type_column:
1601 self.add_column(v,m)
1602#
1603# generate blank characters or blank columns to line buffer
1604#
1605 if t== type_skip:
1606 if v >= 0xa0 and v <= 0xb7:
1607 n= v-0xa0
1608 for i in range(n):
1609 self.add_char(0x20,m)
1610 if v >= 0xb8 and v <= 0xbf:
1611 n=v-0xb8
1612 for i in range(n):
1613 self.add_column(0,m)
1614 buffer_idx+=1
1615#
1616# send line buffer to GUI
1617#
1618 self.line_buffer.prt()
1619#
1620# send log output to GUI
1621#
1622 if log_line !="":
1623 log_line+="\n"
1624 self.guiobject.put_cmd([REMOTECMD_LOG,log_line])
1625#
1626# clear line buffer and printer buffer
1627#
1628 self.line_buffer.clear()
1629 self.printer_buffer.clear()
1630#
1631# update status information
1632#
1633 self.set_status(STA_EL)
1634 self.set_status(STA_BE)
1635#
1636# process escape sequences
1637#
1638 def process_esc(self):
1639#
1640# switch to 8 bit mode
1641#
1642 if self.esc_seq=="|":
1643 self.setMode(mode_8bit)
1644 self.set_status(STA_EB)
1645 self.char_gen.set_charset(CHARSET_ALTERNATE)
1646 return
1647#
1648# single width
1649#
1650 elif self.esc_seq=="&k0S":
1651 self.clearMode(mode_doublewide)
1652 self.clear_status(STA_DW)
1653 return
1654#
1655# double width
1656#
1657 elif self.esc_seq=="&k1S":
1658 self.setMode(mode_doublewide)
1659 self.set_status(STA_DW)
1660 return
1661#
1662# left justify
1663#
1664 elif self.esc_seq=="&l0J":
1665 self.clearMode(mode_rjust)
1666 self.clear_status(STA_RJ)
1667 return
1668#
1669# right justify
1670#
1671 elif self.esc_seq=="&l1J":
1672 self.setMode(mode_rjust)
1673 self.set_status(STA_RJ)
1674 return
1675#
1676# Graphic
1677#
1678 elif self.esc_seq.startswith("*b") and self.esc_seq.endswith("G"):
1679 ret=re.findall(r"\d+",self.esc_seq)
1680 if ret== []:
1681 return
1682 try:
1683 n=int(ret[0])
1684 except ValueError:
1685 return
1686 if n<0 or n> 255:
1687 return
1688 self.num_graphics=n
1689 return
1690#
1691# barcode
1692#
1693 elif self.esc_seq.startswith("*z") and self.esc_seq.endswith("B"):
1694 ret=re.findall(r"\d+",self.esc_seq)
1695 if ret== []:
1696 return
1697 try:
1698 n=int(ret[0])
1699 except ValueError:
1700 return
1701 if n<0 or n> 16:
1702 return
1703 self.num_barcode=n
1704 return
1705#
1706# format
1707#
1708 elif self.esc_seq=="&l2J":
1709 self.printer_buffer.add(0,type_format,self.printer_mode)
1710 self.printer_buffer.add(0,type_format,self.printer_mode)
1711 return
1712#
1713# skip characters
1714#
1715 elif self.esc_seq.startswith("&a+") and self.esc_seq.endswith("C"):
1716 ret=re.findall(r"\d+",self.esc_seq)
1717 if ret== []:
1718 return
1719 try:
1720 n=int(ret[0])
1721 except ValueError:
1722 return
1723 if n<0 or n> 23:
1724 return
1725 n+= 0xa0
1726 self.printer_buffer.add(n,type_skip,self.printer_mode)
1727 return
1728#
1729# skip columns
1730#
1731 elif self.esc_seq.startswith("&a+") and self.esc_seq.endswith("D"):
1732 ret=re.findall(r"\d+",self.esc_seq)
1733 if ret== []:
1734 return
1735 try:
1736 n=int(ret[0])
1737 except ValueError:
1738 return
1739 if n<0 or n> 7:
1740 return
1741 n+= 0xb8
1742 self.printer_buffer.add(n,type_skip,self.printer_mode)
1743 return
1744#
1745# skip absolute
1746#
1747 elif self.esc_seq.startswith("&a") and self.esc_seq.endswith("D"):
1748 ret=re.findall(r"\d+",self.esc_seq)
1749 if ret== []:
1750 return
1751 try:
1752 n=int(ret[0])
1753 except ValueError:
1754 return
1755 if n<0 or n> 168:
1756 return
1757 skip=n-self.printer_buffer.pxlen()
1758 if n<=0:
1759 return
1760 skip_chars= skip // PRINTER_CHARACTER_WIDTH_PIXELS
1761 n= skip_chars+ 0xa0
1762 self.printer_buffer.add(n,type_skip,self.printer_mode)
1763 skip_columns= skip % PRINTER_CHARACTER_WIDTH_PIXELS
1764 n= skip_columns+ 0xb8
1765 self.printer_buffer.add(n,type_skip,self.printer_mode)
1766 return
1767#
1768# nonparse mode
1769#
1770 elif self.esc_seq=="&k0H":
1771 self.clearMode(mode_parse)
1772 return
1773#
1774# parse mode
1775#
1776 elif self.esc_seq=="&k1H":
1777 self.setMode(mode_parse)
1778 return
1779 return
1780#
1781# main printer data processing method
1782#
1783 def process_char(self,ch):
1784#
1785# barcode mode, accumulate code numbers to buffer
1786#
1787 if self.num_barcode > 0:
1788 self.printer_buffer.add(ch,type_barcode,self.printer_mode)
1789 self.num_barcode-=1
1790#
1791# all barcodes read, process line
1792#
1793 if self.num_barcode==0:
1794 self.process_barcodes()
1795 return
1796#
1797# graphics mode (ESC mode only), add columns to buffer
1798#
1799 if self.num_graphics > 0:
1800 self.printer_buffer.add(ch,type_column,self.printer_mode)
1801 self.num_graphics-=1
1802 return
1803#
1804# process ESC sequences
1805#
1806 if (self.esc== False) and (ch== 0x1B) and not self.isMode(mode_8bit):
1807 self.esc= True
1808 self.esc_seq=""
1809 self.esc_prefix=""
1810 return
1811 if self.esc:
1812#
1813# ESC | or escape sequence terminated with capital letter
1814#
1815# if ch == 0x7c or (ch >= 0x41 and ch <= 0x5A):
1816 if chr(ch) in "|CDHSJGB":
1817 self.esc_seq+= chr(ch)
1818 if self.esc_prefix!="":
1819 self.esc_seq= self.esc_prefix+self.esc_seq
1820 self.process_esc()
1821 self.esc= False
1822 self.esc_seq=""
1823 self.esc_prefix=""
1824 return
1825#
1826# repeated escape sequence terminated with lowercase letter
1827# unfortunately b occurs in two escape sequences at different positions
1828#
1829 if chr(ch) in "cdhsjgb" and len(self.esc_seq)>2:
1830 if self.esc_prefix == "":
1831 self.esc_prefix= self.esc_seq[:2]
1832 self.esc_seq= self.esc_seq[2:]
1833 self.esc_seq= self.esc_prefix+self.esc_seq+chr(ch).upper()
1834 self.process_esc()
1835 self.esc_seq=""
1836 return
1837#
1838# still in escape sequence, accumulate characters
1839#
1840 self.esc_seq+= chr(ch)
1841 return
1842#
1843# not in escape sequence, everything goes to the printer buffer now
1844#
1845#
1846# ignore line feed
1847#
1848 if ch== 0x0A and not self.isMode(mode_column):
1849 return
1850#
1851# cr is end of line
1852#
1853 if ch == 0x0D and not self.isMode(mode_column):
1854 self.process_line()
1855 return
1856#
1857# do normal processing: 8bit and escape mode
1858#
1859 if self.isMode(mode_8bit):
1860#
1861# normal character or column
1862#
1863 if ch <= 0x7F:
1864 self.clear_status(STA_EL)
1865 self.clear_status(STA_BE)
1866 if self.isMode(mode_column):
1867 self.printer_buffer.add(ch,type_column,self.printer_mode)
1868 else:
1869 self.printer_buffer.add(ch,type_char,self.printer_mode)
1870#
1871# barcode (only valid in column mode, this is not handled here)
1872# buffers are reset
1873#
1874 elif ch >= 0x80 and ch <= 0x8F:
1875 self.num_barcode= ch - 0x7F
1876 self.printer_buffer.clear()
1877 self.line_buffer.clear()
1878#
1879# skip characters
1880#
1881 elif ch >= 0xA0 and ch <= 0xB7:
1882 self.printer_buffer.add(ch,type_skip,self.printer_mode)
1883#
1884# skip columns
1885#
1886 elif ch >= 0xB8 and ch <= 0xBF:
1887 self.printer_buffer.add(ch,type_skip,self.printer_mode)
1888#
1889# format specifier (2 characters to read)
1890#
1891 elif ch== 0xC0:
1892 self.printer_buffer.add(0,type_format,self.printer_mode)
1893 self.printer_buffer.add(0,type_format,self.printer_mode)
1894#
1895# select width, upper/lowercase, character/column mode
1896# bit0 is lowercase flag
1897# bit1 is column mode flag
1898# bit2 is double wide flag
1899# bit3 is used, but unknown to me (Parse mode?)
1900#
1901 elif ch >= 0xD0 and ch <= 0xDF:
1902 if ch & 0x01:
1903 self.setMode(mode_lowercase)
1904 self.set_status(STA_LC)
1905 else:
1906 self.clearMode(mode_lowercase)
1907 self.clear_status(STA_LC)
1908 if ch & 0x02:
1909 self.setMode(mode_column)
1910 self.set_status(STA_CO)
1911 else:
1912 self.clearMode(mode_column)
1913 self.clear_status(STA_CO)
1914 if ch & 0x04:
1915 self.setMode(mode_doublewide)
1916 self.set_status(STA_DW)
1917 else:
1918 self.clearMode(mode_doublewide)
1919 self.clear_status(STA_DW)
1921#
1922# left justify
1923#
1924 elif ch== 0xE0:
1925 self.clearMode(mode_rjust)
1926 self.clear_status(STA_RJ)
1927#
1928# right justify
1929#
1930 elif ch== 0xE8:
1931 self.setMode(mode_rjust)
1932 self.set_status(STA_RJ)
1933#
1934# escape mode
1935#
1936 elif ch== 0xFC:
1937 self.clearMode(mode_8bit)
1938 self.clear_status(STA_EB)
1939 self.char_gen.set_charset(CHARSET_ASCII)
1940#
1941# allow paper advance
1942#
1943 elif ch== 0xFE:
1944 self.clearMode(mode_inhibit_advance)
1945#
1946# inhibit paper advance
1947#
1948 elif ch== 0xFF:
1949 self.setMode(mode_inhibit_advance)
1950#
1951# unknown 8 bit command
1952#
1953 else:
1954 pass
1955#
1956# escape mode
1957#
1958 else:
1959 if ch< 0x80:
1960 self.printer_buffer.add(ch,type_char,self.printer_mode)
1962#
1963# HP-IL device status bits
1964#
1965 def set_status(self,bitmask):
1966 s= self.pildevice.get_status()
1967 s= s | bitmask
1968 self.pildevice.set_status(s)
1969 return
1971 def clear_status(self,bitmask):
1972 s= self.pildevice.get_status()
1973 s= s & ( ~ bitmask)
1974 self.pildevice.set_status(s)
1975 return
1977 def get_status(self,bitmask):
1978 s= self.pildevice.get_status()
1979 return(s & bitmask)
1980#
1981# process commands sent from the GUI
1982#
1983 def process(self,command):
1985 if command== CMD_MAN:
1986 self.clear_status(STA_MB)
1987 self.clear_status(STA_MA)
1988 return
1989 if command== CMD_NORM:
1990 self.set_status(STA_MB)
1991 self.clear_status(STA_MA)
1992 return
1993 if command== CMD_TRACE:
1994 self.clear_status(STA_MB)
1995 self.set_status(STA_MA)
1996 return
1997 if command== CMD_PRINT_PRESSED:
1998 self.set_status(STA_SR)
1999 self.set_status(STA_PR)
2000 return
2001 if command== CMD_ADV_PRESSED:
2002 if not self.isMode(mode_inhibit_advance):
2003 self.set_status(STA_SR)
2004 self.set_status(STA_PA)
2005 return
2006 if command== CMD_PRINT_RELEASED:
2007 self.clear_status(STA_SR)
2008 self.clear_status(STA_PR)
2009 return
2010 if command== CMD_ADV_RELEASED:
2011 if not self.isMode(mode_inhibit_advance):
2012 self.clear_status(STA_SR)
2013 self.clear_status(STA_PA)
2014 return
2015 if command== CMD_CLEAR:
2016 return
2018#
2019# HP-IL virtual HP82162A object class ---------------------------------------
2020#
2023class cls_pilhp82162a(cls_pildevbase):
2025 def __init__(self,guiobject):
2026 super().__init__()
2028#
2029# overloaded variable initialization
2030#
2031 self.__aid__ = 0x20 # accessory id
2032 self.__defaddr__ = 1 # default address alter AAU
2033 self.__did__ = "" # device id
2034 self.__status_len__=2 # device status is 2 bytes
2035#
2036# object specific variables
2037#
2038 self.__guiobject__= guiobject
2039#
2040# initialize remote command queue and lock
2041#
2042 self.__print_queue__= queue.Queue()
2043 self.__print_queue_lock__= threading.Lock()
2044#
2045# printer processor
2046#
2047 self.__printer__=cls_special_k(self,self.__guiobject__)
2049#
2050# public (overloaded) --------
2051#
2052# enable: reset
2053#
2054 def enable(self):
2055 self.__printer__.reset()
2056 return
2057#
2058# disable: clear the printer command queue
2059#
2060 def disable(self):
2061 self.__print_queue_lock__.acquire()
2062 while True:
2063 try:
2064 self.__print_queue__.get_nowait()
2065 self.__print_queue__.task_done()
2066 except queue.Empty:
2067 break
2068 self.__print_queue_lock__.release()
2069#
2070# process frames
2071#
2072 def process(self,frame):
2074 if self.__isactive__:
2075 self.process_print_queue()
2076 frame= super().process(frame)
2077 return frame
2078#
2079# process the printer command queue
2080#
2081 def process_print_queue(self):
2082 items=[]
2083 self.__print_queue_lock__.acquire()
2084 while True:
2085 try:
2086 i=self.__print_queue__.get_nowait()
2087 items.append(i)
2088 self.__print_queue__.task_done()
2089 except queue.Empty:
2090 break
2091 self.__print_queue_lock__.release()
2092 if len(items):
2093 for c in items:
2094 self.__printer__.process(c)
2095 return
2097#
2098# put command into the print-command queue
2099#
2100 def put_cmd(self,item):
2101 self.__print_queue_lock__.acquire()
2102 self.__print_queue__.put(item)
2103 self.__print_queue_lock__.release()
2104#
2105# set status (2 byte status information)
2106#
2107 def set_status(self,s):
2108 self.__setstatus__(s)
2109 return s
2110#
2111# get status byte (2 byte status information)
2112#
2113 def get_status(self):
2114 s=self.__getstatus__()
2115 return s
2117#
2118# private (overloaded) --------
2119#
2120#
2121# output character to HP82162A
2122#
2123 def __indata__(self,frame):
2124 self.__printer__.process_char(frame & 0xFF)
2126#
2127# clear device: reset printer
2128#
2129 def __clear_device__(self):
2130 super().__clear_device__()
2131#
2132# clear printer queue
2133#
2134 self.__print_queue_lock__.acquire()
2135 while True:
2136 try:
2137 self.__print_queue__.get_nowait()
2138 self.__print_queue__.task_done()
2139 except queue.Empty:
2140 break
2141 self.__print_queue_lock__.release()
2142#
2143# reset device
2144#
2145 self.__printer__.reset()