Tizen 2.1 base
[platform/upstream/hplip.git] / base / mfpdtf.py
1 # -*- coding: utf-8 -*-
2 #
3 # (c) Copyright 2003-2007 Hewlett-Packard 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 # Std Lib
23 import struct
24 import cStringIO
25
26 # Local
27 from g import *
28 from codes import *
29
30 # Page flags
31 NEW_PAGE =            0x01
32 END_PAGE  =           0x02
33 NEW_DOCUMENT =        0x04
34 END_DOCUMENT =        0x08
35 END_STREAM  =         0x10
36 RESERVED_20 =         0x20
37 RESERVED_40 =         0x40
38 RESERVED_80 =         0x80
39
40 MFPDTF_RASTER_BITMAP  = 0
41 MFPDTF_RASTER_GRAYMAP = 1
42 MFPDTF_RASTER_MH      = 2
43 MFPDTF_RASTER_MR      = 3
44 MFPDTF_RASTER_MMR     = 4
45 MFPDTF_RASTER_RGB     = 5
46 MFPDTF_RASTER_YCC411  = 6
47 MFPDTF_RASTER_JPEG    = 7
48 MFPDTF_RASTER_PCL     = 8
49 MFPDTF_RASTER_NOT     = 9
50
51 # Data types for FH
52 DT_UNKNOWN       = 0
53 DT_FAX_IMAGES    = 1
54 DT_SCANNED_IMAGES= 2
55 DT_DIAL_STRINGS  = 3
56 DT_DEMO_PAGES    = 4
57 DT_SPEED_DIALS   = 5
58 DT_FAX_LOGS      = 6
59 DT_CFG_PARMS     = 7
60 DT_LANG_STRS     = 8
61 DT_JUNK_FAX_CSIDS= 9  
62 DT_REPORT_STRS   = 10  
63 DT_FONTS         = 11
64 DT_TTI_BITMAP    = 12
65 DT_COUNTERS      = 13
66 DT_DEF_PARMS     = 14  
67 DT_SCAN_OPTIONS  = 15
68 DT_FW_JOB_TABLE  = 17
69
70 # Raster data record types
71 RT_START_PAGE = 0
72 RT_RASTER = 1
73 RT_END_PAGE = 2
74
75 # FH
76 FIXED_HEADER_SIZE = 8
77
78 # Variants
79 IMAGE_VARIANT_HEADER_SIZE = 10
80 DIAL_STRINGS_VARIANT_HEADER_SIZE = 6
81 FAX_IMAGE_VARIANT_HEADER_SIZE = 74
82
83 # Data records
84 SOP_RECORD_SIZE = 36
85 RASTER_RECORD_SIZE = 4
86 EOP_RECORD_SIZE = 12
87 DIAL_STRING_RECORD_SIZE = 51
88
89 # Page flags 
90 PAGE_FLAG_NEW_PAGE = 0x01
91 PAGE_FLAG_END_PAGE = 0x02
92 PAGE_FLAG_NEW_DOC = 0x04
93 PAGE_FLAG_END_DOC = 0x08
94 PAGE_FLAG_END_STREAM = 0x10
95
96 # Fax data variant header data source
97 SRC_UNKNOWN = 0
98 SRC_HOST = 2
99 SRC_SCANNER = 5
100 SRC_HOST_THEN_SCANNER = 6
101 SRC_SCANNER_THEN_HOST = 7
102
103 # Fax data variant header TTI header control
104 TTI_NONE = 0
105 TTI_PREPENDED_TO_IMAGE = 1
106 TTI_OVERLAYED_ON_IMAGE = 2
107
108 MAJOR_VER = 2
109 MINOR_VER = 0
110
111
112 def parseFixedHeader(buffer):
113     fmt = "<IHBB"
114     block_len, header_len, data_type, page_flags = struct.unpack(fmt, buffer[:8])
115     page_flags = page_flags & 0x1f
116     return block_len, header_len, data_type, page_flags
117
118 def parseImageVariantHeader(buffer, data_type):
119     if data_type == DT_SCANNED_IMAGES:
120         fmt = "<BBHHHH"
121         major_ver, minor_ver, src_pages, copies_per_page, zoom, jpeg_q_factor = struct.unpack(fmt, buffer[:10])
122         return major_ver, minor_ver, src_pages, copies_per_page, zoom, jpeg_q_factor
123     elif data_type == DT_FAX_IMAGES:
124         pass
125
126 def parseRecord(buffer):
127     record_type = struct.unpack("<B", buffer[0])[0]
128
129     if record_type == RT_START_PAGE:
130         fmt = "<BBHHHIIIHHIII"
131         id, encoding, page_num, black_ppr, black_bpp, black_rpp, black_hort_dpi, black_vert_dpi, cmy_ppr, cmy_bpp, cmy_rpp, cmy_hort_dpi, cmy_vert_dpi = \
132             struct.unpack(fmt, buffer[:SOP_RECORD_SIZE])
133         assert id == record_type
134         return id, (encoding, page_num, black_ppr, black_bpp, black_rpp, black_hort_dpi, black_vert_dpi, cmy_ppr, cmy_bpp, cmy_rpp, cmy_hort_dpi, cmy_vert_dpi)
135
136     elif record_type == RT_RASTER:
137         fmt = "<BBH"
138         id, unused, data_size = struct.unpack(fmt, buffer[:RASTER_RECORD_SIZE])
139         assert id == record_type
140         return id, (unused, data_size)
141
142     elif record_type == RT_END_PAGE:
143         fmt = "<BBBBII"
144         id, unused1, unused2, unused3, black_rows, cmy_rows = struct.unpack(fmt, buffer[:EOP_RECORD_SIZE])
145         assert id == record_type
146         return id, (unused1, unused2, unused3, black_rows, cmy_rows)
147
148     log.error("Error: Invalid record type: %d" % record_type)
149     raise Error(ERROR_INTERNAL)
150
151
152
153 def readChannelToStream(device, channel_id, stream, single_read=True, callback=None):
154     STATE_END, STATE_FIXED_HEADER, STATE_VARIANT_HEADER, STATE_RECORD = range(4)
155     state, total_bytes, block_remaining, header_remaining, data_remaining = 1, 0, 0, 0, 0
156     endScan = False
157     while state != STATE_END:
158         log.debug("**** State %d ****" % state)
159         if state == STATE_FIXED_HEADER: 
160
161             if endScan:
162                 state = STATE_END
163                 break
164
165             if data_remaining == 0:
166                 fields, data = device.readChannel(channel_id)
167                 data_remaining = len(data)
168                 if callback is not None:
169                     endScan = callback()
170
171             block_len, header_len, data_type, page_flags = parseFixedHeader(data)
172             block_remaining, header_remaining = block_len-FIXED_HEADER_SIZE, header_len-FIXED_HEADER_SIZE
173             log.debug("Fixed header: (datalen=%d(0x%x),blocklen=%d(0x%x),headerlen=%d(0x%x),datatype=0x%x,pageflags=0x%x)" % 
174                 (len(data), len(data), block_len, block_len, header_len, header_len, data_type, page_flags))
175             data_remaining -= FIXED_HEADER_SIZE
176             data = data[FIXED_HEADER_SIZE:]
177             state = STATE_RECORD
178             log.debug("Data: data=%d,block=%d,header=%d" % (data_remaining, block_remaining, header_remaining))
179
180             if page_flags & PAGE_FLAG_END_STREAM:
181                 state = STATE_END
182                 break
183
184             if header_remaining > 0:
185                 state = STATE_VARIANT_HEADER
186
187
188         elif state == STATE_VARIANT_HEADER:
189             if data_type == DT_SCANNED_IMAGES:
190                 major_ver, minor_ver, src_pages, copies_per_page, zoom, jpeg_q_factor = parseImageVariantHeader(data, data_type)
191                 log.debug("Variant header: (major/minor=%d/%d,src_pages=%d,copies_per_page=%d,zoom=%d,jpeg_q_factor=%d" % 
192                     (major_ver, minor_ver, src_pages, copies_per_page, zoom, jpeg_q_factor))
193                 data = data[IMAGE_VARIANT_HEADER_SIZE:]
194                 block_remaining -= IMAGE_VARIANT_HEADER_SIZE
195                 header_remaining -= IMAGE_VARIANT_HEADER_SIZE
196                 data_remaining -= IMAGE_VARIANT_HEADER_SIZE
197
198             elif data_type == DT_FAX_IMAGES:
199                 log.error("Unsupported data type")
200
201             else:
202                 log.error("Unsupported data type")
203
204             log.debug("Data: data=%d,block=%d,header=%d" % (data_remaining, block_remaining, header_remaining))
205
206             if header_remaining > 0:
207                 log.error("Header size error.")
208                 state = STATE_END
209                 continue
210
211             state = STATE_RECORD
212             if block_remaining == 0:
213                 state = STATE_FIXED_HEADER
214             continue
215
216         elif state == STATE_RECORD:
217             record_type, record = parseRecord(data)
218
219             if record_type == RT_START_PAGE:
220                 encoding, page_num, black_ppr, black_bpp, black_rpp, black_hort_dpi, black_vert_dpi, \
221                     cmy_ppr, cmy_bpp, cmy_rpp, cmy_hort_dpi, cmy_vert_dpi = record
222                 log.debug("Start page record: (encoding=0x%x, page=%d)" % (encoding, page_num))
223                 data = data[SOP_RECORD_SIZE:]
224                 block_remaining -= SOP_RECORD_SIZE
225                 data_remaining -= SOP_RECORD_SIZE
226                 if block_remaining != 0:
227                     log.error("Block size error.")
228                     state = STATE_END
229                     continue
230
231                 if single_read:
232                     state = STATE_END
233                 else:                    
234                     state = STATE_FIXED_HEADER
235                     log.debug("Data: data=%d,block=%d,header=%d" % (data_remaining, block_remaining, header_remaining))
236                 continue
237
238             elif record_type == RT_RASTER:
239                 unused, data_size = record
240                 log.debug("Raster record: (data size=%d(0x%x))" % (data_size, data_size))
241                 data = data[RASTER_RECORD_SIZE:]
242                 block_remaining -= RASTER_RECORD_SIZE
243                 data_remaining -= RASTER_RECORD_SIZE
244                 log.debug("Data: data=%d,block=%d,header=%d" % (data_remaining, block_remaining, header_remaining))
245
246                 if block_remaining > 0 and data_remaining > 0:
247                     log.debug("Writing remainder of data...")
248                     data_len = len(data)
249                     log.debug("Data len=%d(0x%x)" % (data_len,data_len))
250                     stream.write(data[:block_remaining])
251                     block_remaining -= data_len
252                     data_remaining -= data_len
253
254                     if data_remaining != 0:
255                         log.error("Data size error")
256                         state = STATE_END
257                         continue
258
259                 while block_remaining > 0:
260                     if endScan:
261                         #state = STATE_END
262                         break
263
264                     log.debug("Reading more data from device...")
265                     fields, data = device.readChannel(channel_id)
266
267                     if callback is not None:
268                         endScan = callback()
269
270                     data_len = len(data)
271                     log.debug("Data len=%d(0x%x)" % (data_len,data_len))
272                     stream.write(data[:block_remaining])
273                     total_bytes += data_len
274                     block_remaining -= data_len
275
276                 if block_remaining != 0:
277                     log.error("Block size error.")
278                     state = STATE_END
279                     continue
280
281                 state = STATE_FIXED_HEADER
282                 continue
283
284             elif record_type == RT_END_PAGE:
285                 unused1, unused2, unused3, black_rows, cmy_rows = record
286                 log.debug("End page record: (black_rows=%d,cmy_rows=%d)" % (black_rows, cmy_rows))
287                 data = data[EOP_RECORD_SIZE:]
288                 block_remaining -= EOP_RECORD_SIZE
289                 data_remaining -= EOP_RECORD_SIZE
290                 if block_remaining != 0:
291                     log.error("Block size error.")
292                 log.debug("Data: data=%d,block=%d,header=%d" % (data_remaining, block_remaining, header_remaining))
293
294                 if page_flags & PAGE_FLAG_END_DOC or \
295                    page_flags & PAGE_FLAG_END_STREAM:
296                     state = STATE_END
297                 else:
298                     state = STATE_FIXED_HEADER
299                 continue
300
301     log.debug("Read %d bytes" % total_bytes)
302     return endScan 
303
304
305
306 def buildMFPDTFBlock(data_type, page_flags=0, send_variant=False, data=None):
307     # Fixed header
308     # [Variant header - dial, fax, or scan]
309     # Data Record
310
311     block = cStringIO.StringIO()
312     block.write(struct.pack("<I", 0)) # Block len (4bytes)
313     header_len = FIXED_HEADER_SIZE
314
315     if send_variant:
316         if data_type == DT_DIAL_STRINGS:
317             header_len += DIAL_STRINGS_VARIANT_HEADER_SIZE
318
319         elif data_type == DT_FAX_IMAGES:
320             header_len += FAX_IMAGE_VARIANT_HEADER_SIZE
321
322     block.write(struct.pack("<H", header_len)) # Header len (2 bytes)
323     block.write(struct.pack("<B", data_type)) # Data type (1 byte)
324     block.write(struct.pack("<B", page_flags)) # Page flags (1 byte)
325
326     if send_variant:
327         if data_type == DT_DIAL_STRINGS:
328             block.write(struct.pack("<BB", MAJOR_VER, MINOR_VER))
329             block.write(struct.pack("<H", 1)) # num strings
330             block.write(struct.pack("<H", 51)) # ?
331
332         elif data_type == DT_FAX_IMAGES:
333             block.write(struct.pack("<BB", MAJOR_VER, MINOR_VER))
334             block.write(struct.pack("<B", SRC_HOST)) # Data source (1 byte)
335             block.write(struct.pack("<H", 1)) # Num pages (2 bytes)
336             block.write(struct.pack("<B", TTI_NONE)) # TTI control
337             block.write(struct.pack("<I", 0)) # time (4 bytes)
338             block.write("\x00"*20) # T30_CSI (20 bytes)
339             block.write("\x20"*20) # T30_SUB (20 bytes)
340             block.write("\x20"*20) # T30_PWD (20 bytes)
341             block.write("<I", 0) # xaction ID (4 bytes)
342
343     if data_type == DT_DIAL_STRINGS:
344         if data is not None:
345             dial_string = data['dial-string']
346             block.write(dial_string)
347             block.write('\x00'*(51-len(dial_string)))
348
349     elif data_type == DT_FAX_IMAGES:
350         pass
351
352
353     # fixed header (8 bytes):
354     # 
355     # +----------------------------+
356     # |                            |
357     # | block len (32 bits)        |
358     # | length of entire           |
359     # | block of data              |
360     # +----------------------------+
361     # |                            |
362     # | header length (16 bits)    |
363     # | length of fixed and        |
364     # | variant header (if any)    |
365     # | ==8 if no variant (fixed   |
366     # |   only                     |
367     # | >8 if variant header       |
368     # |                            |
369     # +----------------------------+
370     # |                            | 1=FAX
371     # | data type (8 bits)         | 3=DIAL_STRINGS
372     # | data type of data record(s)| 12=TTI BITMAP
373     # |                            |
374     # +----------------------------+
375     # |                            |
376     # | page flags (8 bits)        |
377     # |                            |
378     # +----------------------------+
379     #
380     # followed by variant header and/or 
381     # data record(s)...
382     #
383     # image header variant (10 bytes)
384     # 
385     # +----------------------------+
386     # |                            |
387     # | major ver (8 bits)         |
388     # |                            |
389     # +----------------------------+
390     # |                            |
391     # | minor ver (8 bits)         |
392     # |                            |
393     # +----------------------------+
394     # |                            |
395     # | source pages (16 bits)     |
396     # |                            |
397     # +----------------------------+
398     # |                            |
399     # | copies/page (16 bits)      |
400     # |                            |
401     # +----------------------------+
402     # |                            |
403     # | zoom factor (16 bits)      |
404     # |                            |
405     # +----------------------------+
406     # |                            |
407     # | jpeg Q factor (16 bits)    |
408     # |                            |
409     # +----------------------------+
410     #
411     # dial strings variant header (6 bytes)
412     #
413     # +----------------------------+
414     # |                            |
415     # | major ver (8 bits)         |
416     # |                            |
417     # +----------------------------+
418     # |                            |
419     # | minor ver (8 bits)         |
420     # |                            |
421     # +----------------------------+
422     # |                            |
423     # | num strings (16 bits)      |
424     # |                            |
425     # +----------------------------+
426     # |                            |
427     # | dial string len (16 bits)  |
428     # |                            |
429     # +----------------------------+
430     #
431     # dial string data part
432     # +----------------------------+
433     # |                            |
434     # | dial string (51 bytes)     |
435     # |                            |
436     # +----------------------------+
437     #
438     # start page (SOP) record (36 bytes)
439     # 
440     # +----------------------------+
441     # |                            |
442     # | id = 0 (8 bits)            |
443     # |                            |
444     # +----------------------------+
445     # |                            |
446     # | encoding (8 bits)          |
447     # |                            |
448     # +----------------------------+
449     # |                            |
450     # | page num (16 bits)         |
451     # |                            |
452     # +----------------------------+
453     # |                            |
454     # | black data desc (16 bytes) |
455     # |                            |
456     # +----------------------------+
457     # |                            |
458     # | cmy data desc (16 bytes)   |
459     # |                            |
460     # +----------------------------+
461     #
462     #
463     # raster data record (4 bytes + data)
464     # 
465     # +----------------------------+
466     # |                            |
467     # | id = 1 (8 bits)            |
468     # |                            |
469     # +----------------------------+
470     # |                            |
471     # | unused (8 bits)            |
472     # |                            |
473     # +----------------------------+
474     # |                            |
475     # | data bytes (n) (16 bits)   |
476     # |                            |
477     # +----------------------------+
478     # |                            |
479     # | data (n bytes)             |
480     # |                            |
481     # +----------------------------+
482     #
483     #
484     # end page (EOP) record (12 bytes)
485     # 
486     # +----------------------------+
487     # |                            |
488     # | id = 2 (8 bits)            |
489     # |                            |
490     # +----------------------------+
491     # |                            |
492     # | unused (24 bits)           |
493     # |                            |
494     # +----------------------------+
495     # |                            |
496     # | rows of black (32 bits)    |
497     # |                            |
498     # +----------------------------+
499     # |                            |
500     # | rows of cmy (32 bits)      |
501     # |                            |
502     # +----------------------------+
503     #    
504