/* XLink85 - TI85<->PC link program, Copyright (c) 1996 Jani Halme */ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License or (at */ /* your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, but */ /* WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */ /* General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; it now, write to the Free Software */ /* Foundation, Inc., Mass Ave, Cambridge, MA02139. */ /* */ /* The author can be contacted by email at: jaadha@utu.fi */ #include "config.h" /* TI-85 ID-bytes */ #define ID_COMPUTER 0x05 #define ID_CALCULATOR 0x85 /* TI-85 packet types */ #define PAK_VARHEADER 0x06 #define PAK_DATAPART 0x15 #define PAK_ACKNOWLEDGE 0x56 #define PAK_LASTVAR 0x92 #define PAK_SKIPVAR 0x36 #define PAK_SCREENDUMP 0x64 #define PAK_REQRESEND 0x5a #define PAK_REQDATA 0x09 /* The poor TI-85 cannot keep up with a P100, so let's slow down :) */ #define SPEEDLIMITER 10000 /* I/O -ports for different link types */ #define lpt_out lpt_base #define lpt_in (lpt_base+1) #define com_out (com_base+4) #define com_in (com_base+6) /* .85g -file identifier */ const char identifier[8]="**TI85**"; /* TI-85 variable file extensions */ const char var_extensions[31][5]={ ".85n",".85c",".85v",".85v",".85l",".85l",".85m",".85m",".85k", ".85k",".85e",".85r",".85s",".85d",".85d",".85d",".85d",".85i", ".85p",".85r",".85i",".85_",".85_",".85r",".85r",".85r",".85r", ".85r",".85_",".85b" }; /* TI-85 variable type names */ const char var_types[31][6]={ "REAL","CPLX","VECTR","VECTR","LIST","LIST","MATRX","MATRX","CONST", "CONST","EQU","RANGE","STRNG","GDB","GDB","GDB","GDB","PICT", "PRGRM","RANGE","PICT","UNKN","UNKN","RANGE","RANGE","RANGE","RANGE", "RANGE","UNKN","BAKUP" }; #ifdef DEBUG unsigned char trcount; #endif unsigned char *buffer=NULL; unsigned short last_packet_size; /* function prototypes */ unsigned char get_packet(void); static inline void outb(unsigned short int port, unsigned char val); /* initializes link and checks permissions on /dev/port */ void init_link(void) { buffer=(unsigned char*)malloc(32768*sizeof(unsigned char)); if (buffer==NULL) { printf("Cannot allocate memory, aborting!\n"); exit(1); } switch (link_type) { case PARALLEL_LINK: #ifndef MSDOS if (ioperm(lpt_out,1,1) || ioperm(lpt_in,1,1)) { printf("Cannot access /dev/port, aborting!\n"); exit(1); } #endif outb(lpt_out, 3); break; case CONNECT85_LINK: #ifndef MSDOS if (ioperm(com_out,1,1) || ioperm(com_in,1,1)) { printf("Cannot access /dev/port, aborting!\n"); exit(1); } #endif outb(com_out,3); break; default: printf("Invalid configuration, please recompile!\n"); exit(1); break; } } /* outputs a byte to hardware I/O-port */ static inline void outb (unsigned short int port, unsigned char val) { __asm__ volatile ( "outb %0,%1\n" : : "a" (val), "d" (port) ); } /* inputs a byte from a hardware I/O-port */ static inline int inb (short port) { unsigned char val; __asm__ volatile ("inb %1,%0" : "=a" (val) : "d" ((unsigned short)port)); return val; } /* reset timeout counter */ void timereset(void) { /* timeout not implemented... */ } /* test if the transfer has timed out */ void timetest(void) { /* timeout not implemented */ } /* send a byte thru parallel link */ void put85_parallel(unsigned char data) { int bit, i; for (bit=0; bit<8; bit++) { if (data&1) { outb(lpt_out, 2); while (inb(lpt_in)&0x10); outb(lpt_out, 3); while ((inb(lpt_in)&0x10)==0x00); } else { outb(lpt_out, 1); while (inb(lpt_in)&0x20); outb(lpt_out, 3); while ((inb(lpt_in)&0x20)==0x00); } data>>=1; } for(i=0;i>1)|0x80; outb(lpt_out, 1); while ((inb(lpt_in)&0x20)==0x00) timetest(); outb(lpt_out, 3); } else { data=data>>1; outb(lpt_out, 2); while ((inb(lpt_in)&0x10)==0x00) timetest(); outb(lpt_out, 3); } } for(i=0;i>=1; } } /* receive a byte thru old serial cable */ unsigned char get85_connect85(void) { unsigned char curbit=1; unsigned char byt=0, bits, x; for (bits=1;bits<=8;bits++) { while ((x=getport())==3); if (x==1) { byt+=curbit; outb(com_out,1); x=2; } else { outb(com_out,2); x=1; } while ((getport()&x)==0); outb(com_out,3); curbit<<=1; } return byt; } /* send byte to calculator */ void put85(unsigned char val) { #ifdef DEBUG if (trcount==16) { printf("\n");trcount=0; } printf("%02x ", val); trcount++; #endif switch (link_type) { case PARALLEL_LINK: put85_parallel(val); break; case CONNECT85_LINK: put85_connect85(val); break; default: printf("Invalid configuration, please recompile!\n"); exit(1); break; } } /* receive a byte from calculator */ unsigned char get85(void) { unsigned char val; val=0; switch (link_type) { case PARALLEL_LINK: val=get85_parallel(); break; case CONNECT85_LINK: val=get85_connect85(); break; default: printf("Invalid configuration, please recompile!\n"); exit(1); break; } #ifdef DEBUG if (trcount==16) { printf("\n");trcount=0; } printf("\033[1m%02x\033[0m ", val); trcount++; #endif return val; } /* send a TI-85 packet */ void put_packet(unsigned char packet_type, unsigned short dataword) { unsigned short checksum, i; put85(ID_COMPUTER); put85(packet_type); put85(dataword & 0xff); put85(dataword >> 8); if (dataword!=0 && (packet_type==PAK_VARHEADER || packet_type==PAK_DATAPART || packet_type==PAK_SKIPVAR)) { checksum=0; for(i=0;i> 8); if (get_packet()!=PAK_ACKNOWLEDGE) { printf("Packet not acknowledged, exiting...\n"); exit(1); } } } /* receive a TI-85 packet */ unsigned char get_packet(void) { unsigned char calc_type, packet_type; unsigned short checksum, dataword, i; calc_type=get85(); packet_type=get85(); dataword=get85(); dataword=(get85()<<8)|dataword; if (dataword!=0 && (packet_type==PAK_VARHEADER || packet_type==PAK_DATAPART || packet_type==PAK_SKIPVAR)) { checksum=0; for(i=0;i