/* * Calculate and set the AFE offset. * * low: known-good AFE offset-register value. See note. * high: known-good AFE offset-register value. See note. * * Note: * 'low' and 'high' depend on the scanner model. * Choose them so that * 1. both produce black pixel samples > 0, and never zero. * 2. 'low' produces a a darker black level than 'high', * 3. 'low' and 'high' values are as far apart as possible, * for better precision. * Example: For CanoScan 4400F, select low = 75, high = 0. * Notice that the 'low' register value is not necessarily * less than the 'high' register value. It is what comes * out of the scanner that counts. */ static int calc_afe_blacklevel(struct gl843_device *dev, struct calibration_info *cal, uint8_t low, uint8_t high) { int ret, i; struct gl843_image *img; struct img_stat lo_stat, hi_stat; DBG(DBG_msg, "Calibrating A/D-converter black level.\n"); CHK_MEM(img = create_image(cal->width, cal->height, PXFMT_RGB16)); /* Scan with the lamp off to produce black pixels. */ CHK(set_lamp(dev, LAMP_OFF, 0)); /* Sample 'low' black level */ for (i = 0; i < 3; i++) { CHK(write_afe_gain(dev, i, 1.0)); CHK(write_afe(dev, 32 + i, low)); /* Set 'low' black level */ } CHK(scan_img(dev, img, 10000)); get_image_stats(img, &lo_stat); /* Sample 'high' black level */ for (i = 0; i < 3; i++) { CHK(write_afe(dev, 32 + i, high)); /* Set 'high' black level */ } CHK(scan_img(dev, img, 10000)); get_image_stats(img, &hi_stat); /* Use the line equation to find and set the best offset value */ for (i = 0; i < 3; i++) { double m, c; /* y = mx + c */ int o; /* offset */ m = (hi_stat.avg[i] - lo_stat.avg[i]) / (high - low); c = lo_stat.avg[i] - m * low; o = (int) satf(-c / m + 0.5, 0, 255); cal->offset[i] = o; CHK(write_afe(dev, 32 + i, o)); DBG(DBG_info, "AFE %s offset = %d\n", idx_name(i), o); } ret = 0; chk_failed: free(img); return ret; chk_mem_failed: ret = LIBUSB_ERROR_NO_MEM; goto chk_failed; }
int test_scan(struct gl843_device *dev) { int ret; struct scan_setup ss = {}; struct gl843_image *img = NULL; CHK(write_reg(dev, GL843_SCANRESET, 1)); CHK(wait_until_home(dev)); CHK(setup_static(dev)); ss.source = LAMP_PLATEN; ss.fmt = PXFMT_RGB16; ss.dpi = 1200; ss.start_x = 128; ss.width = 10208; //ss.start_y = 236; ss.start_y = 5; ss.height = 1200; ss.use_backtracking = 1; CHK_MEM(img = create_image(ss.width, ss.height, ss.fmt)); CHK(setup_common(dev, &ss)); CHK(setup_horizontal(dev, &ss)); CHK(setup_vertical(dev, &ss, 0)); CHK(set_lamp(dev, ss.source, 10)); CHK(write_reg(dev, GL843_MTRPWR, 1)); CHK(scan_img(dev, img, 10000)); write_pnm_image("test.pnm", img); CHK(wait_until_home(dev)); CHK(write_reg(dev, GL843_MTRPWR, 0)); chk_mem_failed: chk_failed: free(img); return ret; }
int do_warmup_scan(struct gl843_device *dev, float cal_y_pos) { int ret; struct scan_setup ss = {}; struct calibration_info *cal; int lamp_to = 4; // FIXME: Get user setting CHK(write_reg(dev, GL843_SCANRESET, 1)); CHK(wait_until_home(dev)); CHK(setup_static(dev)); CHK(move_scanner_head(dev, cal_y_pos)); CHK(wait_motor(dev)); // FIXME: Get user setting ss.source = LAMP_PLATEN; ss.fmt = PXFMT_RGB16; ss.dpi = 1200; ss.start_x = 128; ss.width = 10208; ss.height = 16; CHK(setup_common(dev, &ss)); CHK(setup_horizontal(dev, &ss)); CHK_MEM(cal = create_calinfo(ss.source, cal_y_pos, ss.start_x, ss.width, ss.height, ss.dpi)); #if 0 Old stuff enum gl843_lamp lamp = LAMP_PLATEN; int lamp_to = 4; int start_x = 128; int width = 10208; int height = 16; int dpi = 4800; CHK(setup_ccd_and_afe(dev, /* fmt */ PXFMT_RGB16, /* start_x */ start_x, /* width */ width * 4800 / dpi, /* dpi */ dpi, /* afe_dpi */ 1200, /* linesel */ 0, /* tgtime */ 0, /* lperiod */ 11640, /* expr,g,b */ 40000, 40000, 40000)); #endif CHK(select_shading(dev, SHADING_CORR_OFF)); set_reg(dev, GL843_MTRREV, 0); set_reg(dev, GL843_NOTHOME, 0); set_reg(dev, GL843_CLRLNCNT, 1); set_reg(dev, GL843_MTRPWR, 0); set_reg(dev, GL843_AGOHOME, 0); CHK(flush_regs(dev)); CHK(write_afe(dev, 4, 0)); CHK(write_afe(dev, 1, 0x23)); CHK(write_afe(dev, 2, 0x24)); CHK(write_afe(dev, 3, 0x2f)); /* Can be 0x1f or 0x2f */ CHK(set_lamp(dev, LAMP_OFF, 0)); CHK(calc_afe_blacklevel(dev, cal, 75, 0)); CHK(set_lamp(dev, ss.source, lamp_to)); CHK(warm_up_lamp(dev, cal)); CHK(calc_afe_gain(dev, cal)); CHK(calc_shading(dev, cal)); CHK(set_lamp(dev, ss.source, lamp_to)); CHK(send_shading(dev, cal->sc, cal->sc_len, 0)); CHK(select_shading(dev, SHADING_CORR_AREA)); CHK(move_scanner_head(dev, -cal_y_pos)); CHK(wait_until_home(dev)); CHK(write_reg(dev, GL843_MTRPWR, 0)); free(cal); ret = 0; chk_failed: return ret; chk_mem_failed: ret = LIBUSB_ERROR_NO_MEM; goto chk_failed; }
/* Warm up the scanner lamp and calibrate the AFE gain and offsets. * * cal_y_pos: calibration y position, distance from home [mm]. * * Note: it is assumed the scanner head is in the home position * when this function is called. */ int warm_up_scanner(struct gl843_device *dev, enum gl843_lamp source, int lamp_timeout, float cal_y_pos) { int ret; struct scan_setup ss = {}; struct calibration_info *cal; DBG(DBG_msg, "Starting warmup.\n"); /* Move head into position */ CHK(move_scanner_head(dev, cal_y_pos)); CHK(wait_motor(dev)); /* Setup scan */ ss.source = source; if (source == LAMP_PLATEN) { ss.fmt = PXFMT_RGB16; ss.dpi = 1200; ss.start_x = 128; ss.width = 10208; ss.start_y = 5; /* Dummy value */ ss.height = 16; ss.overscan = 0; } else { DBG(DBG_error, "Only platen scanning is implemented right now.\n"); return -1; } CHK_MEM(cal = create_calinfo(ss.source, cal_y_pos, ss.start_x, ss.width, ss.height, ss.dpi)); CHK(setup_static(dev)); CHK(setup_common(dev, &ss)); CHK(setup_horizontal(dev, &ss)); CHK(setup_vertical(dev, &ss, 1)); CHK(select_shading(dev, SHADING_CORR_OFF)); /* Scan with motor and lamp off and calculate AFE black level */ CHK(write_reg(dev, GL843_AGOHOME, 0)); CHK(write_reg(dev, GL843_MTRPWR, 0)); CHK(set_lamp(dev, LAMP_OFF, 0)); CHK(calc_afe_blacklevel(dev, cal, 75, 0)); /* 75 and 0 are CS4400F-specific */ /* Turn on the lamp, do warm up scan, and calculate AFE gain */ CHK(set_lamp(dev, source, lamp_timeout)); CHK(warm_up_lamp(dev, cal)); CHK(calc_afe_gain(dev, cal)); /* Move home when finished */ CHK(move_scanner_head(dev, -cal_y_pos)); CHK(wait_motor(dev)); CHK(write_reg(dev, GL843_MTRPWR, 0)); free(cal); DBG(DBG_msg, "Done.\n"); ret = 0; chk_failed: return ret; chk_mem_failed: ret = LIBUSB_ERROR_NO_MEM; goto chk_failed; }
static int calc_shading(struct gl843_device *dev, struct calibration_info *cal) { int ret, i; struct gl843_image *light_img = NULL, *dark_img = NULL; uint16_t *Ln, *Dn, *p, *p_end; const int target = 0xffff; int div_by_zero = 0; int gain_overflow = 0; DBG(DBG_msg, "Calculating shading correction.\n"); CHK_MEM(light_img = create_image(cal->width, cal->height, PXFMT_RGB16)); CHK_MEM(dark_img = create_image(cal->width, cal->height, PXFMT_RGB16)); /* Scan light (white) pixels */ /* Assume lamp is on */ CHK(scan_img(dev, light_img, 10000)); get_vertical_average(light_img); /* Scan dark (black) pixels */ CHK(set_lamp(dev, LAMP_OFF, 0)); CHK(scan_img(dev, dark_img, 10000)); get_vertical_average(dark_img); /* Calculate shading * Ref: shading & correction in GL843 datasheet. */ p = cal->sc; p_end = p + cal->sc_len; Ln = (uint16_t *) light_img->data; Dn = (uint16_t *) dark_img->data; for (i = 0; i < cal->width * 3; i++) { int diff, gain; diff = *Ln++ - *Dn; if (diff == 0) { div_by_zero = 1; diff = target; } gain = (cal->A * target) / diff; if (gain > 0xffff) { gain_overflow = 1; gain = 0xffff; } *p++ = *Dn++; *p++ = gain; if (p > p_end) { DBG(DBG_error, "internal error: buffer overrun."); break; } } if (host_is_big_endian()) swap_buffer_endianness(cal->sc, cal->sc, cal->sc_len / 2); if (div_by_zero) DBG(DBG_warn, "division by zero detected.\n"); if (gain_overflow) DBG(DBG_warn, "gain overflow detected.\n"); ret = 0; chk_failed: free(light_img); free(dark_img); return ret; chk_mem_failed: ret = LIBUSB_ERROR_NO_MEM; goto chk_failed; }
void display() { n++; // animation angle ++ if(n == 360) n=0; // avoid infinity changeView(); GLfloat ebene[4][3]={ // Grundflaeche {-30.0f, 0.0f,-15.0f}, { 30.0f,0.0f,-15.0f}, { -30.0f, 0.0f,15.0f},{ 30.0f,0.0f, 15.0f}}; GLfloat light_position1[]={ -20.0f, 20.0f, -20.0f, 0.0}; glClearColor(1.0, 1.0, 1.0, 1.0); glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT); float angle; glLightfv(GL_LIGHT0, GL_POSITION, light_position1); glDisable(GL_LIGHTING); // Skybox, Kugel ueber die aktuelle Szene, hellblau glPushMatrix(); // bewegt sich mit der kamera glTranslatef(swipe_left_right, swipe_up_down, swipe_through_back); glColor4ub(15,170,255,100); glutSolidSphere(25,30,30); glPopMatrix(); glPushMatrix(); // Bodenflaeche glTranslatef(0.0f, -3.0f, 0.0f); // nach unten verschoben glColor4ub(143, 163, 112, 255); glBegin(GL_QUAD_STRIP); glVertex3fv(ebene[0]); glVertex3fv(ebene[1]); glVertex3fv(ebene[2]); glVertex3fv(ebene[3]); glEnd(); // Licht glEnable(GL_LIGHTING); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // Teapot glPushMatrix(); set_mat3(); glTranslated(-2.5, 0.5, 3); glRotated(n,0,1,0); glutSolidTeapot(0.5); glPopMatrix(); // Bank ausgeben // Bank2 ausgeben, Drehwinkel: ITMZ: 190 -> 910 % 360 = 190 ... glPushMatrix(); glRotated(190, 0.0f, 1.0f, 0.0f); set_bank(); glPopMatrix(); glPushMatrix(); glTranslated(3.0, 0.0, 0.0); // (laengs, hoch, tief) = (x, y, z) glRotated(190, 0.0f, 1.0f, 0.0f); // (winkel, x, y, z) set_bank(); glPopMatrix(); // Bank2 ausgeben glPushMatrix(); glTranslated(-3.0, 0.0, 0.0); // (laengs, hoch, tief) glRotated(190, 0.0f, 1.0f, 0.0f); set_bank(); glPopMatrix(); // Lampe glPushMatrix(); glTranslated(-5,0,2); glRotated(45, 0,1,0); set_lamp(); glPopMatrix(); // *********** bewegliche Teile ****************** glDisable(GL_LIGHTING); glPushMatrix(); glRotated(90, 1.0, 0.0, 0.0); angle = glutGet(GLUT_ELAPSED_TIME)/1000.0f *15; glRotated(angle, 0.0, 0.0, 1.0); /* Hier Drohe zusammensetzen und Parameter auswerten*/ glTranslatef(0, -4, - drone_y_positon); set_drone(); glPopMatrix(); // Time glPopMatrix(); // Gesamtszene glutSwapBuffers(); glutPostRedisplay(); }