13 # GNU General Public License for more details. |
11 # GNU General Public License for more details. |
14 # |
12 # |
15 # You should have received a copy of the GNU General Public License |
13 # You should have received a copy of the GNU General Public License |
16 # along with Printrun. If not, see <http://www.gnu.org/licenses/>. |
14 # along with Printrun. If not, see <http://www.gnu.org/licenses/>. |
17 |
15 |
18 __version__ = "2015.03.10" |
16 __version__ = "2.0.0rc7" |
19 |
17 |
20 from serialWrapper import Serial, SerialException, PARITY_ODD, PARITY_NONE |
18 import sys |
|
19 if sys.version_info.major < 3: |
|
20 print("You need to run this on Python 3") |
|
21 sys.exit(-1) |
|
22 |
|
23 from serial import Serial, SerialException, PARITY_ODD, PARITY_NONE |
21 from select import error as SelectError |
24 from select import error as SelectError |
22 import threading |
25 import threading |
23 from Queue import Queue, Empty as QueueEmpty |
26 from queue import Queue, Empty as QueueEmpty |
24 import time |
27 import time |
25 import platform |
28 import platform |
26 import os |
29 import os |
27 import sys |
|
28 stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr |
|
29 reload(sys).setdefaultencoding('utf8') |
|
30 sys.stdin, sys.stdout, sys.stderr = stdin, stdout, stderr |
|
31 import logging |
30 import logging |
32 import traceback |
31 import traceback |
33 import errno |
32 import errno |
34 import socket |
33 import socket |
35 import re |
34 import re |
36 from functools import wraps |
35 import selectors |
|
36 from functools import wraps, reduce |
37 from collections import deque |
37 from collections import deque |
38 from printrun import gcoder |
38 from printrun import gcoder |
39 from .utils import install_locale, decode_utf8 |
39 from .utils import set_utf8_locale, install_locale, decode_utf8 |
|
40 try: |
|
41 set_utf8_locale() |
|
42 except: |
|
43 pass |
40 install_locale('pronterface') |
44 install_locale('pronterface') |
|
45 from printrun.plugins import PRINTCORE_HANDLER |
41 |
46 |
42 def locked(f): |
47 def locked(f): |
43 @wraps(f) |
48 @wraps(f) |
44 def inner(*args, **kw): |
49 def inner(*args, **kw): |
45 with inner.lock: |
50 with inner.lock: |
106 self.read_thread = None |
116 self.read_thread = None |
107 self.stop_read_thread = False |
117 self.stop_read_thread = False |
108 self.send_thread = None |
118 self.send_thread = None |
109 self.stop_send_thread = False |
119 self.stop_send_thread = False |
110 self.print_thread = None |
120 self.print_thread = None |
|
121 self.readline_buf = [] |
|
122 self.selector = None |
|
123 self.event_handler = PRINTCORE_HANDLER |
|
124 # Not all platforms need to do this parity workaround, and some drivers |
|
125 # don't support it. Limit it to platforms that actually require it |
|
126 # here to avoid doing redundant work elsewhere and potentially breaking |
|
127 # things. |
|
128 self.needs_parity_workaround = platform.system() == "linux" and os.path.exists("/etc/debian") |
|
129 for handler in self.event_handler: |
|
130 try: handler.on_init() |
|
131 except: logging.error(traceback.format_exc()) |
111 if port is not None and baud is not None: |
132 if port is not None and baud is not None: |
112 self.connect(port, baud) |
133 self.connect(port, baud) |
113 self.xy_feedrate = None |
134 self.xy_feedrate = None |
114 self.z_feedrate = None |
135 self.z_feedrate = None |
115 |
136 |
|
137 def addEventHandler(self, handler): |
|
138 ''' |
|
139 Adds an event handler. |
|
140 |
|
141 @param handler: The handler to be added. |
|
142 ''' |
|
143 self.event_handler.append(handler) |
|
144 |
116 def logError(self, error): |
145 def logError(self, error): |
|
146 for handler in self.event_handler: |
|
147 try: handler.on_error(error) |
|
148 except: logging.error(traceback.format_exc()) |
117 if self.errorcb: |
149 if self.errorcb: |
118 try: self.errorcb(error) |
150 try: self.errorcb(error) |
119 except: logging.error(traceback.format_exc()) |
151 except: logging.error(traceback.format_exc()) |
120 else: |
152 else: |
121 logging.error(error) |
153 logging.error(error) |
176 socket.SOCK_STREAM) |
220 socket.SOCK_STREAM) |
177 self.printer_tcp.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) |
221 self.printer_tcp.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) |
178 self.timeout = 0.25 |
222 self.timeout = 0.25 |
179 self.printer_tcp.settimeout(1.0) |
223 self.printer_tcp.settimeout(1.0) |
180 try: |
224 try: |
181 self.printer_tcp.connect((hostname, port)) |
225 self.printer_tcp.connect((hostname, port_number)) |
182 self.printer_tcp.settimeout(self.timeout) |
226 #a single read timeout raises OSError for all later reads |
183 self.printer = self.printer_tcp.makefile() |
227 #probably since python 3.5 |
|
228 #use non blocking instead |
|
229 self.printer_tcp.settimeout(0) |
|
230 self.printer = self.printer_tcp.makefile('rwb', buffering=0) |
|
231 self.selector = selectors.DefaultSelector() |
|
232 self.selector.register(self.printer_tcp, selectors.EVENT_READ) |
184 except socket.error as e: |
233 except socket.error as e: |
185 if(e.strerror is None): e.strerror="" |
234 if(e.strerror is None): e.strerror="" |
186 self.logError(_("Could not connect to %s:%s:") % (hostname, port) + |
235 self.logError(_("Could not connect to %s:%s:") % (hostname, port_number) + |
187 "\n" + _("Socket error %s:") % e.errno + |
236 "\n" + _("Socket error %s:") % e.errno + |
188 "\n" + e.strerror) |
237 "\n" + e.strerror) |
189 self.printer = None |
238 self.printer = None |
190 self.printer_tcp = None |
239 self.printer_tcp = None |
191 return |
240 return |
192 else: |
241 else: |
193 disable_hup(self.port) |
242 disable_hup(self.port) |
194 self.printer_tcp = None |
243 self.printer_tcp = None |
195 try: |
244 try: |
196 self.printer = Serial(port = self.port, |
245 if self.needs_parity_workaround: |
197 baudrate = self.baud, |
246 self.printer = Serial(port = self.port, |
198 timeout = 0.25, |
247 baudrate = self.baud, |
199 parity = PARITY_ODD) |
248 timeout = 0.25, |
200 self.printer.close() |
249 parity = PARITY_ODD) |
201 self.printer.parity = PARITY_NONE |
250 self.printer.close() |
|
251 self.printer.parity = PARITY_NONE |
|
252 else: |
|
253 self.printer = Serial(baudrate = self.baud, |
|
254 timeout = 0.25, |
|
255 parity = PARITY_NONE) |
|
256 self.printer.port = self.port |
202 try: #this appears not to work on many platforms, so we're going to call it but not care if it fails |
257 try: #this appears not to work on many platforms, so we're going to call it but not care if it fails |
203 self.printer.setDTR(dtr); |
258 self.printer.dtr = dtr |
204 except: |
259 except: |
205 #self.logError(_("Could not set DTR on this platform")) #not sure whether to output an error message |
260 #self.logError(_("Could not set DTR on this platform")) #not sure whether to output an error message |
206 pass |
261 pass |
207 self.printer.open() |
262 self.printer.open() |
208 except SerialException as e: |
263 except SerialException as e: |
213 except IOError as e: |
268 except IOError as e: |
214 self.logError(_("Could not connect to %s at baudrate %s:") % (self.port, self.baud) + |
269 self.logError(_("Could not connect to %s at baudrate %s:") % (self.port, self.baud) + |
215 "\n" + _("IO error: %s") % e) |
270 "\n" + _("IO error: %s") % e) |
216 self.printer = None |
271 self.printer = None |
217 return |
272 return |
|
273 for handler in self.event_handler: |
|
274 try: handler.on_connect() |
|
275 except: logging.error(traceback.format_exc()) |
218 self.stop_read_thread = False |
276 self.stop_read_thread = False |
219 self.read_thread = threading.Thread(target = self._listen) |
277 self.read_thread = threading.Thread(target = self._listen, |
|
278 name='read thread') |
220 self.read_thread.start() |
279 self.read_thread.start() |
221 self._start_sender() |
280 self._start_sender() |
222 |
281 |
223 def reset(self): |
282 def reset(self): |
224 """Reset the printer |
283 """Reset the printer |
225 """ |
284 """ |
226 if self.printer and not self.printer_tcp: |
285 if self.printer and not self.printer_tcp: |
227 self.printer.setDTR(1) |
286 self.printer.dtr = 1 |
228 time.sleep(0.2) |
287 time.sleep(0.2) |
229 self.printer.setDTR(0) |
288 self.printer.dtr = 0 |
|
289 |
|
290 def _readline_buf(self): |
|
291 "Try to readline from buffer" |
|
292 if len(self.readline_buf): |
|
293 chunk = self.readline_buf[-1] |
|
294 eol = chunk.find(b'\n') |
|
295 if eol >= 0: |
|
296 line = b''.join(self.readline_buf[:-1]) + chunk[:(eol+1)] |
|
297 self.readline_buf = [] |
|
298 if eol + 1 < len(chunk): |
|
299 self.readline_buf.append(chunk[(eol+1):]) |
|
300 return line |
|
301 return PR_AGAIN |
|
302 |
|
303 def _readline_nb(self): |
|
304 "Non blocking readline. Socket based files do not support non blocking or timeouting readline" |
|
305 if self.printer_tcp: |
|
306 line = self._readline_buf() |
|
307 if line: |
|
308 return line |
|
309 chunk_size = 256 |
|
310 while True: |
|
311 chunk = self.printer.read(chunk_size) |
|
312 if chunk is SYS_AGAIN and self.selector.select(self.timeout): |
|
313 chunk = self.printer.read(chunk_size) |
|
314 #print('_readline_nb chunk', chunk, type(chunk)) |
|
315 if chunk: |
|
316 self.readline_buf.append(chunk) |
|
317 line = self._readline_buf() |
|
318 if line: |
|
319 return line |
|
320 elif chunk is SYS_AGAIN: |
|
321 return PR_AGAIN |
|
322 else: |
|
323 #chunk == b'' means EOF |
|
324 line = b''.join(self.readline_buf) |
|
325 self.readline_buf = [] |
|
326 self.stop_read_thread = True |
|
327 return line if line else PR_EOF |
|
328 else: # serial port |
|
329 return self.printer.readline() |
230 |
330 |
231 def _readline(self): |
331 def _readline(self): |
232 try: |
332 try: |
233 try: |
333 line_bytes = self._readline_nb() |
234 line = self.printer.readline() |
334 if line_bytes is PR_EOF: |
235 if self.printer_tcp and not line: |
335 self.logError(_("Can't read from printer (disconnected?). line_bytes is None")) |
236 raise OSError(-1, "Read EOF from socket") |
336 return PR_EOF |
237 except socket.timeout: |
337 line = line_bytes.decode('utf-8') |
238 return "" |
|
239 |
338 |
240 if len(line) > 1: |
339 if len(line) > 1: |
241 self.log.append(line) |
340 self.log.append(line) |
|
341 for handler in self.event_handler: |
|
342 try: handler.on_recv(line) |
|
343 except: logging.error(traceback.format_exc()) |
242 if self.recvcb: |
344 if self.recvcb: |
243 try: self.recvcb(line) |
345 try: self.recvcb(line) |
244 except: self.logError(traceback.format_exc()) |
346 except: self.logError(traceback.format_exc()) |
245 if self.loud: logging.info("RECV: %s" % line.rstrip()) |
347 if self.loud: logging.info("RECV: %s" % line.rstrip()) |
246 return line |
348 return line |
|
349 except UnicodeDecodeError: |
|
350 self.logError(_("Got rubbish reply from %s at baudrate %s:") % (self.port, self.baud) + |
|
351 "\n" + _("Maybe a bad baudrate?")) |
|
352 return None |
247 except SelectError as e: |
353 except SelectError as e: |
248 if 'Bad file descriptor' in e.args[1]: |
354 if 'Bad file descriptor' in e.args[1]: |
249 self.logError(_(u"Can't read from printer (disconnected?) (SelectError {0}): {1}").format(e.errno, decode_utf8(e.strerror))) |
355 self.logError(_("Can't read from printer (disconnected?) (SelectError {0}): {1}").format(e.errno, decode_utf8(e.strerror))) |
250 return None |
356 return None |
251 else: |
357 else: |
252 self.logError(_(u"SelectError ({0}): {1}").format(e.errno, decode_utf8(e.strerror))) |
358 self.logError(_("SelectError ({0}): {1}").format(e.errno, decode_utf8(e.strerror))) |
253 raise |
359 raise |
254 except SerialException as e: |
360 except SerialException as e: |
255 self.logError(_(u"Can't read from printer (disconnected?) (SerialException): {0}").format(decode_utf8(str(e)))) |
361 self.logError(_("Can't read from printer (disconnected?) (SerialException): {0}").format(decode_utf8(str(e)))) |
256 return None |
362 return None |
257 except socket.error as e: |
363 except socket.error as e: |
258 self.logError(_(u"Can't read from printer (disconnected?) (Socket error {0}): {1}").format(e.errno, decode_utf8(e.strerror))) |
364 self.logError(_("Can't read from printer (disconnected?) (Socket error {0}): {1}").format(e.errno, decode_utf8(e.strerror))) |
259 return None |
365 return None |
260 except OSError as e: |
366 except OSError as e: |
261 if e.errno == errno.EAGAIN: # Not a real error, no data was available |
367 if e.errno == errno.EAGAIN: # Not a real error, no data was available |
262 return "" |
368 return "" |
263 self.logError(_(u"Can't read from printer (disconnected?) (OS Error {0}): {1}").format(e.errno, e.strerror)) |
369 self.logError(_("Can't read from printer (disconnected?) (OS Error {0}): {1}").format(e.errno, e.strerror)) |
264 return None |
370 return None |
265 |
371 |
266 def _listen_can_continue(self): |
372 def _listen_can_continue(self): |
267 if self.printer_tcp: |
373 if self.printer_tcp: |
268 return not self.stop_read_thread and self.printer |
374 return not self.stop_read_thread and self.printer |
269 return (not self.stop_read_thread |
375 return (not self.stop_read_thread |
270 and self.printer |
376 and self.printer |
271 and self.printer.isOpen()) |
377 and self.printer.is_open) |
272 |
378 |
273 def _listen_until_online(self): |
379 def _listen_until_online(self): |
274 while not self.online and self._listen_can_continue(): |
380 while not self.online and self._listen_can_continue(): |
275 self._send("M105") |
381 self._send("M105") |
276 if self.writefailures >= 4: |
382 if self.writefailures >= 4: |
308 if not self.printing: |
417 if not self.printing: |
309 self._listen_until_online() |
418 self._listen_until_online() |
310 while self._listen_can_continue(): |
419 while self._listen_can_continue(): |
311 line = self._readline() |
420 line = self._readline() |
312 if line is None: |
421 if line is None: |
|
422 logging.debug('_readline() is None, exiting _listen()') |
313 break |
423 break |
314 if line.startswith('DEBUG_'): |
424 if line.startswith('DEBUG_'): |
315 continue |
425 continue |
316 if line.startswith(tuple(self.greetings)) or line.startswith('ok'): |
426 if line.startswith(tuple(self.greetings)) or line.startswith('ok'): |
317 self.clear = True |
427 self.clear = True |
318 if line.startswith('ok') and "T:" in line and self.tempcb: |
428 if line.startswith('ok') and "T:" in line: |
319 # callback for temp, status, whatever |
429 for handler in self.event_handler: |
320 try: self.tempcb(line) |
430 try: handler.on_temp(line) |
321 except: self.logError(traceback.format_exc()) |
431 except: logging.error(traceback.format_exc()) |
|
432 if self.tempcb: |
|
433 # callback for temp, status, whatever |
|
434 try: self.tempcb(line) |
|
435 except: self.logError(traceback.format_exc()) |
322 elif line.startswith('Error'): |
436 elif line.startswith('Error'): |
323 self.logError(line) |
437 self.logError(line) |
324 # Teststrings for resend parsing # Firmware exp. result |
438 # Teststrings for resend parsing # Firmware exp. result |
325 # line="rs N2 Expected checksum 67" # Teacup 2 |
439 # line="rs N2 Expected checksum 67" # Teacup 2 |
326 if line.lower().startswith("resend") or line.startswith("rs"): |
440 if line.lower().startswith("resend") or line.startswith("rs"): |
411 """ |
528 """ |
412 if not self.printing: return False |
529 if not self.printing: return False |
413 self.paused = True |
530 self.paused = True |
414 self.printing = False |
531 self.printing = False |
415 |
532 |
416 # try joining the print thread: enclose it in try/except because we |
533 # ';@pause' in the gcode file calls pause from the print thread |
417 # might be calling it from the thread itself |
534 if not threading.current_thread() is self.print_thread: |
418 try: |
535 try: |
419 self.print_thread.join() |
536 self.print_thread.join() |
420 except RuntimeError, e: |
537 except: |
421 if e.message == "cannot join current thread": |
|
422 pass |
|
423 else: |
|
424 self.logError(traceback.format_exc()) |
538 self.logError(traceback.format_exc()) |
425 except: |
|
426 self.logError(traceback.format_exc()) |
|
427 |
539 |
428 self.print_thread = None |
540 self.print_thread = None |
429 |
541 |
430 # saves the status |
542 # saves the status |
431 self.pauseX = self.analyzer.abs_x |
543 self.pauseX = self.analyzer.abs_x |
432 self.pauseY = self.analyzer.abs_y |
544 self.pauseY = self.analyzer.abs_y |
433 self.pauseZ = self.analyzer.abs_z |
545 self.pauseZ = self.analyzer.abs_z |
434 self.pauseE = self.analyzer.abs_e |
546 self.pauseE = self.analyzer.abs_e |
435 self.pauseF = self.analyzer.current_f |
547 self.pauseF = self.analyzer.current_f |
436 self.pauseRelative = self.analyzer.relative |
548 self.pauseRelative = self.analyzer.relative |
|
549 self.pauseRelativeE = self.analyzer.relative_e |
437 |
550 |
438 def resume(self): |
551 def resume(self): |
439 """Resumes a paused print. |
552 """Resumes a paused print.""" |
440 """ |
|
441 if not self.paused: return False |
553 if not self.paused: return False |
442 if self.paused: |
554 # restores the status |
443 # restores the status |
555 self.send_now("G90") # go to absolute coordinates |
444 self.send_now("G90") # go to absolute coordinates |
556 |
445 |
557 xyFeed = '' if self.xy_feedrate is None else ' F' + str(self.xy_feedrate) |
446 xyFeedString = "" |
558 zFeed = '' if self.z_feedrate is None else ' F' + str(self.z_feedrate) |
447 zFeedString = "" |
559 |
448 if self.xy_feedrate is not None: |
560 self.send_now("G1 X%s Y%s%s" % (self.pauseX, self.pauseY, xyFeed)) |
449 xyFeedString = " F" + str(self.xy_feedrate) |
561 self.send_now("G1 Z" + str(self.pauseZ) + zFeed) |
450 if self.z_feedrate is not None: |
562 self.send_now("G92 E" + str(self.pauseE)) |
451 zFeedString = " F" + str(self.z_feedrate) |
563 |
452 |
564 # go back to relative if needed |
453 self.send_now("G1 X%s Y%s%s" % (self.pauseX, self.pauseY, |
565 if self.pauseRelative: |
454 xyFeedString)) |
566 self.send_now("G91") |
455 self.send_now("G1 Z" + str(self.pauseZ) + zFeedString) |
567 if self.pauseRelativeE: |
456 self.send_now("G92 E" + str(self.pauseE)) |
568 self.send_now('M83') |
457 |
569 # reset old feed rate |
458 # go back to relative if needed |
570 self.send_now("G1 F" + str(self.pauseF)) |
459 if self.pauseRelative: self.send_now("G91") |
|
460 # reset old feed rate |
|
461 self.send_now("G1 F" + str(self.pauseF)) |
|
462 |
571 |
463 self.paused = False |
572 self.paused = False |
464 self.printing = True |
573 self.printing = True |
465 self.print_thread = threading.Thread(target = self._print, |
574 self.print_thread = threading.Thread(target = self._print, |
|
575 name = 'print thread', |
466 kwargs = {"resuming": True}) |
576 kwargs = {"resuming": True}) |
467 self.print_thread.start() |
577 self.print_thread.start() |
468 |
578 |
469 def send(self, command, wait = 0): |
579 def send(self, command, wait = 0): |
470 """Adds a command to the checksummed main command queue if printing, or |
580 """Adds a command to the checksummed main command queue if printing, or |
538 self.resendfrom = -1 |
654 self.resendfrom = -1 |
539 if not self.priqueue.empty(): |
655 if not self.priqueue.empty(): |
540 self._send(self.priqueue.get_nowait()) |
656 self._send(self.priqueue.get_nowait()) |
541 self.priqueue.task_done() |
657 self.priqueue.task_done() |
542 return |
658 return |
543 if self.printing and self.queueindex < len(self.mainqueue): |
659 if self.printing and self.mainqueue.has_index(self.queueindex): |
544 (layer, line) = self.mainqueue.idxs(self.queueindex) |
660 (layer, line) = self.mainqueue.idxs(self.queueindex) |
545 gline = self.mainqueue.all_layers[layer][line] |
661 gline = self.mainqueue.all_layers[layer][line] |
|
662 if self.queueindex > 0: |
|
663 (prev_layer, prev_line) = self.mainqueue.idxs(self.queueindex - 1) |
|
664 if prev_layer != layer: |
|
665 for handler in self.event_handler: |
|
666 try: handler.on_layerchange(layer) |
|
667 except: logging.error(traceback.format_exc()) |
546 if self.layerchangecb and self.queueindex > 0: |
668 if self.layerchangecb and self.queueindex > 0: |
547 (prev_layer, prev_line) = self.mainqueue.idxs(self.queueindex - 1) |
669 (prev_layer, prev_line) = self.mainqueue.idxs(self.queueindex - 1) |
548 if prev_layer != layer: |
670 if prev_layer != layer: |
549 try: self.layerchangecb(layer) |
671 try: self.layerchangecb(layer) |
550 except: self.logError(traceback.format_exc()) |
672 except: self.logError(traceback.format_exc()) |
|
673 for handler in self.event_handler: |
|
674 try: handler.on_preprintsend(gline, self.queueindex, self.mainqueue) |
|
675 except: logging.error(traceback.format_exc()) |
551 if self.preprintsendcb: |
676 if self.preprintsendcb: |
552 if self.queueindex + 1 < len(self.mainqueue): |
677 if self.mainqueue.has_index(self.queueindex + 1): |
553 (next_layer, next_line) = self.mainqueue.idxs(self.queueindex + 1) |
678 (next_layer, next_line) = self.mainqueue.idxs(self.queueindex + 1) |
554 next_gline = self.mainqueue.all_layers[next_layer][next_line] |
679 next_gline = self.mainqueue.all_layers[next_layer][next_line] |
555 else: |
680 else: |
556 next_gline = None |
681 next_gline = None |
557 gline = self.preprintsendcb(gline, next_gline) |
682 gline = self.preprintsendcb(gline, next_gline) |
601 except: |
729 except: |
602 logging.warning(_("Could not analyze command %s:") % command + |
730 logging.warning(_("Could not analyze command %s:") % command + |
603 "\n" + traceback.format_exc()) |
731 "\n" + traceback.format_exc()) |
604 if self.loud: |
732 if self.loud: |
605 logging.info("SENT: %s" % command) |
733 logging.info("SENT: %s" % command) |
|
734 |
|
735 for handler in self.event_handler: |
|
736 try: handler.on_send(command, gline) |
|
737 except: logging.error(traceback.format_exc()) |
606 if self.sendcb: |
738 if self.sendcb: |
607 try: self.sendcb(command, gline) |
739 try: self.sendcb(command, gline) |
608 except: self.logError(traceback.format_exc()) |
740 except: self.logError(traceback.format_exc()) |
609 try: |
741 try: |
610 self.printer.write(str(command + "\n")) |
742 self.printer.write((command + "\n").encode('ascii')) |
611 if self.printer_tcp: |
743 if self.printer_tcp: |
612 try: |
744 try: |
613 self.printer.flush() |
745 self.printer.flush() |
614 except socket.timeout: |
746 except socket.timeout: |
615 pass |
747 pass |
616 self.writefailures = 0 |
748 self.writefailures = 0 |
617 except socket.error as e: |
749 except socket.error as e: |
618 if e.errno is None: |
750 if e.errno is None: |
619 self.logError(_(u"Can't write to printer (disconnected ?):") + |
751 self.logError(_("Can't write to printer (disconnected ?):") + |
620 "\n" + traceback.format_exc()) |
752 "\n" + traceback.format_exc()) |
621 else: |
753 else: |
622 self.logError(_(u"Can't write to printer (disconnected?) (Socket error {0}): {1}").format(e.errno, decode_utf8(e.strerror))) |
754 self.logError(_("Can't write to printer (disconnected?) (Socket error {0}): {1}").format(e.errno, decode_utf8(e.strerror))) |
623 self.writefailures += 1 |
755 self.writefailures += 1 |
624 except SerialException as e: |
756 except SerialException as e: |
625 self.logError(_(u"Can't write to printer (disconnected?) (SerialException): {0}").format(decode_utf8(str(e)))) |
757 self.logError(_("Can't write to printer (disconnected?) (SerialException): {0}").format(decode_utf8(str(e)))) |
626 self.writefailures += 1 |
758 self.writefailures += 1 |
627 except RuntimeError as e: |
759 except RuntimeError as e: |
628 self.logError(_(u"Socket connection broken, disconnected. ({0}): {1}").format(e.errno, decode_utf8(e.strerror))) |
760 self.logError(_("Socket connection broken, disconnected. ({0}): {1}").format(e.errno, decode_utf8(e.strerror))) |
629 self.writefailures += 1 |
761 self.writefailures += 1 |