1# -*- coding: utf-8 -*- 2# 3# (c) Copyright 2003-2015 HP Development Company, L.P. 4# 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. 9# 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. 14# 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 18# 19# Author: Don Welch 20# 21 22 23 24# Std Lib 25import sys 26import os 27import os.path 28import time 29import threading 30from base.sixext.moves import queue 31from io import StringIO 32 33# Local 34from base.g import * 35from base.codes import * 36from base import device, utils, status, pml 37 38# Event queue values (UI ==> Copy thread) 39COPY_CANCELED = 1 40 41# Update queue values (Copy thread ==> UI) 42STATUS_IDLE = 0 43STATUS_SETTING_UP = 1 44STATUS_WARMING_UP = 2 45STATUS_ACTIVE = 3 46STATUS_DONE = 4 47STATUS_ERROR = 5 48 49 50# PML Copier Only 51class PMLCopyDevice(device.Device): 52 def __init__(self, device_uri=None, printer_name=None, 53 service=None, callback=None): 54 55 device.Device.__init__(self, device_uri, printer_name, 56 service, callback) 57 58 self.copy_thread = None 59 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): 65 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() 70 return True 71 else: 72 return False 73 74 def isCopyActive(self): 75 if self.copy_thread is not None: 76 return self.copy_thread.isAlive() 77 else: 78 return False 79 80 def waitForCopyThread(self): 81 if self.copy_thread is not None and \ 82 self.copy_thread.isAlive(): 83 84 self.copy_thread.join() 85 86 87 88class 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): 92 93 threading.Thread.__init__(self) 94 self.dev = dev 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) 106 107 def run(self): 108 STATE_DONE = 0 109 STATE_ERROR = 5 110 STATE_ABORTED = 10 111 STATE_SUCCESS = 20 112 STATE_BUSY = 25 113 STATE_SET_TOKEN = 30 114 STATE_SETUP_STATE = 40 115 STATE_SETUP_PARAMS = 50 116 STATE_START = 60 117 STATE_ACTIVE = 70 118 STATE_RESET_TOKEN = 80 119 120# state = STATE_SET_TOKEN 121 state = STATE_SETUP_STATE 122 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 129 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 134 135 if state == STATE_ERROR: 136 log.debug("%s State: Error" % ("*"*20)) 137 self.write_queue(STATUS_ERROR) 138 state = STATE_RESET_TOKEN 139 140 elif state == STATE_SUCCESS: 141 log.debug("%s State: Success" % ("*"*20)) 142 self.write_queue(STATUS_DONE) 143 state = STATE_RESET_TOKEN 144 145 elif state == STATE_BUSY: 146 log.debug("%s State: Busy" % ("*"*20)) 147 self.write_queue(STATUS_ERROR) 148 state = STATE_RESET_TOKEN 149 150 elif state == STATE_SET_TOKEN: 151 log.debug("%s State: Acquire copy token" % ("*"*20)) 152 153 self.write_queue(STATUS_SETTING_UP) 154 155 try: 156 result_code, token = self.dev.getPML(pml.OID_COPIER_TOKEN) 157 except Error: 158 log.debug("Unable to acquire copy token (1).") 159 state = STATE_SETUP_STATE 160 else: 161 if result_code > pml.ERROR_MAX_OK: 162 state = STATE_SETUP_STATE 163 log.debug("Skipping token acquisition.") 164 else: 165 token = time.strftime("%d%m%Y%H:%M:%S", time.gmtime()) 166 log.debug("Setting token: %s" % token) 167 try: 168 self.dev.setPML(pml.OID_COPIER_TOKEN, token) 169 except Error: 170 log.error("Unable to acquire copy token (2).") 171 state = STATUS_ERROR 172 else: 173 result_code, check_token = self.dev.getPML(pml.OID_COPIER_TOKEN) 174 175 if check_token == token: 176 state = STATE_SETUP_STATE 177 else: 178 log.error("Unable to acquire copy token (3).") 179 state = STATE_ERROR 180 181 elif state == STATE_SETUP_STATE: 182 log.debug("%s State: Setup state" % ("*"*20)) 183 184 if self.copy_type == COPY_TYPE_DEVICE: 185 result_code, copy_state = self.dev.getPML(pml.OID_COPIER_JOB) 186 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 190 191 else: 192 state = STATE_BUSY 193 194 elif self.copy_type == COPY_TYPE_AIO_DEVICE: 195 result_code, copy_state = self.dev.getPML(pml.OID_SCAN_TO_PRINTER) 196 197 if copy_state == pml.SCAN_TO_PRINTER_IDLE: 198 state = STATE_SETUP_PARAMS 199 200 else: 201 state = STATE_BUSY 202 203 204 205 elif state == STATE_SETUP_PARAMS: 206 log.debug("%s State: Setup Params" % ("*"*20)) 207 208 if self.num_copies < 0: self.num_copies = 1 209 if self.num_copies > 99: self.num_copies = 99 210 211 if self.copy_type == COPY_TYPE_DEVICE: # MFP 212 213 # num_copies 214 self.dev.setPML(pml.OID_COPIER_JOB_NUM_COPIES, self.num_copies) 215 216 # contrast 217 self.dev.setPML(pml.OID_COPIER_JOB_CONTRAST, self.contrast) 218 219 # reduction 220 self.dev.setPML(pml.OID_COPIER_JOB_REDUCTION, self.reduction) 221 222 # quality 223 self.dev.setPML(pml.OID_COPIER_JOB_QUALITY, self.quality) 224 225 # fit_to_page 226 if self.scan_src == SCAN_SRC_FLATBED: 227 self.dev.setPML(pml.OID_COPIER_JOB_FIT_TO_PAGE, self.fit_to_page) 228 229 else: # AiO 230 # num_copies 231 self.dev.setPML(pml.OID_COPIER_NUM_COPIES_AIO, self.num_copies) 232 233 # contrast 234 self.contrast = (self.contrast * 10 / 25) + 50 235 self.dev.setPML(pml.OID_COPIER_CONTRAST_AIO, self.contrast) 236 237 if self.fit_to_page == pml.COPIER_FIT_TO_PAGE_ENABLED: 238 self.reduction = 0 239 240 # reduction 241 self.dev.setPML(pml.OID_COPIER_REDUCTION_AIO, self.reduction) 242 243 # quality 244 self.dev.setPML(pml.OID_COPIER_QUALITY_AIO, self.quality) 245 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) 249 250 # tray select 251 self.dev.setPML(pml.OID_COPIER_JOB_INPUT_TRAY_SELECT, pml.COPIER_JOB_INPUT_TRAY_1) 252 253 # media type 254 self.dev.setPML(pml.OID_COPIER_MEDIA_TYPE, pml.COPIER_MEDIA_TYPE_AUTOMATIC) 255 256 # pixel data type 257 self.dev.setPML(pml.OID_PIXEL_DATA_TYPE, pml.PIXEL_DATA_TYPE_COLOR_24_BIT) 258 259 # special features 260 self.dev.setPML(pml.OID_COPIER_SPECIAL_FEATURES, pml.COPY_FEATURE_NONE) 261 262 # media size 263 self.dev.setPML(pml.OID_COPIER_JOB_MEDIA_SIZE, pml.COPIER_JOB_MEDIA_SIZE_US_LETTER) 264 265 266 267 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) 273 274 state = STATE_START 275 276 elif state == STATE_START: 277 log.debug("%s State: Start" % ("*"*20)) 278 279 if self.copy_type == COPY_TYPE_DEVICE: 280 self.dev.setPML(pml.OID_COPIER_JOB, pml.COPIER_JOB_START) 281 282 elif self.copy_type == COPY_TYPE_AIO_DEVICE: 283 self.dev.setPML(pml.OID_SCAN_TO_PRINTER, pml.SCAN_TO_PRINTER_START) 284 285 state = STATE_ACTIVE 286 287 elif state == STATE_ACTIVE: 288 log.debug("%s State: Active" % ("*"*20)) 289 290 if self.copy_type == COPY_TYPE_DEVICE: 291 while True: 292 result_code, copy_state = self.dev.getPML(pml.OID_COPIER_JOB) 293 294 if self.check_for_cancel(): 295 self.dev.setPML(pml.OID_COPIER_JOB, pml.COPIER_JOB_IDLE) # cancel 296 state = STATE_ABORTED 297 break 298 299 if copy_state == pml.COPIER_JOB_START: 300 log.debug("state = start") 301 time.sleep(1) 302 continue 303 304 if copy_state == pml.COPIER_JOB_ACTIVE: 305 self.write_queue(STATUS_ACTIVE) 306 log.debug("state = active") 307 time.sleep(2) 308 continue 309 310 elif copy_state == pml.COPIER_JOB_ABORTING: 311 log.debug("state = aborting") 312 state = STATE_ABORTED 313 break 314 315 elif copy_state == pml.COPIER_JOB_IDLE: 316 log.debug("state = idle") 317 state = STATE_SUCCESS 318 break 319 320 elif self.copy_type == COPY_TYPE_AIO_DEVICE: 321 while True: 322 result_code, copy_state = self.dev.getPML(pml.OID_SCAN_TO_PRINTER) 323 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 327 break 328 329 if copy_state == pml.SCAN_TO_PRINTER_START: 330 log.debug("state = start") 331 time.sleep(1) 332 continue 333 334 if copy_state == pml.SCAN_TO_PRINTER_ACTIVE: 335 self.write_queue(STATUS_ACTIVE) 336 log.debug("state = active") 337 time.sleep(2) 338 continue 339 340 elif copy_state == pml.SCAN_TO_PRINTER_ABORTED: 341 log.debug("state = aborting") 342 state = STATE_ABORTED 343 break 344 345 elif copy_state == pml.SCAN_TO_PRINTER_IDLE: 346 log.debug("state = idle") 347 state = STATE_SUCCESS 348 break 349 350 351 elif state == STATE_RESET_TOKEN: 352 log.debug("%s State: Release copy token" % ("*"*20)) 353 354 try: 355 self.dev.setPML(pml.OID_COPIER_TOKEN, '\x00'*16) 356 except Error: 357 log.error("Unable to release copier token.") 358 359 self.dev.close() # Close the device. 360 361 state = STATE_DONE 362 363 364 def check_for_cancel(self): 365 canceled = False 366 while self.event_queue.qsize(): 367 try: 368 event = self.event_queue.get(0) 369 if event == COPY_CANCELED: 370 canceled = True 371 log.debug("Cancel pressed!") 372 except queue.Empty: 373 break 374 375 return canceled 376 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) 380 time.sleep(0) 381 self.prev_update = message 382