Important:
This project is outdated. See ArTICL: Arduino TI Calculator Linking Library for the new, better, more understandable library.

I wrote these a few months ago for my Arduino to TI-84+ linking project; I thought they might be useful to others. You basically call resetLines() at the beginning of the program, then par_put and par_get as necessary. Note that these of course use the TI-OS protocol, so you can use them for remote control, program injection, screenshot fetching, and all that fun stuff.




Code:
void resetLines();
static int par_put(uint8_t *data, uint32_t len);
static int par_get(uint8_t *data, uint32_t len);
#define TIwhite TIring
#define TIred TItip
#define ERR_READ_TIMEOUT 1000
#define ERR_WRITE_TIMEOUT 2000
#define TIMEOUT 4000
#define GET_ENTER_TIMEOUT 30000

void resetLines() {
   pinMode(TIring, INPUT);           // set pin to input
   digitalWrite(TIring, HIGH);       // turn on pullup resistors
   pinMode(TItip, INPUT);            // set pin to input
   digitalWrite(TItip, HIGH);        // turn on pullup resistors
}
static int par_put(uint8_t *data, uint32_t len) {
   int bit;
   int i, j;
   long previousMillis = 0;
   uint8_t byte;   

   for(j=0;j<len;j++) {
      byte = data[j];
      for (bit = 0; bit < 8; bit++) {
         previousMillis = 0;
         while ((digitalRead(TIring)<<1 | digitalRead(TItip)) != 0x03) {
            if (previousMillis++ > TIMEOUT)
               return ERR_WRITE_TIMEOUT+j+100*bit;
         };
         if (byte & 1) {
            pinMode(TIring,OUTPUT);
            digitalWrite(TIring,LOW);
            previousMillis = 0;
            while (digitalRead(TItip) == HIGH) {
               if (previousMillis++ > TIMEOUT)
                  return ERR_WRITE_TIMEOUT+10+j+100*bit;
            };

            resetLines();
            previousMillis = 0;
            while (digitalRead(TItip) == LOW) {
               if (previousMillis++ > TIMEOUT)
                  return ERR_WRITE_TIMEOUT+20+j+100*bit;
            };
         } else {
            pinMode(TItip,OUTPUT);
            digitalWrite(TItip,LOW);      //should already be set because of the pullup resistor register
            previousMillis = 0;
            while (digitalRead(TIring) == HIGH) {
               if (previousMillis++ > TIMEOUT)
                  return ERR_WRITE_TIMEOUT+30+j+100*bit;
            };

            resetLines();
            previousMillis = 0;
            while (digitalRead(TIring) == LOW) {
               if (previousMillis++ > TIMEOUT)
                  return ERR_WRITE_TIMEOUT+40+j+100*bit;
            };
         }
         byte >>= 1;
      }
      //delayMicroseconds(6);
   }
   return 0;
}

static int par_get(uint8_t *data, uint32_t len) {
   int bit;
   int i, j;
   long previousMillis = 0;

   for(j = 0; j < len; j++) {
      uint8_t v, byteout = 0;
      for (bit = 0; bit < 8; bit++) {
         previousMillis = 0;
         while ((v = (digitalRead(TIring)<<1 | digitalRead(TItip))) == 0x03) {
            if (previousMillis++ > GET_ENTER_TIMEOUT)
               return ERR_READ_TIMEOUT+j+100*bit;
         }
         if (v == 0x01) {
            byteout = (byteout >> 1) | 0x80;
            pinMode(TItip,OUTPUT);
            digitalWrite(TItip,LOW);      //should already be set because of the pullup resistor register
            previousMillis = 0;
            while (digitalRead(TIring) == LOW) {            //wait for the other one to go low
               if (previousMillis++ > TIMEOUT)
                  return ERR_READ_TIMEOUT+10+j+100*bit;
            }
            //pinMode(TIring,OUTPUT);
            digitalWrite(TIring,HIGH);
         } else {
            byteout = (byteout >> 1) & 0x7F;
            pinMode(TIring,OUTPUT);
            digitalWrite(TIring,LOW);      //should already be set because of the pullup resistor register
            previousMillis = 0;
            while (digitalRead(TItip) == LOW) {
               if (previousMillis++ > TIMEOUT)
                  return ERR_READ_TIMEOUT+20+j+100*bit;
            }
            //pinMode(TItip,OUTPUT);
            digitalWrite(TItip,HIGH);
         }
         pinMode(TIring, INPUT);           // set pin to input
         digitalWrite(TIring, HIGH);       // turn on pullup resistors
         pinMode(TItip, INPUT);            // set pin to input
         digitalWrite(TItip, HIGH);        // turn on pullup resistors
      }
      data[j] = byteout;
      //delayMicroseconds(6);
   }
   return 0;
}
AWESOME!!
Would you be able to explain what the code calc-side should look like?
merthsoft wrote:
Would you be able to explain what the code calc-side should look like?
An excellent question. First of all, this can be used out-of-the-box for things like remote-controlling a calculator with injected keypresses, taking remote screenshots, and just about everything on this page from the File Format/Link Protocol Guide. Of course, if you're using it to chat with a user program, I like to recommend that you use CALCnet instead, but with the Rec1stByte and SendAByte bcalls, you can indeed interface with these routines. Both routines use the accumulator for the byte to send or receive and use the TI-OS error system if something goes wrong.
Ah, right. It's the whole silent linking thing, right? So you can just send it commands and the OS will handle things. Good to know about the Rec1stByte and SendAByte bcalls, though. Thanks!
Is there any difference between the TI-83 Linking protocol and TI-89t Linking protocol? I'm asking because I'd like to control a couple of servos using my calculator, which is the only I have in my possession.
CharlieMAC wrote:
Is there any difference between the TI-83 Linking protocol and TI-89t Linking protocol? I'm asking because I'd like to control a couple of servos using my calculator, which is the only I have in my possession.
The bottom two or three layers (if you subscribe to the OSI model) are the same: bytes and bits and the physical connection are the same, other than some voltage-leveling quirks.
Hi.
I'm not very good at electronics and stuff so...
How should I connect the calculator? I have some simple 2,5 mm to 3,5 mm audio cables (which are usable to connect two TI-83 calcs), but I don't have any official cables.
What wires do I have to connect to the Arduino?
Also, How can I send a command?

