#include <stdio.h> #include <fcntl.h> #include <termios.h> #include <sys/types.h> #include <signal.h> #include <errno.h> #define STX 0x02 #define ETX 0x03 #define ENQ 0x05 #define ACK 0x06 #define NAK 0x15 #define ETB 0x17 #define NORMAL 0 #define FINE 1 void flushtty(int fd); void showttystate(int fd); u_char rbyte(int fd); int running=1; int exiting=0; void sigint(); int debug=0; char *where="start"; main(argc,argv) int argc; char **argv; { int qvfd, s, num, attr, i; char buf[8], byte=0; long tym, otym, tym1, tym2, tym3; qvfd=devinit("/dev/term/a"); if (debug) fprintf(stderr,"trying initial ok...\n"); wbyte(qvfd,ENQ); wait_for_input(qvfd,10); if (read(qvfd,&byte,1) != 1) { fprintf(stderr, "Can't communicate! Trying high baud rate...\n"); tty_change_speed(qvfd,B115200); } qvok(qvfd); fprintf(stderr, "(communicating!)\n"); signal(SIGINT,sigint); if (debug) showttystate(qvfd); sleep(1); debug_status("changing speed"); qv_change_speed(qvfd,B115200); num=qvhowmany(qvfd); if (debug) fprintf(stderr,"%d pictures\n",num); /* debug_status("setting mode"); qvmode(qvfd,NORMAL); */ tym=0; while(running) { otym=tym; tym=time(NULL); if (otym) { printf("%d seconds for last snapshot", tym-otym); printf(" (%d, %d, %d, %d)\n", tym1-otym, tym2-tym1, tym3-tym2, tym-tym3); } debug_status("setting sector"); qvsector(qvfd, 0x340); tym1=time(NULL); /* take a picture */ usleep(700000); /* seems to lessen camera lock-ups */ debug_status("taking picture (ok)"); qvok(qvfd); debug_status("taking picture (command)"); wbyte(qvfd,'D'); wbyte(qvfd,'R'); s = rbyte(qvfd); debug_status("taking picture (command, ACK)"); /* sleep(1); */ wbyte(qvfd,ACK); s = rbyte(qvfd); /* debug_status("taking picture (reset sector)"); qvsector(qvfd, 0x600); */ /* sleep(1); */ debug_status("getting picture num"); /* get the picture number */ num=qvhowmany(qvfd); /* get picture attributes */ attr=qvattr(qvfd,num); if (debug) { fprintf(stderr, "attr=0x%x\n", attr); } tym2=time(NULL); debug_status("getting picture data"); /* grab the picture */ get_picture(qvfd,num,attr); /* sleep(1); */ debug_status("deleting picture data"); /* delete the picture */ qvdelete(qvfd,num); tym3=time(NULL); debug_status("resetting camera"); /* reset the camera? */ qvreset(qvfd); } clean_exit(qvfd); } int qvok (fd) int fd; { int i; for (i=0; i<100; ++i) { if (debug) fprintf(stderr,"trying ok...\n"); wbyte(fd,ENQ); if (rbyte(fd) == ACK) { if (debug) fprintf(stderr,"OK\n"); return(1); } } fprintf(stderr,"error at %s\n", where); perror("qv is not OK!"); exit(-1); } int qvhowmany (fd) int fd; { int x; qvok(fd); write(fd,"MP",2); x = rbyte(fd); if (x != 0x62) { fprintf(stderr,"error at %s\n", where); perror("howmany invalid response"); exit(-1); } wbyte(fd,ACK); x = rbyte(fd); return((int) x); } int qvattr (fd,picnum) int fd, picnum; { u_int c; qvok(fd); write(fd,"DY",2); wbyte(fd, 0x02); wbyte(fd, picnum); rbyte(fd); wbyte(fd,ACK); c=rbyte(fd); return(c); } int qvsector (fd, n) int fd; int n; { u_char c; qvok(fd); write(fd,"PP",2); wbyte(fd,(u_char)(n >> 8) & 0xff); wbyte(fd,(u_char)n & 0xff); c=rbyte(fd); wbyte(fd,ACK); } int devinit(devfile) char *devfile; { int fd, mode, val; struct termios tio; fd=open(devfile,O_RDWR | O_NDELAY); if (fd < 0) { perror("open"); exit(-1); } val=1; /* if (ioctl(fd, TIOCSSOFTCAR, &val) < 0) { perror("soft carrier detect"); exit(-1); } */ /* if (ioctl(fd, TIOCEXCL, 0) < 0) { perror("exclusive"); exit(-1); } if (ioctl(fd, TIOCHPCL, 0) < 0) { perror("hold"); exit(-1); } */ tty_change_speed(fd, B9600); return(fd); } int qv_change_speed(fd, baud) int fd, baud; { int mode, val; struct termios tio; int baud_code; switch(baud) { case B9600: baud_code=46; break; case B19200: baud_code=22; break; case B38400: baud_code=11; break; case B57600: baud_code=7; break; case B115200: baud_code=3; break; case B153600: baud_code=2; break; case B230400: baud_code=1; break; case B460800: baud_code=0; break; default: fprintf(stderr,"No such baud available!\n"); exit(1); } qvok(fd); wbyte(fd,'C'); wbyte(fd,'B'); wbyte(fd,baud_code); rbyte(fd); wbyte(fd,ACK); sleep(1); tty_change_speed(fd, baud); return(0); } int tty_change_speed(fd, baud) int fd, baud; { int mode, val; struct termios tio; if (tcgetattr(fd, &tio) < 0) { perror("tcgetattr"); exit(-1); } tio.c_iflag=0; tio.c_oflag=0; tio.c_cflag=CS8 | CREAD | CLOCAL ; tio.c_lflag=0; tio.c_cc[VMIN]=1; tio.c_cc[VTIME]=5; if (cfsetispeed(&tio, baud)) { perror("set input speed"); exit(-1); } if (cfsetospeed(&tio, baud)) { perror("set output speed"); exit(-1); } if (tcsetattr(fd, TCSANOW, &tio) < 0) { perror("tcsetattr"); exit(-1); } mode = TIOCM_RTS; if(ioctl(fd, TIOCMBIC, &mode) < 0){ /* RTS OFF */ fprintf(stderr, "Can't set RTS OFF.\n"); close(fd); return(-1); } mode = TIOCM_CTS|TIOCM_DTR; if(ioctl(fd, TIOCMBIS, &mode) < 0){ /* CTS DTR ON */ fprintf(stderr, "Can't set CTS DTR ON.\n"); close(fd); return(-1); } /* showttystate(fd); */ flushtty(fd); return(0); } int clean_exit(fd) int fd; { int mode, val; struct termios tio; int baud_code; /* don't re-enter */ if (exiting) { exit(1); } exiting=1; flushtty(fd); if (tcgetattr(fd, &tio) < 0) { perror("tcgetattr"); exit(-1); } tio.c_iflag=0; tio.c_oflag=0; tio.c_cflag=CS8 | CREAD | CLOCAL ; tio.c_lflag=0; tio.c_cc[VMIN]=1; tio.c_cc[VTIME]=5; if (cfsetispeed(&tio, B9600)) { perror("set input speed"); exit(-1); } if (cfsetospeed(&tio, B9600)) { perror("set output speed"); exit(-1); } qvok(fd); wbyte(fd,'C'); wbyte(fd,'B'); wbyte(fd, 46); rbyte(fd); wbyte(fd,ACK); sleep(1); if (tcsetattr(fd, TCSANOW, &tio) < 0) { perror("tcsetattr"); exit(-1); } fprintf(stderr, "Exited cleanly!\n"); exit(0); } int qvdelete (fd,picnum) int fd, picnum; { qvok(fd); wbyte(fd,'D'); wbyte(fd,'F'); wbyte(fd,picnum); wbyte(fd,255); rbyte(fd); wbyte(fd,ACK); } int show_picture (fd,picnum) int fd, picnum; { qvok(fd); wbyte(fd,'D'); wbyte(fd,'A'); wbyte(fd,picnum); rbyte(fd); wbyte(fd,ACK); } int get_picture (fd,picnum,attr) int fd, picnum, attr; { u_char c, buf[128*1024], *ptr; int i, sum, blksz, nr; FILE *fp; show_picture(fd,picnum); /* the DL may not be necessary, but it doesn't take much time */ qvok(fd); wbyte(fd,'D'); wbyte(fd,'L'); rbyte(fd); /* should be 6f */ wbyte(fd,ACK); qvok(fd); wbyte(fd,'M'); if (attr & 0x02) { /* fine mode */ wbyte(fd,'g'); } else { /* normal mode */ wbyte(fd,'G'); } rbyte(fd); /* should be 6b */ wbyte(fd,ACK); wbyte(fd,0x12); ptr=buf; while(1) { if (debug) fprintf(stderr,"======starting block read======\n"); sum=0; c=rbyte(fd); if (c!=STX) { fprintf(stderr,"didn't get STX (got 0x%x)\n", c); exit(1); } c=rbyte(fd); sum+=c; blksz=c*256; c=rbyte(fd); sum+=c; blksz += c; if (blksz == 0) break; nr=0; /* while ((nr+=read(fd,ptr+nr,blksz-nr)) < blksz); */ while (nr < blksz) { wait_for_input(fd,5); nr += read(fd,ptr+nr,blksz-nr); if (errno == EINTR && running == 0) { clean_exit(fd); } } if (debug) fprintf(stderr, " read completed, nr=%d\n",nr); for (i=0; i<blksz; ++i) sum += ptr[i]; c=rbyte(fd); sum+=c; if (c!=ETB) { fprintf(stderr,"didn't get ETB (got 0x%x)\n", c); exit(1); } c=rbyte(fd); /* checksum */ if ((0xff&(~c)) != (sum &0xff)) { if (debug) fprintf(stderr,"RETRYING!!! (sum=%d, checksum=%d)\n", sum, c); wbyte(fd,NAK); } else { wbyte(fd,ACK); if (debug) fprintf(stderr,"======YAY successful block read======\n"); /* save JPEG data */ ptr += blksz; } } c=rbyte(fd); if (c!=ETX) { fprintf(stderr,"didn't get ETX (got 0x%x)\n", c); exit(1); } c=rbyte(fd); if (c!=0xFC) { fprintf(stderr,"didn't get 0xFC (got 0x%x)\n", c); exit(1); } wbyte(fd,ACK); if ((fp=fopen("/tmp/test.jpg","w")) == NULL) { perror("fopen"); clean_exit(fd); } if (attr & 0x02) { /* fine mode */ write_jpeg_fine(buf,fp); } else { /* normal mode */ write_jpeg(buf,fp); } fclose(fp); system("/home/fine/bin/update-webcam /tmp/test.jpg &"); } int qvreset (fd) int fd; { qvok(fd); /* QE is much faster than QR, doesn't require a sleep, doesn't reset the speed (more time savings because we don't have to set it back) and seems to work fine */ wbyte(fd,'Q'); wbyte(fd,'E'); rbyte(fd); wbyte(fd,ACK); /* sleep(2); */ qvok(fd); } int wait_for_input(fd,tymout) int fd, tymout; { fd_set readfds; int nfds; struct timeval tv; tv.tv_sec=tymout; tv.tv_usec=0; FD_ZERO(&readfds); FD_SET(fd,&readfds); nfds=select(fd+1, &readfds, NULL, NULL, &tv); if (nfds == 0) { if (errno == EINTR && running == 0) { clean_exit(fd); } return(-1); } return(0); } u_char rbyte (fd) int fd; { u_char byte; wait_for_input(fd,30); if (read(fd,&byte,1) != 1) { if (errno == EINTR && running == 0) { clean_exit(fd); } fprintf(stderr,"error at %s\n", where); perror("read"); exit(1); } if (debug) fprintf(stderr,"rbyte: %d\n",byte); return(byte); } int wbyte (fd,byte) int fd; u_char byte; { if (write(fd,&byte,1) != 1) { perror("write"); exit(1); } } void flushtty(fd) int fd; { u_char c; fd_set readfds; int nfds; struct timeval tv; int i,j; unsigned char u; FD_ZERO(&readfds); FD_SET(fd, &readfds); tv.tv_sec = 0; tv.tv_usec = 0; while (1) { nfds = select(fd +1 , &readfds, NULL, NULL, &tv); if(nfds == 0){ return; } else { if(FD_ISSET(fd, &readfds)){ if(read(fd, &c, 1) < 0){ fprintf(stderr,"tty read fail.\n"); return; } if (debug) fprintf(stderr,"flushtty: read %d\n", c); } } } } void showttystate (fd) int fd; { int mode, val; struct termios tio; fprintf(stderr,"State of fd %d\n",fd); if (ioctl(fd, TIOCGSOFTCAR, &val) < 0) { perror("soft carrier detect"); exit(-1); } fprintf(stderr,"SoftCar=%s ",val?"T":"F"); if(ioctl(fd, TIOCMGET, &mode) < 0) { perror("modem line bits"); exit(-1); } fprintf(stderr,(mode & TIOCM_RTS) ? "RTS is on " : "RTS is off "); fprintf(stderr,(mode & TIOCM_CTS) ? "CTS is on " : "CTS is off "); fprintf(stderr,(mode & TIOCM_DTR) ? "DTR is on " : "DTR is off "); fprintf(stderr,(mode & TIOCM_CAR) ? "CAR is on " : "CAR is off "); if (tcgetattr(fd, &tio) < 0) { perror("tcgetattr"); exit(-1); } fprintf(stderr,"\n "); fprintf(stderr,"ospd=%d ",cfgetospeed(&tio)); fprintf(stderr,"ispd=%d ",cfgetispeed(&tio)); fprintf(stderr,"iflag=%d ",tio.c_iflag); fprintf(stderr,"oflag=%d ",tio.c_oflag); fprintf(stderr,"cflag=%d ",tio.c_cflag); fprintf(stderr,"\n"); } void sigint(sig) int sig; { running=0; } int debug_status(msg) char *msg; { where=msg; if (debug) { fprintf(stderr, "************ %s\n", msg); } } /* The following is verbatim code from QVplay */ u_short get_u_short(buf) u_char *buf; { return ((u_short)buf[0] << 8) | buf[1]; } u_int get_u_int(buf) u_char *buf; { u_int t; t = (((u_int)buf[0] << 8) | buf[1]) << 16;; t |= ((u_int)buf[2] << 8) | buf[3];; return t; } #include "/home/fine/qv/QVplay095/src/cam2jpgtab.h" #include "/home/fine/qv/QVplay095/src/jpegtab_f.h" int write_file(buf, len, outfp) u_char *buf; int len; FILE *outfp; { int i, l; i = 0; while( len > i) { l = ( (len - i) < BUFSIZ) ? (len -i) : BUFSIZ; if(fwrite(&buf[i], sizeof(u_char), l, outfp) != l){ perror("write_file"); return(-1); }; i = i + l; } return(i); } int write_jpeg(buf, outfp) u_char *buf; FILE *outfp; { int i = 0; int areaNum; int ysize; int usize; int vsize; areaNum = get_u_short(buf); /* areaNum == 0x03 */ ysize = get_u_short(buf + 2); usize = get_u_short(buf + 4); vsize = get_u_short(buf + 6); i = i + 8; if(write_file(soi, sizeof(soi), outfp) == -1) return(-1); if(write_file(app0, sizeof(app0), outfp) == -1) return(-1); if(write_file(dqt0, sizeof(dqt0), outfp) == -1) return(-1); if(write_file(&buf[i], 64, outfp) == -1) return(-1); i = i + 64; if(write_file(dqt1, sizeof(dqt1), outfp) == -1) return(-1); if(write_file(&buf[i], 64, outfp) == -1) return(-1); i = i + 64; if(write_file(sof, sizeof(sof), outfp) == -1) return(-1); if(write_file(dht, sizeof(dht), outfp) == -1) return(-1); if(write_file(sos_y, sizeof(sos_y), outfp) == -1) return(-1); if(write_file(&buf[i], ysize, outfp) == -1) return(-1); i = i + ysize; if(write_file(sos_u, sizeof(sos_u), outfp) == -1) return(-1); if(write_file(&buf[i], usize, outfp) == -1) return(-1); i = i + usize; if(write_file(sos_v, sizeof(sos_v), outfp) == -1) return(-1); if(write_file(&buf[i], vsize, outfp) == -1) return(-1); i = i + vsize; if(write_file(eoi, sizeof(eoi), outfp) == -1) return(-1); return(i); } int write_jpeg_fine(buf, outfp) u_char *buf; FILE *outfp; { int i = 0; int size; u_char c = 0x01; size = get_u_int(buf + 4); i = i + 8; if(write_file(soi, sizeof(soi), outfp) == -1) return(-1); if(write_file(app_f, sizeof(app_f), outfp) == -1) return(-1); if(write_file(dqt_f, sizeof(dqt_f), outfp) == -1) return(-1); if(write_file(&buf[i], 64, outfp) == -1) return(-1); i = i + 64; if(write_file(&c, 1, outfp) == -1) return(-1); if(write_file(&buf[i], 64, outfp) == -1) return(-1); i = i + 64; if(write_file(sof_f, sizeof(sof_f), outfp) == -1) return(-1); if(write_file(dht_f, sizeof(dht_f), outfp) == -1) return(-1); if(write_file(sos_f, sizeof(sos_f), outfp) == -1) return(-1); if(write_file(&buf[i], size, outfp) == -1) return(-1); if(write_file(eoi, sizeof(eoi), outfp) == -1) return(-1); return(i); }