diff --git a/backend/canon_dr-cmd.h b/backend/canon_dr-cmd.h index 523368991..0ef883f8b 100644 --- a/backend/canon_dr-cmd.h +++ b/backend/canon_dr-cmd.h @@ -222,6 +222,7 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) #define SR_datatype_endorser 0x90 #define SR_datatype_fineoffset 0x90 #define SR_datatype_finegain 0x91 +#define SR_datatype_imprinters 0x96 /*DR-X10C*/ /* ==================================================================== */ /* READ */ @@ -258,6 +259,18 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) #define get_R_COUNTERS_total(in) getnbyte(in + 0x04, 4) #define get_R_COUNTERS_last_srv(in) getnbyte(in + 0x44, 4) +/*imprinters*/ +#define R_IMPRINTER_len 0x20 +#define R_PRE_IMPRINTER 0 +#define R_POST_IMPRINTER 1 +#define get_R_IMPRINTER_found(in) getbitfield(in+1, 1, 0) +/*4 bytes at in + 0: (DR-X10C) +pre-imprinter on: 0x07010000 +pre-imprinter off: 0x06000000 +post-imprinter on: 0x03010000 +post-imprinter off: 0x02000000 +*/ + /*endorser unread?*/ /*fine gain*/ @@ -458,6 +471,14 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) #define SM2_pc_buffer 0x02 #define SM2_pc_hw_enhancement 0x03 #define SM2_pc_dropout 0x06 +#define SM2_pc_date_time 0x07 +#define SM2_pc_imprinter_settings 0x33 +#define SM2_pc_imprinter_specstring 0x34 + +/* ==================================================================== */ +/* GET SCAN MODE 2 */ +#define GET_SCAN_MODE2_code 0xe4 +#define GET_SCAN_MODE2_len 12 /* ==================================================================== */ /* SET SCAN MODE 2 */ @@ -469,11 +490,15 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) /* the payload */ #define SSM2_PAY_len 0x10 +#define SSM2_IMPRINTER_STRING_PAY_len 0x8e /* for DF (0x00) page */ -#define set_SSM2_DF_thick(sb, val) setbitfield(sb+3, 1, 2, val) +#define set_SSM2_DF_imprint(sb, val) setbitfield(sb+2, 1, 0, val) +#define set_SSM2_DF_post_addon(sb, val) setbitfield(sb+2, 1, 1, val) #define set_SSM2_DF_len(sb, val) setbitfield(sb+3, 1, 0, val) +#define set_SSM2_DF_thick(sb, val) setbitfield(sb+3, 1, 2, val) #define set_SSM2_DF_staple(sb, val) setbitfield(sb+3, 1, 4, val) +#define set_SSM2_DF_imprint2(sb, val) setbitfield(sb+3, 1, 6, val) /* for ULTRA (0x01) page */ #define set_SSM2_ULTRA_top(sb, val) putnbyte(sb + 0x07, val, 2) @@ -493,6 +518,32 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) #define set_SSM2_DO_en(sb, val) sb[0x0a] = val #define set_SSM2_DO_side(sb, val) sb[0x05] = val +/* for IMPRINT DATE & TIME (0x07) */ +#define set_SSM2_imprint_year(sb, val) putnbyte(sb + 0x02, val, 2) +#define set_SSM2_imprint_month(sb, val) putnbyte(sb + 0x04, val, 1) +#define set_SSM2_imprint_day(sb, val) putnbyte(sb + 0x05, val, 1) +#define set_SSM2_imprint_hour(sb, val) putnbyte(sb + 0x06, val, 1) +#define set_SSM2_imprint_min(sb, val) putnbyte(sb + 0x07, val, 1) +#define set_SSM2_imprint_sec(sb, val) putnbyte(sb + 0x08, val, 1) + +/* for IMPRINTER SETTINGS (0x33) page */ +#define set_SSM2_postimprint_cmd(sb) sb[0x04] = 1 +#define set_SSM2_postimprint_addon(sb) setbitfield(sb, 1, 1, 1) +#define set_SSM2_imprint_hoffset(sb, val) putnbyte(sb + 0x05, val, 2) +#define set_SSM2_imprint_voffset(sb, val) putnbyte(sb + 0x07, val, 2) + +/* for IMPRINTER STRING SPECIFICATION (0x34) page */ +#define IMPRINTER_12x12_FONT 0 +#define IMPRINTER_8x12_FONT 1 +#define set_SSM2_imprint_fontsize(sb, val) setbitfield(sb + 0xA, 1, 0, val) +#define set_SSM2_imprint_spacing(sb, val) setbitfield(sb + 0xA, 1, 1, val) +#define set_SSM2_imprint_addonmode(sb, val) setbitfield(sb + 0x9, 3, 4, val) +#define IMPRINTER_0_FONT_ROT 0 +#define IMPRINTER_90_FONT_ROT 1 +#define IMPRINTER_180_FONT_ROT 2 +#define IMPRINTER_270_FONT_ROT 3 +#define set_SSM2_imprint_fontrot(sb, val) setbitfield(sb + 0x9, 3, 0, val) + /* ==================================================================== */ /* window descriptor macros for SET_WINDOW and GET_WINDOW */ diff --git a/backend/canon_dr.c b/backend/canon_dr.c index 908f833c3..58299d77e 100644 --- a/backend/canon_dr.c +++ b/backend/canon_dr.c @@ -357,6 +357,8 @@ - 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 @@ -395,6 +397,7 @@ #include /*tan*/ #include /*usleep*/ #include /*gettimeofday*/ +#include /*localtime*/ #include /*strtol*/ #include "../include/sane/sanei_backend.h" @@ -408,7 +411,7 @@ #include "canon_dr.h" #define DEBUG 1 -#define BUILD 63 +#define BUILD 64 /* values for SANE_DEBUG_CANON_DR env var: - errors 5 @@ -451,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; @@ -994,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) { @@ -1879,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; @@ -1901,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"); @@ -1908,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 */ @@ -2014,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; @@ -2798,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; @@ -3197,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); @@ -3530,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 */ @@ -3735,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, @@ -4525,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) @@ -4614,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; diff --git a/backend/canon_dr.h b/backend/canon_dr.h index fa38cd444..e84b5b7a1 100644 --- a/backend/canon_dr.h +++ b/backend/canon_dr.h @@ -51,6 +51,22 @@ enum scanner_Option OPT_SIDE, OPT_HW_CROP, + /*imprinter option group*/ + OPT_IMPRINT_GROUP, + OPT_PRE_IMPRINT_SPECSTRING, + OPT_PRE_IMPRINT_H_OFFSET, + OPT_PRE_IMPRINT_V_OFFSET, + OPT_PRE_IMPRINT_FONT_SIZE, + OPT_PRE_IMPRINT_FONT_ROT, + OPT_PRE_IMPRINT_SPACING, + OPT_POST_IMPRINT_SPECSTRING, + OPT_POST_IMPRINT_H_OFFSET, + OPT_POST_IMPRINT_V_OFFSET, + OPT_POST_IMPRINT_FONT_SIZE, + OPT_POST_IMPRINT_FONT_ROT, + OPT_POST_IMPRINT_SPACING, + OPT_POST_IMPRINT_ADDON_MODE, + /*sensor group*/ OPT_SENSOR_GROUP, OPT_START, @@ -108,6 +124,32 @@ struct img_params }; +struct imprint_params +{ + /* ------------------------------------------------------------------------------ */ + /* allowed values for post imprinter (in mm units): */ + /* 21, 35, 47, 59, 72, 99, 114, 143, 155, 167, 196, 211, 239, 251, 263, 275, 289 */ + /* allowed values for pre imprinter (in mm units): */ + /* 14, 28, 41, 53, 65, 106 */ + int h_offset; + /* --------------------------------------- */ + /* allowed values: 0 to 500 (in mm units) */ + int v_offset; + + int font_size; + int font_rot; + int spacing; + +#define IMPRINT_SPECSTRING_LEN 64 + /* ---------------------------------- */ + /* special tokens: */ + /* \TIME time in HH:MM:SS */ + /* \DMY date in DD/MM/YYYY */ + /* \YMD date in YYYY/MM/DD */ + /* [[0-9]+] scan page count */ + char specstring[IMPRINT_SPECSTRING_LEN]; +}; + struct scanner { /* --------------------------------------------------------------------- */ @@ -206,6 +248,8 @@ struct scanner int has_ssm2; /* newer scanners user this similar command */ int has_ssm_pay_head_len; /* newer scanners put the length twice in ssm */ int has_hwcrop; + int has_pre_imprinter; + int has_post_imprinter; int can_read_sensors; int can_read_panel; int can_write_panel; @@ -320,13 +364,34 @@ struct scanner unsigned char lut[256]; /* --------------------------------------------------------------------- */ - /* values used by the software enhancement code (deskew, crop, etc) */ + /* values used by the software enhancement code (deskew, crop, etc) */ SANE_Status deskew_stat; int deskew_vals[2]; double deskew_slope; int crop_vals[4]; + /* imprinter params */ + struct imprint_params pre_imprint; + struct imprint_params post_imprint; + enum { + /*Black-on-White*/ + ADDON_BoW = 0, + /*White-on-Black*/ + ADDON_WoB, + /*Black-on-Image*/ + ADDON_BoI, + ADDON_DISABLED + } post_imprint_addon_mode; + + /* imprinter param constraints */ + SANE_Int pre_imprinter_h_offset_list[7]; + SANE_Int post_imprinter_h_offset_list[18]; + SANE_Range imprinter_v_offset_range; + SANE_String_Const imprint_font_size_list[3]; + SANE_Int imprinter_font_angle_list[5]; + SANE_String_Const imprint_addon_mode_list[5]; + /* this is defined in sane spec as a struct containing: SANE_Frame format; SANE_Bool last_frame; @@ -546,6 +611,7 @@ static SANE_Status sense_handler (int scsi_fd, u_char * result, void *arg); static SANE_Status init_inquire (struct scanner *s); static SANE_Status init_vpd (struct scanner *s); static SANE_Status init_model (struct scanner *s); +static SANE_Status init_imprinters (struct scanner *s); static SANE_Status init_panel (struct scanner *s); static SANE_Status init_counters (struct scanner *s); static SANE_Status init_user (struct scanner *s); @@ -639,6 +705,12 @@ static SANE_Status calibrate_fine_dest_hw(struct scanner *s); static SANE_Status write_AFE (struct scanner *s); static SANE_Status calibration_scan (struct scanner *s, int); +static SANE_Status send_imprint_positioning(struct scanner* s, int is_postimprint, int enabled); +static SANE_Status send_imprint_specstring(struct scanner* s, int is_postimprint); +static SANE_Status send_imprint_date_and_time(struct scanner* s); +static SANE_Status load_imprinting_settings(struct scanner *s); +static SANE_Status detect_imprinter(struct scanner *s, SANE_Int option); + static void hexdump (int level, char *comment, unsigned char *p, int l); static void default_globals (void);