[sane-devel] Canon N670U:merlin670-V0.01 developers release (small bugfix)
kilgota at khayyam.math.auburn.edu
kilgota at khayyam.math.auburn.edu
Fri Feb 1 02:43:17 GMT 2002
As mentioned already, this program does not seem to want to create a
temporary file called n670u.raw . As mentioned below, one can always
create it first, with "touch," but introduction of a small change on line
593 of the file will take care of it, too.
There, it is possible to add to the "open" operation the option O_CREAT
and this takes care of the problem. Suitably edited file attached at the
end of this note.
Theodore Kilgore
---------- Forwarded message ----------
Date: Thu, 31 Jan 2002 19:40:45 -0600 (CST)
From: kilgota at khayyam.math.auburn.edu
Reply-To: kilgota at banach.math.auburn.edu
To: Gunther.Mayer at t-online.de
Cc: sane-devel at mostang.com
Subject: Re: [sane-devel] Canon N670U:merlin670-V0.01 developers release
This works. I got a scan out of it.
Further remarks:
1. apparently I had to rmmod scanner first, or it was unhappy.
2. I had to run the program as root
3. It didn't want somehow to create the temporary file n670u.raw, but
after I did
touch n670u.raw
it went right ahead and did the scan and exited after going the length of
an A4 paper.
4. Congratulations. Not bad.
Theodore Kilgore
> ---------- Forwarded message ----------
> Date: Thu, 31 Jan 2002 23:44:56 +0100
> From: Gunther Mayer <Gunther.Mayer at t-online.de>
> To: Sane-devel at mostang.com
> Subject: [sane-devel] Canon N670U:merlin670-V0.01 developers release
>
> Hi,
> my hack "merlin670" already scans at 150 dpi color:
> http://home.t-online.de/home/gunther.mayer/merlin-V0.01.c
>
> This is an early release for developers, no fancy features!
> You must even twiddle to get it compiled. See comments in the source.
>
> This is
> - based on libusb (no kernel module scanner.o needed).
> - standalone wrt SANE
>
> Regards, Gunther
> _______________________________________________
> Sane-devel mailing list
> Sane-devel at www.mostang.com
> http://www.mostang.com/mailman/listinfo/sane-devel
>
----------------edited merlin-V0.01.c follows------------------------
/*
* Canon N670U Scanner LM9833 merlin test quick'n dirty
(c) Gunther Mayer 2002
GNU Public license
*
* Test program
* For developers only !!!
* Just get it scanning, pending refinements.
INSTALLING and USING:
1) get,compile,install libusb-0.1.4
No need for "scanner.o" kernel module !
2) mkdir merlin in libusb's directory (so ".." works)
3) cp merlin670.c merlin
4) cc -o merlin670 -lusb -lm merlin670.c
adjust libraries as needed
5) ./merlin670 will do a 150 dpi color scan
When you press Ctrl-C "n670u.ppm" will be written (else ca. A4 size
will be scanned)
*/
/* CANON USB models (Canon Vendor ID VID=0x04A9):
PID model
??? FB320U
??? FB1210U
??? FB630U/636U
??? D2400UF
??? D660U
??? D1230U
2202 FB620U
2206 N650U
2207 N1220U
220B D646U
220D N670U/N676U ***
220E N1240U
N-Series: CIS Scanner
D-Series: CCD Scanner
*/
#include <stdio.h>
#include "../usb.h" //libusb !
#include "../usbi.h"
#include <errno.h>
#include <sys/types.h>
#include <fcntl.h>
#include <math.h>
#include <signal.h>
#define wr(reg,val) writereg(reg,val)
#define wr2(reg,val) {writereg(reg+1,val&0xff); writereg(reg,val>>8);}
void init_like_3a(int);
usb_dev_handle *u;
usb_dev_handle *findscanner(int vendor, int product);
int fraw,ctrlc;
void raw2ppm(int lines,int pixperline)
{ int f,j=0,i=0,rr,gg,bb;
FILE *o;
char r[16384],g[16384],b[16384];
printf("Creating n670u.ppm %dx%d\n",pixperline,lines);
f=open("n670u.raw", O_RDONLY);
o=fopen("n670u.ppm","w");
fprintf(o,"P6\n%d %d\n255\n",pixperline,lines);
while(j<lines) {
j++;
rr=read(f,r,pixperline);
gg=read(f,g,pixperline);
bb=read(f,b,pixperline);
for(i=0;i<pixperline;i++)
fprintf(o,"%c%c%c",r[i],g[i],b[i]);
}
fclose(o);
}
int writereg(int reg, int val)
{ char buf[5]; int i;
buf[0]=0; //0=write command
buf[1]=reg;// register
buf[2]=0; // MSB number of data bytes to write
buf[3]=1; // LSB number of data bytes to write
buf[4]=val;
//int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout);
i=usb_bulk_write(u,3, buf, 5, 500 /*msec*/);
if(i!=5) {
printf(" write reg 0x%02x:0x%02x usb_bulk_write returned %d\n",reg,val,i);
exit(1);
}
}
int readreg_n(int reg,int n, char *b)
{ char buf[5];int i;
buf[0]=1; //1=read command
buf[1]=reg; // register
buf[2]=n>>8; // MSB of data bytes to read
buf[3]=n&0xff;// LSB of data bytes to read
i=usb_bulk_write(u,3, buf, 4, 500 /*msec*/);
if(i!=4) {
printf("usb_bulk_write returned %d\n",i);
exit(1);
}
i=usb_bulk_read(u,2, b, n, 500);
if(i!=n) {
printf("usb_bulk_read returned %d\n",i);
exit(1);
}
return i;
}
unsigned char readreg(int reg)
{ char buf[5];
char reply[1]; int i;
buf[0]=1; //1=read command
buf[1]=reg;// register
buf[2]=0; // MSB number
buf[3]=1; // LSB number
i=usb_bulk_write(u,3, buf, 4, 500 /*msec*/);
if(i!=4) {
printf("usb_bulk_write returned %d\n",i);
exit(1);
}
i=usb_bulk_read(u,2, reply, 1, 500);
if(i!=1)
printf("usb_bulk_read returned %d\n",i);
return reply[0];
}
// read registers from Scanner:
void dumpregs()
{ int i;
for(i=0x0;i<0x80;i++) {
if((i%16) ==0) printf("\n0x%02x:",i);
if((i%8)==0) printf(" ");
if(i==0 || i==5 || i==6) // the dataport read returns with "0 Bytes read", of course.
printf("XX ");
else
printf("%02x ",readreg(i));
}
printf("\n");
}
// datasheet chapter 10.2
void do_softreset()
{
printf("softreset\n");
writereg(0x18,0x05);
writereg(0x07,0); // idle state
writereg(0x18,0x18); // disable sampling
writereg(0x07,0x20); // trigger reset
writereg(0x18,0x05);
writereg(0x07,0); //idle
}
void buttons()
{ int i=10;
printf("reg7=0x%02x , reg2 is 0x%02x\n",readreg(7),readreg(2));
writereg(0x59,0);
printf("reg7=0x%02x , reg2 is 0x%02x\n",readreg(7),readreg(2));
writereg(0x5a,0x90); // Defunct beim Schreiben von 0x10 !!!
printf("reg7=0x%02x , reg2 is 0x%02x\n",readreg(7),readreg(2));
//writereg(0x5b,0);
while(i) { // i--;
printf("reg2 is 0x%02x\n",readreg(2));
}
}
void scan150_ini(void)
{
wr(0x08,0x06); //mclk
//wr(0x08,0x0a);
wr(0x09,0x1c); //150dpi
wr(0x22,0); //pix start
wr(0x23,0x4b);
wr(0x24,0x13); // A4
//wr(0x25,0xab);
wr(0x25,0xae); // LineDataSize is rounded up to the next even integer 1242 !?
//wr(0x24,0xb2); // nogo
wr(0x29,0x02); //lamps
wr2(0x2c,0x0017);
wr2(0x2e,0x11d2);
wr2(0x30,0x0017);
wr2(0x32,0x10db);
wr2(0x34,0x0017);
wr2(0x36,0x0c04);
wr(0x38,1);
wr(0x39,1);
wr(0x3a,1);
wr(0x3b,1);
wr(0x3c,1);
wr(0x3d,1);
//wr(0x42,0x20); //nono 0x26 notjet
wr(0x42,0x21);
wr(0x45,0x13); // motor on
wr2(0x46,0x01f2); //stepsize
wr2(0x48,0x01f2); // FF stepize
wr(0x4e,0x2f);
wr(0x4f,0x01);
wr(0x50,0x3f);
wr(0x51,0xfc); // phase difference on pause
wr(0x52,0x77); //0x07 from snoop would produce colorstripes at pause
wr(0x53,0xc8);
wr(0x58,0); // Sensors must be off, else scanning just halts.
}
// write 4096 bytes to the data port (register 0x06) per color.
// The LM9833 will use the 12 most significant bits of
// 16bit ADC as index. So we get a 8 Bit output value per color
// LM9833 pdf Figure 43 is plain wrong (as it shows 12 bit values
// to be written to the dataport)
void download_gamma(float gamma) // Gamma=1 for Linear.
{
char buf[0x14];
int color,i,j,r; double x,y;
for(color=0;color<3;color++) {
wr(0x03,0x02 + color*4); // Bits 0 and 1:0x02 Bits 2 and 3:color
wr(0x04,0x00);
wr(0x05,0x00);
for(i=0;i<=0xff;i++) {
buf[0]=0; //0=write command
buf[1]=0x06; /* register*/
buf[2]=0;// MSB number
buf[3]=0x10; // LSB number bytes written
for(j=0x4;j<0x14;j++) {
x=(i*16 + j-4)/4096.0;
y=pow(x,1.0/gamma)*256 ;
buf[j]=y;
//printf("x gam is %f %f %f\n",x,y,gamma);
}
r=usb_bulk_write(u,3, buf, 0x14, 500 /*msec*/);
if(r!=0x14) {
printf(" write reg 0x%02x: gamma usb_bulk_write returned %d\n",6,r);
exit(1);
}
}
}
}
void mysigint(int s)
{ printf("CTRL-C received.\n");
ctrlc=1;
}
void scan150(void)
{ int z=0,i=0,k=0;
int r,r1,r3,r7,r4c,r4d; char buf[0x2000];
int lastr1,lastr3,lastr7;
signal(SIGINT,mysigint);
scan150_ini(); //geht jetzt!
//scan150_ini_from_register_dump(); // doesnt work
printf("Register Dump before scan:");
dumpregs();
/*wr(0x03,0x0a);
wr(0x04,0x40);
wr(0x05,0x00);*/
r=readreg(0x06);
printf("reg6 is 0x%02x\n",r);
printf("registercheck before scan:");
{ int r1,r3,r7,r4c,r4d; char buf[0x2000];
r1=readreg(0x01);
r3=readreg(0x03);
r7=readreg(0x07);
r4c=readreg(0x4c);
r4d=readreg(0x4d);
printf("r1=%d r3=0x%02x r7=0x%2x r4c4d=%02x%02x\n",r1,r3,r7,r4c,r4d);
}
printf("download gamma 2.5...\n");
download_gamma(2.5);
//wr(0x4a,5); //skip
/*wr(0x58,0); // sensor home OFF
wr(0x07,0x00);*/
printf("\nSCAN 150dpi COLOR until CTRL-C or DIN A4\n");
wr(0x07,0x03); // scannnnn
while(1) {
r1=readreg(0x01);
r3=readreg(0x03);
r7=readreg(0x07);
if(ctrlc==1) break;
//if((lastr1!=r1)||(lastr3!=r3)||(lastr7!=r7))
// printf("r1=%d r3=0x%02x r7=0x%2x\n",r1,r3,r7);
if(r1>0x02) {
r=readreg_n(0x00,0x2000,buf);
k=k+0x2000;
z=k/1242/3-1;
if(z>1650) break; // ca. DINA4
write(fraw,buf,0x2000);
close(fraw);
fraw=open("n670u.raw", O_RDWR|O_APPEND);
//printf("READ=%d ",r);
printf("."); fflush(stdout);
}
lastr3=r3; lastr1=r1; lastr7=r7;
}
printf("\n");
do_softreset();
raw2ppm(z,1242);
init_like_3a(1);
}
void playlamp()
{
wr(0x08,0x3f); // warning: psychedelic frequencies
wr2(0x2c,0x0017);
wr2(0x2e,0x1225);
wr2(0x30,0x0017);
wr2(0x32,0x1225);
wr2(0x34,0x0017);
wr2(0x36,0x1225);
wr(0x29,0x02);
dumpregs();
}
void init_like_3a(int early)
{ int r,i;
wr(0x03,0);
wr(0x04,0);
wr(0x05,0);
wr(0x06,0);
wr(0x08,0x0a);
wr(0x09,0x1a);
wr(0x0a,0);
wr(0x0b,0x15);
wr(0x0c,0x4c);
wr(0x0d,0x2f);
wr(0x0e,0);
wr(0x0f,0);
wr(0x10,0);
wr(0x11,0x04);
wr(0x12,0x05);
wr(0x13,0x06);
wr(0x14,0x07);
wr(0x15,0);
wr(0x16,0);
wr(0x17,0);
wr(0x18,0x05);
wr(0x19,0);
wr(0x1a,0);
wr(0x1b,0x01);
wr(0x1c,0);
wr(0x1d,0);
wr(0x1e,0);
wr(0x1f,0x4b);
wr(0x20,0x14);
wr(0x21,0xad);
wr(0x22,0);
wr(0x23,0x4b);
wr(0x24,0x14);
wr(0x25,0x3b);
wr(0x26,0x15);
wr(0x27,0);
// 0x28 reserved
wr(0x29,0);
wr(0x2a,0);
wr(0x2b,0);
wr(0x2c,0x03);
wr(0x2d,0xff);
wr(0x2e,0);
wr(0x2f,0x01);
wr(0x30,0x03);
wr(0x31,0xff);
wr(0x32,0);
wr(0x33,0x01);
wr(0x34,0x03);
wr(0x35,0xff);
wr(0x36,0);
wr(0x37,0x01);
wr(0x38,0);
wr(0x39,0);
wr(0x3a,0);
wr(0x3b,0x01);
wr(0x3c,0x01);
wr(0x3d,0);
wr(0x3e,0);
wr(0x3f,0);
wr(0x40,0x40);
wr(0x41,0);
wr(0x42,0x20);
wr(0x43,0);
wr(0x44,0);
wr(0x45,0x13);
wr(0x46,0x03);
wr(0x47,0xe3);
wr(0x48,0x01);
wr(0x49,0xf2);
wr(0x4a,0);
wr(0x4b,0);
wr(0x4c,0);
wr(0x4d,0);
wr(0x4e,0x8c);
wr(0x4f,0x01);
wr(0x50,0);
wr(0x51,0xfc);
wr(0x52,0x35);
wr(0x53,0x94);
wr(0x54,0);
wr(0x55,0x0f);
wr(0x56,0x08);
wr(0x57,0x1f);
wr(0x58,0x04);
wr(0x59,0x44);
// 5a 5b
wr(0x5c,0x01);
wr(0x5d,0);
wr(0x5e,0);
wr(0x5f,0);
wr(0x60,0);
wr(0x61,0);
wr(0x62,0);
wr(0x63,0);
wr(0x64,0);
wr(0x65,0);
wr(0x66,0);
wr(0x67,0);
wr(0x68,0);
wr(0x69,0);
wr(0x6a,0);
wr(0x6b,0);
wr(0x6c,0);
wr(0x6d,0);
wr(0x6e,0);
wr(0x6f,0);
wr(0x70,0);
wr(0x71,0);
wr(0x72,0);
wr(0x73,0);
wr(0x74,0);
wr(0x75,0);
wr(0x76,0);
wr(0x77,0);
wr(0x78,0);
wr(0x79,0);
wr(0x7a,0);
wr(0x7b,0);
wr(0x7c,0);
wr(0x7d,0);
wr(0x7e,0);
wr(0x7f,0);
// 5a 5b
wr(0x5a,0x94);
wr(0x5b,0x19);
/*
wr(0x07,0); // URB 127
{ int r18;
r18=readreg(0x18);
wr(0x18,0x18);
wr(0x07,0x20);
wr(0x18,r18); //0x05
wr(0x07,0x00);
wr(0x07,0x00);
}
*/
wr(0x5b,0x11); // URB 140
wr(0x5b,0x91);
r=readreg(0x5a);
wr(0x5a,0x14);
r=readreg(0x09);
wr(0x09,r);
wr(0x5a,0x16); //URB 151 ERR-1
wr(0x59,0x66); // URB 152
wr(0x70,0x73); // URB 406
wr(0x2c,0x3f); //URB 473 LAMP off
wr(0x30,0x3f);
wr(0x34,0x3f);
//playlamp(); exit(1);
//wr(0x48,0x01); // fast feed step size
wr(0x48,0x00);
wr(0x49,0xf2);
wr(0x57,0x3f); // //URB 421 pwm
//wr(0x57,0x1f);
//wr(0x58,0);// XXXXXXXXXX
r=readreg(0x02);
printf("r2 is 0x%02x\n",r);
if(r==0) {printf("r is null.exit\n");exit(1);}
if(!(r&1)) {// not at home position
printf("Homing sensor...\n");
wr(0x07,02);
while(1) {
static int lastr=2000; int r7,r2;
r2=readreg(0x02);
r7=readreg(0x07);
if(lastr!=r7) printf("r2=0x%02x, r7=%02x\n",r2,r7);
lastr=r7;
if(r7!=2) break;
}
}
if(early) return;
wr(0x4a,0x2);
printf("Sensor prog FORW\n");
wr(0x07,0x05);
while(1) {
static int lastr=2000; int r2,r7;
r2=readreg(0x02);
r7=readreg(0x07);
if(lastr!=r7) printf("r2=0x%02x, r7=%02x\n",r2,r7);
lastr=r7;
if(r7!=5) break;
}
wr(0x07,0x02); // REVERSE until HOME
i=10;
while(1) {
int r2,r7; static int lastr=2000;
r2=readreg(0x02);
r7=readreg(0x07);
if(lastr!=r) printf("r2=0x%02x, r7=%02x\n",r2,r7);
lastr=r;
if(r7!=2) break;
}
return;
wr(0x57,0x33); //URB 570
wr(0x07,0x01); //FORWARD 2581ms
wr(0x51,0x00); // accel profile
// wait for reg02 go from 63->62
while(1) {
int r;
r=readreg(0x02);
printf("r2 is 0x%02x ",r);
if(r!=0x63) break;
}
wr(0x07,0x00); // STOP
}
int main(void)
{ int i=0,r=0;
printf("Merlin670 V0.01 for developers only\n");
u=findscanner(0x04a9 /*canon*/ ,0x220d /* N670U/N676U*/);
if(u==NULL) {printf("scanner not found. exiting.\n"); return 1;}
//printf("found u=%p\n",u);
//printf("Bus/Device= %p/%p, config=%d interface=%d altsetting=%d\n",
// u->bus, u->device, u->config, u->interface, u->altsetting);
i=usb_claim_interface(u,0);
printf("usb_claim_interface returned %d\n",i);
if(i!=0) { printf("could not claim scanner)! exiting.\n");
exit(1);}
i=usb_set_configuration(u,1);
printf("usb_set_configuration returned %d\n",i);
if(i!=0) exit(1);
writereg(7,0);
printf("Initial Register Dump",i,r);
dumpregs();
fraw=open("n670u.raw",O_CREAT|O_TRUNC|O_RDWR);
if(fraw==-1)
{printf("couldn open n670u.raw, errno=%d\n",errno); exit(1);}
init_like_3a(0);
scan150();
//buttons(); exit(1);
return 0;
}
usb_dev_handle *findscanner(int vendor, int product)
{
struct usb_bus *bus;
struct usb_device *dev;
usb_init();
usb_find_busses();
usb_find_devices();
printf("Searching USB for CanoScan N670U/N676U VID=%04x PID=%04x\n",vendor,product);
printf("bus/device idVendor/idProduct\n");
for (bus = usb_busses; bus; bus = bus->next) {
for (dev = bus->devices; dev; dev = dev->next) {
printf("%s/%s %04X/%04X\n", bus->dirname, dev->filename,
dev->descriptor.idVendor, dev->descriptor.idProduct);
if((dev->descriptor.idVendor==vendor)&&
(dev->descriptor.idProduct==product))
return usb_open(dev);
}
}
return NULL;
}
More information about the sane-devel
mailing list