kopia lustrzana https://gitlab.com/sane-project/backends
638 wiersze
24 KiB
C
638 wiersze
24 KiB
C
/* sane - Scanner Access Now Easy.
|
|
|
|
pieusb_buffer.c
|
|
|
|
Copyright (C) 2012-2015 Jan Vleeshouwers, Michael Rickmann, Klaus Kaempf
|
|
|
|
This file is part of the SANE package.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the
|
|
License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
|
MA 02111-1307, USA.
|
|
|
|
As a special exception, the authors of SANE give permission for
|
|
additional uses of the libraries contained in this release of SANE.
|
|
|
|
The exception is that, if you link a SANE library with other files
|
|
to produce an executable, this does not by itself cause the
|
|
resulting executable to be covered by the GNU General Public
|
|
License. Your use of that executable is in no way restricted on
|
|
account of linking the SANE library code into it.
|
|
|
|
This exception does not, however, invalidate any other reasons why
|
|
the executable file might be covered by the GNU General Public
|
|
License.
|
|
|
|
If you submit changes to SANE to the maintainers to be included in
|
|
a subsequent release, you agree by submitting the changes that
|
|
those changes may be distributed with this exception intact.
|
|
|
|
If you write modifications of your own for SANE, it is your choice
|
|
whether to permit this exception to apply to your modifications.
|
|
If you do not wish that, delete this exception notice. */
|
|
|
|
/* =========================================================================
|
|
*
|
|
* Read buffer
|
|
*
|
|
* Data obtained from the scanner cannot be presented to the frontend immediately.
|
|
* The scanner returns data in the 'index' or 'line' color format, which means it
|
|
* returns data in batches which contain a single color of a scan line.
|
|
*
|
|
* These must finally be converted into the SANE data format (data for a single
|
|
* pixel in consecutive bytes). Apart from that, sane_read() must be able to
|
|
* return any amount of data bytes.
|
|
*
|
|
* In between, data processing may be necessary, usually requiring the whole
|
|
* image to be available.
|
|
*
|
|
* To accommodate all this, the buffer stores all samples as 16-bit values, even
|
|
* if the original values are 8-bit or even 1 bit. This is a waste of space, but
|
|
* makes processing much easier, and it is only temporary.
|
|
*
|
|
* The read buffer is constructed by a call to buffer_create(), which initializes
|
|
* the buffer based on width, height, number of colors and depth. The buffer
|
|
* contains data organized in color planes, with each plane consisting of lines,
|
|
* each line of a fixed number of (single color) pixels, and each pixel of a fixed
|
|
* number of bits (or bytes).
|
|
*
|
|
* The buffer maintains read and write pointers.
|
|
*
|
|
* Multi-color data with a bit depth of 1 are packed in single color bytes, so
|
|
* the data obtained from the scanner does not need conversion.
|
|
*
|
|
* ========================================================================= */
|
|
|
|
#define DEBUG_DECLARE_ONLY
|
|
|
|
/* Configuration defines */
|
|
#include "../include/sane/config.h"
|
|
|
|
/* SANE includes */
|
|
#include "../include/sane/sane.h"
|
|
#include "../include/sane/saneopts.h"
|
|
#include "../include/sane/sanei_usb.h"
|
|
#include "../include/sane/sanei_config.h"
|
|
|
|
/* Backend includes */
|
|
#define BACKEND_NAME pieusb
|
|
#include "../include/sane/sanei_backend.h"
|
|
#include "pieusb.h"
|
|
|
|
#include "pieusb_specific.h"
|
|
#include "pieusb_buffer.h"
|
|
|
|
#ifdef HAVE_ALLOCA_H
|
|
#include <alloca.h>
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#include <sys/mman.h>
|
|
|
|
#include "byteorder.h"
|
|
|
|
static void buffer_update_read_index(struct Pieusb_Read_Buffer* buffer, int increment);
|
|
|
|
/* READER */
|
|
|
|
/**
|
|
* Initialize the buffer.
|
|
* A scanner has a Pieusb_Read_Buffer struct as one of its members.
|
|
*
|
|
* @param buffer the buffer to initialize
|
|
* @param width number of pixels on a line (row)
|
|
* @param height number of lines in the buffer (pixels in a column)
|
|
* @param colors bitmap specifying the colors in the scanned data (bitmap: 0000 IBGR)
|
|
* @param depth number of bits of a color
|
|
* @param bigendian how to store multi-byte values: bigendian if true
|
|
* @param maximum_size maximum size of buffer (-1 = size of image)
|
|
*/
|
|
|
|
SANE_Status
|
|
sanei_pieusb_buffer_create(struct Pieusb_Read_Buffer* buffer, SANE_Int width, SANE_Int height, SANE_Byte color_spec, SANE_Byte depth)
|
|
{
|
|
int k, result;
|
|
unsigned int buffer_size_bytes;
|
|
unsigned char g;
|
|
|
|
/* Base parameters */
|
|
buffer->width = width;
|
|
buffer->height = height;
|
|
buffer->colors = 0;
|
|
if (color_spec & 0x01) { buffer->color_index_red = 0; buffer->colors++; } else { buffer->color_index_red = -1; }
|
|
if (color_spec & 0x02) { buffer->color_index_green = 1; buffer->colors++; } else { buffer->color_index_green = -1; }
|
|
if (color_spec & 0x04) { buffer->color_index_blue = 2; buffer->colors++; } else { buffer->color_index_blue = -1; }
|
|
if (color_spec & 0x08) { buffer->color_index_infrared = 3; buffer->colors++; } else { buffer->color_index_infrared = -1; }
|
|
if (buffer->colors == 0) {
|
|
DBG(DBG_error, "sanei_pieusb_buffer_create(): no colors specified\n");
|
|
return SANE_STATUS_INVAL;
|
|
}
|
|
buffer->depth = depth;
|
|
if (depth < 1 || depth > 16) {
|
|
DBG(DBG_error, "sanei_pieusb_buffer_create(): unsupported depth %d\n", depth);
|
|
return SANE_STATUS_INVAL;
|
|
}
|
|
buffer->packing_density = (depth == 1) ? 8 : 1; /* These are all the situations we have */
|
|
|
|
/* Derived*/
|
|
buffer->packet_size_bytes = (buffer->depth * buffer->packing_density + 7) / 8;
|
|
buffer->line_size_packets = (buffer->width + buffer->packing_density -1) / buffer->packing_density;
|
|
buffer->line_size_bytes = buffer->line_size_packets * buffer->packet_size_bytes;
|
|
buffer->image_size_bytes = buffer->colors * buffer->height * buffer->line_size_bytes;
|
|
|
|
/* Create empty file */
|
|
snprintf(buffer->buffer_name, L_tmpnam, "/tmp/sane.XXXXXX");
|
|
if (buffer->data_file != 0) /* might still be open from previous invocation */
|
|
close(buffer->data_file);
|
|
buffer->data_file = mkstemp(buffer->buffer_name);
|
|
if (buffer->data_file == -1) {
|
|
buffer->data_file = 0;
|
|
buffer->data = NULL;
|
|
perror("sanei_pieusb_buffer_create(): error opening image buffer file");
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
/* Stretch the file size */
|
|
buffer_size_bytes = buffer->width * buffer->height * buffer->colors * sizeof(SANE_Uint);
|
|
if (buffer_size_bytes == 0) {
|
|
close(buffer->data_file);
|
|
buffer->data_file = 0;
|
|
DBG(DBG_error, "sanei_pieusb_buffer_create(): buffer_size is zero: width %d, height %d, colors %d\n", buffer->width, buffer->height, buffer->colors);
|
|
return SANE_STATUS_INVAL;
|
|
}
|
|
result = lseek(buffer->data_file, buffer_size_bytes-1, SEEK_SET);
|
|
if (result == -1) {
|
|
close(buffer->data_file);
|
|
buffer->data_file = 0;
|
|
buffer->data = NULL;
|
|
DBG(DBG_error, "sanei_pieusb_buffer_create(): error calling lseek() to 'stretch' the file to %d bytes\n", buffer_size_bytes-1);
|
|
perror("sanei_pieusb_buffer_create(): error calling lseek()");
|
|
return SANE_STATUS_INVAL;
|
|
}
|
|
/* Write one byte at the end */
|
|
g = 0x00;
|
|
result = write(buffer->data_file, &g, 1);
|
|
if (result < 0) {
|
|
close(buffer->data_file);
|
|
buffer->data_file = 0;
|
|
buffer->data = NULL;
|
|
perror("sanei_pieusb_buffer_create(): error writing a byte at the end of the file");
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
#ifdef HAVE_MMAP
|
|
/* Create memory map */
|
|
buffer->data = mmap(NULL, buffer_size_bytes, PROT_WRITE | PROT_READ, MAP_SHARED, buffer->data_file, 0);
|
|
if (buffer->data == MAP_FAILED) {
|
|
close(buffer->data_file);
|
|
buffer->data = NULL;
|
|
perror("sanei_pieusb_buffer_create(): error mapping file");
|
|
return SANE_STATUS_INVAL;
|
|
}
|
|
#else
|
|
#error mmap(2) not available, aborting
|
|
#endif
|
|
buffer->data_size = buffer_size_bytes;
|
|
/* Reading and writing */
|
|
buffer->p_read = calloc(buffer->colors, sizeof(SANE_Uint*));
|
|
if (buffer->p_read == NULL)
|
|
return SANE_STATUS_NO_MEM;
|
|
buffer->p_write = calloc(buffer->colors, sizeof(SANE_Uint*));
|
|
if (buffer->p_write == NULL)
|
|
return SANE_STATUS_NO_MEM;
|
|
for (k = 0; k < buffer->colors; k++) {
|
|
buffer->p_write[k] = buffer->data + k * buffer->height * buffer->width;
|
|
buffer->p_read[k] = buffer->p_write[k];
|
|
}
|
|
buffer->read_index[0] = 0;
|
|
buffer->read_index[1] = 0;
|
|
buffer->read_index[2] = 0;
|
|
buffer->read_index[3] = 0;
|
|
|
|
/* Statistics */
|
|
buffer->bytes_read = 0;
|
|
buffer->bytes_written = 0;
|
|
buffer->bytes_unread = 0;
|
|
|
|
DBG(DBG_info,"pieusb: Read buffer created: w=%d h=%d ncol=%d depth=%d in file %s\n",
|
|
buffer->width, buffer->height, buffer->colors, buffer->depth, buffer->buffer_name);
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
/**
|
|
* Delete buffer and free its resources
|
|
*
|
|
* @param buffer
|
|
*/
|
|
void
|
|
sanei_pieusb_buffer_delete(struct Pieusb_Read_Buffer* buffer)
|
|
{
|
|
#ifdef HAVE_MMAP
|
|
munmap(buffer->data, buffer->data_size);
|
|
#else
|
|
#error mmap(2) not available, aborting
|
|
#endif
|
|
/* ftruncate(buffer->data_file,0); Can we delete given a file-descriptor? */
|
|
close(buffer->data_file);
|
|
/* remove fs entry */
|
|
unlink(buffer->buffer_name);
|
|
buffer->data_file = 0;
|
|
buffer->data_size = 0;
|
|
free(buffer->p_read);
|
|
free(buffer->p_write);
|
|
buffer->data = 0;
|
|
buffer->width = 0;
|
|
buffer->height = 0;
|
|
buffer->depth = 0;
|
|
buffer->colors = 0;
|
|
buffer->packing_density = 0;
|
|
|
|
DBG(DBG_info,"pieusb: Read buffer deleted\n");
|
|
}
|
|
|
|
/**
|
|
* Add a line to the reader buffer, for the given color.
|
|
* The buffer checks and decides how to interpret the data.
|
|
*
|
|
* @param buffer
|
|
* @param color Color code for line
|
|
* @param line
|
|
* @param size Number of bytes in line
|
|
* @return 1 if successful, 0 if not
|
|
*/
|
|
SANE_Int
|
|
sanei_pieusb_buffer_put_single_color_line(struct Pieusb_Read_Buffer* buffer, SANE_Byte color, void* line, SANE_Int size)
|
|
{
|
|
|
|
SANE_Int c, k, m, n;
|
|
|
|
/* Check index code */
|
|
c = -1;
|
|
switch (color) {
|
|
case 'R':
|
|
c = buffer->color_index_red;
|
|
break;
|
|
case 'G':
|
|
c = buffer->color_index_green;
|
|
break;
|
|
case 'B':
|
|
c = buffer->color_index_blue;
|
|
break;
|
|
case 'I':
|
|
c = buffer->color_index_infrared;
|
|
break;
|
|
}
|
|
if (c == -1) {
|
|
DBG(DBG_error, "sanei_pieusb_buffer_put_single_color_line(): color '%c' not specified when buffer was created\n", color);
|
|
return 0;
|
|
}
|
|
DBG(DBG_info_buffer, "sanei_pieusb_buffer_put_single_color_line() line color = %d (0=R, 1=G, 2=B, 3=I)\n",c);
|
|
|
|
/* Check line size (for a line with a single color) */
|
|
if (buffer->line_size_bytes != size) {
|
|
DBG(DBG_error, "sanei_pieusb_buffer_put_single_color_line(): incorrect line size, expecting %d, got %d\n", buffer->line_size_bytes, size);
|
|
return 0;
|
|
}
|
|
|
|
/* The general approach for all densities and packet sizes
|
|
* - process packet_size_bytes at a time
|
|
* - use packing_density to decode the full packet into separate values
|
|
* - now save these values as neighbouring pixels on the current line
|
|
* Use custom code for the 1-byte and 2-byte single sample cases,
|
|
* because the general approach is a bit overkill for them.
|
|
*/
|
|
|
|
if (buffer->packet_size_bytes == 1 && buffer->packing_density == 1) {
|
|
uint8_t* p_packet = (uint8_t*)line;
|
|
n = 0;
|
|
while (n < size) {
|
|
/* Get next packet data & store in buffer */
|
|
*buffer->p_write[c]++ = *p_packet++;
|
|
n++;
|
|
}
|
|
} else if (buffer->packet_size_bytes == 2 && buffer->packing_density == 1) {
|
|
uint16_t* p_packet = (uint16_t*)line;
|
|
n = 0;
|
|
while (n < size) {
|
|
/* Get next packet data & store in buffer */
|
|
*buffer->p_write[c]++ = le16toh (*p_packet++);
|
|
n += 2;
|
|
}
|
|
} else {
|
|
uint8_t* p_packet = (uint8_t*)line;
|
|
uint8_t *packet = (uint8_t *)alloca(buffer->packet_size_bytes * sizeof(uint8_t));
|
|
SANE_Uint val;
|
|
uint8_t mask = ~(0xFF >> buffer->depth); /* byte with depth most significant bits set */
|
|
n = 0;
|
|
while (n < size) {
|
|
/* Get next packet data */
|
|
for (k = 0; k < buffer->packet_size_bytes; k++) packet[k] = *p_packet++;
|
|
/* Unpack packing_density samples from packet. Of course,
|
|
* buffer->depth * packing_density <= # bits in packet.
|
|
* That is checked at buffer creation. */
|
|
for (k = 0; k < buffer->packing_density; k++) {
|
|
/* Take 1st depth bits and store in val */
|
|
val = (packet[0] & mask) >> (8-buffer->depth);
|
|
/* Now shift packet bytes depth bits left */
|
|
for (m = 0; m < buffer->packet_size_bytes; m++) {
|
|
/* Shift left one sample */
|
|
packet[m] <<= buffer->depth;
|
|
if (m < buffer->packet_size_bytes-1) {
|
|
/* If there are more bytes, insert 1st depth bits of next byte */
|
|
packet[m] |= (packet[m+1] >> (8-buffer->depth));
|
|
}
|
|
}
|
|
/* Store in buffer */
|
|
*buffer->p_write[c]++ = val;
|
|
}
|
|
n += buffer->packet_size_bytes;
|
|
}
|
|
}
|
|
|
|
/* Update state & statistics */
|
|
buffer->bytes_written += size;
|
|
buffer->bytes_unread += size;
|
|
|
|
/* Output current buffer state */
|
|
/* buffer_output_state(buffer); */
|
|
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Write line of full color pixels to the buffer.
|
|
*
|
|
* @param buffer Read buffer
|
|
* @param pixel array of full color pixel data
|
|
* @param size Number of bytes in the line
|
|
* @return 1 if successful, 0 if not
|
|
*/
|
|
/**
|
|
*
|
|
*/
|
|
SANE_Int
|
|
sanei_pieusb_buffer_put_full_color_line(struct Pieusb_Read_Buffer* buffer, void* line, int size)
|
|
{
|
|
int k, c, m, n;
|
|
|
|
DBG(DBG_info_buffer, "sanei_pieusb_buffer_put_full_color_line() entered\n");
|
|
|
|
/* Check line size */
|
|
if (buffer->line_size_bytes * buffer->colors != size) {
|
|
DBG(DBG_error, "sanei_pieusb_buffer_put_full_color_line(): incorrect line size, expecting %d, got %d\n", buffer->line_size_bytes * buffer->colors, size);
|
|
return 0;
|
|
}
|
|
|
|
/* The general approach for all densities and packet sizes
|
|
* - process packet_size_bytes at a time
|
|
* - use packing_density to decode the full packet into separate values
|
|
* - now save these values as neighbouring pixels on the current line
|
|
* Use custom code for the 1-byte and 2-byte single sample cases,
|
|
* because the general approach is a bit overkill for them.
|
|
*/
|
|
|
|
if (buffer->packet_size_bytes == 1 && buffer->packing_density == 1) {
|
|
uint8_t* p_packet = (uint8_t*)line;
|
|
n = 0;
|
|
while (n < size) {
|
|
/* Get next packet data & store in buffer */
|
|
for (c = 0; c < buffer->colors; c++) {
|
|
*buffer->p_write[c]++ = *p_packet++;
|
|
n++;
|
|
}
|
|
}
|
|
} else if (buffer->packet_size_bytes == 2 && buffer->packing_density == 1) {
|
|
uint16_t* p_packet = (uint16_t*)line;
|
|
n = 0;
|
|
while (n < size) {
|
|
/* Get next packet data & store in buffer */
|
|
for (c = 0; c < buffer->colors; c++) {
|
|
*buffer->p_write[c]++ = le16toh (*p_packet++);
|
|
n += 2;
|
|
}
|
|
}
|
|
} else {
|
|
uint8_t* p_packet = (uint8_t*)line;
|
|
uint8_t *packet = (uint8_t *)alloca(buffer->packet_size_bytes * sizeof(uint8_t));
|
|
SANE_Uint val;
|
|
uint8_t mask = ~(0xFF >> buffer->depth); /* byte with depth most significant bits set */
|
|
/* DBG(DBG_info,"buffer_put_full_color_line(): mask %02x\n",mask); */
|
|
n = 0;
|
|
while (n < size) {
|
|
/* Get next packet data */
|
|
for (c = 0; c < buffer->colors; c++) {
|
|
for (k = 0; k < buffer->packet_size_bytes; k++) {
|
|
packet[k] = *p_packet++;
|
|
/* DBG(DBG_info,"buffer_put_full_color_line(): packet[%d] = %02x\n",k,packet[k]); */
|
|
}
|
|
/* Unpack packing_density samples from packet. Of course,
|
|
* buffer->depth * packing_density <= # bits in packet.
|
|
* That is checked at buffer creation. */
|
|
for (k = 0; k < buffer->packing_density; k++) {
|
|
/* Take 1st depth bits and store in val */
|
|
val = (packet[0] & mask) >> (8-buffer->depth);
|
|
/* DBG(DBG_info,"buffer_put_full_color_line(): val[%d] = %02x\n",k,val); */
|
|
/* Now shift packet bytes depth bits left */
|
|
for (m = 0; m < buffer->packet_size_bytes; m++) {
|
|
/* Shift left one sample */
|
|
packet[m] <<= buffer->depth;
|
|
/* DBG(DBG_info,"buffer_put_full_color_line(): shift packet[%d] = %02x\n",m,packet[m]); */
|
|
if (m < buffer->packet_size_bytes-1) {
|
|
/* If there are more bytes, insert 1st depth bits of next byte */
|
|
packet[m] |= (packet[m+1] >> (8-buffer->depth));
|
|
/* DBG(DBG_info,"buffer_put_full_color_line(): shift packet[%d] = %02x\n",m,packet[m]); */
|
|
}
|
|
}
|
|
/* Store in buffer */
|
|
*buffer->p_write[c]++ = val;
|
|
}
|
|
n += buffer->packet_size_bytes;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Update state & statistics */
|
|
buffer->bytes_written += size;
|
|
buffer->bytes_unread += size;
|
|
|
|
/* Output current buffer state */
|
|
/* buffer_output_state(buffer); */
|
|
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Return bytes from the buffer. Do not mind pixel boundaries.
|
|
* Since the image data is organized in color planes, return bytes from the
|
|
* planes in the defined order. Take care to return multi-byte values after
|
|
* each other. Pack unpacked values.
|
|
*
|
|
* @param buffer Buffer to return bytes from.
|
|
* @param data Byte array to return bytes in
|
|
* @param max_len Maximum number of bytes returned
|
|
* @param len Actual number of bytes returned
|
|
*/
|
|
void
|
|
sanei_pieusb_buffer_get(struct Pieusb_Read_Buffer* buffer, SANE_Byte* data, SANE_Int max_len, SANE_Int* len)
|
|
{
|
|
SANE_Byte *pdata;
|
|
SANE_Int n, i, n_bits, N;
|
|
|
|
DBG(DBG_info_buffer, "sanei_pieusb_buffer_get() entered\n");
|
|
|
|
/* Read from the p_read locations */
|
|
pdata = data;
|
|
n = 0;
|
|
N = buffer->width * buffer->height;
|
|
/* Determine bytes to return */
|
|
if (buffer->packet_size_bytes == 1 && buffer->packing_density == 1) {
|
|
/* Single byte values in buffer */
|
|
while (n < max_len && buffer->bytes_read < buffer->image_size_bytes) {
|
|
/* Return byte*/
|
|
*pdata++ = *(buffer->data + N*buffer->read_index[0] + buffer->width*buffer->read_index[1] + buffer->read_index[2]) & 0xFF;
|
|
/* Update read indices */
|
|
buffer_update_read_index(buffer,1);
|
|
/* Update number of bytes read */
|
|
buffer->bytes_read++;
|
|
n++;
|
|
}
|
|
} else if (buffer->packet_size_bytes == 1 && buffer->packing_density == 8) {
|
|
/* Unpacked bits in buffer: repack */
|
|
while (n < max_len && buffer->bytes_read < buffer->image_size_bytes) {
|
|
uint8_t val = 0;
|
|
/* How many bits to pack? At the end of a line it may be less than 8 */
|
|
n_bits = 8;
|
|
if (buffer->width - buffer->read_index[2] < 8) {
|
|
n_bits = buffer->width - buffer->read_index[2];
|
|
}
|
|
/* Pack n_bits samples from same color plane */
|
|
for (i = 0; i < n_bits; i++) {
|
|
if (*(buffer->data + N*buffer->read_index[0] + buffer->width*buffer->read_index[1] + buffer->read_index[2] + i) > 0) {
|
|
val |= (0x80 >> i);
|
|
}
|
|
}
|
|
/* Return byte */
|
|
*pdata++ = val;
|
|
/* Update read indices */
|
|
buffer_update_read_index(buffer,n_bits);
|
|
/* Update number of bytes read */
|
|
buffer->bytes_read++;
|
|
n++;
|
|
}
|
|
} else if (buffer->packet_size_bytes == 2) {
|
|
/* Two-byte values in buffer */
|
|
while (n < max_len && buffer->bytes_read < buffer->image_size_bytes) {
|
|
/* Pointer to byte to return */
|
|
SANE_Uint val = *(buffer->data + N*buffer->read_index[0] + buffer->width*buffer->read_index[1] + buffer->read_index[2]);
|
|
/* Return byte */
|
|
if (buffer->read_index[3] == 0) {
|
|
*pdata++ = *((SANE_Byte*)(&val));
|
|
} else {
|
|
*pdata++ = *((SANE_Byte*)(&val)+1);
|
|
}
|
|
/* Update read indices */
|
|
buffer_update_read_index(buffer,1);
|
|
/* Update number of bytes read */
|
|
buffer->bytes_read++;
|
|
n++;
|
|
}
|
|
} else {
|
|
/* not implemented */
|
|
DBG(DBG_error, "buffer_put(): paccket size & density of %d/%d not implementd\n", buffer->packet_size_bytes, buffer->packing_density);
|
|
return;
|
|
}
|
|
*len = n;
|
|
|
|
/* Update statistics */
|
|
buffer->bytes_unread -= n;
|
|
|
|
/* Output current buffer state */
|
|
/* buffer_output_state(buffer); */
|
|
}
|
|
|
|
/**
|
|
* Update read index to point a given number of bytes past the current position.
|
|
*
|
|
* @param buffer the buffer to initialize
|
|
* @param increment the amount of bytes to move the index
|
|
*/
|
|
static void buffer_update_read_index(struct Pieusb_Read_Buffer* buffer, int increment)
|
|
{
|
|
/* Update read indices
|
|
* [3] = byte-index in 2-byte value: increased first, if we have 2-byte data
|
|
* [2] = index of pixel on line: increased after color plane
|
|
* [1] = index of line: increased after line is complete
|
|
* [0] = color index: increased first since SANE requires full color pixels */
|
|
if (buffer->read_index[3] == 0 && buffer->packet_size_bytes == 2) {
|
|
buffer->read_index[3] = 1;
|
|
} else {
|
|
buffer->read_index[3] = 0;
|
|
buffer->read_index[0]++;
|
|
if (buffer->read_index[0] == buffer->colors) {
|
|
buffer->read_index[0] = 0;
|
|
buffer->read_index[2] += increment;
|
|
if (buffer->read_index[2] >= buffer->width) {
|
|
buffer->read_index[2] = 0;
|
|
buffer->read_index[1]++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
/**
|
|
* Display the buffer state.
|
|
*
|
|
* @param buffer the buffer to initialize
|
|
*/
|
|
|
|
static void buffer_output_state(struct Pieusb_Read_Buffer* buffer)
|
|
{
|
|
SANE_Int line_size;
|
|
SANE_Int N, k, loc[4];
|
|
|
|
line_size = buffer->line_size_bytes * buffer->colors; /* Full line size in bytes */
|
|
|
|
DBG(DBG_info_buffer, "Buffer data\n");
|
|
DBG(DBG_info_buffer," width/height/colors/depth = %d %d %d %d (buffer size %d)\n",
|
|
buffer->width, buffer->height, buffer->colors, buffer->depth, buffer->image_size_bytes);
|
|
|
|
/* Summary */
|
|
N = buffer->width * buffer->height;
|
|
for (k = 0; k < buffer->colors; k++) {
|
|
loc[k] = buffer->p_read[k] - buffer->data - k*N;
|
|
}
|
|
for (k = buffer->colors; k < 4; k++) {
|
|
loc[k] = 0;
|
|
}
|
|
DBG(DBG_info_buffer, " reading at: lines = %d:%d:%d:%d\n", loc[0], loc[1], loc[2], loc[3]);
|
|
for (k = 0; k < buffer->colors; k++) {
|
|
loc[k] = buffer->p_write[k] - buffer->data - k*N;
|
|
}
|
|
for (k = buffer->colors; k < 4; k++) {
|
|
loc[k] = 0;
|
|
}
|
|
DBG(DBG_info_buffer, " writing at: lines = %d:%d:%d:%d\n", loc[0], loc[1], loc[2], loc[3]);
|
|
|
|
/* Progress */
|
|
double fdata = (double)buffer->bytes_unread/buffer->image_size_bytes*100;
|
|
double fread = (double)buffer->bytes_read/buffer->image_size_bytes*100;
|
|
double fwritten = (double)buffer->bytes_written/buffer->image_size_bytes*100;
|
|
DBG(DBG_info_buffer, " byte counts: image = %d, data = %d (%.0f%%), read = %d (%.0f%%), written = %d (%.0f%%)\n",
|
|
buffer->image_size_bytes, buffer->bytes_unread, fdata, buffer->bytes_read, fread, buffer->bytes_written, fwritten);
|
|
DBG(DBG_info_buffer, " line counts: image = %.1f, data = %.1f, read = %.1f, written = %.1f\n",
|
|
(double)buffer->image_size_bytes/line_size, (double)buffer->bytes_unread/line_size, (double)buffer->bytes_read/line_size, (double)buffer->bytes_written/line_size);
|
|
|
|
}
|
|
#endif
|