--------------------------------------------------------------------------- TI85/TI82 Link-protocol V2.0 January 1995 --------------------------------------------------------------------------- If anyone have any information about the TI92/95 linkprotocol, please send it to me so I can add it to this document. --------------------------------------------------------------------------- You use the information in this document on your own risk! Per Finander E-mail:pfimdt93@tufvan.hv.se Thanks to: Pascal Bouron (bouron@aaricia.ens-cachan.fr) for providing additional information about TI82/85 & CBL protocol TSTENBERG@ntcclu.ntc.nokia.com for the C routines and information. Mattias Lindquist (mattias.lindquist@tube.ct.se) for providing me with a graphlink. --------------------------------------------------------------------------- Old black link: The linkinterface uses 2 outputs (RTS/DTR) and 2 inputs (CTS/DSR) on the serial port to communicate with the TI85/TI82. The bits CTS/DSR can be read from port $3F8+6, bit 4 (CTS) and bit 5 (DSR). The bits RTS/DTR is controlled from port $3F8+4, bit 0 (DTR) and bit 1 (RTS). $3F8 is the port- address for COM1: (or $2F8 if COM2: is used). New gray graphlink: The new link uses the serial channel to communicate with the computer. I haven't any use for the RTS/DTR outputs except they will provide the link with power. The data is sent in 9600 baud, 1 stop bit, no parity. An interrupt routine should be used when receiving data from the link. Otherwise any activity like the smartdrive can cause loss of data when receiving data from the link. I've included 5 routines in Pascal to show how to send/receive bytes to/from the TI85/TI82. These routines are not optimized and doesn't contain any timeout check. The constant "PortAddr" contains the base-port address to the com-port. PortAddr=$3F8 if the link-interface is in COM1: or $2F8 if COM2: is used. The "InitPort" procedure must be called as fast as possible, because if CTS & DSR isn't set, then the calculator will slow down when the link is connected. A new variable have been added: "Graphlink". If "Graphlink" is true the linkprocedures will use the serial channel, otherwise the I/O- pins will be used. --------------------------------------------------------------------------- All data is sent in packages. A link-packet looks like this: ID From: $85=TI85 ($82=TI82), $05 (Computer communicating with TI85) / | $02 (Computer communicating with TI82) | $15 (Unknown - accepted by TI85. If anyone | finds out the purpuse, send me a note) | The CBL version also accepts other ID:s | | Command: $06 : Variable-header (used to initiate a variabletransmission) | | $15 : Data part (the datapart of a variable) | | $36 : Answer skip/abort | | $56 : Package received OK (used to acknowledge a package) | | $92 : No more variables to send (used to end a transmission) | | $6D : Send screendump | | Low byte | | Data word / Size of DataPart | High byte | | | Data zero or more bytes | | |-- |-- |---- |----------------- |- |- $85 $56 00 00 [DataPart:00 .. 00 Checksum: 00 00] Checksum=(Sum of all bytes in the datapart) and 65535 A transmission can look like this: a variable: ABC:REAL=3.1415... (PI) from TI85 to computer (all values in hex) ID $85=TI85 (byte, $82 for a TI82) | Command (byte): Var-header | | Packet length (word, 4+NameLength for a Var-header) | | | | | | ------Datapart------ | | | Variable length (word) | | | | Type (byte 0=Real number) | | | | | Name Length (byte) | | | | | | Name | | | | | | | Checksum,(0A+03+41+42+43) and FFFF |- |- |---- |---- |- |- |------- |---- TI85: 85 06 07 00 0A 00 00 03 41 42 43 D3 00 COMPUTER: 05 56 00 00 |- |- |---- | | No packet | Command: Received OK ID $05 = Computer <=> TI85 ($02 = Computer <=> TI82) Received OK | Command: Data part | | Packet length: 10 bytes for a REAL | | | Data (PI) |- |- |---- |---------------------------- TI85: 85 56 00 00 85 15 0A 00 00 00 FC 31 41 59 26 53 58 98 COMPUTER: 05 09 00 00 |- |---- | No packet Command: Ready to receive data part Checksum Command: No more variables | | 10 bytes data was sent |---- |- |---- TI85: 30 03 85 92 0A 00 "Done..." COMPUTER: 05 56 00 00 05 56 00 00 END |- |- Received OK Received OK If a TI82 is used instead of a TI85, the Var-header command changes: 1. The "Type" byte - TI82/TI85 have different variable types 2. The "Name length" byte - don't exists for the TI82. The name is Zero- terminated (except system variables - see "name/type data for TI82"). After a Var-header have been sent, then the calculator (or computer) waits for a "Received OK"-command and an answer. The answer can be one of the following (the computer sends, TI85 receives and answers) : 85 09 07 00 : Continue (header-datalength: 7 bytes) 85 5A 07 00 : Checksum error, send last package again The two following answers can occur if the variable already exists in memory: 85 36 01 00 02 02 00 : Variable skipped ("Skip" was pressed) 85 36 01 00 01 01 00 : Variable refused ("Exit" was pressed) 85 36 01 00 03 : Out of memory If more than one variable is send, then a "Var-header" command when the reciever (calculator or computer),have acknowledged the datapackage instead of a "No more variables"-command. --------------------------------------------------------------------------- The "Type"-byte for a TI85 can have one of the following values (hex): 00 Real 01 Cplx 02 Vectr 03 Vectr complex 04 List 05 List complex 06 Matrx 07 Matrx complex 08 Const 09 Const complex 0A Equ 0B Range 0C Strng 0D-10 GDB 11 Pict 12 Prgm 13 Range 14 PrtScreen (without Name) !! 15 ? 16 ? 17 Func (range) 18 Pol (range) 19 Param (range) 1A Difeq (range) 1B ZRCL (range) 1C ? 1D Backup (without Name) !! --------------------------------------------------------------------------- Note: The "Send screendump" command can be sent to the TI85/TI82 to download a screendump to the computer. The TI85 will send a "Received Ok"-command and the a datapackage of 1024 bytes (768 bytes for the TI82). The data- package is a copy of the memoryarea $FC00-FFFF (the screen). This works almost anytime (it's not necessary the calculator is in the LINK-menu), but it won't work when a program is running (except if the program is waiting for a key). --------------------------------------------------------------------------- The var type/name data for a TI82 : 00 :Real 01 :List 01 5D 00 00 00 00 00 00 00 = L1 01 5D 01 00 00 00 00 00 00 = L2 01 5D 02 00 00 00 00 00 00 = L3 01 5D 03 00 00 00 00 00 00 = L4 01 5D 04 00 00 00 00 00 00 = L5 02 :Matrix 02 5C 00 00 00 00 00 00 00 = MA 02 5C 01 00 00 00 00 00 00 = MB 02 5C 02 00 00 00 00 00 00 = MC 02 5C 03 00 00 00 00 00 00 = MD 02 5C 04 00 00 00 00 00 00 = ME 03 :Y-Var 03 5E 10 00 00 00 00 00 00 = Y1 03 5E 11 00 00 00 00 00 00 = Y2 03 5E 12 00 00 00 00 00 00 = Y3 03 5E 13 00 00 00 00 00 00 = Y4 03 5E 14 00 00 00 00 00 00 = Y5 03 5E 15 00 00 00 00 00 00 = Y6 03 5E 16 00 00 00 00 00 00 = Y7 03 5E 17 00 00 00 00 00 00 = Y8 03 5E 18 00 00 00 00 00 00 = Y9 03 5E 19 00 00 00 00 00 00 = Y0 03 5E 20 00 00 00 00 00 00 = Xt1 03 5E 21 00 00 00 00 00 00 = Yt1 03 5E 22 00 00 00 00 00 00 = Xt2 03 5E 23 00 00 00 00 00 00 = Yt2 03 5E 24 00 00 00 00 00 00 = Xt3 03 5E 25 00 00 00 00 00 00 = Yt3 03 5E 26 00 00 00 00 00 00 = Xt4 03 5E 27 00 00 00 00 00 00 = Yt4 03 5E 28 00 00 00 00 00 00 = Xt5 03 5E 29 00 00 00 00 00 00 = Yt5 03 5E 2A 00 00 00 00 00 00 = Xt6 03 5E 2B 00 00 00 00 00 00 = Yt6 03 5E 40 00 00 00 00 00 00 = r1 03 5E 41 00 00 00 00 00 00 = r2 03 5E 42 00 00 00 00 00 00 = r3 03 5E 43 00 00 00 00 00 00 = r4 03 5E 44 00 00 00 00 00 00 = r5 03 5E 45 00 00 00 00 00 00 = r6 03 5E 80 00 00 00 00 00 00 = Un 03 5E 81 00 00 00 00 00 00 = Vn 05 :Program 07 :Pic 07 60 00 00 00 00 00 00 00 = Pic1 07 60 01 00 00 00 00 00 00 = Pic2 07 60 02 00 00 00 00 00 00 = Pic3 07 60 03 00 00 00 00 00 00 = Pic4 07 60 04 00 00 00 00 00 00 = Pic5 07 60 05 00 00 00 00 00 00 = Pic6 08 :GDB 08 61 00 00 00 00 00 00 00 = GDB1 08 61 01 00 00 00 00 00 00 = GDB2 08 61 02 00 00 00 00 00 00 = GDB3 08 61 03 00 00 00 00 00 00 = GDB4 08 61 04 00 00 00 00 00 00 = GDB5 08 61 05 00 00 00 00 00 00 = GDB6 0B :WINDW 0B 5E 81 00 00 00 00 00 00 = Window 0C :ZSTO 0C 5E 81 00 00 00 00 00 00 = RclWindow 0D :TABLE 0D 5E 81 00 00 00 00 00 00 = TblSet 0E :PrintScreen 0F :Backup --------------------------------------------------------------------------- "Command-byte" for the TI82 C9 :Variable header for "Send(" Command General Structure : =================== ID Cd Sl Sh [Data Part] Cl Ch ID : 82 or 02 Cd : Command :(06,15,36,56,6D,92,C9) Sl : Size of the data part is: Sh : Size = $100*Sh+Sl Cl : Checksum of the data-part Ch : Checksum = $100*Ch+Cl Example : --------- 02 56 00 00 : Computer -> TI , Package receive ok , no packet 82 56 00 00 : TI -> Computer , Package receive ok , no packet 02 09 00 00 : Computer -> TI , Ready to receive , no packet 82 92 ll hh : TI -> Computer , No more variable, hhll was sent Data part : =========== -> If Cd is 06 or C9 : ---------------------- [..]=Ll Lh Ty {Name = 8 bytes} Ll: Length of the variable Lh: Length = $100*Lh+Ll Ty:Type-Byte The names are always 8 bytes: ABC = 41 42 43 00 00 00 00 00 L1 = 5D 00 00 00 00 00 00 00 Examples : ========== Transmission of PROGRAM:ABC :[A] : : : : From 82 | Command : [here 06=Variable header] | | Size of data part [here = $000B] | | | Size of the variable [here = $0009] | | | | Type [$05=Prgm] | | | | Name and 00 | | | | | | | | | |\_________________ | | |\ | | | | | | | |\ | | | \ | | | | | | | | \ Checksum | | | | | A B C | | | | \ | | | | | | | | TI82 :82 06 0B 00 09 00 05 41 42 43 00 00 00 00 00 D4 00 ___________ Computer: 02 56 00 00 Data part of the variable | Length ___________ ___|_______ | [A] CR CR CR CR CR TI82 :___________ 82 56 00 00 82 15 09 00 07 00 5C 00 3F 3F 3F 3F 3F Computer:02 09 00 00 Checksum | | TI82 :9E 01 82 92 09 00 "Done" Computer: 02 56 00 00 02 56 00 00 END --------------------------------------------------------------------------- Pascal/C procedures to communicate with the TI85/TI82 and a demo program (pascal) to show how to receive a screendump or a variable from a TI85. Note: An interruptroutine should be used when receiving data from a graphlink. The "Receive"-routine can miss data if the smartdrive uses the harddisk while receiving data (for example) ! var GraphLink:Boolean; { True : Graphlink / False : Old black link } ****** Procedure to set/reset RTS/DTR: procedure SetPort(Bits:Byte); { Input: "Bits", a byte 0 - 3, bit 0 = DTR, bit 1 = RTS } begin Port[PortAddr+4]:=Bits and 3; end; ****** Function to read CTS/DSR: function GetPort:Byte; { Returns a byte 0 - 3, bit 0 = CTS, bit 1 = DSR } { if GetPort returns 0, then the calculator have noticed a timeout } var P:Byte; begin P:=(Port[PortAddr+6] and 48) div 16; if P<>(Port[PortAddr+6] and 48) div 16 then P:=(Port[PortAddr+6] and 48) div 16; GetPort:=P; { if KeyPressed then HALT(1); } { Add the line above if you don't add a timeout-check somewhere else. } { The program will probably hang in "GetPort" when the calculator } { causes a Timeout } end; ****** To send a byte to the TI85/TI82: const Bits:array[0..7] of Byte=(1,2,4,8,16,32,64,128); procedure Send(V:Byte); var Q:Byte; begin if GraphLink then begin Q:=Port[PortAddr+5]; while (Q and $40)=0 do Q:=Port[PortAddr+5]; Port[PortAddr]:=V; end else begin Q:=0; repeat if GetPort=3 then begin if (V and Bits[Q])=0 then begin SetPort(1); while ((GetPort and 2)=2) do ; SetPort(3); while ((GetPort and 2)=0) do ; end else begin SetPort(2); while ((GetPort and 1)=1) do ; SetPort(3); while ((GetPort and 1)=0) do ; end; Inc(Q); end; until Q=8; end; end; ****** To recieve a byte from the TI85/TI82: function Receive:Byte; var N,V,P:Byte; begin if GraphLink then begin P:=Port[PortAddr+5]; while (P and 1)=0 do P:=Port[PortAddr+5]; Receive:=Port[PortAddr]; end else begin N:=0; V:=0; repeat P:=GetPort; if P<>3 then begin if P=1 then begin SetPort(1); V:=V or Bits[N]; end; if P=2 then begin SetPort(2); end; while ((GetPort and (3-P))=0) do ; SetPort(3); while ((GetPort and P)=0) do ; Inc(N); if N=8 then begin Receive:=V; Exit; end; end; until false; end; end; ****** Initiates the com-port (MUST be called before anything else) procedure InitPort; var P:Byte; begin Port[PortAddr+4]:=3; { Set 9600 baud 1 stopbit No parity. Needed for the graphlink } Port[PortAddr+3]:=3+128; Port[PortAddr]:=$0C; Port[PortAddr+1]:=$00; Port[PortAddr+3]:=3; SetPort(3); { Clear receive register } P:=Port[PortAddr+5]; while (P and 1)>0 do begin P:=Port[PortAddr]; Delay(1); P:=Port[PortAddr+5]; end; end; ****** C routines /* ============================ */ typedef unsigned char uchar; typedef unsigned int uint; uint port = 0x3f8; /* = COM1, 0x2f8 for COM2 */ /* ============================ */ void setport(uchar bits) { outportb(port + 4, bits & 3); /* simple enuf to write inline code */ } /* ============================ */ uchar getport(void) { uchar b; b = inportb(port + 6) / 16 & 3; /* if (kbhit()) exit(1); */ return b; } /* ============================ */ void send(uchar b) { uchar bits; for (bits = 1; bits <= 8; bits++) { if (b & 1) outportb(port + 4,2); else outportb(port + 4,1); while (getport() != 0); outportb(port + 4,3); while (getport() != 3); b >>= 1; } } /* ============================ */ uchar recvbyt(void) { uchar curbit = 1; uchar byt = 0, bits, x; for (bits = 1; bits <= 8; bits++) { while ((x = getport()) == 3); if (x == 1) { byt += curbit; outportb(port + 4,1); x = 2; } else { outportb(port + 4,2); x = 1; } while ((getport() & x) == 0); outportb(port + 4,3); curbit <<= 1; } return byt; } /* ============================ */ /* init port: I've found that this is enough */ outportb(port + 4,3); *** Demo program to show how to receive vars/screendumps for the TI85 *** begin 644 link.zip M4$L#!!0````(`$^(*2!)\6"M/V\H2 M_X[$_S"B2'&*H;;S:`AUI3:4%!T.!,BA5%4^;.P-\<&QH_4:&J'^[V=G[?4C M<1*J>Z[NM038.X^=F9W?[.PR9^$#(S,8THA?>,'CR>[.[LX+G-)9"(K&0XBF MX3/@CWB/(PI\2L$7[(+%H6[,:`2_4&X2,DD;GG=:1_"J1\KUPOF">0]3#@/* MX,P+2."*%_/XN+5!;G='V!)!GY'Y5.\Q+HUWPB#BNSO(\MGC49I2_(FP1-B9AXRKR;K@3`D[22@_ M]87NY93GD+DIY6^=T]D\H^!<*67@.5R$25$RHTS#:AR81F::8B?.(^6PPFX) M]N-EYKZK]V>Y/5[`Z0-E)4T7-'C@4ST9ZDVI\QC%L_1S(/S\Y+HL%?^6NR,# MBUF1NA.&/B7!";S`D,54C$@&S`-X!V?$CW#LRG=A[(M998(DR_0";^4#`Y4O M,JDH?\>H^`TWP]MWI\.;;L(-65;!+>5HGB97$EW&11+SGP?SF'=A#\?W="`P M%C0PX!`:.HP]+EYM$!J3#U-\B"E2[6/ZX`72053]0[E_T!QU;=0')'"A@?/0 MP#TIF7\6!P[WP@"M9Y2XT$/#;S/#)XH._<3PKEJF%[BA/&9!M,96H2BW56A$ MA4+(FRA-8KY$WM`188&$F4-\)_8)#QE,R1.%(.2>B)R8@WLS&L8\M2M+ZH$R MJ!R'KJV58]$>R2@T.W5PO2J5G%RQYD,_U!%P-& MHTCX(QW^^NEBJ)GUA/X"0ILJ0Q3(.!3N"Z%%&(,;!C4.Q"W$X=#!G(E2U>_9\'S_&9.PO1%B#!_`"V$L-W(/GBN"G]4CJM\1?,%E?'+T2O# M5Z1*.;N\,*W124Y]GGH^!>U:KM5^TZC;A@CK%J$2:=2U[Q0-'<6`5]A@%.09 MG5/"\V_E1Q)YNU'I1\ZGW4EK$<(_KD=H\09^\:C:HE)JZ4E#H"G\H6ZK;EMU M#$2EA%+8^"V%QAJ%ZX*V.I_U^OG,NFW^JPZ8&QU8'3P/'.UZ67V9,PZXY\.U MW2FDCWBM@A"CCD>?J$+1A(6S2AQE=?F&.M1[HCEF%(PN]3N]4!Q_"TJ#UT!I MD(4+H[591%E9YAEM@]-E&4YW6]$EK$C7LKP@29G?A#?DL,W-`-N,+V'='80L M@>MET?OUV2-GM5XW:P4HJE16Y;36.!S4U^;U!I!4*1NL5810N%Q5(IR\M#N; MGDL+6N5\%>@FV,-M@=UYX'&/%JL]90EK[@HL!QVS!@3&(7 M3(AX.,=NZC*$.6$>7Z3;\[*:!JHY,*VLUBSO8?M&KY)T8$JB44UL%*U;39@7 MZ/F4,"Q?N(SB[X,7<7AZ5R\E&6DRT%J8BN4^J311F3&V8KYT"I(7$8 MI<%I/)L75RIS.7"U?:-5/RD-M-VE`<.H',C"E.8YF(;5/#`-6>4CZ&8<`/N= M%NRWVB`DY<^'0[AZ+%/-5DIM(O64<((YP7'`4"HUG*&>R:G3FF06CY!+AW+5 M]_?R1SV"19VKTJ8;'SP/WW>Q%0DA/>I5K-WNLUJ.EOS%*!2:?_ M<3_JVFE4RFN4Q>S4B^9BB24ZYZD?F"O/Q./2'@*/=%&PL>]V[6.EK#_KVA:> M\.[ZGZ#=-.`G-#L&-O5.Z(/_5:+3-7;9@W-(I]_N%C=2,F MG;X(M%J/!$$H3/.$D5_ZG\3$1Y_[Y[6B]U^)7]Q'2AZ70FR]%^%5>E,HI8.8#[R?U-?N M]>^ZV:JV\I;R'@8PJ0+IX(474,U(KQ_$GTQ4$G#,*%#RZ-Y0XOY!%_:;-+*K M0TI1SP\C*A=#C'Q)#2>1755D00/^#J M\5>)UFK_5N%-ZE'MJXR^VJ5<'0(RPQN>O6+(TX@TL1U/'6Z,#F0J)&IZ4Z9E MD:AGTV8+6=*VZ@HFQ"*Y;TGV`LQ!6;_++AK'O^7BC6@J:B>=F"HQ7^ M+8BJ<#I+T[QO4'C8G+?_(03_A_GYWRDG,H9A0)/=(^\HRXVC:D&[]KYUUL$^ M9+]QUK%[5W^:.N`0OEJ96]FYO&O+ZV<4^"NB$/JNO`9G$^)0'?='CA?6A_)_ M%_FE]:]"VX0GB'B>GV>*?4[QA/P"WU0C)3LLY.4A_GL@>*#P1'PQCY)-TZDZ M&/)NLROS_XUIZ#7S2'6[D6RMW7@VSZE61B5XF^N1,9X"L&\:$^