diff options
Diffstat (limited to 'backend/artec_eplus48u.h')
-rw-r--r-- | backend/artec_eplus48u.h | 596 |
1 files changed, 596 insertions, 0 deletions
diff --git a/backend/artec_eplus48u.h b/backend/artec_eplus48u.h new file mode 100644 index 0000000..cc30214 --- /dev/null +++ b/backend/artec_eplus48u.h @@ -0,0 +1,596 @@ +#ifndef ARTEC48U_H +#define ARTEC48U_H + +#include "../include/sane/sane.h" +#include "../include/sane/sanei.h" +#include "../include/sane/saneopts.h" +#include <sys/types.h> +#ifdef HAVE_SYS_IPC_H +#include <sys/ipc.h> +#endif +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> + +#include "../include/sane/sanei_usb.h" +#include "../include/sane/sanei_thread.h" + +#define _MAX_ID_LEN 20 + +/*Uncomment next line for button support. This + actually isn't supported by the frontends. */ +/*#define ARTEC48U_USE_BUTTONS 1*/ + +#define ARTEC48U_PACKET_SIZE 64 +#define DECLARE_FUNCTION_NAME(name) \ + IF_DBG ( static const char function_name[] = name; ) + +typedef SANE_Byte Artec48U_Packet[ARTEC48U_PACKET_SIZE]; +#define XDBG(args) do { IF_DBG ( DBG args ); } while (0) + +/* calculate the minimum/maximum values */ +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + +/* return the lower/upper 8 bits of a 16 bit word */ +#define HIBYTE(w) ((SANE_Byte)(((SANE_Word)(w) >> 8) & 0xFF)) +#define LOBYTE(w) ((SANE_Byte)(w)) + + +#define CHECK_DEV_NOT_NULL(dev, func_name) \ + do { \ + if (!(dev)) \ + { \ + XDBG ((3, "%s: BUG: NULL device\n", (func_name))); \ + return SANE_STATUS_INVAL; \ + } \ + } while (SANE_FALSE) + +/** Check that the device is open. + * + * @param dev Pointer to the device object (Artec48U_Device). + * @param func_name Function name (for use in debug messages). + */ +#define CHECK_DEV_OPEN(dev, func_name) \ + do { \ + CHECK_DEV_NOT_NULL ((dev), (func_name)); \ + if ((dev)->fd == -1) \ + { \ + XDBG ((3, "%s: BUG: device %p not open\n", (func_name), (void*)(dev)));\ + return SANE_STATUS_INVAL; \ + } \ + } while (SANE_FALSE) + +#define CHECK_DEV_ACTIVE(dev,func_name) \ + do { \ + CHECK_DEV_OPEN ((dev), (func_name)); \ + if (!(dev)->active) \ + { \ + XDBG ((3, "%s: BUG: device %p not active\n", \ + (func_name), (void*)(dev))); \ + return SANE_STATUS_INVAL; \ + } \ + } while (SANE_FALSE) + +typedef struct Artec48U_Device Artec48U_Device; +typedef struct Artec48U_Scan_Request Artec48U_Scan_Request; +typedef struct Artec48U_Scanner Artec48U_Scanner; +typedef struct Artec48U_Scan_Parameters Artec48U_Scan_Parameters; +typedef struct Artec48U_AFE_Parameters Artec48U_AFE_Parameters; +typedef struct Artec48U_Exposure_Parameters Artec48U_Exposure_Parameters; +typedef struct Artec48U_Line_Reader Artec48U_Line_Reader; +typedef struct Artec48U_Delay_Buffer Artec48U_Delay_Buffer; + +enum artec_options +{ + OPT_NUM_OPTS = 0, + OPT_MODE_GROUP, + OPT_SCAN_MODE, + OPT_BIT_DEPTH, + OPT_BLACK_LEVEL, + OPT_RESOLUTION, + OPT_ENHANCEMENT_GROUP, + OPT_BRIGHTNESS, + OPT_CONTRAST, + OPT_GAMMA, + OPT_GAMMA_R, + OPT_GAMMA_G, + OPT_GAMMA_B, + OPT_DEFAULT_ENHANCEMENTS, + OPT_GEOMETRY_GROUP, + OPT_TL_X, + OPT_TL_Y, + OPT_BR_X, + OPT_BR_Y, + OPT_CALIBRATION_GROUP, + OPT_CALIBRATE, + OPT_CALIBRATE_SHADING, +#ifdef ARTEC48U_USE_BUTTONS + OPT_BUTTON_STATE, +#endif + /* must come last: */ + NUM_OPTIONS +}; + +/** Artec48U analog front-end (AFE) parameters. + */ +struct Artec48U_AFE_Parameters +{ + SANE_Byte r_offset; /**< Red channel offset */ + SANE_Byte r_pga; /**< Red channel PGA gain */ + SANE_Byte g_offset; /**< Green channel offset (also used for mono) */ + SANE_Byte g_pga; /**< Green channel PGA gain (also used for mono) */ + SANE_Byte b_offset; /**< Blue channel offset */ + SANE_Byte b_pga; /**< Blue channel PGA gain */ +}; + +/** TV9693 exposure time parameters. + */ +struct Artec48U_Exposure_Parameters +{ + SANE_Int r_time; /**< Red exposure time */ + SANE_Int g_time; /**< Red exposure time */ + SANE_Int b_time; /**< Red exposure time */ +}; + +struct Artec48U_Device +{ + Artec48U_Device *next; + /** Device file descriptor. */ + int fd; + /** Device activation flag. */ + SANE_Bool active; + SANE_String_Const name; + SANE_Device sane; /** Scanner model data. */ + SANE_String_Const firmware_path; + double gamma_master; + double gamma_r; + double gamma_g; + double gamma_b; + Artec48U_Exposure_Parameters exp_params; + Artec48U_AFE_Parameters afe_params; + Artec48U_AFE_Parameters artec_48u_afe_params; + Artec48U_Exposure_Parameters artec_48u_exposure_params; + + SANE_Int optical_xdpi; + SANE_Int optical_ydpi; + SANE_Int base_ydpi; + SANE_Int xdpi_offset; /* in optical_xdpi units */ + SANE_Int ydpi_offset; /* in optical_ydpi units */ + SANE_Int x_size; /* in optical_xdpi units */ + SANE_Int y_size; /* in optical_ydpi units */ +/* the number of lines, that we move forward before we start reading the + shading lines */ + int shading_offset; +/* the number of lines we read for the black shading buffer */ + int shading_lines_b; +/* the number of lines we read for the white shading buffer */ + int shading_lines_w; + + SANE_Fixed x_offset, y_offset; + SANE_Bool read_active; + SANE_Byte *read_buffer; + size_t requested_buffer_size; + size_t read_pos; + size_t read_bytes_in_buffer; + size_t read_bytes_left; + unsigned int is_epro; + unsigned int epro_mult; +}; + +/** Scan parameters for artec48u_device_setup_scan(). + * + * These parameters describe a low-level scan request; many such requests are + * executed during calibration, and they need to have parameters separate from + * the main request (Artec48U_Scan_Request). E.g., on the BearPaw 2400 TA the + * scan to find the home position is always done at 300dpi 8-bit mono with + * fixed width and height, regardless of the high-level scan parameters. + */ +struct Artec48U_Scan_Parameters +{ + SANE_Int xdpi; /**< Horizontal resolution */ + SANE_Int ydpi; /**< Vertical resolution */ + SANE_Int depth; /**< Number of bits per channel */ + SANE_Bool color; /**< Color mode flag */ + + SANE_Int pixel_xs; /**< Logical width in pixels */ + SANE_Int pixel_ys; /**< Logical height in pixels */ + SANE_Int scan_xs; /**< Physical width in pixels */ + SANE_Int scan_ys; /**< Physical height in pixels */ + SANE_Int scan_bpl; /**< Number of bytes per scan line */ + SANE_Bool lineart; /**<Lineart is not really supported by device*/ +}; + + +/** Parameters for the high-level scan request. + * + * These parameters describe the scan request sent by the SANE frontend. + */ +struct Artec48U_Scan_Request +{ + SANE_Fixed x0; /**< Left boundary */ + SANE_Fixed y0; /**< Top boundary */ + SANE_Fixed xs; /**< Width */ + SANE_Fixed ys; /**< Height */ + SANE_Int xdpi; /**< Horizontal resolution */ + SANE_Int ydpi; /**< Vertical resolution */ + SANE_Int depth; /**< Number of bits per channel */ + SANE_Bool color; /**< Color mode flag */ +}; +/** Scan action code (purpose of the scan). + * + * The scan action code affects various scanning mode fields in the setup + * command. + */ +typedef enum Artec48U_Scan_Action +{ + SA_CALIBRATE_SCAN_WHITE, /**< Scan white shading buffer */ + SA_CALIBRATE_SCAN_BLACK, /**< Scan black shading buffer */ + SA_CALIBRATE_SCAN_OFFSET_1, /**< First scan to determin offset */ + SA_CALIBRATE_SCAN_OFFSET_2, /**< Second scan to determine offset */ + SA_CALIBRATE_SCAN_EXPOSURE_1, /**< First scan to determin offset */ + SA_CALIBRATE_SCAN_EXPOSURE_2, /**< Second scan to determine offset */ + SA_SCAN /**< Normal scan */ +} +Artec48U_Scan_Action; + + +struct Artec48U_Delay_Buffer +{ + SANE_Int line_count; + SANE_Int read_index; + SANE_Int write_index; + unsigned int **lines; + SANE_Byte *mem_block; +}; + +struct Artec48U_Line_Reader +{ + Artec48U_Device *dev; /**< Low-level interface object */ + Artec48U_Scan_Parameters params; /**< Scan parameters */ + + /** Number of pixels in the returned scanlines */ + SANE_Int pixels_per_line; + + SANE_Byte *pixel_buffer; + + Artec48U_Delay_Buffer r_delay; + Artec48U_Delay_Buffer g_delay; + Artec48U_Delay_Buffer b_delay; + SANE_Bool delays_initialized; + + SANE_Status (*read) (Artec48U_Line_Reader * reader, + unsigned int **buffer_pointers_return); +}; + +#ifndef SANE_OPTION +typedef union +{ + SANE_Word w; + SANE_Word *wa; /* word array */ + SANE_String s; +} +Option_Value; +#endif + +struct Artec48U_Scanner +{ + Artec48U_Scanner *next; + Artec48U_Scan_Parameters params; + Artec48U_Scan_Request request; + Artec48U_Device *dev; + Artec48U_Line_Reader *reader; + FILE *pipe_handle; + SANE_Pid reader_pid; + int pipe; + int reader_pipe; + SANE_Option_Descriptor opt[NUM_OPTIONS]; + Option_Value val[NUM_OPTIONS]; + SANE_Status exit_code; + SANE_Parameters sane_params; + SANE_Bool scanning; + SANE_Bool eof; + SANE_Bool calibrated; + SANE_Word gamma_array[4][65536]; + SANE_Word contrast_array[65536]; + SANE_Word brightness_array[65536]; + SANE_Byte *line_buffer; + SANE_Byte *lineart_buffer; + SANE_Word lines_to_read; + unsigned int temp_shading_buffer[3][10240]; /*epro*/ + unsigned int *buffer_pointers[3]; + unsigned char *shading_buffer_w; + unsigned char *shading_buffer_b; + unsigned int *shading_buffer_white[3]; + unsigned int *shading_buffer_black[3]; + unsigned long byte_cnt; +}; + + +/** Create a new Artec48U_Device object. + * + * The newly created device object is in the closed state. + * + * @param dev_return Returned pointer to the created device object. + * + * @return + * - #SANE_STATUS_GOOD - the device object was created. + * - #SANE_STATUS_NO_MEM - not enough system resources to create the object. + */ +static SANE_Status artec48u_device_new (Artec48U_Device ** dev_return); + +/** Destroy the device object and release all associated resources. + * + * If the device was active, it will be deactivated; if the device was open, it + * will be closed. + * + * @param dev Device object. + * + * @return + * - #SANE_STATUS_GOOD - success. + */ +static SANE_Status artec48u_device_free (Artec48U_Device * dev); + +/** Open the scanner device. + * + * This function opens the device special file @a dev_name and tries to detect + * the device model by its USB ID. + * + * If the device is detected successfully (its USB ID is found in the supported + * device list), this function sets the appropriate model parameters. + * + * If the USB ID is not recognized, the device remains unconfigured; an attempt + * to activate it will fail unless artec48u_device_set_model() is used to force + * the parameter set. Note that the open is considered to be successful in + * this case. + * + * @param dev Device object. + * @param dev_name Scanner device name. + * + * @return + * - #SANE_STATUS_GOOD - the device was opened successfully (it still may be + * unconfigured). + */ +static SANE_Status artec48u_device_open (Artec48U_Device * dev); + +/** Close the scanner device. + * + * @param dev Device object. + */ +static SANE_Status artec48u_device_close (Artec48U_Device * dev); + +/** Activate the device. + * + * The device must be activated before performing any I/O operations with it. + * All device model parameters must be configured before activation; it is + * impossible to change them after the device is active. + * + * This function might need to acquire resources (it calls + * Artec48U_Command_Set::activate). These resources will be released when + * artec48u_device_deactivate() is called. + * + * @param dev Device object. + * + * @return + * - #SANE_STATUS_GOOD - device activated successfully. + * - #SANE_STATUS_INVAL - invalid request (attempt to activate a closed or + * unconfigured device). + */ +static SANE_Status artec48u_device_activate (Artec48U_Device * dev); + +/** Deactivate the device. + * + * This function reverses the action of artec48u_device_activate(). + * + * @param dev Device object. + * + * @return + * - #SANE_STATUS_GOOD - device deactivated successfully. + * - #SANE_STATUS_INVAL - invalid request (the device was not activated). + */ +static SANE_Status artec48u_device_deactivate (Artec48U_Device * dev); + +/** Write a data block to the TV9693 memory. + * + * @param dev Device object. + * @param addr Start address in the TV9693 memory. + * @param size Size of the data block in bytes. + * @param data Data block to write. + * + * @return + * - #SANE_STATUS_GOOD - success. + * - #SANE_STATUS_IO_ERROR - a communication error occured. + * + * @warning + * @a size must be a multiple of 64 (at least with TV9693), otherwise the + * scanner (and possibly the entire USB bus) will lock up. + */ +static SANE_Status +artec48u_device_memory_write (Artec48U_Device * dev, SANE_Word addr, + SANE_Word size, SANE_Byte * data); + +/** Read a data block from the TV9693 memory. + * + * @param dev Device object. + * @param addr Start address in the TV9693 memory. + * @param size Size of the data block in bytes. + * @param data Buffer for the read data. + * + * @return + * - #SANE_STATUS_GOOD - success. + * - #SANE_STATUS_IO_ERROR - a communication error occured. + * + * @warning + * @a size must be a multiple of 64 (at least with TV9693), otherwise the + * scanner (and possibly the entire USB bus) will lock up. + */ +static SANE_Status +artec48u_device_memory_read (Artec48U_Device * dev, SANE_Word addr, + SANE_Word size, SANE_Byte * data); + +/** Execute a control command. + * + * @param dev Device object. + * @param cmd Command packet. + * @param res Result packet (may point to the same buffer as @a cmd). + * + * @return + * - #SANE_STATUS_GOOD - success. + * - #SANE_STATUS_IO_ERROR - a communication error occured. + */ +static SANE_Status +artec48u_device_req (Artec48U_Device * dev, Artec48U_Packet cmd, + Artec48U_Packet res); + +/** Execute a "small" control command. + * + * @param dev Device object. + * @param cmd Command packet; only first 8 bytes are used. + * @param res Result packet (may point to the same buffer as @a cmd). + * + * @return + * - #SANE_STATUS_GOOD - success. + * - #SANE_STATUS_IO_ERROR - a communication error occured. + */ +static SANE_Status +artec48u_device_small_req (Artec48U_Device * dev, Artec48U_Packet cmd, + Artec48U_Packet res); + +/** Read raw data from the bulk-in scanner pipe. + * + * @param dev Device object. + * @param buffer Buffer for the read data. + * @param size Pointer to the variable which must be set to the requested data + * size before call. After completion this variable will hold the number of + * bytes actually read. + * + * @return + * - #SANE_STATUS_GOOD - success. + * - #SANE_STATUS_IO_ERROR - a communication error occured. + */ +static SANE_Status +artec48u_device_read_raw (Artec48U_Device * dev, SANE_Byte * buffer, + size_t * size); + +static SANE_Status +artec48u_device_set_read_buffer_size (Artec48U_Device * dev, + size_t buffer_size); + +static SANE_Status +artec48u_device_read_prepare (Artec48U_Device * dev, size_t expected_count); + +static SANE_Status +artec48u_device_read (Artec48U_Device * dev, SANE_Byte * buffer, + size_t * size); + +static SANE_Status artec48u_device_read_finish (Artec48U_Device * dev); + + +/** + * Create a new Artec48U_Line_Reader object. + * + * @param dev The low-level scanner interface object. + * @param params Scan parameters prepared by artec48u_device_setup_scan(). + * @param reader_return Location for the returned object. + * + * @return + * - SANE_STATUS_GOOD - on success + * - SANE_STATUS_NO_MEM - cannot allocate memory for object or buffers + * - other error values - failure of some internal functions + */ +static SANE_Status +artec48u_line_reader_new (Artec48U_Device * dev, + Artec48U_Scan_Parameters * params, + Artec48U_Line_Reader ** reader_return); + +/** + * Destroy the Artec48U_Line_Reader object. + * + * @param reader The Artec48U_Line_Reader object to destroy. + */ +static SANE_Status artec48u_line_reader_free (Artec48U_Line_Reader * reader); + +/** + * Read a scanline from the Artec48U_Line_Reader object. + * + * @param reader The Artec48U_Line_Reader object. + * @param buffer_pointers_return Array of pointers to image lines (1 or 3 + * elements) + * + * This function reads a full scanline from the device, unpacks it to internal + * buffers and returns pointer to these buffers in @a + * buffer_pointers_return[i]. For monochrome scan, only @a + * buffer_pointers_return[0] is filled; for color scan, elements 0, 1, 2 are + * filled with pointers to red, green, and blue data. The returned pointers + * are valid until the next call to artec48u_line_reader_read(), or until @a + * reader is destroyed. + * + * @return + * - SANE_STATUS_GOOD - read completed successfully + * - other error value - an error occured + */ +static SANE_Status +artec48u_line_reader_read (Artec48U_Line_Reader * reader, + unsigned int **buffer_pointers_return); + +static SANE_Status +artec48u_download_firmware (Artec48U_Device * dev, + SANE_Byte * data, SANE_Word size); + +static SANE_Status +artec48u_is_moving (Artec48U_Device * dev, SANE_Bool * moving); + +static SANE_Status artec48u_carriage_home (Artec48U_Device * dev); + +static SANE_Status artec48u_stop_scan (Artec48U_Device * dev); + +static SANE_Status +artec48u_setup_scan (Artec48U_Scanner * s, + Artec48U_Scan_Request * request, + Artec48U_Scan_Action action, + SANE_Bool calculate_only, + Artec48U_Scan_Parameters * params); + +static SANE_Status +artec48u_scanner_new (Artec48U_Device * dev, + Artec48U_Scanner ** scanner_return); + +static SANE_Status artec48u_scanner_free (Artec48U_Scanner * scanner); + +static SANE_Status +artec48u_scanner_start_scan (Artec48U_Scanner * scanner, + Artec48U_Scan_Request * request, + Artec48U_Scan_Parameters * params); + +static SANE_Status +artec48u_scanner_read_line (Artec48U_Scanner * scanner, + unsigned int **buffer_pointers, + SANE_Bool shading); + +static SANE_Status artec48u_scanner_stop_scan (Artec48U_Scanner * scanner); + +static SANE_Status +artec48u_calculate_shading_buffer (Artec48U_Scanner * s, int start, int end, + int resolution, SANE_Bool color); + +static SANE_Status download_firmware_file (Artec48U_Device * chip); + +static SANE_Status +artec48u_generic_set_exposure_time (Artec48U_Device * dev, + Artec48U_Exposure_Parameters * params); + +static SANE_Status +artec48u_generic_set_afe (Artec48U_Device * dev, + Artec48U_AFE_Parameters * params); + +static SANE_Status artec48u_generic_start_scan (Artec48U_Device * dev); + +static SANE_Status +artec48u_generic_read_scanned_data (Artec48U_Device * dev, SANE_Bool * ready); + +static SANE_Status init_options (Artec48U_Scanner * s); + +static SANE_Status load_calibration_data (Artec48U_Scanner * s); + +static SANE_Status save_calibration_data (Artec48U_Scanner * s); +#endif |