1 # -*- coding: utf-8 -*-
3 # (c) Copyright 2003-2007 Hewlett-Packard Development Company, L.P.
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 from __future__ import generators
31 from cStringIO import StringIO
35 from base.codes import *
36 from base import device, utils, status, pml
38 # Event queue values (UI ==> Copy thread)
41 # Update queue values (Copy thread ==> UI)
51 class PMLCopyDevice(device.Device):
52 def __init__(self, device_uri=None, printer_name=None,
53 service=None, callback=None):
55 device.Device.__init__(self, device_uri, printer_name,
58 self.copy_thread = None
60 def copy(self, num_copies=1, contrast=0, reduction=100,
61 quality=pml.COPIER_QUALITY_NORMAL,
62 fit_to_page=pml.COPIER_FIT_TO_PAGE_ENABLED,
63 scan_src=SCAN_SRC_FLATBED,
64 update_queue=None, event_queue=None):
66 if not self.isCopyActive():
67 self.copy_thread = PMLCopyThread(self, num_copies, contrast, reduction, quality,
68 fit_to_page, scan_src, update_queue, event_queue)
69 self.copy_thread.start()
74 def isCopyActive(self):
75 if self.copy_thread is not None:
76 return self.copy_thread.isAlive()
80 def waitForCopyThread(self):
81 if self.copy_thread is not None and \
82 self.copy_thread.isAlive():
84 self.copy_thread.join()
88 class PMLCopyThread(threading.Thread):
89 def __init__(self, dev, num_copies, contrast, reduction, quality,
90 fit_to_page, scan_src,
91 update_queue=None, event_queue=None):
93 threading.Thread.__init__(self)
95 self.num_copies = num_copies
96 self.contrast = contrast
97 self.reduction = reduction
98 self.quality = quality
99 self.fit_to_page = fit_to_page
100 self.scan_src = scan_src
101 self.event_queue = event_queue
102 self.update_queue = update_queue
103 self.prev_update = ''
104 self.copy_type = self.dev.copy_type
105 log.debug("Copy-type = %d" % self.copy_type)
114 STATE_SETUP_STATE = 40
115 STATE_SETUP_PARAMS = 50
118 STATE_RESET_TOKEN = 80
120 # state = STATE_SET_TOKEN
121 state = STATE_SETUP_STATE
123 while state != STATE_DONE: # ------------------------- Copier Thread
124 # revisit - Checking cancel and setting state here means
125 # every state can unconditionally transition to STATE_ABORTED.
126 # This has not been verified.
127 # if self.check_for_cancel():
128 # state = STATE_ABORTED
130 if state == STATE_ABORTED:
131 log.debug("%s State: Aborted" % ("*"*20))
132 self.write_queue(STATUS_DONE) # This was STATUS_ERROR.
133 state = STATE_RESET_TOKEN
135 if state == STATE_ERROR:
136 log.debug("%s State: Error" % ("*"*20))
137 self.write_queue(STATUS_ERROR)
138 state = STATE_RESET_TOKEN
140 elif state == STATE_SUCCESS:
141 log.debug("%s State: Success" % ("*"*20))
142 self.write_queue(STATUS_DONE)
143 state = STATE_RESET_TOKEN
145 elif state == STATE_BUSY:
146 log.debug("%s State: Busy" % ("*"*20))
147 self.write_queue(STATUS_ERROR)
148 state = STATE_RESET_TOKEN
150 elif state == STATE_SET_TOKEN:
151 log.debug("%s State: Acquire copy token" % ("*"*20))
153 self.write_queue(STATUS_SETTING_UP)
156 result_code, token = self.dev.getPML(pml.OID_COPIER_TOKEN)
158 log.debug("Unable to acquire copy token (1).")
159 state = STATE_SETUP_STATE
161 if result_code > pml.ERROR_MAX_OK:
162 state = STATE_SETUP_STATE
163 log.debug("Skipping token acquisition.")
165 token = time.strftime("%d%m%Y%H:%M:%S", time.gmtime())
166 log.debug("Setting token: %s" % token)
168 self.dev.setPML(pml.OID_COPIER_TOKEN, token)
170 log.error("Unable to acquire copy token (2).")
173 result_code, check_token = self.dev.getPML(pml.OID_COPIER_TOKEN)
175 if check_token == token:
176 state = STATE_SETUP_STATE
178 log.error("Unable to acquire copy token (3).")
181 elif state == STATE_SETUP_STATE:
182 log.debug("%s State: Setup state" % ("*"*20))
184 if self.copy_type == COPY_TYPE_DEVICE:
185 result_code, copy_state = self.dev.getPML(pml.OID_COPIER_JOB)
187 if copy_state == pml.COPIER_JOB_IDLE:
188 self.dev.setPML(pml.OID_COPIER_JOB, pml.COPIER_JOB_SETUP)
189 state = STATE_SETUP_PARAMS
194 elif self.copy_type == COPY_TYPE_AIO_DEVICE:
195 result_code, copy_state = self.dev.getPML(pml.OID_SCAN_TO_PRINTER)
197 if copy_state == pml.SCAN_TO_PRINTER_IDLE:
198 state = STATE_SETUP_PARAMS
205 elif state == STATE_SETUP_PARAMS:
206 log.debug("%s State: Setup Params" % ("*"*20))
208 if self.num_copies < 0: self.num_copies = 1
209 if self.num_copies > 99: self.num_copies = 99
211 if self.copy_type == COPY_TYPE_DEVICE: # MFP
214 self.dev.setPML(pml.OID_COPIER_JOB_NUM_COPIES, self.num_copies)
217 self.dev.setPML(pml.OID_COPIER_JOB_CONTRAST, self.contrast)
220 self.dev.setPML(pml.OID_COPIER_JOB_REDUCTION, self.reduction)
223 self.dev.setPML(pml.OID_COPIER_JOB_QUALITY, self.quality)
226 if self.scan_src == SCAN_SRC_FLATBED:
227 self.dev.setPML(pml.OID_COPIER_JOB_FIT_TO_PAGE, self.fit_to_page)
231 self.dev.setPML(pml.OID_COPIER_NUM_COPIES_AIO, self.num_copies)
234 self.contrast = (self.contrast * 10 / 25) + 50
235 self.dev.setPML(pml.OID_COPIER_CONTRAST_AIO, self.contrast)
237 if self.fit_to_page == pml.COPIER_FIT_TO_PAGE_ENABLED:
241 self.dev.setPML(pml.OID_COPIER_REDUCTION_AIO, self.reduction)
244 self.dev.setPML(pml.OID_COPIER_QUALITY_AIO, self.quality)
246 self.dev.setPML(pml.OID_PIXEL_DATA_TYPE, pml.PIXEL_DATA_TYPE_COLOR_24_BIT)
247 self.dev.setPML(pml.OID_COPIER_SPECIAL_FEATURES, pml.COPY_FEATURE_NONE)
248 self.dev.setPML(pml.OID_COPIER_PHOTO_MODE, pml.ENHANCE_LIGHT_COLORS | pml.ENHANCE_TEXT)
251 self.dev.setPML(pml.OID_COPIER_JOB_INPUT_TRAY_SELECT, pml.COPIER_JOB_INPUT_TRAY_1)
254 self.dev.setPML(pml.OID_COPIER_MEDIA_TYPE, pml.COPIER_MEDIA_TYPE_AUTOMATIC)
257 self.dev.setPML(pml.OID_PIXEL_DATA_TYPE, pml.PIXEL_DATA_TYPE_COLOR_24_BIT)
260 self.dev.setPML(pml.OID_COPIER_SPECIAL_FEATURES, pml.COPY_FEATURE_NONE)
263 self.dev.setPML(pml.OID_COPIER_JOB_MEDIA_SIZE, pml.COPIER_JOB_MEDIA_SIZE_US_LETTER)
268 log.debug("num_copies = %d" % self.num_copies)
269 log.debug("contrast= %d" % self.contrast)
270 log.debug("reduction = %d" % self.reduction)
271 log.debug("quality = %d" % self.quality)
272 log.debug("fit_to_page = %d" % self.fit_to_page)
276 elif state == STATE_START:
277 log.debug("%s State: Start" % ("*"*20))
279 if self.copy_type == COPY_TYPE_DEVICE:
280 self.dev.setPML(pml.OID_COPIER_JOB, pml.COPIER_JOB_START)
282 elif self.copy_type == COPY_TYPE_AIO_DEVICE:
283 self.dev.setPML(pml.OID_SCAN_TO_PRINTER, pml.SCAN_TO_PRINTER_START)
287 elif state == STATE_ACTIVE:
288 log.debug("%s State: Active" % ("*"*20))
290 if self.copy_type == COPY_TYPE_DEVICE:
292 result_code, copy_state = self.dev.getPML(pml.OID_COPIER_JOB)
294 if self.check_for_cancel():
295 self.dev.setPML(pml.OID_COPIER_JOB, pml.COPIER_JOB_IDLE) # cancel
296 state = STATE_ABORTED
299 if copy_state == pml.COPIER_JOB_START:
300 log.debug("state = start")
304 if copy_state == pml.COPIER_JOB_ACTIVE:
305 self.write_queue(STATUS_ACTIVE)
306 log.debug("state = active")
310 elif copy_state == pml.COPIER_JOB_ABORTING:
311 log.debug("state = aborting")
312 state = STATE_ABORTED
315 elif copy_state == pml.COPIER_JOB_IDLE:
316 log.debug("state = idle")
317 state = STATE_SUCCESS
320 elif self.copy_type == COPY_TYPE_AIO_DEVICE:
322 result_code, copy_state = self.dev.getPML(pml.OID_SCAN_TO_PRINTER)
324 if self.check_for_cancel():
325 self.dev.setPML(pml.OID_SCAN_TO_PRINTER, pml.SCAN_TO_PRINTER_IDLE) # cancel
326 state = STATE_ABORTED
329 if copy_state == pml.SCAN_TO_PRINTER_START:
330 log.debug("state = start")
334 if copy_state == pml.SCAN_TO_PRINTER_ACTIVE:
335 self.write_queue(STATUS_ACTIVE)
336 log.debug("state = active")
340 elif copy_state == pml.SCAN_TO_PRINTER_ABORTED:
341 log.debug("state = aborting")
342 state = STATE_ABORTED
345 elif copy_state == pml.SCAN_TO_PRINTER_IDLE:
346 log.debug("state = idle")
347 state = STATE_SUCCESS
351 elif state == STATE_RESET_TOKEN:
352 log.debug("%s State: Release copy token" % ("*"*20))
355 self.dev.setPML(pml.OID_COPIER_TOKEN, '\x00'*16)
357 log.error("Unable to release copier token.")
359 self.dev.close() # Close the device.
364 def check_for_cancel(self):
366 while self.event_queue.qsize():
368 event = self.event_queue.get(0)
369 if event == COPY_CANCELED:
371 log.debug("Cancel pressed!")
377 def write_queue(self, message):
378 if self.update_queue is not None and message != self.prev_update:
379 self.update_queue.put(message)
381 self.prev_update = message