I tried this, but it's probably wrong.

uint8_t command [4] = {0x23,0x87,0xA6,0x00};
par_put(command, 4);
bartjakobs wrote:
Hi.
I'm not very good at electronics and stuff so...
How should I connect the calculator? I have some simple 2,5 mm to 3,5 mm audio cables (which are usable to connect two TI-83 calcs), but I don't have any official cables.
What wires do I have to connect to the Arduino?
Also, How can I send a command?

I tried this, but it's probably wrong.

uint8_t command [4] = {0x23,0x87,0xA6,0x00};
par_put(command, 4);
Welcome to Cemetech! You should Introduce Yourself if you get a change. That code is exactly right, as long as you have resetLines() at the beginning of your program somewhere. Ground should go to ground, and the two signal lines should go to GPIO pins on the Arduino. You get to define that yourself:


Code:
#define TIring <pin number>
#define TItip <pin number>
Thank you SO much for finally releasing this code. So much more helpful this way. But I can't just use the Omnicalc linking commands... I'm reading your other links that your pointed out to see how my particular calc-side needs to be. Also, I'll need to add in some stuff that interprets the html for me, but this is going to help a lot!
I released this over a year and a half ago; look at the date on the first post. What are you talking about with HTML? Why not just use CALCnet and Gossamer?
So if i for example wanted to send the keypress "A" to my TI, would this work:


Code:

uint8_t A [4] = {0x23,0x15,0x41,0x00};
par_put(A, 4);

?
lyron wrote:
So if i for example wanted to send the keypress "A" to my TI, would this work:


Code:

uint8_t A [4] = {0x23,0x15,0x41,0x00};
par_put(A, 4);

?
Welcome to Cemetech! A capital 'A' is 0x9A instead of 0x41 according to this list of keycodes, but other than that, yes. By the way, be sure to Introduce Yourself when you get a chance.
KermMartian wrote:

A capital 'A' is 0x9A instead of 0x41 according to this list of keycodes, but other than that, yes.


Okay, now i'm using this code:

Code:
/*
TI 84+ control script
By Niek Blankers

With thanks to Kerm Martian for the par_get and par_put code
*/

void resetLines();
static int par_put(uint8_t *data, uint32_t len);
static int par_get(uint8_t *data, uint32_t len);
#define TIring 7 //White
#define TItip 8 //Red
#define ERR_READ_TIMEOUT 1000
#define ERR_WRITE_TIMEOUT 2000
#define TIMEOUT 4000
#define GET_ENTER_TIMEOUT 30000

void setup(){
resetLines();

}

void loop(){
uint8_t A [4] = {0x23,0x15,0x41,0x00};  //packet for sending capital A
par_put(A, 4); //send the packet
delay(2000);
}



