1 /************************************************************************************\
2 bb_ledm.c - HP SANE backend support for ledm based multi-function peripherals
3 (c) 2010 Copyright Hewlett-Packard Development Company, LP
5 Primary Author: Naga Samrat Chowdary, Narla
6 Contributing Authors: Yashwant Kumar Sahu, Sarbeswar Meher
7 \************************************************************************************/
20 # include "saneopts.h"
32 # define _STRINGIZE(x) #x
33 # define STRINGIZE(x) _STRINGIZE(x)
35 # define _BUG(args...) syslog(LOG_ERR, __FILE__ " " STRINGIZE(__LINE__) ": " args)
38 # define _DBG(args...) syslog(LOG_INFO, __FILE__ " " STRINGIZE(__LINE__) ": " args)
40 # define _DBG(args...)
56 enum SCANNER_STATE_REASON
58 SSR_ATTENTION_REQUIRED = 1,
62 SSR_INTERNAL_STORAGE_FULL,
72 int width; /* in 1/1000 of an inch */
73 int height; /* in 1/1000 of an inch */
76 struct device_settings
78 enum COLOR_ENTRY color[CE_MAX];
79 enum SCAN_FORMAT formats[SF_MAX];
80 int jpeg_quality_factor_supported; /* 0=false, 1=true */
81 enum DOCUMENT_TYPE docs[DT_MAX];
82 int document_size_auto_detect_supported; /* 0=false, 1=true */
88 int flatbed_supported; /* 0=false, 1=true */
89 struct media_size minimum_size;
90 struct media_size maximum_size;
91 struct media_size optical_resolution;
92 int platen_resolution_list[MAX_LIST_SIZE];
97 int supported; /* 0=false, 1=true */
98 int duplex_supported; /* 0=false, 1=true */
99 struct media_size minimum_size;
100 struct media_size maximum_size;
101 struct media_size optical_resolution;
102 int adf_resolution_list[MAX_LIST_SIZE];
105 struct scanner_configuration
107 struct device_settings settings;
108 struct device_platen platen;
109 struct device_adf adf;
112 struct scanner_status
115 enum SCANNER_STATE state;
116 enum SCANNER_STATE_REASON reason;
117 int paper_in_adf; /* 0=false, 1=true */
118 int scan_to_available; /* 0=false, 1=true */
121 struct wscn_scan_elements
123 struct scanner_configuration config;
124 struct scanner_status status;
125 char model_number[32];
128 struct wscn_create_scan_job_response
132 int lines; /* number of lines */
133 int bytes_per_line; /* zero if jpeg */
134 enum SCAN_FORMAT format;
135 int jpeg_quality_factor;
136 int images_to_transfer; /* number of images to scan */
137 enum INPUT_SOURCE source;
138 enum DOCUMENT_TYPE doc;
139 struct media_size input_size;
140 int scan_region_xoffset;
141 int scan_region_yoffset;
142 int scan_region_width;
143 int scan_region_height;
144 enum COLOR_ENTRY color;
145 struct media_size resolution;
148 struct bb_ledm_session
150 struct wscn_create_scan_job_response job; /* actual scan job attributes (valid after sane_start) */
151 struct wscn_scan_elements elements; /* scanner elements (valid after sane_open and sane_start) */
152 HTTP_HANDLE http_handle;
155 /* Following elements must match their associated enum table. */
156 static const char *sf_element[SF_MAX] = { "", "raw", "jpeg" }; /* SCAN_FORMAT (compression) */
157 static const char *ce_element[CE_MAX] = { "", "K1", "Gray8", "Color8" }; /* COLOR_ENTRY */
158 static const char *is_element[IS_MAX] = { "", "Platen", "Adf", "ADFDuplex" }; /* INPUT_SOURCE */
160 # define POST_HEADER "POST /Scan/Jobs HTTP/1.1\r\nHost: localhost\r\nUser-Agent: \
161 hplip\r\nAccept: text/plain, */*\r\nAccept-Language: en-us,en\r\n\
162 Accept-Charset: ISO-8859-1,utf-8\r\nKeep-Alive: 1000\r\nProxy-Connection: keep-alive\r\n\
163 Content-Type: */*; charset=UTF-8\r\nX-Requested-With: XMLHttpRequest\r\n\
164 Content-Length: %d\r\nCookie: AccessCounter=new\r\n\
165 Pragma: no-cache\r\nCache-Control: no-cache\r\n\r\n"
167 # define GET_SCANNER_ELEMENTS "GET /Scan/ScanCaps HTTP/1.1\r\n\
168 Host: localhost\r\nUser-Agent: hplip\r\n\
169 Accept: text/xml\r\n\
170 Accept-Language: en-us,en\r\n\
171 Accept-Charset:utf-8\r\n\
172 Keep-Alive: 20\r\nProxy-Connection: keep-alive\r\nCookie: AccessCounter=new\r\n0\r\n\r\n"
174 # define GET_SCANNER_STATUS "GET /Scan/Status HTTP/1.1\r\n\
175 Host: localhost\r\nUser-Agent: hplip\r\n\
176 Accept: text/xml\r\n\
177 Accept-Language: en-us,en\r\n\
178 Accept-Charset:utf-8\r\n\
179 Keep-Alive: 20\r\nProxy-Connection: keep-alive\r\nCookie: AccessCounter=new\r\n0\r\n\r\n"
181 # define CREATE_SCAN_JOB_REQUEST "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\
182 <ScanSettings xmlns=\"http://www.hp.com/schemas/imaging/con/cnx/scan/2008/08/19\">\
183 <XResolution>%d</XResolution>\
184 <YResolution>%d</YResolution>\
190 <CompressionQFactor>15</CompressionQFactor>\
191 <ColorSpace>%s</ColorSpace>\
192 <BitDepth>%d</BitDepth>\
193 <InputSource>%s</InputSource>\
194 <InputSourceType>%s</InputSourceType>%s\
195 <GrayRendering>NTSC</GrayRendering>\
198 <Brightness>1000</Brightness>\
199 <Contrast>1000</Contrast>\
200 <Highlite>0</Highlite>\
201 <Shadow>0</Shadow></ToneMap>\
202 <ContentType>Photo</ContentType></ScanSettings>"
204 # define CANCEL_JOB_REQUEST "PUT %s HTTP/1.1\r\nHost: localhost\r\nUser-Agent: hplip\r\n\
205 Accept: text/plain\r\nAccept-Language: en-us,en\r\nAccept-Charset:utf-8\r\nKeep-Alive: 10\r\n\
206 Content-Type: text/xml\r\nProxy-Connection: Keep-alive\r\nX-Requested-With: XMLHttpRequest\r\nReferer: localhost\r\n\
207 Content-Length: %d\r\nCookie: AccessCounter=new\r\n\r\n"
209 #define CANCEL_JOB_DATA "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
210 <j:Job xmlns:j=\"http://www.hp.com/schemas/imaging/con/ledm/jobs/2009/04/30\" \
211 xmlns:dd=\"http://www.hp.com/schemas/imaging/con/dictionaries/1.0/\" \
212 xmlns:fax=\"http://www.hp.com/schemas/imaging/con/fax/2008/06/13\" \
213 xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \
214 xsi:schemaLocation=\"http://www.hp.com/schemas/imaging/con/ledm/jobs/2009/04/30 ../schemas/Jobs.xsd\">\
215 <j:JobState>Canceled</j:JobState></j:Job>"
217 # define GET_SCAN_JOB_URL "GET %s HTTP/1.1\r\nHost: localhost\r\nUser-Agent: hplip\r\n\
218 Accept: text/plain\r\nAccept-Language: en-us,en\r\nAccept-Charset:utf-8\r\nX-Requested-With: XMLHttpRequest\r\n\
219 Keep-Alive: 300\r\nProxy-Connection: keep-alive\r\nCookie: AccessCounter=new\r\n0\r\n\r\n"
221 # define ZERO_FOOTER "\r\n0\r\n\r\n"
223 # define READY_TO_UPLOAD "<PageState>ReadyToUpload</PageState>"
224 # define CANCELED_BY_DEVICE "<PageState>CanceledByDevice</PageState>"
225 # define CANCELED_BY_CLIENT "<PageState>CanceledByClient</PageState>"
226 # define ADF_LOADED "<AdfState>Loaded</AdfState>"
227 # define ADF_EMPTY "<AdfState>Empty</AdfState>"
228 # define SCANNER_IDLE "<ScannerState>Idle</ScannerState>"
229 # define SCANNER_BUSY_WITH_SCAN_JOB "<ScannerState>BusyWithScanJob</ScannerState>"
230 # define JOBSTATE_PROCESSING "<j:JobState>Processing</j:JobState>"
231 # define JOBSTATE_CANCELED "<j:JobState>Canceled</j:JobState>"
232 # define JOBSTATE_COMPLETED "<j:JobState>Completed</j:JobState>"
234 static int parse_scan_elements(const char *payload, int size, struct wscn_scan_elements *elements)
239 char *tail=(char *)payload;
241 memset(elements, 0, sizeof(struct wscn_scan_elements));
245 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
250 if(strncmp(tag, "ColorEntries", 12) == 0)
255 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
256 if(strncmp(tag, "Platen", 6) ==0) break;
257 if(strncmp(tag, "/ColorEntries", 13) ==0) break;
258 if(strncmp(tag, "ColorType", 9)==0)
260 get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
261 if (strcmp(value, ce_element[CE_K1]) == 0)
262 elements->config.settings.color[CE_K1] = CE_K1;
263 else if (strcmp(value, ce_element[CE_GRAY8]) == 0)
264 elements->config.settings.color[CE_GRAY8] = CE_GRAY8;
265 else if (strcmp(value, ce_element[CE_COLOR8]) == 0)
266 elements->config.settings.color[CE_COLOR8] = CE_COLOR8;
268 // _BUG("unknowned element=%s, sf_element[SF_JPEG]=%s, sf_element[SF_RAW]=%s\n", value, sf_element[SF_JPEG], sf_element[SF_RAW] );
269 _DBG("FormatSupported:%s\n", value);
270 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
271 if(strncmp(tag, "/ColorEntries", 13) == 0) h=0;
273 if(strncmp(tag, "/ColorEntries", 13) == 0) h=0;
277 if(strncmp(tag, "Platen", 6) == 0)
279 elements->config.platen.flatbed_supported = 1;
280 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
281 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
282 get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
283 elements->config.platen.minimum_size.width=strtol(value, NULL, 10);
284 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
285 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
286 get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
287 elements->config.platen.minimum_size.height=strtol(value, NULL, 10);
288 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
289 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
290 get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
291 elements->config.platen.maximum_size.width=strtol(value, NULL, 10);
292 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
293 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
294 get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
295 elements->config.platen.maximum_size.height=strtol(value, NULL, 10);
296 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
297 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
298 get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
299 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
300 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
301 get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
302 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
303 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
304 get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
305 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
306 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
307 get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
308 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
309 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
310 get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
311 elements->config.platen.optical_resolution.width=strtol(value, NULL, 10);
312 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
313 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
314 get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
315 elements->config.platen.optical_resolution.height=strtol(value, NULL, 10);
316 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
317 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
318 get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
320 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
321 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
323 elements->config.platen.platen_resolution_list[0]=0;
324 while(strcmp(tag, "/SupportedResolutions"))
326 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
327 if(!strcmp(tag, "Resolution"))
329 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
330 get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
331 _DBG ("parse_scan_elements platen_resolution_list value=%s\n", value);
332 if(strtol(value, NULL, 10) && elements->config.platen.platen_resolution_list[i-1] != strtol(value, NULL, 10))
334 elements->config.platen.platen_resolution_list[i++]=strtol(value, NULL, 10);
337 elements->config.platen.platen_resolution_list[0]=i-1;
340 if(strncmp(tag, "Adf", 3) == 0 && strlen(tag) == 3)
342 elements->config.adf.supported = 1;
343 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
344 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
345 get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
346 elements->config.adf.minimum_size.width=strtol(value, NULL, 10);
347 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
348 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
349 get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
350 elements->config.adf.minimum_size.height=strtol(value, NULL, 10);
351 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
352 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
353 get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
354 elements->config.adf.maximum_size.width=strtol(value, NULL, 10);
355 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
356 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
357 get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
358 elements->config.adf.maximum_size.height=strtol(value, NULL, 10);
359 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
360 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
361 get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
362 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
363 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
364 get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
365 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
366 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
367 get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
368 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
369 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
370 get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
371 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
372 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
373 get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
374 elements->config.adf.optical_resolution.width=strtol(value, NULL, 10);
375 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
376 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
377 get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
378 elements->config.adf.optical_resolution.height=strtol(value, NULL, 10);
379 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
380 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
381 get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
383 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
384 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
386 elements->config.adf.adf_resolution_list[0]=0;
387 while(strcmp(tag, "/SupportedResolutions"))
389 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
390 if(!strcmp(tag, "Resolution"))
392 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
393 get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
394 _DBG ("parse_scan_elements adf_resolution_list value=%s", value);
395 if(strtol(value, NULL, 10) && elements->config.adf.adf_resolution_list[i-1] != strtol(value, NULL, 10))
396 elements->config.adf.adf_resolution_list[i++]=strtol(value, NULL, 10);
399 elements->config.adf.adf_resolution_list[0]=i-1;
400 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
401 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);//FeederCapacity
402 get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
403 _DBG ("parse_scan_elements FeederCapacity=%s", value);
404 elements->config.settings.feeder_capacity = strtol(value, NULL, 10);
405 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
406 get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
407 if(!strcmp(tag, "AdfDuplexer"))
409 elements->config.adf.duplex_supported = 1;
410 _DBG ("parse_scan_elements duplex_supported");
413 } /* end while (1) */
415 } /* parse_scan_elements */
417 static struct bb_ledm_session* create_session()
419 struct bb_ledm_session* pbb;
421 if ((pbb = malloc(sizeof(struct bb_ledm_session))) == NULL)
426 memset(pbb, 0, sizeof(struct bb_ledm_session));
428 } /* create_session */
430 static int read_http_payload(struct ledm_session *ps, char *payload, int max_size, int sec_timeout, int *bytes_read)
432 struct bb_ledm_session *pbb = ps->bb_session;
433 int stat=1, total=0, len;
435 enum HTTP_RESULT ret;
436 int payload_length=-1;
441 if(http_read_header(pbb->http_handle, payload, max_size, tmo, &len) != HTTP_R_OK)
444 _DBG("read_http_payload len=%d %s\n",len,payload);
445 temp = strstr(payload, "HTTP/1.1 201 Created");
448 *bytes_read = total = len;
453 temp=strstr(payload, "Content-Length:");
457 temp=strtok(temp, "\r\n");
458 payload_length=strtol(temp, NULL, 10);
459 if (payload_length == 0)
461 *bytes_read = total = len;
466 memset(payload, ' ', len);
467 if(payload_length==-1)
473 ret = http_read(pbb->http_handle, payload+total, max_size-total, tmo, &len);
477 if (ret == HTTP_R_EOF)
479 _DBG("read_http_payload1 DONE......\n");
483 if (!(ret == HTTP_R_OK || ret == HTTP_R_EOF))
485 _DBG("read_http_payload1 ERROR......\n");
489 }//end if(payload_length==-1)
493 while (total < payload_length)
495 ret = http_read(pbb->http_handle, payload+total, max_size-total, tmo, &len);
498 if (ret == HTTP_R_EOF)
500 _DBG("read_http_payload2 DONE......\n");
504 if (!(ret == HTTP_R_OK || ret == HTTP_R_EOF))
506 _DBG("read_http_payload2 ERROR......\n");
517 } /* read_http_payload */
519 static int get_scanner_elements(struct ledm_session *ps, struct wscn_scan_elements *elements)
521 struct bb_ledm_session *pbb = ps->bb_session;
526 if (http_open(ps->dd, HPMUD_S_LEDM_SCAN, &pbb->http_handle) != HTTP_R_OK)
528 _BUG("unable to open http connection %s\n", ps->uri);
532 /* Write the xml payload. */
533 if (http_write(pbb->http_handle, GET_SCANNER_ELEMENTS, sizeof(GET_SCANNER_ELEMENTS)-1, tmo) != HTTP_R_OK)
535 _BUG("unable to get_scanner_elements %s\n", ps->uri);
539 /* Read http response. */
540 if (read_http_payload(ps, buf, sizeof(buf), tmo, &bytes_read))
543 _DBG("get_scanner_elements bytes_read=%d len=%d buf=%s\n", bytes_read, strlen(buf), buf);
545 http_unchunk_data(buf);
546 bytes_read=strlen(buf);
548 _DBG("get_scanner_elements buf=%s\n", buf);
549 parse_scan_elements(buf, bytes_read, elements);
553 if (pbb->http_handle)
555 http_close(pbb->http_handle);
556 pbb->http_handle = 0;
559 } /* get_scanner_elements */
561 static int cancel_job(struct ledm_session *ps)
563 struct bb_ledm_session *pbb = ps->bb_session;
564 int len, stat=1, tmo=5/*EXCEPTION_TIMEOUT*/;
568 _DBG("cancel_job user_cancel=%d job_id=%d url=%s \n", ps->user_cancel, ps->job_id, ps->url);
569 if (ps->job_id == 0 || ps->user_cancel == 0)
576 if (http_open(ps->dd, HPMUD_S_LEDM_SCAN, &pbb->http_handle) != HTTP_R_OK)
578 _BUG("unable to open http connection %s\n", ps->uri);
582 len = snprintf(buf, sizeof(buf), CANCEL_JOB_REQUEST, ps->url, strlen(CANCEL_JOB_DATA));
583 if (http_write(pbb->http_handle, buf, len, 1) != HTTP_R_OK)
585 _BUG("unable to cancel_job %s\n", ps->url);
588 len = snprintf(buf, sizeof(buf), CANCEL_JOB_DATA);
589 if (http_write(pbb->http_handle, buf, len, 1) != HTTP_R_OK)
591 _BUG("unable to cancel_job %s\n", ps->url);
594 if (read_http_payload(ps, buf, sizeof(buf), tmo, &bytes_read))
600 if (pbb->http_handle)
602 http_close(pbb->http_handle);
603 pbb->http_handle = 0;
608 /* --------------------------- LEDM API Calls -----------------------------*/
610 int bb_open(struct ledm_session *ps)
612 struct bb_ledm_session *pbb;
613 struct device_settings *ds;
618 if ((ps->bb_session = create_session()) == NULL)
621 pbb = ps->bb_session;
623 /* Get scanner elements from device. */
624 if (get_scanner_elements(ps, &pbb->elements))
629 /* Determine supported Scan Modes. */
630 ds = &pbb->elements.config.settings;
631 for(i=0, j=0; i<CE_MAX; i++)
633 if (ds->color[i] == CE_K1)
635 ps->scanModeList[j] = SANE_VALUE_SCAN_MODE_LINEART;
636 ps->scanModeMap[j++] = CE_K1;
638 if (ds->color[i] == CE_GRAY8)
640 ps->scanModeList[j] = SANE_VALUE_SCAN_MODE_GRAY;
641 ps->scanModeMap[j++] = CE_GRAY8;
643 if (ds->color[i] == CE_COLOR8)
645 ps->scanModeList[j] = SANE_VALUE_SCAN_MODE_COLOR;
646 ps->scanModeMap[j++] = CE_COLOR8;
650 /* Determine scan input sources. */
652 if (pbb->elements.config.platen.flatbed_supported)
654 ps->inputSourceList[i] = STR_ADF_MODE_FLATBED;
655 ps->inputSourceMap[i++] = IS_PLATEN;
657 if (pbb->elements.config.adf.supported)
659 ps->inputSourceList[i] = STR_ADF_MODE_ADF;
660 ps->inputSourceMap[i++] = IS_ADF;
662 if (pbb->elements.config.adf.duplex_supported)
664 ps->inputSourceList[i] = STR_TITLE_DUPLEX;
665 ps->inputSourceMap[i++] = IS_ADF_DUPLEX;
668 /* Determine if jpeg quality factor is supported. */
669 if (pbb->elements.config.settings.jpeg_quality_factor_supported)
670 ps->option[LEDM_OPTION_JPEG_QUALITY].cap &= ~SANE_CAP_INACTIVE;
672 ps->option[LEDM_OPTION_JPEG_QUALITY].cap |= SANE_CAP_INACTIVE;
675 /* Set flatbed x,y extents. */
676 ps->platen_min_width = SANE_FIX(pbb->elements.config.platen.minimum_size.width/1000.0*MM_PER_INCH);
677 ps->platen_min_height = SANE_FIX(pbb->elements.config.platen.minimum_size.height/1000.0*MM_PER_INCH);
678 ps->platen_tlxRange.max = SANE_FIX(pbb->elements.config.platen.maximum_size.width/11.811023);
679 ps->platen_brxRange.max = ps->platen_tlxRange.max;
680 ps->platen_tlyRange.max = SANE_FIX(pbb->elements.config.platen.maximum_size.height/11.811023);
681 ps->platen_bryRange.max = ps->platen_tlyRange.max;
683 /* Set adf/duplex x,y extents. */
684 ps->adf_min_width = SANE_FIX(pbb->elements.config.adf.minimum_size.width/1000.0*MM_PER_INCH);
685 ps->adf_min_height = SANE_FIX(pbb->elements.config.adf.minimum_size.height/1000.0*MM_PER_INCH);
686 ps->adf_tlxRange.max = SANE_FIX(pbb->elements.config.adf.maximum_size.width/11.811023);
687 ps->adf_brxRange.max = ps->adf_tlxRange.max;
688 ps->adf_tlyRange.max = SANE_FIX(pbb->elements.config.adf.maximum_size.height/11.811023);
689 ps->adf_bryRange.max = ps->adf_tlyRange.max;
691 i = pbb->elements.config.platen.platen_resolution_list[0] + 1;
694 _DBG("bb_open platen_resolution_list = %d\n", pbb->elements.config.platen.platen_resolution_list[i]);
695 ps->platen_resolutionList[i] = pbb->elements.config.platen.platen_resolution_list[i];
696 ps->resolutionList[i] = pbb->elements.config.platen.platen_resolution_list[i];
699 i = pbb->elements.config.adf.adf_resolution_list[0] + 1;
700 while(i--) ps->adf_resolutionList[i] = pbb->elements.config.adf.adf_resolution_list[i];
708 int bb_close(struct ledm_session *ps)
710 _DBG("bb_close()\n");
711 free(ps->bb_session);
712 ps->bb_session = NULL;
716 /* Set scan parameters. If scan has started, use actual known parameters otherwise estimate. */
717 int bb_get_parameters(struct ledm_session *ps, SANE_Parameters *pp, int option)
719 struct bb_ledm_session *pbb = ps->bb_session;
720 pp->last_frame = SANE_TRUE;
723 _DBG("bb_get_parameters(option=%d)\n", option);
725 switch(ps->currentScanMode)
728 pp->format = SANE_FRAME_GRAY; /* lineart (GRAY8 converted to MONO by IP) */
733 pp->format = SANE_FRAME_GRAY; /* grayscale */
739 pp->format = SANE_FRAME_RGB; /* color */
747 case SPO_STARTED: /* called by xsane */
748 if (ps->currentCompression == SF_RAW && ps->currentScanMode != CE_GRAY8)
750 /* Set scan parameters based on scan job response values */
751 //pp->lines = pbb->job.lines;
752 pp->lines = (int)(SANE_UNFIX(ps->effectiveBry - ps->effectiveTly)/MM_PER_INCH*ps->currentResolution);
753 pp->pixels_per_line = pbb->job.pixels_per_line;
754 pp->bytes_per_line = pbb->job.bytes_per_line;
756 else /* Must be SF_JFIF or ScanMode==CE_BLACK_AND_WHITE1. */
758 /* Set scan parameters based on IP. Note for Linart, use IP for hpraw and jpeg. */
759 //pp->lines = ps->image_traits.lNumRows;
760 pp->lines = (int)(SANE_UNFIX(ps->effectiveBry - ps->effectiveTly)/MM_PER_INCH*ps->currentResolution);
761 pp->pixels_per_line = ps->image_traits.iPixelsPerRow;
762 pp->bytes_per_line = BYTES_PER_LINE(pp->pixels_per_line, pp->depth * factor);
765 case SPO_STARTED_JR: /* called by sane_start */
766 /* Set scan parameters based on scan job response values */
767 pp->lines = pbb->job.lines;
768 pp->pixels_per_line = pbb->job.pixels_per_line;
769 pp->bytes_per_line = pbb->job.bytes_per_line;
771 case SPO_BEST_GUESS: /* called by xsane & sane_start */
772 /* Set scan parameters based on best guess. */
773 pp->lines = (int)round(SANE_UNFIX(ps->effectiveBry - ps->effectiveTly)/MM_PER_INCH*ps->currentResolution);
774 pp->pixels_per_line = (int)round(SANE_UNFIX(ps->effectiveBrx -ps->effectiveTlx)/MM_PER_INCH*ps->currentResolution);
775 pp->bytes_per_line = BYTES_PER_LINE(pp->pixels_per_line, pp->depth * factor);
783 int bb_is_paper_in_adf(struct ledm_session *ps) /* 0 = no paper in adf, 1 = paper in adf, -1 = error */
787 struct bb_ledm_session *pbb = ps->bb_session;
789 if(http_open(ps->dd, HPMUD_S_LEDM_SCAN, &pbb->http_handle) != HTTP_R_OK)
792 if (http_write(pbb->http_handle, GET_SCANNER_STATUS, sizeof(GET_SCANNER_STATUS)-1, 10) != HTTP_R_OK)
796 read_http_payload(ps, buf, sizeof(buf), EXCEPTION_TIMEOUT, &bytes_read);
798 http_close(pbb->http_handle); /* error, close http connection */
799 pbb->http_handle = 0;
800 _DBG("bb_is_paper_in_adf .job_id=%d buf=%s\n", ps->job_id, buf);
801 if(strstr(buf, ADF_LOADED)) return 1;
802 if(strstr(buf, ADF_EMPTY) && strstr(buf, SCANNER_BUSY_WITH_SCAN_JOB)) return 2;
807 SANE_Status bb_start_scan(struct ledm_session *ps)
809 char buf[4096] = {0};
812 int i, timeout = 10 ;
813 char szPage_ID[5] = {0};
814 char szJob_ID[5] = {0};
815 SANE_Status stat = SANE_STATUS_IO_ERROR;
816 struct bb_ledm_session *pbb = ps->bb_session;
819 _DBG("bb_start_scan() entering...job_id=%d\n", ps->job_id);
822 if(http_open(ps->dd, HPMUD_S_LEDM_SCAN, &pbb->http_handle) != HTTP_R_OK)
827 if (http_write(pbb->http_handle, GET_SCANNER_STATUS, sizeof(GET_SCANNER_STATUS)-1, timeout) != HTTP_R_OK)
832 read_http_payload(ps, buf, sizeof(buf), timeout, &bytes_read);
834 if(!strstr(buf, SCANNER_IDLE))
836 stat = SANE_STATUS_DEVICE_BUSY;
840 http_close(pbb->http_handle);
841 pbb->http_handle = 0;
843 if(http_open(ps->dd, HPMUD_S_LEDM_SCAN, &pbb->http_handle) != HTTP_R_OK)
847 len = snprintf(buf, sizeof(buf), CREATE_SCAN_JOB_REQUEST,
848 ps->currentResolution,//<XResolution>
849 ps->currentResolution,//<YResolution>
850 (int) (ps->currentTlx / 5548.7133),//<XStart>
851 (int) ((ps->currentBrx / 5548.7133) - (ps->currentTlx / 5548.7133)),//<Width>
852 (int) (ps->currentTly / 5548.7133),//<YStart>
853 (int) ((ps->currentBry / 5548.7133) - (ps->currentTly / 5548.7133)),//<Height>
855 (! strcmp(ce_element[ps->currentScanMode], "Color8")) ? "Color" : (! strcmp(ce_element[ps->currentScanMode], "Gray8")) ? "Gray" : "Gray",//<ColorSpace>
856 ((! strcmp(ce_element[ps->currentScanMode], "Color8")) || (! strcmp(ce_element[ps->currentScanMode], "Gray8"))) ? 8: 8,//<BitDepth>
857 ps->currentInputSource == IS_PLATEN ? is_element[1] : is_element[2],//<InputSource>
858 ps->currentInputSource == IS_PLATEN ? is_element[1] : is_element[2],//<InputSourceType>
859 ps->currentInputSource != IS_ADF_DUPLEX ? "" : "<AdfOptions><AdfOption>Duplex</AdfOption></AdfOptions>");
861 len = len + strlen(ZERO_FOOTER);
863 len = snprintf(buf1, sizeof(buf1), POST_HEADER, len);
864 if (http_write(pbb->http_handle, buf1, strlen(buf1), timeout) != HTTP_R_OK)
869 if (http_write(pbb->http_handle, buf, strlen(buf), 1) != HTTP_R_OK)
874 /* Write zero footer. */
875 if (http_write(pbb->http_handle, ZERO_FOOTER, sizeof(ZERO_FOOTER)-1, 1) != HTTP_R_OK)
879 memset(buf, 0, sizeof(buf));
881 if (read_http_payload(ps, buf, sizeof(buf), timeout, &bytes_read))
884 http_close(pbb->http_handle);
885 pbb->http_handle = 0;
888 char* jl=strstr(buf, "Location:");
889 if (!jl) goto bugout;
900 strcpy(ps->url, joblist);
902 c=strstr(c, "JobList");
906 int job_id=strtol(c, NULL, 10);
907 itoa(job_id, szJob_ID,10);
908 itoa(1, szPage_ID,10);
915 if (ps->currentInputSource == IS_PLATEN)
917 stat = SANE_STATUS_INVAL;
922 itoa(ps->job_id,szJob_ID,10);
923 itoa(ps->page_id, szPage_ID,10);
925 _DBG("bb_start_scan() url=%s page_id=%d\n", ps->url, ps->page_id);
927 memset(buf, 0, sizeof(buf)-1);
929 if(http_open(ps->dd, HPMUD_S_LEDM_SCAN, &pbb->http_handle) != HTTP_R_OK)
932 while(strstr(buf, READY_TO_UPLOAD) == NULL)
934 _DBG("bb_start_scan() ENTERING....buf=%s\n", buf);
935 len = snprintf(buf, sizeof(buf), GET_SCAN_JOB_URL, ps->url);
937 if (http_write(pbb->http_handle, buf, strlen(buf), 1) != HTTP_R_OK)
942 if (read_http_payload (ps, buf, sizeof(buf), 5, &len) != HTTP_R_OK)
945 _DBG("bb_start_scan() read_http_payload FAILED len=%d buf=%s\n", len, buf);
948 if (strstr(buf,JOBSTATE_CANCELED) || strstr(buf, CANCELED_BY_DEVICE) || strstr(buf, CANCELED_BY_CLIENT))
950 //_DBG("bb_start_scan() SCAN CANCELLED\n");
951 stat = SANE_STATUS_GOOD;
955 if (strstr(buf, JOBSTATE_COMPLETED))
957 stat = SANE_STATUS_GOOD;
960 usleep(500000);//0.5 sec delay
963 char *c = strstr(buf, "<BinaryURL>");
964 _DBG("bb_start_scan() BinaryURL=%s \n", c);
972 BinaryURL[i++] = *c ;
976 //_DBG("bb_start_scan() BinaryURL=%s\n", BinaryURL);
977 len = snprintf(buf, sizeof(buf), GET_SCAN_JOB_URL, BinaryURL);
979 if (http_write(pbb->http_handle, buf, strlen(buf), timeout) != HTTP_R_OK)
984 if (http_read_header(pbb->http_handle, buf, sizeof(buf), timeout, &len) != HTTP_R_OK)
989 if(strstr(buf, "HTTP/1.1 400 Bad Request")) http_read_header(pbb->http_handle, buf, sizeof(buf), timeout, &len);
991 stat = SANE_STATUS_GOOD;
993 if (stat && pbb->http_handle)
995 http_close(pbb->http_handle); /* error, close http connection */
996 pbb->http_handle = 0;
999 } /* bb_start_scan */
1001 int get_size(struct ledm_session* ps)
1003 struct bb_ledm_session *pbb = ps->bb_session;
1005 int i=0, tmo=50, len;
1007 if(ps->currentResolution >= 1200) tmo *= 5;
1011 if(http_read_size(pbb->http_handle, buffer+i, 1, tmo, &len) == 2) return 0;
1012 if( i && *(buffer+i) == '\n' && *(buffer+i-1) == '\r') break;
1016 return strtol(buffer, NULL, 16);
1019 int bb_get_image_data(struct ledm_session* ps, int maxLength)
1021 struct bb_ledm_session *pbb = ps->bb_session;
1025 _DBG("bb_get_image_data http_handle=%p cnt=%d pbb=%p\n", pbb->http_handle, ps->cnt, pbb);
1026 if(ps->currentResolution >= 1200) tmo *= 5;
1030 size = get_size(ps);
1033 http_read_size(pbb->http_handle, buf_size, 2, tmo, &len);
1034 http_read_size(pbb->http_handle, buf_size, -1, tmo, &len);
1037 http_read_size(pbb->http_handle, ps->buf, size, tmo, &len);
1039 http_read_size(pbb->http_handle, buf_size, 2, tmo, &len);
1045 int bb_end_page(struct ledm_session *ps, int io_error)
1047 struct bb_ledm_session *pbb = ps->bb_session;
1049 _DBG("bb_end_page(error=%d)\n", io_error);
1051 if (pbb->http_handle)
1053 http_close(pbb->http_handle);
1054 pbb->http_handle = 0;
1059 int bb_end_scan(struct ledm_session* ps, int io_error)
1061 struct bb_ledm_session *pbb = ps->bb_session;
1063 _DBG("bb_end_scan(error=%d)\n", io_error);
1065 if (pbb->http_handle)
1067 http_close(pbb->http_handle);
1068 pbb->http_handle = 0;
1071 memset(ps->url, 0, sizeof(ps->url));