[sane-devel] genesys backend
Pierre Willenbrock
pierre at pirsoft.dnsalias.org
Mon Aug 29 18:01:44 UTC 2005
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);
More information about the sane-devel
mailing list