C Code HELP: Control HP49-50 por puerto serial + Internet


Hola en la actualización reciente de HPcalc.org (sep 2011), hay un software para conexión a internet:

leyendo la info, uno de los autores incluye un archivo zip que dice:
You can also Control a hp49g+ via the SerialPort
Redactando ...
Dentro del archivo hay un código fuente en Lenguaje C, quien de vosotros me ayudáis a compilarlo
y ver como trabaja
Este código podría ser muy funcional para proyecto de conexión Calculadora con PC o Microcontrolador
#include
#include
#include
#include
#include
#include
#include
#include
#include
int fd;
struct termios oldtio,oldtiostdin;
int gotstdin;
static void __attribute__((noreturn)) cleanExit(int status) {
tcsetattr(fd,TCSANOW,&oldtio);
close(fd);
if (gotstdin) tcsetattr(STDIN_FILENO,TCSANOW,&oldtiostdin);
exit(EXIT_SUCCESS);
}
static unsigned char readChar(void) {
unsigned char c;
ssize_t size;
if ((size=read(fd,&c,1))<0 && errno!=EINTR) {
perror("read");
cleanExit(EXIT_FAILURE);
} else if (size==0) {
fprintf(stderr,"unexpected end of file\n");
cleanExit(EXIT_FAILURE);
} else if (size<0) return readChar();
else return c;
}
static inline unsigned read4(void) {
unsigned char c=readChar();
if (c>'9') return (c-'A')+10;
else return c-'0';
}
static inline unsigned read8(void) {
unsigned temp=read4();
return temp|read4()<<4;
}
static inline unsigned read16(void) {
unsigned temp=read4();
temp=temp|(read4()<<4);
temp=temp|(read4()<<8);
return temp|(read4()<<12);
}
static void writeChar(unsigned char c) {
ssize_t size;
if ((size=write(fd,&c,1))<0 && errno!=EINTR) {
perror("write");
cleanExit(EXIT_FAILURE);
} else if (size<=0) writeChar(c);
}
static void oops(unsigned char c) {
switch(c) {
case 'E':
fprintf(stderr,"hp told unknown code %c ?!\n",readChar());
return;
case 'K':
fprintf(stderr,"hp told unknown keycode ?!\n");
return;
case 'I':
fprintf(stderr,"internal error, throw your calc into the bin\n");
cleanExit(EXIT_FAILURE);
case 'M':
fprintf(stderr,"not enough memory, free some\n");
cleanExit(EXIT_FAILURE);
case 'S':
fprintf(stderr,"resync\n");
return;
default:
fprintf(stderr,"received %c\n",c);
return;
}
}
static inline int waitFor(unsigned char exp) {
unsigned char c=readChar();
if (c!=exp) {
oops(c);
return 0;
}
return 1;
}
static int doReset(void) {
int flags;
char c;
int tries,ztries;
struct timeval to;
fd_set set;
const static char z='Z';
/* flush pending chars */
flags=fcntl(fd,F_GETFL);
fcntl(fd,F_SETFL,flags|O_NONBLOCK);
tcflush(fd,TCIOFLUSH);
do {
FD_ZERO(&set);
FD_SET(fd,&set);
to.tv_sec=0;
to.tv_usec=100000;
} while (select(fd+1,&set,NULL,NULL,&to) && read(fd,&c,1)==1);
/* try to send Zs */
for (ztries=0;ztries<2;ztries++) {
if (write(fd,&z,sizeof(z))<=0) {
to.tv_sec=0;
to.tv_usec=100000;
select(1,NULL,NULL,NULL,&to);
continue;
}
fcntl(fd,F_SETFL,flags);
/* and try to get Rs */
for (tries=0;tries<2;) {
FD_ZERO(&set);
FD_SET(fd,&set);
to.tv_sec=0;
to.tv_usec=100000;
if (select(fd+1,&set,NULL,NULL,&to) && read(fd,&c,1)==1) {
if (c=='R') return 1; // hoping this is really ok
/* skip grobs */
if ((c>='0' && c<='9') || (c>='A' && c<='F')) continue;
}
tries++;
}
fcntl(fd,F_SETFL,flags|O_NONBLOCK);
}
fcntl(fd,F_SETFL,flags);
return 0;
}
static inline int waitForR(void) {
if (!waitFor('R')) {
fprintf(stderr,"expected R\n");
if (!doReset()) {
fprintf(stderr,"reset failed, aborting\n");
cleanExit(EXIT_FAILURE);
}
return 0;
}
return 1;
}
static inline int waitFor8(unsigned exp) {
unsigned u=read8();
if (u!=exp) {
fprintf(stderr,"unexpected value %x, expected %c\n",u,exp);
if (!doReset()) {
fprintf(stderr,"reset failed, aborting");
cleanExit(EXIT_FAILURE);
}
return 0;
}
return 1;
}
static int checkValidKey(unsigned char c) {
unsigned row=(c&0xf0)>>4;
unsigned col=c&0x0f;
switch (row) {
case 1: case 3:
if (col<1 || col>6) {
fprintf(stderr,"bad key press");
return 0;
}
break;
case 2:
if (col<1 || (col>3 && col !=5)) {
fprintf(stderr,"bad key press");
return 0;
}
break;
case 4: case 5: case 6: case 7: case 8: case 9: case 10:
if ((col<1 || col>5) && c!=0x5a && c!= 0x4b) {
fprintf(stderr,"bad key press");
return 0;
}
break;
default:
fprintf(stderr,"bad key press");
return 0;
}
return 1;
}
static void sendKeyPress(unsigned char c) {
if (!checkValidKey(c)) return;
writeChar('K');
writeChar(c);
if (c==0x5a) waitForR();
else if (waitFor(c) && c!=0x4b) waitForR();
}
static void sendKeyDown(unsigned char c) {
if (!checkValidKey(c)) return;
writeChar('D');
writeChar(c);
if (c==0x5a) waitForR();
else if (waitFor(c) && c!=0x4b) waitForR();
}
static void sendKeyUp(unsigned char c) {
if (!checkValidKey(c)) return;
writeChar('U');
writeChar(c);
if (c==0x5a) waitForR();
else if (waitFor(c) && c!=0x4b) waitForR();
}
static void waitReady(void) {
writeChar('W');
waitForR();
}
static unsigned char asciitokey[256]={
0, 0, 0, 0, 0, 0, 0, 0,0x45,0x71,0xa5, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0xa1, 0, 0, 0, 0,
0xa4,0x93,0x75,0x94,0x82,0x92,0xa5,0x43,0x85,0x85,0x75,0x95,0xa4,0x85,0xa2,0x65,
0xa2,0x92,0x93,0x94,0x82,0x83,0x84,0x72,0x73,0x74,0xa3,0x93,0x63,0x62,0x64,0x94,
0xa5,0x11,0x12,0x13,0x14,0x15,0x16,0x21,0x22,0x23,0x31,0x32,0x33,0x41,0x42,0x43,
0x44,0x51,0x52,0x53,0x54,0x55,0x61,0x62,0x63,0x64,0x65,0x75,0x83,0x75,0x51,0x85,
0x43,0x11,0x12,0x13,0x14,0x15,0x16,0x21,0x22,0x23,0x31,0x32,0x33,0x41,0x42,0x43,
0x44,0x51,0x52,0x53,0x54,0x55,0x61,0x62,0x63,0x64,0x65,0x95,0x23,0x95,0x92,0x45,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
int main(int argc, char *argv[]) {
struct termios newtio;
unsigned char c;
int i,j,k;
ssize_t size;
int down=0,up=0;
unsigned cksum;
unsigned width,height,indics;
fd_set set,cur;
int fdmax1;
struct timeval to;
if (argc<2) {
fprintf(stderr,"usage: %s /dev/ttysomething\n",argv[0]);
exit(EXIT_FAILURE);
}
if ((fd=open(argv[1],O_RDWR))<0) {
perror("open");
exit(EXIT_FAILURE);
}
if (tcgetattr(fd,&oldtio)<0) {
perror("tcgetattr(ttyS)");
exit(EXIT_FAILURE);
}
memcpy(&newtio,&oldtio,sizeof(newtio));
newtio.c_iflag = 0;
newtio.c_oflag = 0;
newtio.c_lflag = 0;
newtio.c_cflag = CS8 | CLOCAL | CREAD | HUPCL;
if (cfsetospeed(&newtio,B115200)<0) {
perror("cfsetospeed");
cleanExit(EXIT_FAILURE);
}
if (cfsetispeed(&newtio,B115200)<0) {
perror("cfsetispeed");
cleanExit(EXIT_FAILURE);
}
signal(SIGTERM,cleanExit);
signal(SIGHUP,cleanExit);
signal(SIGINT,cleanExit);
signal(SIGQUIT,cleanExit);
signal(SIGPIPE,cleanExit);
if (tcsetattr(fd,TCSANOW,&newtio)<0) {
perror("tcsetattr(ttyS)");
cleanExit(EXIT_FAILURE);
}
if (tcgetattr(STDIN_FILENO,&oldtiostdin)<0) {
perror("tcgetattr(stdin)");
cleanExit(EXIT_FAILURE);
}
memcpy(&newtio,&oldtiostdin,sizeof(newtio));
newtio.c_lflag &= ~(ICANON|ECHO);
gotstdin=1;
if (tcsetattr(STDIN_FILENO,TCSANOW,&newtio)<0) {
perror("tcsetattr(stdin)");
cleanExit(EXIT_FAILURE);
}
while (!doReset()) {
printf("please press [ON]-R\n");
while (readChar()!='S' && (fprintf(stderr,"please press [ON]-S then [ON]-R\n"),0));
printf("started\n");
}
FD_ZERO(&set);
FD_SET(STDIN_FILENO,&set);
FD_SET(fd,&set);
if (fd>STDIN_FILENO)
fdmax1=fd+1;
else
fdmax1=STDIN_FILENO+1;
while (1) {
writeChar('S');
if (waitFor8('S')) {
width=read8();
height=read8();
if (width!=136 || height!=80)
printf("strange screen: %ux%u\n",width,height);
indics=read8();
printf("%3s %3s %5s %5s %4s %5s %s\n",
indics&1?"<=\\":"",
indics&2?"/=>" :"",
indics&4?"alpha":"",
indics&8?"alarm":"",
indics&16?"busy":"",
indics&32?"trans":"",down?"down":up?"up":"");
cksum=0;
for (j=0;j>=1;
}
}
putchar('\n');
}
if (cksum!=read16()) printf("bad checksum\n");
waitFor8('R');
} else if (!doReset()) {
fprintf(stderr,"reset failed, aborting\n");
cleanExit(EXIT_FAILURE);
}
memcpy(&cur,&set,sizeof(cur));
to.tv_sec=0;
to.tv_usec=100000; // 100ms
if (select(fdmax1,&cur,NULL,NULL,&to)) {
if (FD_ISSET(STDIN_FILENO,&cur)) {
if ((size=read(STDIN_FILENO,&c,1))<0 && errno!=EINTR) {
perror("read");
cleanExit(EXIT_FAILURE);
} else if (size==0)
cleanExit(EXIT_SUCCESS);
else if (size==1) {
switch (c) {
case 'D'-'@': // ^V: hold down next key
down=1;
up=0;
break;
case 'U'-'@': // ^U: release up next key
down=0;
up=1;
break;
case 'W'-'@': // ^W: wait until ready
waitReady();
break;
default:
if ((c=asciitokey[c])) {
if (down) {
sendKeyDown(c);
down=0;
} else if (up) {
sendKeyUp(c);
up=0;
} else
sendKeyPress(c);
}
break;
}
}
}
if (FD_ISSET(fd,&cur))
oops(readChar());
}
}
cleanExit(EXIT_SUCCESS); }
Info sobre hp49g+ text controler
---------------------
Samuel Thibault
- launch a quite big xterm (136x82 should be nice)
- type
make
it should compile cleanly on many unices
- then connect your calculator thanks to the USB cable
- turn the calculator on, your system should detect the serial USB plug (run a
command like dmesg to see it)
- run
./hp49g+control /dev/ttyUSB0
/dev/ttyUSB0 being the device on which the HP was detected
- finally press [ON]-R on the calc
- enjoy
- press [ON]-S on the calc
- press Ctrl-C on Unix
If you stop the program *before* you pressed [ON]-S on the calc, the calc may
hang... To recover, simply re-run the program, and now press [ON]-S on the calc
*before* pressing Ctrl-C.
You may press keys on the Unix keyboard quite naturally (A-Z, 1-9, ESC for [ON],
Enter for [ENTER], etc...
You can hold down keys by pressing Ctrl-D before the key to press and hold down.
To release some key up, press Ctrl-U before the key to release up.
One can even do some warmstart:
Ctrl-D Esc C Ctrl-U Esc
and then you can grab the meta-kernel logo 
Sorry, CdB's greyscales don't work





