I am happy to say that I believe I have figured out the issue. I am providing an explanation as well as the modified code at the bottom.
Explanation
Since the TI 84+ CSE was able to utilize Get( without any issues, while the TI-84+ could not, I decided to enable verbosity in HelloWorld. This was done by simply uncommenting the following code inside the eventLoopTick function:
Code: //cbl.setVerbosity(true, &Serial); // Comment this in for message information
With verbosity enabled, I decided to comment the two serial print lines in CBL2.cpp to make the serial output less cluttered
Code:
// See if there's a message coming
rval = get(msg_header, data_, &length, maxlength_, quick_fail ? TIMEOUT : GET_ENTER_TIMEOUT);
if (rval) {
if (serial_) {
//serial_->print("No msg: code ");
//serial_->println(rval);
}
return 0; // No message coming
}
I also commented the serial print call in the getByte function of TICL.cpp
Code:
previousMicros = micros();
while ((linevals = ((digitalRead(ring_) << 1) | digitalRead(tip_))) == 0x03) {
if (micros() - previousMicros > timeout) {
resetLines();
if (serial_) {
//serial_->print("died waiting for bit "); serial_->println(bit);
}
return ERR_READ_ENTER_TIMEOUT;
}
}
Now when I compared the serial output from utilizing both of the calculators. The first thing I noticed was that The TI-84+ had a shorter output of 46 lines, compared to the CSE's 90 lines of output. After analyzing the output from sending different message to both calculators. I began noticing a couple things.
1. The portion I highlighted in blue would always remain the same except for the bytes on lines 7 and 9 depending on the calculator. It appears that this information is utilized for sending to the calculator.
2. After several tests, I noticed that in the red portion, the TI 84+ was always short by 4 compared to the CSE. On line 33, I noticed that the CSE always sent a byte of 4 while the for the normal calculator it was always zero. This can also be noticed in the blue portion as well. The Arduino always gets a byte of 4 for the CSE but 0 for the TI-84+ on line 9.
Aside from those differences, the outputs were virtually the same. At this point, I needed to change to correct the bytes so that the output would like the CSE output. I added a counter to the code to see how many times bytes were sent with TICL::sendbyte() This picture shows that shows that. https://i.imgur.com/UBsBXct.png
After taking note of when byte 4 was supposed to be sent, I adjusted the code to send it it as well as add 4 to the total byte. All changes take place in TICL.cpp.
These 2 lines are declared at the top:
Code:
int bytePosition;
boolean needsRepair = false;
The following code goes right at the start of TICL:sendByte():
Code:
if(bytePosition == 10 && byte == 0){
byte = 4;
needsRepair = true;
}
if(bytePosition == 21 && needsRepair){
byte += 4;
}
bytePosition += 1;
and finally, the following is placed inside TICL:get() right after datalength is set.
Code:
if(header[1] == 86 && header[0] == 130){
// Recv typ 0x56 from EP 0x82
needsRepair = false;
bytePosition = 0;
}
This is the final code edit:
Code:
/*************************************************
* TICL.cpp - Core of ArTICL library for linking *
* TI calculators and Arduinos. *
* Created by Christopher Mitchell, *
* 2011-2019, all rights reserved. *
*************************************************/
#include "Arduino.h"
#include "TICL.h"
int bytePosition;
boolean needsRepair = false;
// Constructor with default communication lines
TICL::TICL() {
setLines(DEFAULT_TIP, DEFAULT_RING);
serial_ = NULL;
}
// Constructor with custom communication lines. Fun
// fact: You can use this and multiple TICL objects to
// talk to multiple endpoints at the same time.
TICL::TICL(int tip, int ring) {
setLines(tip, ring);
serial_ = NULL;
}
// This should be called during the setup() function
// to set the communication lines to their initial values
void TICL::begin() {
resetLines();
}
// Determine whether debug printing is enabled
void TICL::setVerbosity(bool verbose, HardwareSerial* serial) {
if (verbose) {
serial_ = serial;
} else {
serial_ = NULL;
}
}
// Change the lines after construction
void TICL::setLines(int tip, int ring) {
tip_ = tip;
ring_ = ring;
}
// Send an entire message from the Arduino to
// the attached TI device, byte by byte
int TICL::send(uint8_t* header, uint8_t* data, int datalength, uint8_t(*data_callback)(int)) {
if (serial_) {
serial_->print("snd type 0x");
serial_->print(header[1], HEX);
serial_->print(" as EP 0x");
serial_->print(header[0], HEX);
serial_->print(" len ");
serial_->println(datalength);
}
// Send all of the bytes in the header
for(int idx = 0; idx < 4; idx++) {
int rval = sendByte(header[idx]);
if (rval != 0) {
return rval;
}
}
// If no data, we're done
if (datalength == 0) {
return 0;
}
// These also indicate that there are
// no data bytes to be sent
if (header[1] == CTS ||
header[1] == VER ||
header[1] == ACK ||
header[1] == ERR ||
header[1] == RDY ||
header[1] == SCR ||
header[1] == KEY ||
header[1] == EOT)
{
return 0;
}
// Send all of the bytes in the data buffer
uint16_t checksum = 0;
for(int idx = 0; idx < datalength; idx++) {
uint8_t outbyte;
// Get a byte if we need
if (data_callback != NULL) {
outbyte = data_callback(idx);
} else {
outbyte = data[idx];
}
// Try to send this byte
int rval = sendByte(outbyte);
if (rval != 0) {
return rval;
}
checksum += outbyte;
}
// Send the checksum
int rval = sendByte(checksum & 0x00ff);
if (rval != 0) {
return rval;
}
rval = sendByte((checksum >> 8) & 0x00ff);
return rval;
}
// Send a single byte from the Arduino to the attached
// TI device, returning nonzero if a failure occurred.
int TICL::sendByte(uint8_t byte) {
unsigned long previousMicros;
if (serial_) {
if(bytePosition == 10 && byte == 0){
byte = 4;
needsRepair = true;
}
if(bytePosition == 21 && needsRepair){
byte += 4;
}
bytePosition += 1;
serial_->print("["); serial_->print(bytePosition); serial_->print("]");
serial_->print("Sending byte ");
serial_->println(byte);
}
// Send all of the bits in this byte
for(int bit = 0; bit < 8; bit++) {
// Wait for both lines to be high before sending the bit
previousMicros = micros();
while (digitalRead(ring_) == LOW || digitalRead(tip_) == LOW) {
if (micros() - previousMicros > TIMEOUT) {
resetLines();
return ERR_WRITE_TIMEOUT;
}
}
// Pull one line low to indicate a new bit is going out
bool bitval = (byte & 1);
int line = (bitval)?ring_:tip_;
pinMode(line, OUTPUT);
digitalWrite(line, LOW);
// Wait for peer to acknowledge by pulling opposite line low
line = (bitval)?tip_:ring_;
previousMicros = micros();
while (digitalRead(line) == HIGH) {
if (micros() - previousMicros > TIMEOUT) {
resetLines();
return ERR_WRITE_TIMEOUT;
}
}
// Wait for peer to indicate readiness by releasing that line
resetLines();
previousMicros = micros();
while (digitalRead(line) == LOW) {
if (micros() - previousMicros > TIMEOUT) {
resetLines();
return ERR_WRITE_TIMEOUT;
}
}
resetLines();
// Rotate the next bit to send into the low bit of the byte
byte >>= 1;
}
return 0;
}
// Returns 0 for a successfully-read message or non-zero
// for failure. If return value is 0 and datalength is zero,
// then the message is just a 4-byte message in the header
// buffer. If the
int TICL::get(uint8_t* header, uint8_t* data, int* datalength,
int maxlength, int timeout)
{
int rval;
// Get the 4-byte header: sender, message, length
for(int idx = 0; idx < 4; idx++) {
rval = getByte(&header[idx], timeout);
if (rval) {
return rval;
}
}
*datalength = (int)header[2] | ((int)header[3] << 8);
if (serial_) {
serial_->print("Recv typ 0x");
serial_->print(header[1], HEX);
serial_->print(" from EP 0x");
serial_->print(header[0], HEX);
serial_->print(" len ");
serial_->println(*datalength);
}
if(header[1] == 86 && header[0] == 130){
// Recv typ 0x56 from EP 0x82
needsRepair = false;
bytePosition = 0;
}
if (*datalength == 0) {
return 0;
}
// These also indicate that there are
// no data bytes to be received
if (header[1] == CTS ||
header[1] == VER ||
header[1] == ACK ||
header[1] == ERR ||
header[1] == RDY ||
header[1] == SCR ||
header[1] == KEY ||
header[1] == EOT)
{
return 0;
}
// Check if this is a data-free message
if (*datalength > maxlength) {
if (serial_) {
serial_->print("Msg buf ovfl: ");
serial_->print(*datalength);
serial_->print(" > ");
serial_->println(maxlength);
}
return ERR_BUFFER_OVERFLOW;
}
// Get the data bytes, if there are any.
uint16_t checksum = 0;
for(int idx = 0; idx < *datalength; idx++) {
// Try to get all the bytes, or fail if any of the
// individual byte reads fail
rval = getByte(&data[idx]);
if (rval != 0) {
return rval;
}
// Update checksum
checksum += data[idx];
}
// Receive and check the checksum
uint8_t recv_checksum[2];
for(int idx = 0; idx < 2; idx++) {
rval = getByte(&recv_checksum[idx]);
if (rval)
return rval;
}
// Die on a bad checksum
if (checksum !=
(uint16_t)(((int)recv_checksum[1] << 8) | (int)recv_checksum[0]))
{
return ERR_BAD_CHECKSUM;
}
return 0;
}
// Receive a single byte from the attached TI device,
// returning nonzero if a failure occurred.
int TICL::getByte(uint8_t* byte, int timeout) {
unsigned long previousMicros = 0;
*byte = 0;
// Pull down each bit and store it
for (int bit = 0; bit < 8; bit++) {
int linevals;
previousMicros = micros();
while ((linevals = ((digitalRead(ring_) << 1) | digitalRead(tip_))) == 0x03) {
if (micros() - previousMicros > timeout) {
resetLines();
if (serial_) {
//serial_->print("died waiting for bit "); serial_->println(bit);
}
return ERR_READ_ENTER_TIMEOUT;
}
}
// Store the bit, then acknowledge it
*byte = (*byte >> 1) | ((linevals == 0x01)?0x80:0x00);
int line = (linevals == 0x01)?tip_:ring_;
pinMode(line, OUTPUT);
digitalWrite(line, LOW);
// Wait for the peer to indicate readiness
line = (linevals == 0x01)?ring_:tip_;
previousMicros = micros();
while (digitalRead(line) == LOW) { //wait for the other one to go high again
if (micros() - previousMicros > TIMEOUT) {
resetLines();
if (serial_) {
serial_->print("died waiting for bit ack "); serial_->println(bit);
}
return ERR_READ_TIMEOUT;
}
}
// Now set them both high and to input
resetLines();
}
if (serial_) {
serial_->print("Got byte ");
serial_->println(*byte);
}
return 0;
}
void TICL::resetLines(void) {
pinMode(ring_, INPUT_PULLUP); // set pin to input with pullups
pinMode(tip_, INPUT_PULLUP); // set pin to input with pullups
}
Hopefully someone can come up with a more sophisticated fix but these changes don't seem to cause any issues.
Users in these two threads had the same issue:
https://www.cemetech.net/forum/viewtopic.php?t=13880
https://cemetech.net/forum/viewtopic.php?t=16165