[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