diff --git a/backend/hpljm1005.c b/backend/hpljm1005.c index 2a7116ccd..235336952 100644 --- a/backend/hpljm1005.c +++ b/backend/hpljm1005.c @@ -46,16 +46,11 @@ #define BUILD 1 #include "../include/sane/config.h" -#include - -#include #include #include #include -#include #include #include -#include #include #include #define BACKEND_NAME hpljm1005 @@ -110,10 +105,10 @@ static int cur_idx; #define RGB 1 #define GRAY 0 -#define MAX_X_H 0x350 +#define MAX_X_H 0x351 #define MAX_Y_H 0x490 -#define MAX_X_S 220 -#define MAX_Y_S 330 +#define MAX_X_S 216 +#define MAX_Y_S 297 #define OPTION_MAX 9 @@ -144,6 +139,12 @@ static const SANE_String_Const mode_list[] = { #define STATUS_SCANNING 1 #define STATUS_CANCELING 2 +struct buffer_s { + char *buffer; + size_t w_offset; + size_t size; +}; + struct device_s { struct device_s *next; @@ -151,15 +152,16 @@ struct device_s int idx; /* Index in the usbid array */ int dn; /* Usb "Handle" */ SANE_Option_Descriptor optiond[OPTION_MAX]; - char *buffer; - int bufs; + struct buffer_s buf_r; /* also for gray mode */ + struct buffer_s buf_g; + struct buffer_s buf_b; int read_offset; - int write_offset_r; - int write_offset_g; - int write_offset_b; int status; int width; int height; + int height_h; + int data_width; /* width + some padding 0xFF which should be ignored */ + int scanned_pixels; SANE_Word optionw[OPTION_MAX]; uint32_t conf_data[512]; uint32_t packet_data[512]; @@ -186,58 +188,6 @@ round2(double x) return (double)(x >= 0.0) ? (int)(x+0.5) : (int)(x-0.5); } -static void -update_img_size (struct device_s *dev) -{ - int dx, dy; - - /* Only update the width when not scanning, - * otherwise the scanner give us the correct width */ - if (dev->status == STATUS_SCANNING) - { - dev->height = -1; - return; - } - - dx = dev->optionw[X2_OFFSET] - dev->optionw[X1_OFFSET]; - dy = dev->optionw[Y2_OFFSET] - dev->optionw[Y1_OFFSET]; - - switch (dev->optionw[RES_OFFSET]) - { - case 75: - dev->width = round2 ((dx / ((double) MAX_X_S)) * 640); - dev->height = round2 ((dy / ((double) MAX_Y_S)) * 880); - break; - case 100: - dev->width = round2 ((dx / ((double) MAX_X_S)) * 848); - dev->height = round2 ((dy / ((double) MAX_Y_S)) * 1180); - break; - case 150: - dev->width = round2 ((dx / ((double) MAX_X_S)) * 1264); - dev->height = round2 ((dy / ((double) MAX_Y_S)) * 1775); - break; - case 200: - dev->width = round2 ((dx / ((double) MAX_X_S)) * 1696); - dev->height = round2 ((dy / ((double) MAX_Y_S)) * 2351); - break; - case 300: - dev->width = round2 ((dx / ((double) MAX_X_S)) * 2528); - dev->height = round2 ((dy / ((double) MAX_Y_S)) * 3510); - break; - case 600: - dev->width = round2 ((dx / ((double) MAX_X_S)) * 5088); - dev->height = round2 ((dy / ((double) MAX_Y_S)) * 7020); - break; - case 1200: - dev->width = round2 ((dx / ((double) MAX_X_S)) * 10208); - dev->height = round2 ((dy / ((double) MAX_Y_S)) * 14025); - break; - } - - DBG(2,"New image size: %dx%d\n",dev->width, dev->height); - -} - /* This function is copy/pasted from the Epson backend */ static size_t max_string_size (const SANE_String_Const strings[]) @@ -721,7 +671,6 @@ sane_get_parameters (SANE_Handle h, SANE_Parameters * p) p->last_frame = SANE_TRUE; p->depth = 8; - update_img_size (dev); p->pixels_per_line = dev->width; p->lines = dev->height; p->bytes_per_line = p->pixels_per_line; @@ -805,7 +754,7 @@ send_conf (struct device_s *dev) dev->conf_data[21] = 0; dev->conf_data[22] = htonl (0x491); dev->conf_data[23] = htonl (0x352); - + dev->height_h = y2 - y1; if (dev->optionw[COLOR_OFFSET] == RGB) { dev->conf_data[15] = htonl (0x2); @@ -821,116 +770,151 @@ send_conf (struct device_s *dev) sanei_usb_write_bulk (dev->dn, (unsigned char *) dev->conf_data, &size); } -static SANE_Status -get_data (struct device_s *dev) +static SANE_Status create_buffer(struct buffer_s *buf, int buffer_size) { + if (buf->buffer) + { + free(buf->buffer); + } + + buf->buffer = malloc(buffer_size); + if (!buf->buffer) + return SANE_STATUS_NO_MEM; + buf->size = buffer_size; + buf->w_offset = 0; + return SANE_STATUS_GOOD; +} + +static SANE_Status create_buffers(struct device_s *dev, int buf_size) { + if (create_buffer(&dev->buf_r, buf_size) != SANE_STATUS_GOOD) + return SANE_STATUS_NO_MEM; + if (dev->optionw[COLOR_OFFSET] == RGB) + { + if (create_buffer(&dev->buf_g, buf_size) != SANE_STATUS_GOOD) + return SANE_STATUS_NO_MEM; + if (create_buffer(&dev->buf_b, buf_size) != SANE_STATUS_GOOD) + return SANE_STATUS_NO_MEM; + } + return SANE_STATUS_GOOD; +} + +static SANE_Status remove_buffers(struct device_s *dev) { + if (dev->buf_r.buffer) + free(dev->buf_r.buffer); + if (dev->buf_g.buffer) + free(dev->buf_g.buffer); + if (dev->buf_b.buffer) + free(dev->buf_b.buffer); + dev->buf_r.w_offset = dev->buf_g.w_offset = dev->buf_b.w_offset = 0; + dev->buf_r.size = dev->buf_g.size = dev->buf_b.size = 0; + dev->buf_r.buffer = dev->buf_g.buffer = dev->buf_b.buffer = NULL; + dev->read_offset = 0; + return SANE_STATUS_GOOD; +} + +static SANE_Status get_data (struct device_s *dev) { int color; size_t size; int packet_size; unsigned char *buffer = (unsigned char *) dev->packet_data; if (dev->status == STATUS_IDLE) + { + DBG(101, "STATUS == IDLE\n"); return SANE_STATUS_IO_ERROR; + } /* first wait a standard data pkt */ do + { + size = 32; + sanei_usb_read_bulk (dev->dn, buffer, &size); + if (size) { - size = 32; - sanei_usb_read_bulk (dev->dn, buffer, &size); - if (size) - { - if (ntohl (dev->packet_data[0]) == MAGIC_NUMBER) - { - if (ntohl (dev->packet_data[1]) == PKT_DATA) - break; - if (ntohl (dev->packet_data[1]) == PKT_END_DATA) - { - dev->status = STATUS_IDLE; - DBG(100,"End of scan encountered on device %s\n",dev->devname); - send_pkt (PKT_GO_IDLE, 0, dev); - wait_ack (dev, NULL); - wait_ack (dev, NULL); - send_pkt (PKT_UNKNOW_1, 0, dev); - wait_ack (dev, NULL); - send_pkt (PKT_RESET, 0, dev); - sleep (2); /* Time for the scanning head to go back home */ - return SANE_STATUS_EOF; - } - } - } + if (ntohl (dev->packet_data[0]) == MAGIC_NUMBER) + { + if (ntohl (dev->packet_data[1]) == PKT_DATA) + break; + if (ntohl (dev->packet_data[1]) == PKT_END_DATA) + { + dev->status = STATUS_IDLE; + DBG(100,"End of scan encountered on device %s\n",dev->devname); + send_pkt (PKT_GO_IDLE, 0, dev); + wait_ack (dev, NULL); + wait_ack (dev, NULL); + send_pkt (PKT_UNKNOW_1, 0, dev); + wait_ack (dev, NULL); + send_pkt (PKT_RESET, 0, dev); + sleep (2); /* Time for the scanning head to go back home */ + return SANE_STATUS_EOF; + } + } } - while (1); + } while (1); packet_size = ntohl (dev->packet_data[5]); - if (!dev->buffer) - { - dev->bufs = packet_size - 24 /* size of header */ ; - if (dev->optionw[COLOR_OFFSET] == RGB) - dev->bufs *= 3; - dev->buffer = malloc (dev->bufs); - if (!dev->buffer) - return SANE_STATUS_NO_MEM; - dev->write_offset_r = 0; - dev->write_offset_g = 1; - dev->write_offset_b = 2; - - } + if (! dev->buf_r.buffer) + { + /* + For some reason scanner sends packets in order: + R G B ... R G B R G B RRR GGG BBB + To hanle the last triple portion create a triple size buffer + */ + int buf_size = (packet_size - 24) * 3; /* 24 - size of header */ ; + if (create_buffers(dev, buf_size) != SANE_STATUS_GOOD) + return SANE_STATUS_NO_MEM; + } /* Get the "data header" */ do - { - size = 24; - sanei_usb_read_bulk (dev->dn, buffer, &size); - } - while (!size); + { + size = 24; + sanei_usb_read_bulk (dev->dn, buffer, &size); + } while (!size); color = ntohl (dev->packet_data[0]); packet_size -= size; - dev->width = ntohl (dev->packet_data[5]); - DBG(100,"Got data size %d on device %s. Scan width: %d\n",packet_size, dev->devname, dev->width); + dev->width = ntohl (dev->packet_data[4]); + dev->height = dev->height_h * dev->optionw[RES_OFFSET] / 100; + dev->data_width = ntohl (dev->packet_data[5]); + DBG(100,"Got data size %d on device %s. Scan width: %d, data width: %d\n",packet_size, dev->devname, dev->width, dev->data_width); /* Now, read the data */ do + { + int ret; + do { - int j; - int i; - int ret; - do - { - size = packet_size > 512 ? 512 : packet_size; - ret = sanei_usb_read_bulk (dev->dn, buffer, &size); - } - while (!size || ret != SANE_STATUS_GOOD); - packet_size -= size; - switch (color) - { - case RED_LAYER: - DBG(101,"Got red layer data on device %s\n",dev->devname); - i = dev->write_offset_r + 3 * size; - if (i > dev->bufs) - i = dev->bufs; - for (j = 0; dev->write_offset_r < i; dev->write_offset_r += 3) - dev->buffer[dev->write_offset_r] = buffer[j++]; - break; - case GREEN_LAYER: - DBG(101,"Got green layer data on device %s\n",dev->devname); - i = dev->write_offset_g + 3 * size; - if (i > dev->bufs) - i = dev->bufs; - for (j = 0; dev->write_offset_g < i; dev->write_offset_g += 3) - dev->buffer[dev->write_offset_g] = buffer[j++]; - break; - case BLUE_LAYER: - DBG(101,"Got blue layer data on device %s\n",dev->devname); - i = dev->write_offset_b + 3 * size; - if (i > dev->bufs) - i = dev->bufs; - for (j = 0; dev->write_offset_b < i; dev->write_offset_b += 3) - dev->buffer[dev->write_offset_b] = buffer[j++]; - break; - case GRAY_LAYER: - DBG(101,"Got gray layer data on device %s\n",dev->devname); - if (dev->write_offset_r + (int)size >= dev->bufs) - size = dev->bufs - dev->write_offset_r; - memcpy (dev->buffer + dev->write_offset_r, buffer, size); - dev->write_offset_r += size; - break; - } + size = packet_size > 512 ? 512 : packet_size; + ret = sanei_usb_read_bulk (dev->dn, buffer, &size); + } while (!size || ret != SANE_STATUS_GOOD); + packet_size -= size; + struct buffer_s * current_buf; + char color_char; + switch (color) + { + case GRAY_LAYER: + color_char = 'g'; + current_buf = &dev->buf_r; + break; + case RED_LAYER: + color_char = 'R'; + current_buf = &dev->buf_r; + break; + case GREEN_LAYER: + color_char = 'G'; + current_buf = &dev->buf_g; + break; + case BLUE_LAYER: + color_char = 'B'; + current_buf = &dev->buf_b; + break; + default: + DBG(101, "Unknown color code: %d \n", color); + return SANE_STATUS_IO_ERROR; } + DBG(101,"Got %c layer data on device %s\n", color_char, dev->devname); + if (current_buf->w_offset + size > current_buf->size) { + DBG(100, "buffer overflow\n"); + return SANE_STATUS_IO_ERROR; + } + memcpy(current_buf->buffer + current_buf->w_offset, buffer, size); + current_buf->w_offset += size; + } while (packet_size > 0); return SANE_STATUS_GOOD; } @@ -943,13 +927,8 @@ sane_start (SANE_Handle h) size_t size; dev->read_offset = 0; - dev->write_offset_r = 0; - dev->write_offset_g = 1; - dev->write_offset_b = 2; - - free (dev->buffer); - dev->buffer = NULL; - + dev->scanned_pixels = 0; + remove_buffers(dev); send_pkt (PKT_RESET, 0, dev); send_pkt (PKT_READ_STATUS, 0, dev); @@ -992,16 +971,12 @@ static void do_cancel(struct device_s *dev) { while (get_data (dev) == SANE_STATUS_GOOD); - free (dev->buffer); - dev->buffer = NULL; + remove_buffers(dev); } static int min3 (int r, int g, int b) { - /* Optimize me ! */ - g--; - b -= 2; if (r < g && r < b) return r; if (b < r && b < g) @@ -1009,57 +984,83 @@ min3 (int r, int g, int b) return g; } +static int +min_buf_w_offset (struct device_s * dev) +{ + if (dev->optionw[COLOR_OFFSET] == RGB) + return min3 (dev->buf_r.w_offset, dev->buf_g.w_offset, dev->buf_b.w_offset); + return dev->buf_r.w_offset; +} + +static int is_buf_synchronized(struct device_s * dev) { + if (dev->optionw[COLOR_OFFSET] == RGB) + return dev->buf_r.w_offset == dev->buf_g.w_offset + && dev->buf_r.w_offset == dev->buf_b.w_offset; + return 1; +} + SANE_Status sane_read (SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen, SANE_Int * len) { struct device_s *dev = (struct device_s *) h; int available; int ret; + if (dev->optionw[COLOR_OFFSET] == RGB) { + maxlen /= 3; + } *len = 0; if (dev->status == STATUS_IDLE) + { + DBG(101, "STATUS == IDLE\n"); return SANE_STATUS_IO_ERROR; - if (dev->optionw[COLOR_OFFSET] == RGB) + } + while (min_buf_w_offset(dev) <= dev->read_offset) + { + ret = get_data (dev); + if (ret != SANE_STATUS_GOOD) { - while (min3 (dev->write_offset_r, dev->write_offset_g, - dev->write_offset_b) <= dev->read_offset) - { - ret = get_data (dev); - if (ret != SANE_STATUS_GOOD) - { - if (min3 (dev->write_offset_r, - dev->write_offset_g, - dev->write_offset_b) <= dev->read_offset) - return ret; - } - } - available = min3 (dev->write_offset_r, dev->write_offset_g, - dev->write_offset_b); + if (min_buf_w_offset(dev) <= dev->read_offset) { + return ret; + } } - else + } + available = min_buf_w_offset(dev); + int pixel_len = available - dev->read_offset; + if (pixel_len > maxlen) + pixel_len = maxlen; + int img_size = dev->width * dev->height; + for(int i=0; iread_offset+i; + if (pos % dev->data_width >= dev->width) + continue; + if (dev->scanned_pixels >= img_size) { - while (dev->write_offset_r <= dev->read_offset) - { - ret = get_data (dev); - if (ret != SANE_STATUS_GOOD) - if (dev->write_offset_r <= dev->read_offset) - return ret; - } - available = dev->write_offset_r; + DBG(101, "Extra pixels received.\n"); + break; } - *len = available - dev->read_offset; - if (*len > maxlen) - *len = maxlen; - memcpy (buf, dev->buffer + dev->read_offset, *len); - dev->read_offset += *len; - if (dev->read_offset == dev->bufs) + dev->scanned_pixels++; + buf[(*len)++] = dev->buf_r.buffer[pos]; + if (dev->optionw[COLOR_OFFSET] == RGB) { - free (dev->buffer); - dev->buffer = NULL; - dev->read_offset = 0; - dev->write_offset_r = 0; - dev->write_offset_g = 1; - dev->write_offset_b = 2; + buf[(*len)++] = dev->buf_g.buffer[pos]; + buf[(*len)++] = dev->buf_b.buffer[pos]; } + } + DBG(101, "Moved %d pixels to buffer. Total pixel scanned: %d \n", *len, dev->scanned_pixels); + if (dev->scanned_pixels == img_size) + DBG(100, "Full image received\n"); + dev->read_offset += pixel_len; + + /* + If w_offset is the same in all buffers and has already been completely transferred + to the common buffer - flush buffer. It will be recreated in get_data with a reserve + for the last triple portions + */ + if (is_buf_synchronized(dev) && available == dev->read_offset) + { + remove_buffers(dev); + } /* Special case where sane_cancel is called while scanning */ if (dev->status == STATUS_CANCELING) @@ -1082,8 +1083,7 @@ sane_cancel (SANE_Handle h) return; } - free (dev->buffer); - dev->buffer = NULL; + remove_buffers(dev); } SANE_Status