//TI LINK PROTOCOL CODE
void resetLines() {
   pinMode(TIring, INPUT);           // set pin to input
   digitalWrite(TIring, HIGH);       // turn on pullup resistors
   pinMode(TItip, INPUT);            // set pin to input
   digitalWrite(TItip, HIGH);        // turn on pullup resistors
}
static int par_put(uint8_t *data, uint32_t len) {
   int bit;
   int i, j;
   long previousMillis = 0;
   uint8_t byte;   

   for(j=0;j<len;j++) {
      byte = data[j];
      for (bit = 0; bit < 8; bit++) {
         previousMillis = 0;
         while ((digitalRead(TIring)<<1 | digitalRead(TItip)) != 0x03) {
            if (previousMillis++ > TIMEOUT)
               return ERR_WRITE_TIMEOUT+j+100*bit;
         };
         if (byte & 1) {
            pinMode(TIring,OUTPUT);
            digitalWrite(TIring,LOW);
            previousMillis = 0;
            while (digitalRead(TItip) == HIGH) {
               if (previousMillis++ > TIMEOUT)
                  return ERR_WRITE_TIMEOUT+10+j+100*bit;
            };

            resetLines();
            previousMillis = 0;
            while (digitalRead(TItip) == LOW) {
               if (previousMillis++ > TIMEOUT)
                  return ERR_WRITE_TIMEOUT+20+j+100*bit;
            };
         } else {
            pinMode(TItip,OUTPUT);
            digitalWrite(TItip,LOW);      //should already be set because of the pullup resistor register
            previousMillis = 0;
            while (digitalRead(TIring) == HIGH) {
               if (previousMillis++ > TIMEOUT)
                  return ERR_WRITE_TIMEOUT+30+j+100*bit;
            };

            resetLines();
            previousMillis = 0;
            while (digitalRead(TIring) == LOW) {
               if (previousMillis++ > TIMEOUT)
                  return ERR_WRITE_TIMEOUT+40+j+100*bit;
            };
         }
         byte >>= 1;
      }
      //delayMicroseconds(6);
   }
   return 0;
}

static int par_get(uint8_t *data, uint32_t len) {
   int bit;
   int i, j;
   long previousMillis = 0;

   for(j = 0; j < len; j++) {
      uint8_t v, byteout = 0;
      for (bit = 0; bit < 8; bit++) {
         previousMillis = 0;
         while ((v = (digitalRead(TIring)<<1 | digitalRead(TItip))) == 0x03) {
            if (previousMillis++ > GET_ENTER_TIMEOUT)
               return ERR_READ_TIMEOUT+j+100*bit;
         }
         if (v == 0x01) {
            byteout = (byteout >> 1) | 0x80;
            pinMode(TItip,OUTPUT);
            digitalWrite(TItip,LOW);      //should already be set because of the pullup resistor register
            previousMillis = 0;
            while (digitalRead(TIring) == LOW) {            //wait for the other one to go low
               if (previousMillis++ > TIMEOUT)
                  return ERR_READ_TIMEOUT+10+j+100*bit;
            }
            //pinMode(TIring,OUTPUT);
            digitalWrite(TIring,HIGH);
         } else {
            byteout = (byteout >> 1) & 0x7F;
            pinMode(TIring,OUTPUT);
            digitalWrite(TIring,LOW);      //should already be set because of the pullup resistor register
            previousMillis = 0;
            while (digitalRead(TItip) == LOW) {
               if (previousMillis++ > TIMEOUT)
                  return ERR_READ_TIMEOUT+20+j+100*bit;
            }
            //pinMode(TItip,OUTPUT);
            digitalWrite(TItip,HIGH);
         }
         pinMode(TIring, INPUT);           // set pin to input
         digitalWrite(TIring, HIGH);       // turn on pullup resistors
         pinMode(TItip, INPUT);            // set pin to input
         digitalWrite(TItip, HIGH);        // turn on pullup resistors
      }
      data[j] = byteout;
      //delayMicroseconds(6);
   }
   return 0;
}


And hooked everything up but it doesn't do anything Sad [/code]
How do you have the calculator's link port connected to the Arduino?
KermMartian wrote:
How do you have the calculator's link port connected to the Arduino?


I purchased a 2.5mm jack and soldered some wires to the correct terminals.
lyron wrote:
KermMartian wrote:
How do you have the calculator's link port connected to the Arduino?


I purchased a 2.5mm jack and soldered some wires to the correct terminals.
And it's a stereo (3-conductor) jack? Are you sure you have the two signal pins on the right Arduino pins, and the ground to ground? Does the calculator's cursor change at all?
KermMartian wrote:
lyron wrote:
KermMartian wrote:
How do you have the calculator's link port connected to the Arduino?


I purchased a 2.5mm jack and soldered some wires to the correct terminals.
And it's a stereo (3-conductor) jack? Are you sure you have the two signal pins on the right Arduino pins, and the ground to ground? Does the calculator's cursor change at all?


Here's a photo:


The cursor does not move at all.

Tari: resized huge image
Could anybody else try my code?
lyron wrote:
Could anybody else try my code?
I can try it later; I need to get my Arduino from my office. Make sure that the plug is flush into your calculator's port, by the way. Do you have a TI-83+/SE or a TI-84+/SE? If the latter, regular 2.5mm plugs sometimes have too wide of a flange (the metal disc below the plug) to fully mate into the socket.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 4
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement