From 84357741a6a6e6430f199b2c3f7498e0e97da9ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Sun, 12 Feb 2023 17:35:53 +0100 Subject: New upstream version 1.2.1 --- backend/canon_dr.c | 937 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 929 insertions(+), 8 deletions(-) (limited to 'backend/canon_dr.c') diff --git a/backend/canon_dr.c b/backend/canon_dr.c index 95799e7..58299d7 100644 --- a/backend/canon_dr.c +++ b/backend/canon_dr.c @@ -3,7 +3,7 @@ This file is part of the SANE package, and implements a SANE backend for various Canon DR-series scanners. - Copyright (C) 2008-2021 m. allan noah + Copyright (C) 2008-2022 m. allan noah Yabarana Corp. www.yabarana.com provided significant funding EvriChart, Inc. www.evrichart.com provided funding and loaned equipment @@ -355,6 +355,10 @@ - rewrite do_cmd() timeout handling - remove long timeout TUR from v61 (did not help) - allow config file to set initial tur timeout for DR-X10C (#142) + v63 2022-11-18, CQ, MAN + - add support for reading the total and roller counters + v64 2022-11-18, CQ, MAN + - add complete support for imprinters on X10C (#585) SANE FLOW DIAGRAM @@ -393,6 +397,7 @@ #include /*tan*/ #include /*usleep*/ #include /*gettimeofday*/ +#include /*localtime*/ #include /*strtol*/ #include "../include/sane/sanei_backend.h" @@ -406,7 +411,7 @@ #include "canon_dr.h" #define DEBUG 1 -#define BUILD 62 +#define BUILD 64 /* values for SANE_DEBUG_CANON_DR env var: - errors 5 @@ -449,6 +454,13 @@ #define STRING_NONE SANE_I18N("None") #define STRING_JPEG SANE_I18N("JPEG") +#define STRING_IMPRINTER_8x12_FONT SANE_I18N("8x12") +#define STRING_IMPRINTER_12x12_FONT SANE_I18N("12x12") + +#define STRING_IMPRINTER_ADDON_BoW SANE_I18N("Black-on-White") +#define STRING_IMPRINTER_ADDON_BoI SANE_I18N("Black-on-Image") +#define STRING_IMPRINTER_ADDON_WoB SANE_I18N("White-on-Black") + /* Also set via config file. */ static int global_buffer_size; static int global_buffer_size_default = 2 * 1024 * 1024; @@ -494,7 +506,7 @@ static struct scanner *scanner_devList = NULL; SANE_Status sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) { - authorize = authorize; /* get rid of compiler warning */ + (void) authorize; /* get rid of compiler warning */ DBG_INIT (); DBG (10, "sane_init: start\n"); @@ -547,7 +559,7 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) int num_devices=0; int i=0; - local_only = local_only; /* get rid of compiler warning */ + (void) local_only; /* get rid of compiler warning */ DBG (10, "sane_get_devices: start\n"); @@ -992,6 +1004,12 @@ attach_one (const char *device_name, int connType) return ret; } + /* this detects imprinters if they are available */ + ret = init_imprinters (s); + if (ret != SANE_STATUS_GOOD) { + DBG (5, "attach_one: errors while trying to detect optional imprinters, continuing\n"); + } + /* enable/read the buttons */ ret = init_panel (s); if (ret != SANE_STATUS_GOOD) { @@ -1001,6 +1019,13 @@ attach_one (const char *device_name, int connType) return ret; } + /* enable/read the lifecycle counters */ + ret = init_counters (s); + if (ret != SANE_STATUS_GOOD) { + DBG (5, "attach_one: unable to detect lifecycle counters, continuing\n"); + return ret; + } + /* sets SANE option 'values' to good defaults */ ret = init_user (s); if (ret != SANE_STATUS_GOOD) { @@ -1168,6 +1193,7 @@ init_inquire (struct scanner *s) if (strncmp ("DR", s->model_name, 2) && strncmp ("CR", s->model_name, 2) && strncmp ("P-", s->model_name, 2) + && strncmp ("R", s->model_name, 1) ) { DBG (5, "The device at '%s' is reported to be a '%s'\n", s->device_name, s->model_name); @@ -1388,8 +1414,9 @@ init_model (struct scanner *s) s->max_x_fb = s->max_x; s->max_y_fb = s->max_y; - /* missing from vpd- we will unset this for b&w machines below */ + /* missing from vpd- we will unset these for some machines below */ s->can_color = 1; + s->can_read_lifecycle_counters = 1; /* specific settings missing from vpd */ if (strstr (s->model_name,"DR-9080")){ @@ -1491,6 +1518,34 @@ init_model (struct scanner *s) s->can_monochrome=0; } + else if (strstr (s->model_name,"R40") + ){ + /* confirmed */ + s->gray_interlace[SIDE_FRONT] = GRAY_INTERLACE_C120; + s->gray_interlace[SIDE_BACK] = GRAY_INTERLACE_C120; + s->color_interlace[SIDE_FRONT] = COLOR_INTERLACE_C120; + s->color_interlace[SIDE_BACK] = COLOR_INTERLACE_C120; + s->duplex_interlace = DUPLEX_INTERLACE_2510; + /*s->duplex_offset = 320; now set in config file*/ + s->fixed_width = 1; + s->need_ccal = 1; + s->fcal_src = FCAL_SRC_SCAN; + s->fcal_dest = FCAL_DEST_SW; + s->rgb_format = 1; + s->sw_lut = 1; + + /*only in Y direction, so we trash them in X*/ + s->std_res_x[DPI_100]=0; + s->std_res_x[DPI_150]=0; + s->std_res_x[DPI_200]=0; + s->std_res_x[DPI_240]=0; + s->std_res_x[DPI_400]=0; + + /* suspected settings */ + s->ccal_version = 3; + s->has_df_ultra = 1; + } + /* copied from 2510, possibly incorrect */ else if (strstr (s->model_name,"DR-3010")){ s->rgb_format = 1; @@ -1840,6 +1895,7 @@ init_model (struct scanner *s) } else if (strstr (s->model_name,"DR-X10C")){ + int i = 0; /* Required for USB coms */ s->has_ssm = 0; @@ -1862,6 +1918,61 @@ init_model (struct scanner *s) s->std_res_y[DPI_600]=1; s->has_hwcrop = 1; + + /*valid horizontal offsets for post-imprinter*/ + s->post_imprinter_h_offset_list[++i] = 21; + s->post_imprinter_h_offset_list[++i] = 35; + s->post_imprinter_h_offset_list[++i] = 47; + s->post_imprinter_h_offset_list[++i] = 59; + s->post_imprinter_h_offset_list[++i] = 72; + s->post_imprinter_h_offset_list[++i] = 99; + s->post_imprinter_h_offset_list[++i] = 114; + s->post_imprinter_h_offset_list[++i] = 143; + s->post_imprinter_h_offset_list[++i] = 155; + s->post_imprinter_h_offset_list[++i] = 167; + s->post_imprinter_h_offset_list[++i] = 196; + s->post_imprinter_h_offset_list[++i] = 211; + s->post_imprinter_h_offset_list[++i] = 239; + s->post_imprinter_h_offset_list[++i] = 251; + s->post_imprinter_h_offset_list[++i] = 263; + s->post_imprinter_h_offset_list[++i] = 275; + s->post_imprinter_h_offset_list[++i] = 289; + s->post_imprinter_h_offset_list[0] = i; + + i = 0; + /*valid horizontal offsets for pre-imprinter*/ + s->pre_imprinter_h_offset_list[++i] = 14; + s->pre_imprinter_h_offset_list[++i] = 28; + s->pre_imprinter_h_offset_list[++i] = 41; + s->pre_imprinter_h_offset_list[++i] = 53; + s->pre_imprinter_h_offset_list[++i] = 65; + s->pre_imprinter_h_offset_list[++i] = 106; + s->pre_imprinter_h_offset_list[0] = i; + + /*valid vertical offsets for imprinters*/ + s->imprinter_v_offset_range.min = 0; + s->imprinter_v_offset_range.max = 500; + s->imprinter_v_offset_range.quant = 1; + + i = 0; + /*valid font angles for imprinters*/ + s->imprinter_font_angle_list[++i] = 0; + s->imprinter_font_angle_list[++i] = 90; + s->imprinter_font_angle_list[++i] = 180; + s->imprinter_font_angle_list[++i] = 270; + s->imprinter_font_angle_list[0] = i; + + i = 0; + s->imprint_font_size_list[i++] = STRING_IMPRINTER_8x12_FONT; + s->imprint_font_size_list[i++] = STRING_IMPRINTER_12x12_FONT; + s->imprint_font_size_list[i] = NULL; + + i = 0; + s->imprint_addon_mode_list[i++] = STRING_IMPRINTER_ADDON_BoI; + s->imprint_addon_mode_list[i++] = STRING_IMPRINTER_ADDON_BoW; + s->imprint_addon_mode_list[i++] = STRING_IMPRINTER_ADDON_WoB; + s->imprint_addon_mode_list[i++] = STRING_NONE; + s->imprint_addon_mode_list[i] = NULL; } DBG (10, "init_model: finish\n"); @@ -1869,6 +1980,30 @@ init_model (struct scanner *s) return SANE_STATUS_GOOD; } +/* + * try to detect imprinters. + */ +static SANE_Status +init_imprinters (struct scanner *s) +{ + SANE_Status ret = SANE_STATUS_GOOD; + + s->has_pre_imprinter = 0; + s->has_post_imprinter = 0; + + ret = detect_imprinter(s,R_PRE_IMPRINTER); + if(ret != SANE_STATUS_GOOD){ + return ret; + } + + ret = detect_imprinter(s,R_POST_IMPRINTER); + if(ret != SANE_STATUS_GOOD){ + return ret; + } + + return ret; +} + /* * This function enables the buttons and preloads the current panel values */ @@ -1900,6 +2035,28 @@ init_panel (struct scanner *s) return ret; } +/* + * This function disables the lifecycle counters if not available + */ +static SANE_Status +init_counters (struct scanner *s) +{ + SANE_Status ret = SANE_STATUS_GOOD; + + DBG (10, "init_counters: start\n"); + + ret = read_counters(s); + if(ret){ + DBG (5, "init_counters: disabling lifecycle counters\n"); + s->can_read_lifecycle_counters = 0; + return ret; + } + + DBG (10, "init_counters: finish\n"); + + return ret; +} + /* * set good default user values. * struct is already initialized to 0. @@ -1953,6 +2110,10 @@ init_user (struct scanner *s) s->threshold = 90; s->compress_arg = 50; + s->pre_imprint.h_offset = 65; + s->post_imprint.h_offset = 155; + s->post_imprint_addon_mode = ADDON_BoI; + DBG (10, "init_user: finish\n"); return SANE_STATUS_GOOD; @@ -2737,6 +2898,197 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->cap = SANE_CAP_INACTIVE; } + /* "Imprinter" group --------------------------------------------------- */ + if(option==OPT_IMPRINT_GROUP){ + opt->name = "imprinter-options"; + opt->title = SANE_I18N ("Imprinter Options"); + opt->desc = SANE_I18N ("Controls for imprinter units"); + opt->type = SANE_TYPE_GROUP; + opt->constraint_type = SANE_CONSTRAINT_NONE; + + /*flaming hack to get scanimage to hide group*/ + if ( !(s->has_pre_imprinter || s->has_post_imprinter) ) + opt->type = SANE_TYPE_BOOL; + } + + if(option==OPT_PRE_IMPRINT_SPECSTRING){ + opt->name = "pre-imprint-string"; + opt->title = "Pre-Imprinter string"; + opt->desc = "String specifier for the pre-imprinter text"; + opt->type = SANE_TYPE_STRING; + opt->size = IMPRINT_SPECSTRING_LEN; + if (s->has_pre_imprinter) + opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + else + opt->cap = SANE_CAP_INACTIVE; + } + + if(option==OPT_PRE_IMPRINT_H_OFFSET){ + opt->name = "pre-imprint-h-offset"; + opt->title = "Pre-Imprinter horizontal offset"; + opt->desc = "Integer specifying the horizontal positioning of the pre-imprinter"; + opt->type = SANE_TYPE_INT; + opt->unit = SANE_UNIT_MM; + opt->size = sizeof(SANE_Word); + opt->constraint_type = SANE_CONSTRAINT_WORD_LIST; + opt->constraint.word_list = s->pre_imprinter_h_offset_list; + if (s->has_pre_imprinter) + opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + else + opt->cap = SANE_CAP_INACTIVE; + } + + if(option==OPT_PRE_IMPRINT_V_OFFSET){ + opt->name = "pre-imprint-v-offset"; + opt->title = "Pre-Imprinter vertical offset"; + opt->desc = "Integer specifying the vertical positioning of the pre-imprinter"; + opt->type = SANE_TYPE_INT; + opt->unit = SANE_UNIT_MM; + opt->size = sizeof(SANE_Word); + opt->constraint_type = SANE_CONSTRAINT_RANGE; + opt->constraint.range = &s->imprinter_v_offset_range; + if (s->has_pre_imprinter) + opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + else + opt->cap = SANE_CAP_INACTIVE; + } + + if(option==OPT_PRE_IMPRINT_FONT_SIZE){ + opt->name = "pre-imprint-font-size"; + opt->title = "Pre-Imprinter font size"; + opt->desc = "Integer specifying the pre-imprint font size"; + opt->type = SANE_TYPE_STRING; + opt->constraint_type = SANE_CONSTRAINT_STRING_LIST; + opt->constraint.string_list = s->imprint_font_size_list; + opt->size = maxStringSize (opt->constraint.string_list); + if (s->has_pre_imprinter) + opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + else + opt->cap = SANE_CAP_INACTIVE; + } + + if(option==OPT_PRE_IMPRINT_FONT_ROT){ + opt->name = "pre-imprint-font-rot"; + opt->title = "Pre-Imprinter font rotation"; + opt->desc = "Integer specifying the pre-imprint font rotation"; + opt->type = SANE_TYPE_INT; + opt->unit = SANE_UNIT_NONE; + opt->size = sizeof(SANE_Word); + opt->constraint_type = SANE_CONSTRAINT_WORD_LIST; + opt->constraint.word_list = s->imprinter_font_angle_list; + if (s->has_pre_imprinter) + opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + else + opt->cap = SANE_CAP_INACTIVE; + } + + if(option==OPT_PRE_IMPRINT_SPACING){ + opt->name = "pre-imprint-spacing"; + opt->title = "Pre-Imprinter spacing"; + opt->desc = "Enables the pre-imprint extra spacing"; + opt->type = SANE_TYPE_BOOL; + if (s->has_pre_imprinter) + opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + else + opt->cap = SANE_CAP_INACTIVE; + } + + if(option==OPT_POST_IMPRINT_SPECSTRING){ + opt->name = "post-imprint-string"; + opt->title = "Post-Imprinter string"; + opt->desc = "String specifier for the post-imprinter text"; + opt->type = SANE_TYPE_STRING; + opt->size = IMPRINT_SPECSTRING_LEN; + if (s->has_post_imprinter) + opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + else + opt->cap = SANE_CAP_INACTIVE; + } + + if(option==OPT_POST_IMPRINT_H_OFFSET){ + opt->name = "post-imprint-h-offset"; + opt->title = "Post-Imprinter horizontal offset"; + opt->desc = "Integer specifying the horizontal positioning of the post-imprinter"; + opt->type = SANE_TYPE_INT; + opt->unit = SANE_UNIT_MM; + opt->size = sizeof(SANE_Word); + opt->constraint_type = SANE_CONSTRAINT_WORD_LIST; + opt->constraint.word_list = s->post_imprinter_h_offset_list; + if (s->has_post_imprinter) + opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + else + opt->cap = SANE_CAP_INACTIVE; + } + + if(option==OPT_POST_IMPRINT_V_OFFSET){ + opt->name = "post-imprint-v-offset"; + opt->title = "Post-Imprinter vertical offset"; + opt->desc = "Integer specifying the vertical positioning of the post-imprinter"; + opt->type = SANE_TYPE_INT; + opt->unit = SANE_UNIT_MM; + opt->size = sizeof(SANE_Word); + opt->constraint_type = SANE_CONSTRAINT_RANGE; + opt->constraint.range = &s->imprinter_v_offset_range; + if (s->has_post_imprinter) + opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + else + opt->cap = SANE_CAP_INACTIVE; + } + + if(option==OPT_POST_IMPRINT_FONT_SIZE){ + opt->name = "post-imprint-font-size"; + opt->title = "Post-Imprinter font size"; + opt->desc = "Integer specifying the post-imprint font size"; + opt->type = SANE_TYPE_STRING; + opt->constraint_type = SANE_CONSTRAINT_STRING_LIST; + opt->constraint.string_list = s->imprint_font_size_list; + opt->size = maxStringSize (opt->constraint.string_list); + if (s->has_post_imprinter) + opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + else + opt->cap = SANE_CAP_INACTIVE; + } + + if(option==OPT_POST_IMPRINT_FONT_ROT){ + opt->name = "post-imprint-font-rot"; + opt->title = "Post-Imprinter font rotation"; + opt->desc = "Integer specifying the post-imprint font rotation"; + opt->type = SANE_TYPE_INT; + opt->unit = SANE_UNIT_NONE; + opt->size = sizeof(SANE_Word); + opt->constraint_type = SANE_CONSTRAINT_WORD_LIST; + opt->constraint.word_list = s->imprinter_font_angle_list; + if (s->has_post_imprinter) + opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + else + opt->cap = SANE_CAP_INACTIVE; + } + + if(option==OPT_POST_IMPRINT_SPACING){ + opt->name = "post-imprint-spacing"; + opt->title = "Post-Imprinter spacing"; + opt->desc = "Enables the post-imprint extra spacing"; + opt->type = SANE_TYPE_BOOL; + if (s->has_post_imprinter) + opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + else + opt->cap = SANE_CAP_INACTIVE; + } + + if(option==OPT_POST_IMPRINT_ADDON_MODE){ + opt->name = "post-imprint-addon-mode"; + opt->title = "Post-Imprinter addon mode"; + opt->desc = "Integer specifying the type of post-imprint addon rendered in the scanned image"; + opt->type = SANE_TYPE_STRING; + opt->constraint_type = SANE_CONSTRAINT_STRING_LIST; + opt->constraint.string_list = s->imprint_addon_mode_list; + opt->size = maxStringSize (opt->constraint.string_list); + if (s->has_post_imprinter) + opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + else + opt->cap = SANE_CAP_INACTIVE; + } + /* "Sensor" group ------------------------------------------------------ */ if(option==OPT_SENSOR_GROUP){ opt->name = SANE_NAME_SENSORS; @@ -2830,6 +3182,34 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->cap = SANE_CAP_INACTIVE; } + if(option==OPT_ROLLERCOUNTER){ + opt->name = "roller-counter"; + opt->title = "Roller Counter"; + opt->desc = "Scans since last roller replacement"; + opt->type = SANE_TYPE_INT; + opt->unit = SANE_UNIT_NONE; + opt->constraint_type = SANE_CONSTRAINT_NONE; + + if (s->can_read_lifecycle_counters) + opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; + else + opt->cap = SANE_CAP_INACTIVE; + } + + if(option==OPT_TOTALCOUNTER){ + opt->name = "total-counter"; + opt->title = "Total Counter"; + opt->desc = "Total scan count of the device"; + opt->type = SANE_TYPE_INT; + opt->unit = SANE_UNIT_NONE; + opt->constraint_type = SANE_CONSTRAINT_NONE; + + if (s->can_read_lifecycle_counters) + opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; + else + opt->cap = SANE_CAP_INACTIVE; + } + if(option==OPT_ADF_LOADED){ opt->name = "adf-loaded"; opt->title = "ADF Loaded"; @@ -3108,6 +3488,122 @@ sane_control_option (SANE_Handle handle, SANE_Int option, *val_p = s->hwcrop; return SANE_STATUS_GOOD; + case OPT_PRE_IMPRINT_SPECSTRING: + strcpy(val, s->pre_imprint.specstring); + return SANE_STATUS_GOOD; + + case OPT_PRE_IMPRINT_H_OFFSET: + *val_p = s->pre_imprint.h_offset; + return SANE_STATUS_GOOD; + + case OPT_PRE_IMPRINT_V_OFFSET: + *val_p = s->pre_imprint.v_offset; + return SANE_STATUS_GOOD; + + case OPT_PRE_IMPRINT_FONT_SIZE: + switch (s->pre_imprint.font_size){ + case IMPRINTER_12x12_FONT: + strcpy(val, STRING_IMPRINTER_12x12_FONT); + break; + + case IMPRINTER_8x12_FONT: + strcpy(val, STRING_IMPRINTER_8x12_FONT); + break; + } + return SANE_STATUS_GOOD; + + case OPT_PRE_IMPRINT_FONT_ROT: + switch (s->pre_imprint.font_rot){ + case IMPRINTER_0_FONT_ROT: + *val_p = 0; + break; + + case IMPRINTER_90_FONT_ROT: + *val_p = 90; + break; + + case IMPRINTER_180_FONT_ROT: + *val_p = 180; + break; + + case IMPRINTER_270_FONT_ROT: + *val_p = 270; + break; + } + return SANE_STATUS_GOOD; + + case OPT_PRE_IMPRINT_SPACING: + *val_p = s->pre_imprint.spacing; + return SANE_STATUS_GOOD; + + case OPT_POST_IMPRINT_SPECSTRING: + strcpy(val, s->post_imprint.specstring); + return SANE_STATUS_GOOD; + + case OPT_POST_IMPRINT_H_OFFSET: + *val_p = s->post_imprint.h_offset; + return SANE_STATUS_GOOD; + + case OPT_POST_IMPRINT_V_OFFSET: + *val_p = s->post_imprint.v_offset; + return SANE_STATUS_GOOD; + + case OPT_POST_IMPRINT_FONT_SIZE: + switch (s->post_imprint.font_size){ + case IMPRINTER_12x12_FONT: + strcpy(val, STRING_IMPRINTER_12x12_FONT); + break; + + case IMPRINTER_8x12_FONT: + strcpy(val, STRING_IMPRINTER_8x12_FONT); + break; + } + return SANE_STATUS_GOOD; + + case OPT_POST_IMPRINT_FONT_ROT: + switch (s->post_imprint.font_rot){ + case IMPRINTER_0_FONT_ROT: + *val_p = 0; + break; + + case IMPRINTER_90_FONT_ROT: + *val_p = 90; + break; + + case IMPRINTER_180_FONT_ROT: + *val_p = 180; + break; + + case IMPRINTER_270_FONT_ROT: + *val_p = 270; + break; + } + return SANE_STATUS_GOOD; + + case OPT_POST_IMPRINT_SPACING: + *val_p = s->post_imprint.spacing; + return SANE_STATUS_GOOD; + + case OPT_POST_IMPRINT_ADDON_MODE: + switch (s->post_imprint_addon_mode){ + case ADDON_BoW: + strcpy(val, STRING_IMPRINTER_ADDON_BoW); + break; + + case ADDON_BoI: + strcpy(val, STRING_IMPRINTER_ADDON_BoI); + break; + + case ADDON_WoB: + strcpy(val, STRING_IMPRINTER_ADDON_WoB); + break; + + case ADDON_DISABLED: + strcpy(val, STRING_NONE); + break; + } + return SANE_STATUS_GOOD; + /* Sensor Group */ case OPT_START: ret = read_panel(s,OPT_START); @@ -3144,6 +3640,16 @@ sane_control_option (SANE_Handle handle, SANE_Int option, *val_p = s->panel_counter; return ret; + case OPT_ROLLERCOUNTER: + ret = read_counters(s); + *val_p = s->roller_counter; + return ret; + + case OPT_TOTALCOUNTER: + ret = read_counters(s); + *val_p = s->total_counter; + return ret; + case OPT_ADF_LOADED: ret = read_sensors(s,OPT_ADF_LOADED); *val_p = s->sensor_adf_loaded; @@ -3431,6 +3937,119 @@ sane_control_option (SANE_Handle handle, SANE_Int option, s->hwcrop = val_c; return SANE_STATUS_GOOD; + case OPT_PRE_IMPRINT_SPECSTRING: + if (strlen(val) < IMPRINT_SPECSTRING_LEN){ + strncpy(s->pre_imprint.specstring, val, IMPRINT_SPECSTRING_LEN); + return SANE_STATUS_GOOD; + } + DBG (5, "sane_control_option: pre-imprint spec string '%s' exceed the limit of %d characters\n", (SANE_String)val, IMPRINT_SPECSTRING_LEN); + return SANE_STATUS_INVAL; + + case OPT_PRE_IMPRINT_H_OFFSET: + s->pre_imprint.h_offset = val_c; + return SANE_STATUS_GOOD; + + case OPT_PRE_IMPRINT_V_OFFSET: + s->pre_imprint.v_offset = val_c; + return SANE_STATUS_GOOD; + + case OPT_PRE_IMPRINT_FONT_SIZE: + if (!strcmp (val, STRING_IMPRINTER_12x12_FONT)) { + s->pre_imprint.font_size = IMPRINTER_12x12_FONT; + } + if (!strcmp (val, STRING_IMPRINTER_8x12_FONT)) { + s->pre_imprint.font_size = IMPRINTER_8x12_FONT; + } + return SANE_STATUS_GOOD; + + case OPT_PRE_IMPRINT_FONT_ROT: + switch (val_c){ + case 0: + s->pre_imprint.font_rot = IMPRINTER_0_FONT_ROT; + break; + + case 90: + s->pre_imprint.font_rot = IMPRINTER_90_FONT_ROT; + break; + + case 180: + s->pre_imprint.font_rot = IMPRINTER_180_FONT_ROT; + break; + + case 270: + s->pre_imprint.font_rot = IMPRINTER_270_FONT_ROT; + break; + } + return SANE_STATUS_GOOD; + + case OPT_PRE_IMPRINT_SPACING: + s->pre_imprint.spacing = val_c; + return SANE_STATUS_GOOD; + + case OPT_POST_IMPRINT_SPECSTRING: + if (strlen(val) < IMPRINT_SPECSTRING_LEN){ + strncpy(s->post_imprint.specstring, val, IMPRINT_SPECSTRING_LEN); + return SANE_STATUS_GOOD; + } + DBG (5, "sane_control_option: post-imprint spec string '%s' exceed the limit of %d characters\n", (SANE_String)val, IMPRINT_SPECSTRING_LEN); + return SANE_STATUS_INVAL; + + case OPT_POST_IMPRINT_H_OFFSET: + s->post_imprint.h_offset = val_c; + return SANE_STATUS_GOOD; + + case OPT_POST_IMPRINT_V_OFFSET: + s->post_imprint.v_offset = val_c; + return SANE_STATUS_GOOD; + + case OPT_POST_IMPRINT_FONT_SIZE: + if (!strcmp (val, STRING_IMPRINTER_12x12_FONT)) { + s->post_imprint.font_size = IMPRINTER_12x12_FONT; + } + if (!strcmp (val, STRING_IMPRINTER_8x12_FONT)) { + s->post_imprint.font_size = IMPRINTER_8x12_FONT; + } + return SANE_STATUS_GOOD; + + case OPT_POST_IMPRINT_FONT_ROT: + switch (val_c){ + case 0: + s->post_imprint.font_rot = IMPRINTER_0_FONT_ROT; + break; + + case 90: + s->post_imprint.font_rot = IMPRINTER_90_FONT_ROT; + break; + + case 180: + s->post_imprint.font_rot = IMPRINTER_180_FONT_ROT; + break; + + case 270: + s->post_imprint.font_rot = IMPRINTER_270_FONT_ROT; + break; + } + return SANE_STATUS_GOOD; + + case OPT_POST_IMPRINT_SPACING: + s->post_imprint.spacing = val_c; + return SANE_STATUS_GOOD; + + case OPT_POST_IMPRINT_ADDON_MODE: + if (!strcmp (val, STRING_IMPRINTER_ADDON_BoW)) { + s->post_imprint_addon_mode = ADDON_BoW; + } + if (!strcmp (val, STRING_IMPRINTER_ADDON_BoI)) { + s->post_imprint_addon_mode = ADDON_BoI; + } + if (!strcmp (val, STRING_IMPRINTER_ADDON_WoB)) { + s->post_imprint_addon_mode = ADDON_WoB; + } + if (!strcmp (val, STRING_NONE)) { + s->post_imprint_addon_mode = ADDON_DISABLED; + } + return SANE_STATUS_GOOD; + } } /* else */ @@ -3636,6 +4255,14 @@ ssm_df (struct scanner *s) set_SSM2_DF_staple(out, 1); } + int requires_postimprint = s->has_post_imprinter && (strlen(s->post_imprint.specstring) > 0); + int requires_preimprint = s->has_pre_imprinter && (strlen(s->pre_imprint.specstring) > 0); + if (s->has_post_imprinter) + set_SSM2_DF_post_addon(out, requires_postimprint); + if (requires_postimprint || requires_preimprint){ + set_SSM2_DF_imprint(out, 1); + } + ret = do_cmd ( s, 1, 0, cmd, cmdLen, @@ -3896,6 +4523,50 @@ ssm_do (struct scanner *s) return ret; } +static SANE_Status +read_counters(struct scanner *s) +{ + SANE_Status ret = SANE_STATUS_GOOD; + + unsigned char cmd[READ_len]; + size_t cmdLen = READ_len; + + unsigned char in[R_COUNTERS_len]; + size_t inLen = R_COUNTERS_len; + + if (!s->can_read_lifecycle_counters){ + DBG(10, "read_counters: unsupported\n"); + return ret; + } + + DBG(10, "read_counters: start\n"); + + memset(cmd,0,cmdLen); + set_SCSI_opcode(cmd, READ_code); + set_R_datatype_code(cmd, SR_datatype_counters); + set_R_xfer_length(cmd, inLen); + + ret = do_cmd( + s, 1, 0, + cmd, cmdLen, + NULL, 0, + in, &inLen + ); + + if (ret == SANE_STATUS_GOOD || ret == SANE_STATUS_EOF){ + + s->total_counter = get_R_COUNTERS_total(in); + s->roller_counter = s->total_counter - get_R_COUNTERS_last_srv(in); + + DBG(10, "read_counters: total counter: %d roller_counter %d \n",s->total_counter,s->roller_counter); + ret = SANE_STATUS_GOOD; + }else{ + DBG(10, "read_counters: ERROR: %d\n",ret); + } + + return ret; +} + static SANE_Status read_sensors(struct scanner *s,SANE_Int option) { @@ -4382,6 +5053,248 @@ update_params(struct scanner *s, int calib) return ret; } +/* simplify handling cmd SANE_STATUS_EOF as SANE_STATUS_GOOD */ +SANE_Status +send_cmd(struct scanner *s, unsigned char* cmd, size_t cmdLen, + unsigned char* out, size_t outLen, + unsigned char * inBuff, size_t * inLen) +{ + SANE_Status ret=SANE_STATUS_GOOD; + + ret = do_cmd ( + s, 1, 0, + cmd, cmdLen, + out, outLen, + inBuff, inLen + ); + + if (ret == SANE_STATUS_EOF) { + ret = SANE_STATUS_GOOD; + } + + return ret; +} + +SANE_Status +send_imprint_positioning(struct scanner* s, int is_postimprint, int enabled) +{ + unsigned char cmd[SET_SCAN_MODE2_len]; + size_t cmdLen=SET_SCAN_MODE2_len; + + unsigned char out[SSM2_PAY_len]; + size_t outLen=SSM2_PAY_len; + + unsigned char out_prefix[5]={ 0x01, 0x00, 0x60, 0x00, 0x60 }; + size_t outPrefixLen=5; + + memset(cmd,0,cmdLen); + set_SCSI_opcode(cmd,SET_SCAN_MODE2_code); + set_SSM2_page_code(cmd,SM2_pc_imprinter_settings); + if (is_postimprint) + set_SSM2_postimprint_cmd(cmd); + set_SSM2_pay_len(cmd,outLen); + + memset(out,0,outLen); + memcpy(out,out_prefix,outPrefixLen); + + int h_offset; + int v_offset; + if (is_postimprint){ + if (s->post_imprint_addon_mode != ADDON_DISABLED) + set_SSM2_postimprint_addon(out); + h_offset = s->post_imprint.h_offset; + v_offset = s->post_imprint.v_offset; + + if (enabled) + DBG (10, "send_imprint_positioning: post-imprinter: h_offset: %d v_offset: %d\n",h_offset,v_offset); + }else{ + h_offset = s->pre_imprint.h_offset; + v_offset = s->pre_imprint.v_offset; + if (enabled) + DBG (10, "send_imprint_positioning: pre-imprinter: h_offset: %d v_offset: %d\n",h_offset,v_offset); + } + if(!enabled) + h_offset = v_offset = 0; + set_SSM2_imprint_hoffset(out,h_offset); + set_SSM2_imprint_voffset(out,v_offset); + + return send_cmd(s, cmd, cmdLen, out, outLen, NULL, NULL); +} + +SANE_Status +send_imprint_specstring(struct scanner* s, int is_postimprint) +{ + unsigned char cmd[SET_SCAN_MODE2_len]; + size_t cmdLen = SET_SCAN_MODE2_len; + + unsigned char out[SSM2_IMPRINTER_STRING_PAY_len]; + size_t outLen = SSM2_IMPRINTER_STRING_PAY_len; + + memset(cmd,0,cmdLen); + set_SCSI_opcode(cmd, SET_SCAN_MODE2_code); + set_SSM2_page_code(cmd, SM2_pc_imprinter_specstring); + if (is_postimprint) + set_SSM2_postimprint_cmd(cmd); + set_SSM2_pay_len(cmd, outLen); + + memset(out,0,outLen); + /* most of these bytes have yet to be identified to specific functionalities, + as they never seem to change under different imprinting mode */ + unsigned char out_prefix[32] = { + 0x01, 0x00, + 0x60, 0x00, + 0x60, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x03, 0x00, + 0x00, 0x00, + 0x01, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x01, + 0x04, 0x00, + 0x00, 0x00 + }; + memcpy(out, out_prefix, 32); + if (is_postimprint){ + set_SSM2_imprint_fontsize(out, s->post_imprint.font_size); + set_SSM2_imprint_fontrot(out, s->post_imprint.font_rot); + set_SSM2_imprint_spacing(out, s->post_imprint.spacing); + if (s->post_imprint_addon_mode != ADDON_DISABLED) + set_SSM2_imprint_addonmode(out, s->post_imprint_addon_mode); + strcpy((SANE_Char*)(out + 45), (SANE_String_Const) s->post_imprint.specstring); + DBG (10, "send_imprint_specstring: post-imprinter: font size: %d rotation: %d spacing: %d text: '%s' imprint-addon-mode: %d\n",s->post_imprint.font_size,s->post_imprint.font_rot,s->post_imprint.spacing,s->post_imprint.specstring,s->post_imprint_addon_mode); + }else{ + set_SSM2_imprint_fontsize(out, s->pre_imprint.font_size); + set_SSM2_imprint_fontrot(out, s->pre_imprint.font_rot); + set_SSM2_imprint_spacing(out, s->pre_imprint.spacing); + strcpy((SANE_Char*)(out + 45), (SANE_String_Const) s->pre_imprint.specstring); + DBG (10, "send_imprint_specstring: pre-imprinter: font size: %d rotation: %d spacing: %d text: '%s'\n",s->pre_imprint.font_size,s->pre_imprint.font_rot,s->pre_imprint.spacing,s->pre_imprint.specstring); + } + + return send_cmd(s, cmd, cmdLen, out, outLen, NULL, NULL); +} + +SANE_Status +send_imprint_date_and_time(struct scanner* s) +{ + unsigned char cmd[SET_SCAN_MODE2_len]; + size_t cmdLen = SET_SCAN_MODE2_len; + + unsigned char out[SSM2_PAY_len]; + size_t outLen = SSM2_PAY_len; + + memset(cmd,0,cmdLen); + set_SCSI_opcode(cmd, SET_SCAN_MODE2_code); + set_SSM2_page_code(cmd, SM2_pc_date_time); + set_SSM2_pay_len(cmd, outLen); + + memset(out,0,outLen); + + time_t t = time(NULL); + struct tm tM = *localtime(&t); + + set_SSM2_imprint_year(out, tM.tm_year + 1900); + set_SSM2_imprint_month(out, tM.tm_mon + 1); + set_SSM2_imprint_day(out, tM.tm_mday); + set_SSM2_imprint_hour(out, tM.tm_hour); + set_SSM2_imprint_min(out, tM.tm_min); + set_SSM2_imprint_sec(out, tM.tm_sec); + + return send_cmd(s, cmd, cmdLen, out, outLen, NULL, NULL); +} + +SANE_Status +load_imprinting_settings(struct scanner *s) +{ + SANE_Status ret = SANE_STATUS_GOOD; + + int requires_preimprint = (strlen(s->pre_imprint.specstring) > 0); + int requires_postimprint = (strlen(s->post_imprint.specstring) > 0); + int send_date_time = (s->has_pre_imprinter && requires_preimprint) || (s->has_post_imprinter && requires_postimprint); + + if (s->has_pre_imprinter){ + ret = send_imprint_positioning(s, 0, requires_preimprint); + DBG(10, "load_imprinting_settings: send_pre_imprint_positioning = %d \n", ret); + if (ret != SANE_STATUS_GOOD) + return ret; + if (requires_preimprint){ + ret = send_imprint_specstring(s, 0); + DBG(10, "load_imprinting_settings: send_pre_imprint_specstring = %d \n", ret); + if (ret != SANE_STATUS_GOOD) + return ret; + } + } + + if (s->has_post_imprinter){ + ret = send_imprint_positioning(s, 1, requires_postimprint); + DBG(10, "load_imprinting_settings: send_post_imprint_positioning = %d \n", ret); + if (ret != SANE_STATUS_GOOD) + return ret; + if (requires_postimprint){ + ret = send_imprint_specstring(s, 1); + DBG(10, "load_imprinting_settings: send_post_imprint_specstring = %d \n", ret); + if (ret != SANE_STATUS_GOOD) + return ret; + } + } + + if (send_date_time){ + ret = send_imprint_date_and_time(s); + DBG(10, "load_imprinting_settings: send_imprint_date_and_time = %d \n", ret); + } + return ret; +} + +static SANE_Status +detect_imprinter(struct scanner *s,SANE_Int option) +{ + SANE_Status ret = SANE_STATUS_GOOD; + + unsigned char cmd[READ_len]; + size_t cmdLen = READ_len; + + unsigned char in[R_IMPRINTER_len]; + size_t inLen = R_IMPRINTER_len; + + DBG (10, "detect_imprinter: start %d\n", option); + + memset(cmd,0,cmdLen); + set_SCSI_opcode(cmd, READ_code); + set_R_datatype_code(cmd, SR_datatype_imprinters); + set_R_xfer_uid(cmd, option); + set_R_xfer_length(cmd, inLen); + + ret = do_cmd( + s, 1, 0, + cmd, cmdLen, + NULL, 0, + in, &inLen + ); + + if (ret == SANE_STATUS_GOOD || ret == SANE_STATUS_EOF) { + ret = SANE_STATUS_GOOD; + } + + int imprinter_found = get_R_IMPRINTER_found(in); + const char* imprinter_type = "unknown"; + if (option == R_PRE_IMPRINTER){ + s->has_pre_imprinter = imprinter_found; + imprinter_type = "pre-imprinter"; + } + else if (option == R_POST_IMPRINTER){ + s->has_post_imprinter = imprinter_found; + imprinter_type = "post-imprinter"; + } + + DBG (10, "detect_imprinter: type: %s. found status bit: %d \n",imprinter_type,imprinter_found); + + return ret; +} + /* reset image size parameters after buffer_xxx functions changed them */ SANE_Status update_i_params(struct scanner *s) @@ -4471,6 +5384,14 @@ sane_start (SANE_Handle handle) goto errors; } + if (s->has_pre_imprinter || s->has_post_imprinter){ + ret = load_imprinting_settings(s); + if (ret != SANE_STATUS_GOOD) { + DBG (5, "sane_start: ERROR: invalid imprinting settings\n"); + goto errors; + } + } + /* reset the page counter after calibration */ s->panel_counter = 0; s->prev_page = 0; @@ -7204,7 +8125,7 @@ sense_handler (int fd, unsigned char * sensed_data, void *arg) DBG (5, "sense_handler: start\n"); /* kill compiler warning */ - fd = fd; + (void) fd; /* copy the rs return data into the scanner struct so that the caller can use it if he wants @@ -7465,8 +8386,8 @@ do_scsi_cmd(struct scanner *s, int runRS, int timeout, int ret; /*shut up compiler*/ - runRS=runRS; - timeout=timeout; + (void) runRS; + (void) timeout; DBG(10, "do_scsi_cmd: start\n"); -- cgit v1.2.3