Hi As promised
Pierre Willenbrock schrieb: > Next i will implement the slope table generation in the way St?phane > suggested. > i am sending the result of this work. I introduced a new flag GENESYS_FLAG_ALT_SLOPE_CREATE to indicate that the alternate slope creation functions should be used. Apart from that the patch contains my version of sanei_genesys_exposure_time(called sanei_genesys_exposure_time2 to not collide with uses of the other function) and a few bug fixes: * size argument of sanei_genesys_create_gamma_table changed from float to int * sanei_genesys_read_reg_from_set and sanei_genesys_set_reg_from_set check for address of current register. If this is 0 they should stop. * fixed raw data dumping: should write first set of data and close file * moved call to sanei_genesys_init_structs to before init_options as init_options depends on an initialized device struct. Next i'd like to rewrite genesys_read_ordered_data to be more maintainable and able to convert the cis style planar data to "chunky" data. For that i need to know what the "stagger" effect exactly is. I am not sure i got that one right. The conversion stack i have in mind looks like this: 1. (opt)uncis (assumes color components to be laid out planar) 2. (opt)unstagger (assumes pixels to be depth*channels/8 bytes, unshrinked) 3. (opt)shrink_lines (assumes pixels to be depth*channels/8 bytes) 4. (opt)reverse_RGB (assumes pixels to be BGR or BBGGRR)) here we should save the finished lines for use with line distance correction 5. (opt)line_distance_correction (assumes RGB or RRGGBB) My implementation currently used for Canon LiDE 35 does quite a lot byte moving which considerably slows down the conversion, and is probably not correct regarding the stagger effect. Regards, Pierre -------------- next part -------------- diff -ur experimental/genesys/genesys.c transit/backend/genesys.c --- experimental/genesys/genesys.c 2005-08-28 16:49:58.415784750 +0200 +++ transit/backend/genesys.c 2005-08-29 17:32:04.443483750 +0200 @@ -149,6 +149,7 @@ /* ------------------------------------------------------------------------ */ /* Write data to a pnm file (e.g. calibration). For debugging only */ +/* data is RGB or grey, with little endian byte order */ SANE_Status sanei_genesys_write_pnm_file (char *filename, u_int8_t * data, int depth, int channels, int pixels_per_line, int lines) @@ -214,7 +215,7 @@ { SANE_Int i; - for (i = 0; i < GENESYS_MAX_REGS; i++) + for (i = 0; i < GENESYS_MAX_REGS && reg[i].address; i++) { if (reg[i].address == address) { @@ -231,7 +232,7 @@ { SANE_Int i; - for (i = 0; i < GENESYS_MAX_REGS; i++) + for (i = 0; i < GENESYS_MAX_REGS && reg[i].address; i++) { if (reg[i].address == address) reg[i].value = value; @@ -298,6 +299,8 @@ return status; } + *val = 0; + status = sanei_usb_control_msg (dev->dn, REQUEST_TYPE_IN, REQUEST_REGISTER, VALUE_READ_REGISTER, INDEX, 1, val); @@ -421,6 +424,7 @@ } /* returns pixels per line from register set */ +/*candidate for moving into chip specific files?*/ static int genesys_pixels_per_line (Genesys_Register_Set * reg) { @@ -440,7 +444,7 @@ /** read the number of valid words in scanner's RAM * ie registers 42-43-44 */ - +/*candidate for moving into chip specific files?*/ static SANE_Status genesys_read_valid_words (Genesys_Device * dev, int *words) { @@ -487,6 +491,253 @@ return sanei_genesys_write_register (dev, 0x0f, 0x00); } +/* main function for slope creation */ +/** + * This function generates a slope table using the given slope + * truncated at the given exposure time or step count, whichever comes first. + * The reached step time is then stored in final_exposure and used for the rest + * of the table. The summed time of the acerleation steps is returned, and the + * number of accerelation steps is put into used_steps. + * + * @param dev Device struct + * @param slope_table Table to write to + * @param max_step Size of slope_table in steps + * @param use_steps Maximum number of steps to use for acceleration + * @param stop_at Minimum step time to use + * @param vstart Start step time of default slope + * @param vend End step time of default slope + * @param steps Step count of default slope + * @param g Power for default slope + * @param used_steps Final number of steps is stored here + * @param vfinal Final step time is stored here + * @return Time for acceleration + * @note all times in pixel time + */ +static SANE_Int +genesys_generate_slope_table ( + u_int8_t * slope_table, unsigned int max_steps, + unsigned int use_steps, u_int16_t stop_at, + u_int16_t vstart, u_int16_t vend, unsigned int steps, double g, + unsigned int *used_steps, unsigned int *vfinal) +{ + double t; + SANE_Int sum = 0; + unsigned int i; + unsigned int c = 0; + u_int16_t t2; + unsigned int dummy; + unsigned int _vfinal; + if (!used_steps) + used_steps = &dummy; + if (!vfinal) + vfinal = &_vfinal; + + DBG (DBG_proc, + "genesys_generate_slope_table: table size: %d\n", + max_steps); + + DBG (DBG_proc, + "genesys_generate_slope_table: stop at time: %d, use %d steps max\n", + stop_at, use_steps); + + DBG (DBG_proc, + "genesys_generate_slope_table: target slope: " + "vstart: %d, vend: %d, steps: %d, g: %g\n", + vstart, vend, steps, g); + + sum = 0; + c = 0; + *used_steps = 0; + + if (use_steps < 1) + use_steps = 1; + + if (stop_at < vstart) + { + t2 = vstart; + for (i = 0; i < steps && i < use_steps-1 && i < max_steps; i++,c++) + { + t = pow (((double) i) / ((double) (steps - 1)), g); + t2 = vstart * (1 - t) + t * vend; + if (t2 < stop_at) + break; + *slope_table++ = t2 & 0xff; + *slope_table++ = t2 >> 8; + DBG (DBG_io, "slope_table[%3d] = %5d\n", c, t2); + sum += t2; + } + if (t2 > stop_at) { + DBG (DBG_warn, "Can not reach target speed(%d) in %d steps.\n", + stop_at, use_steps); + DBG (DBG_warn, "Expect image to be distorted. " + "Ignore this if only feeding.\n"); + } + *vfinal = t2; + *used_steps += i; + max_steps -= i; + } + else + *vfinal = stop_at; + + for (i = 0; i < max_steps; i++,c++) + { + *slope_table++ = (*vfinal) & 0xff; + *slope_table++ = (*vfinal) >> 8; + DBG (DBG_io, "slope_table[%3d] = %5d\n", c, *vfinal); + } + + (*used_steps)++; + sum += *vfinal; + + DBG (DBG_proc, + "sanei_genesys_generate_slope_table: returns sum=%d, used %d steps, completed\n", sum, *used_steps); + + return sum; +} + +/* Generate slope table for motor movement */ +/** + * This function generates a slope table using the slope from the motor struct + * truncated at the given exposure time or step count, whichever comes first. + * The reached step time is then stored in final_exposure and used for the rest + * of the table. The summed time of the acerleation steps is returned, and the + * number of accerelation steps is put into used_steps. + * + * @param dev Device struct + * @param slope_table Table to write to + * @param max_step Size of slope_table in steps + * @param use_steps Maximum number of steps to use for acceleration + * @param step_type Generate table for this step_type. 0=>full, 1=>half, + * 2=>quarter + * @param exposure_time Minimum exposure time of a scan line + * @param yres Resoltuion of a scan line + * @param used_steps Final number of steps is stored here + * @param final_exposure Final step time is stored here + * @return Time for acceleration + * @note all times in pixel time + */ +SANE_Int +sanei_genesys_create_slope_table3 (Genesys_Device * dev, + u_int8_t * slope_table, int max_step, + unsigned int use_steps, + int step_type, int exposure_time, + double yres, + unsigned int *used_steps, + unsigned int *final_exposure + ) +{ + unsigned int sum_time = 0; + unsigned int vtarget; + unsigned int vend; + unsigned int vstart; + unsigned int vfinal; + + DBG (DBG_proc, + "sanei_genesys_create_slope_table: step_type = %d, " + "exposure_time = %d, yres = %g\n", step_type, + exposure_time, yres); + DBG (DBG_proc, "sanei_genesys_create_slope_table: yres = %.2f\n", yres); + + /* final speed */ + vtarget = (exposure_time * yres) / dev->motor.base_ydpi; + + vstart = dev->motor.slopes[step_type].maximum_start_speed; + vend = dev->motor.slopes[step_type].maximum_speed; + + vtarget >>= step_type; + if (vtarget > 65535) + vtarget = 65535; + + vstart >>= step_type; + if (vstart > 65535) + vstart = 65535; + + vend >>= step_type; + if (vend > 65535) + vend = 65535; + + sum_time = genesys_generate_slope_table( + slope_table, max_step, + + use_steps, + vtarget, + + vstart, + vend, + dev->motor.slopes[step_type].minimum_steps << step_type, + dev->motor.slopes[step_type].g, + used_steps, + &vfinal); + + if (final_exposure) + *final_exposure = (vfinal * dev->motor.base_ydpi) / yres; + + DBG (DBG_proc, + "sanei_genesys_create_slope_table: returns sum_time=%d, completed\n", + sum_time); + + return sum_time; +} + +/* Generate slope table for motor movement */ +/* This function translates a call of the old slope creation function to a + call to the new one + */ +static SANE_Int +genesys_create_slope_table4 (Genesys_Device * dev, + u_int16_t * slope_table, int steps, + int step_type, int exposure_time, + SANE_Bool same_speed, double yres) +{ + unsigned int sum_time = 0; + unsigned int vtarget; + unsigned int vend; + unsigned int vstart; + + DBG (DBG_proc, + "sanei_genesys_create_slope_table: %d steps, step_type = %d, " + "exposure_time = %d, same_speed =%d\n", steps, step_type, + exposure_time, same_speed); + DBG (DBG_proc, "sanei_genesys_create_slope_table: yres = %.2f\n", yres); + + /* final speed */ + vtarget = (exposure_time * yres) / dev->motor.base_ydpi; + + vstart = dev->motor.slopes[step_type].maximum_start_speed; + vend = dev->motor.slopes[step_type].maximum_speed; + + vtarget >>= step_type; + if (vtarget > 65535) + vtarget = 65535; + + vstart >>= step_type; + if (vstart > 65535) + vstart = 65535; + + vend >>= step_type; + if (vend > 65535) + vend = 65535; + + sum_time = genesys_generate_slope_table( + (u_int8_t*)slope_table, 128, + + steps, + vtarget, + + vstart, + vend, + dev->motor.slopes[step_type].minimum_steps << step_type, + dev->motor.slopes[step_type].g, + NULL, + NULL); + + DBG (DBG_proc, + "sanei_genesys_create_slope_table: returns sum_time=%d, completed\n", + sum_time); + + return sum_time; +} + /* alternate slope table creation function */ /* the hardcoded values (g and vstart) will go in a motor struct */ static SANE_Int @@ -640,6 +891,11 @@ dev = dev; + if (dev->model->flags & GENESYS_FLAG_ALT_SLOPE_CREATE) + return genesys_create_slope_table4 (dev, slope_table, steps, + step_type, exposure_time, + same_speed, yres); + if (dev->model->motor_type == MOTOR_5345 || dev->model->motor_type == MOTOR_HP2300) return genesys_create_slope_table2 (dev, slope_table, steps, @@ -798,12 +1054,16 @@ /* computes gamma table */ void -sanei_genesys_create_gamma_table (u_int16_t * gamma_table, float size, +sanei_genesys_create_gamma_table (u_int16_t * gamma_table, int size, float maximum, float gamma_max, float gamma) { int i; float value; + DBG (DBG_proc, + "sanei_genesys_create_gamma_table: size = %d, " + "maximum = %g, gamma_max = %g, gamma = %g\n", + size, maximum, gamma_max, gamma); for (i = 0; i < size; i++) { value = gamma_max * pow ((float) i / size, 1.0 / gamma); @@ -811,9 +1071,28 @@ value = maximum; gamma_table[i] = value; } + DBG (DBG_proc, + "sanei_genesys_create_gamma_table: completed\n"); } +/* computes the exposure_time on the basis of the given vertical dpi, + the number of pixels the ccd needs to send, + the step_type and the corresponding maximum speed from the motor struct */ +/* maybe we can determine step_type here, too*/ +SANE_Int +sanei_genesys_exposure_time2 (Genesys_Device * dev, float ydpi, + int step_type, int endpixel) +{ + int exposure_by_ccd = endpixel+32; + int exposure_by_motor = (dev->motor.slopes[step_type].maximum_speed + *dev->motor.base_ydpi)/ydpi; + if (exposure_by_ccd > exposure_by_motor) + return exposure_by_ccd; + else + return exposure_by_motor; +} + /* computes the exposure_time on the basis of the given horizontal dpi */ /* we will clean/simplify it by using constants from a future motor struct */ SANE_Int @@ -1518,7 +1797,7 @@ DBG (DBG_info,"channels %d y_size %d xres %d\n", channels, dev->model->y_size, dev->settings.xres); size = channels * 2 * SANE_UNFIX(dev->model->y_size) * dev->settings.xres / 25.4; - // 1 1 mm 1/inch inch/mm + /* 1 1 mm 1/inch inch/mm*/ calibration_data = malloc (size); if (!calibration_data) @@ -3181,6 +3460,10 @@ DBG (DBG_proc, "genesys_read_ordered_data: nothing more to scan: EOF\n"); *len = 0; +#ifdef SANE_DEBUG_LOG_RAW_DATA + fclose(f); + f = NULL; +#endif return SANE_STATUS_EOF; } @@ -3273,10 +3556,12 @@ (1 << depth) - 1); } } - else - { - fwrite (work_buffer, size, 1, f); - } + + if (f != NULL) { +/*TODO: convert big/little endian if depth == 16. + note: imagemagick got this wrong for P5/P6.*/ + fwrite ((dev->read_buffer + end), size, 1, f); + } #endif dev->read_bytes_left -= size; @@ -4194,6 +4479,9 @@ first_handle = s; *handle = s; + if (!dev->already_initialized) + sanei_genesys_init_structs (dev); + RIE (init_options (s)); if (genesys_init_cmd_set (s->dev) != SANE_STATUS_GOOD) diff -ur experimental/genesys/genesys_devices.c transit/backend/genesys_devices.c --- experimental/genesys/genesys_devices.c 2005-08-28 16:49:58.647799250 +0200 +++ transit/backend/genesys_devices.c 2005-08-29 17:33:59.422669500 +0200 @@ -241,24 +241,112 @@ /* UMAX */ { 1200, /* motor base steps */ - 2400 /* maximum motor resolution */ - } - , + 2400, /* maximum motor resolution */ + 1, /* maximum step mode*/ + {{ + 11000, /* maximum start speed */ + 3000, /* maximum end speed */ + 128, /* step count */ + 1.0, /* nonlinearity */ + }, + { + 11000, + 3000, + 128, + 1.0, + }, + }, + }, { /* MD5345/6228/6471 */ 1200, - 2400} - , + 2400, + 1, + {{ + 2000, + 1375, + 128, + 0.5, + }, + { + 2000, + 1375, + 128, + 0.5, + }, + }, + }, { /* ST24 */ 2400, - 2400} - , + 2400, + 1, + {{ + 2289, + 2100, + 128, + 0.3, + }, + { + 2289, + 2100, + 128, + 0.3, + }, + }, + }, { /* HP 2400c */ 1200, - 2400} - , + 2400, + 1, + {{ + 11000, + 3000, + 128, + 1.0, + }, + { + 11000, + 3000, + 128, + 1.0, + }, + }, + }, { /* HP 2300c */ 600, - 1200} + 1200, + 1, + {{ + 3200, + 1200, + 128, + 0.5, + }, + { + 3200, + 1200, + 128, + 0.5, + }, + }, + }, + { /* Canon LiDE 35 */ + 1200, + 2400, + 1, + {{ + 3000, + 1300, + 50, + 0.8, + }, + { + 3000, + 1400, + 50, + 0.8, + }, + }, + }, }; /* here we have the various device settings... diff -ur experimental/genesys/genesys_gl646.c transit/backend/genesys_gl646.c --- experimental/genesys/genesys_gl646.c 2005-08-28 16:49:59.683864000 +0200 +++ transit/backend/genesys_gl646.c 2005-08-29 17:35:03.046645750 +0200 @@ -4083,7 +4083,6 @@ } } - sanei_genesys_init_structs (dev); dev->dark_average_data = NULL; dev->white_average_data = NULL; diff -ur experimental/genesys/genesys_gl841.c transit/backend/genesys_gl841.c --- experimental/genesys/genesys_gl841.c 2005-08-28 16:50:00.835936000 +0200 +++ transit/backend/genesys_gl841.c 2005-08-29 17:35:27.844195500 +0200 @@ -4621,8 +4621,6 @@ } } - sanei_genesys_init_structs (dev); - dev->dark_average_data = NULL; dev->white_average_data = NULL; diff -ur experimental/genesys/genesys_low.h transit/backend/genesys_low.h --- experimental/genesys/genesys_low.h 2005-08-28 16:50:03.988133000 +0200 +++ transit/backend/genesys_low.h 2005-08-29 18:14:04.220960000 +0200 @@ -84,8 +84,14 @@ #define GENESYS_FLAG_DARK_CALIBRATION (1 << 8) /* do dark calibration */ #define GENESYS_FLAG_STAGGERED_LINE (1 << 9) /* pixel columns are shifted vertically for hi-res modes */ -#define GENESYS_FLAG_MUST_WAIT (1 << 10) /* tells wether the scanner should wait 1 minute after init - before doing anything */ +#define GENESYS_FLAG_MUST_WAIT (1 << 10) /* tells wether the scanner + should wait 1 minute after + init before doing anything + */ + + +#define GENESYS_FLAG_ALT_SLOPE_CREATE (1 << 11) /* use alternative slope + creation function */ /* USB control message values */ #define REQUEST_TYPE_IN (USB_TYPE_VENDOR | USB_DIR_IN) @@ -153,7 +159,7 @@ { int optical_res; int black_pixels; - int dummy_pixel; + int dummy_pixel; /* value of dummy register. */ int CCD_start_xoffset; /* last pixel of CCD margin at optical resolution */ int sensor_pixels; /* total pixels used by the sensor */ int fau_gain_white_ref; /* TA CCD target code (reference gain) */ @@ -177,8 +183,22 @@ typedef struct { - SANE_Int base_ydpi; /* motor base steps */ - SANE_Int optical_ydpi; /* maximum resolution in y-direction */ + SANE_Int maximum_start_speed; /* maximum speed allowed when accelerating from standstill. Unit: pixeltime/step */ + SANE_Int maximum_speed; /* maximum speed allowed. Unit: pixeltime/step */ + SANE_Int minimum_steps; /* number of steps used for default curve */ + float g; /* power for non-linear acceleration curves. */ +/* vs*(1-i^g)+ve*(i^g) where + vs = start speed, ve = end speed, + i = 0.0 for first entry and i = 1.0 for last entry in default table*/ +} Genesys_Motor_Slope; + + +typedef struct +{ + SANE_Int base_ydpi; /* motor base steps. Unit: 1/" */ + SANE_Int optical_ydpi; /* maximum resolution in y-direction. Unit: 1/" */ + SANE_Int max_step_type; /* maximum step type. 0-2 */ + Genesys_Motor_Slope slopes[3]; /* slopes to derive individual slopes from */ } Genesys_Motor; typedef enum Genesys_Color_Order @@ -224,6 +244,7 @@ #define MOTOR_ST24 2 #define MOTOR_HP2400 3 #define MOTOR_HP2300 4 +#define MOTOR_CANONLIDE35 5 /* Forward typedefs */ @@ -487,6 +508,10 @@ u_int16_t data); extern SANE_Int +sanei_genesys_exposure_time2 (Genesys_Device * dev, + float ydpi, int step_type, int endpixel); + +extern SANE_Int sanei_genesys_exposure_time (Genesys_Device * dev, Genesys_Register_Set * reg, int xdpi); @@ -496,8 +521,17 @@ int step_type, int exposure_time, SANE_Bool same_speed, double yres); +SANE_Int +sanei_genesys_create_slope_table3 (Genesys_Device * dev, + u_int8_t * slope_table, int max_step, + unsigned int use_steps, + int step_type, int exposure_time, + double yres, + unsigned int *used_steps, + unsigned int *final_exposure); + extern void -sanei_genesys_create_gamma_table (u_int16_t * gamma_table, float size, +sanei_genesys_create_gamma_table (u_int16_t * gamma_table, int size, float maximum, float gamma_max, float gamma); From stef...@modulonet.fr Mon Aug 29 20:22:07 2005 From: stef...@modulonet.fr (=?iso-8859-15?q?St=E9phane_VOLTZ?=) Date: Mon Aug 29 20:23:23 2005 Subject: [sane-devel] genesys backend In-Reply-To: <43134d88.3050...@pirsoft.dnsalias.org> References: <42ffc607.9030...@pirsoft.dnsalias.org> <430f9b1a.9050...@pirsoft.dnsalias.org> <43134d88.3050...@pirsoft.dnsalias.org> Message-ID: <200508292222.07858.stef...@modulonet.fr> Le Lundi 29 Ao?t 2005 20:01, Pierre Willenbrock a ?crit?: > Hi > > As promised > > Pierre Willenbrock schrieb: > > Next i will implement the slope table generation in the way St?phane > > suggested. > > i am sending the result of this work. I introduced a new flag > GENESYS_FLAG_ALT_SLOPE_CREATE to indicate that the alternate slope > creation functions should be used. > > Apart from that the patch contains my version of > sanei_genesys_exposure_time(called sanei_genesys_exposure_time2 to not > collide with uses of the other function) and a few bug fixes: > * size argument of sanei_genesys_create_gamma_table changed from float > to int > * sanei_genesys_read_reg_from_set and sanei_genesys_set_reg_from_set > check for address of current register. If this is 0 they should stop. > * fixed raw data dumping: should write first set of data and close file > * moved call to sanei_genesys_init_structs to before init_options as > init_options depends on an initialized device struct. > > Next i'd like to rewrite genesys_read_ordered_data to be more > maintainable and able to convert the cis style planar data to "chunky" > data. > It is indeed a rather complicated function. Data doesn't come in an easy form. But I don't exactly see why you want to convert to planar data first. > For that i need to know what the "stagger" effect exactly is. I am not > sure i got that one right. > At high motor resolution, lines are staggered, ie they aren't horizontal lines. On pixel is on a line, the folowing colunm is on another ... A drawing may be more evident: 'O' are pixel of on horizontal line, '.' other lines data ...O.....O.....O.....O.....O.....O.....O ..O.O...O.O...O.O...O.O...O.O...O.O...O. .O...O.O...O.O...O.O...O.O...O.O...O.O.. O.....O.....O.....O.....O.....O.....O... > The conversion stack i have in mind looks like this: > > 1. (opt)uncis (assumes color components to be laid out planar) > 2. (opt)unstagger (assumes pixels to be depth*channels/8 bytes, > unshrinked) > 3. (opt)shrink_lines (assumes pixels to be depth*channels/8 bytes) > 4. (opt)reverse_RGB (assumes pixels to be BGR or BBGGRR)) > here we should save the finished lines for use with line distance > correction 5. (opt)line_distance_correction (assumes RGB or RRGGBB) > > My implementation currently used for Canon LiDE 35 does quite a lot byte > moving which considerably slows down the conversion, and is probably not > correct regarding the stagger effect. > > Regards, > Pierre I'll test and check in your patch Wednesday morning. Regards, Stef