I have access to ones at school that I could test his code on my 86 with, though the PC link they use is rather buggy so saving or uploading logs would be a bit difficult.
I don't have an oscilloscope. I sure wish I did!
I could try using LINE IN on my soundcard as a poor man's oscilloscope. At a 48KHz (or 96KHz if my soundcard supports it) sample rate I could at least see the overall frame timings and where the bytes start and end, and possibly make out some of the bits too. The bit-level protocol is cutting it close at 48KHz.
I'll see what I can do tomorrow. I need to get some sleep tonight.
I could try using LINE IN on my soundcard as a poor man's oscilloscope. At a 48KHz (or 96KHz if my soundcard supports it) sample rate I could at least see the overall frame timings and where the bytes start and end, and possibly make out some of the bits too. The bit-level protocol is cutting it close at 48KHz.
I'll see what I can do tomorrow. I need to get some sleep tonight.
Yeah, like Jonimus, saving and uploading data from the oscilloscope is a problem with the oscilloscopes I have access to at work, AFAICT.
Christop, if you do, make sure you put some isolation circuitry first so you don't destroy your sound card.
Pah, isolation circuitry! The linkport is only ~5 volts, and it's not grounded at all so it's already "floating" (I wouldn't plug it into my soundcard if I'm using a 5V wallwort to power the calc). Heck, I've plugged in more "dangerous" sources into my soundcard than this.
Anyway, I captured some waveforms for testcn2.86p last night, and it appears that it sends the jamming signal for about 10.3ms, releases clock for about 230us, and then pulls down both lines for 125us for the byte guard (phase 3 of the byte-level protocol), but after that both clock and data are high for about 6.6ms, after which it starts the jamming phase for the next frame. Somehow it's not sending the bytes properly, or at all. I'll look into this today if I can.
Anyway, I captured some waveforms for testcn2.86p last night, and it appears that it sends the jamming signal for about 10.3ms, releases clock for about 230us, and then pulls down both lines for 125us for the byte guard (phase 3 of the byte-level protocol), but after that both clock and data are high for about 6.6ms, after which it starts the jamming phase for the next frame. Somehow it's not sending the bytes properly, or at all. I'll look into this today if I can.
Sounds great, glad you were able to make some progress towards debugging. On IRC I offered to send you and Lionel the reference z80 implementation if you want to take a look; let me know.
I increased the delays so I could see all of the link port transitions on my soundcard oscilloscope. I can see each bit being sent now, and it looks perfect, except I sent the payload length with the high bit set (whoops!). Let me fix that issue and then I'll upload a new version for someone to test.
By the way, in which order are the bits sent in each byte? The whitepaper is a little confusing on that point:
I chose to send the MSb first. Is that correct?
If it needs to be MSb first, then I think that's another problem with Lionel's code. He has a ror.b instruction which pushes the least-significant bit from the byte into the carry flag (and the comment above the ror.b disagrees with the instruction ).
By the way, in which order are the bits sent in each byte? The whitepaper is a little confusing on that point:
Quote:
An important note: although to function
correctly, the routine that CALCnet2.2 implements to transmit reverses the byte to be sent, the
most significant bit (MSB) of the byte is sent first, and the LSB last.
correctly, the routine that CALCnet2.2 implements to transmit reverses the byte to be sent, the
most significant bit (MSB) of the byte is sent first, and the LSB last.
I chose to send the MSb first. Is that correct?
If it needs to be MSb first, then I think that's another problem with Lionel's code. He has a ror.b instruction which pushes the least-significant bit from the byte into the carry flag (and the comment above the ror.b disagrees with the instruction ).
Right, definitely looks like an error in my code (since the MSB is supposed to be sent first, I remember asking for confirmation), well spotted
Fixing it does not enable the 84+SE to detect the 89T, however...
If you have the sound card set up as an oscilloscope and the adapter (which I don't have at the moment, although I have the items scattered in various places), maybe you'll be able to help with debugging the TI-68k version before I get the output from the oscilloscopes at work (I talked about it with a teacher colleague before leaving for today)
Fixing it does not enable the 84+SE to detect the 89T, however...
If you have the sound card set up as an oscilloscope and the adapter (which I don't have at the moment, although I have the items scattered in various places), maybe you'll be able to help with debugging the TI-68k version before I get the output from the oscilloscopes at work (I talked about it with a teacher colleague before leaving for today)
It us indeed highest bit first. The link port port data bit on the TI-83 series is in a low bit, which is why I mention that I flip the byte and then rotate right one bit at a time.
Lionel Debroux wrote:
Right, definitely looks like an error in my code (since the MSB is supposed to be sent first, I remember asking for confirmation), well spotted
Fixing it does not enable the 84+SE to detect the 89T, however...
If you have the sound card set up as an oscilloscope and the adapter (which I don't have at the moment, although I have the items scattered in various places), maybe you'll be able to help with debugging the TI-68k version before I get the output from the oscilloscopes at work (I talked about it with a teacher colleague before leaving for today)
Fixing it does not enable the 84+SE to detect the 89T, however...
If you have the sound card set up as an oscilloscope and the adapter (which I don't have at the moment, although I have the items scattered in various places), maybe you'll be able to help with debugging the TI-68k version before I get the output from the oscilloscopes at work (I talked about it with a teacher colleague before leaving for today)
I ran your code in TiEmu, and it crashes with an Address Error (black bar on the top) when I press any key to quit. It does this on the TI-89 and TI-92+. I have the latest OS from the TI site (2.09). I'm a little hesitant to put it on my real 92+ if it's going to crash every time like that.
What adapter are your referring to? If you mean an adapter cable to plug the calculator into the soundcard, I actually just have a 3.5mm stereo cable plugged into the soundcard, my TI link cable plugged into the TI-86, and 3 alligator clip cables connecting the two. Yay alligator clips!
KermMartian wrote:
It us indeed highest bit first. The link port port data bit on the TI-83 series is in a low bit, which is why I mention that I flip the byte and then rotate right one bit at a time.
Thanks for confirming. So flipping the byte was just an implementation detail as a kind of optimization, then?
Quote:
I ran your code in TiEmu, and it crashes with an Address Error (black bar on the top) when I press any key to quit. It does this on the TI-89 and TI-92+. I have the latest OS from the TI site (2.09). I'm a little hesitant to put it on my real 92+ if it's going to crash every time like that.
Oh, really ? It has never crashed here, either on TIEmu or the real 89T HW4 or 89 HW2
Yeah, if it crashes for you on TIEmu, you'd probably better not send that to your calculator. But I don't understand why...
Quote:
What adapter are your referring to? If you mean an adapter cable to plug the calculator into the soundcard, I actually just have a 3.5mm stereo cable plugged into the soundcard, my TI link cable plugged into the TI-86, and 3 alligator clip cables connecting the two. Yay alligator clips!
I must have a male 3.5mm stereo jack with a wire, and I do have a female 2.5mm stereo jack, which I could solder together... but they're 75 km away from the place where I work during the week
Re-posting the latest version:
Code:
#define USE_TI89
#define USE_TI92P
#define USE_V200
#define MIN_AMS 100
#define OPTIMIZE_ROM_CALLS
#define SAVE_SCREEN
#include <alloc.h>
#include <cert.h>
#include <flash.h>
#include <graph.h>
#include <intr.h>
#include <inttypes.h>
#include <kbd.h>
#include <link.h>
#include <peekpoke.h>
#include <stdio.h>
#include <string.h>
#include <system.h>
static volatile uint32_t int1_ticks = 0;
static volatile uint32_t int5_ticks = 0;
static INT_HANDLER saved_int_1;
static INT_HANDLER saved_int_5;
static uint8_t frame[30];
__attribute__((__regparm__(2))) void send_frame(uint8_t * ptr asm("%a0"), uint16_t len asm("%d0"));
//! New AUTO_INT_1 handler: count ticks, and execute AMS's handler, which handles keyboard reading.
DEFINE_INT_HANDLER(MyInt1)
{
int1_ticks++;
ExecuteHandler(saved_int_1);
}
//! New AUTO_INT_5 handler: count ticks, but don't execute the AMS timers and battery checker at a non-default rate.
DEFINE_INT_HANDLER(MyInt5)
{
int5_ticks++;
send_frame(frame, 13);
//ExecuteHandler(saved_int_5);
}
// Notes:
// * clock -> tip
// * SET bit 0 of 60000E to pull down
// * bit 2 of 60000E SET means pulled down.
// * data -> ring
// * SET bit 1 of 60000E to pull down
// * bit 3 of 60000E SET means pulled down.
// Length is currently limited to 255 bytes.
asm("
.set CLOCK_WRITE_BIT, 0
.set DATA_WRITE_BIT, 1
.set CLOCK_READ_BIT, 2
.set DATA_READ_BIT, 3
| Write clock
.macro PULLDOWN_CLOCK
bset #CLOCK_WRITE_BIT,(%a1)
.endm
.macro PULLUP_CLOCK
bclr #CLOCK_WRITE_BIT,(%a1)
.endm
| Write data
.macro PULLDOWN_DATA
bset #DATA_WRITE_BIT,(%a1)
.endm
.macro PULLUP_DATA
bclr #DATA_WRITE_BIT,(%a1)
.endm
| Write clock and data at the same time
.macro PULLDOWN_BOTH
st.b (%a1)
.endm
.macro PULLUP_BOTH
sf.b (%a1) | clr.b (%a1)
.endm
.macro PULLUP_CLOCK_PULLDOWN_DATA
move.b #0x2,(%a1)
.endm
.macro PULLDOWN_CLOCK_PULLUP_DATA
move.b #0x1,(%a1)
.endm
| Read clock / data / both
.macro READ_CLOCK
btst #CLOCK_READ_BIT,(%a1)
.endm
.macro READ_DATA
btst #DATA_READ_BIT,(%a1)
.endm
.macro READ_BOTH dest
move.b (%a1),dest
.endm
.macro SEND_BIT
| Clock high for 17 µs, low for 35 µs, high for 52 µs
| Data = input bit for 52 µs, high for 52 µs
bclr #CLOCK_WRITE_BIT,%d2
move.b %d2,(%a1)
moveq #19,%d0
0:
dbf %d0,0b
bset #CLOCK_WRITE_BIT,%d2
move.b %d2,(%a1)
moveq #39,%d0
1:
dbf %d0,1b
PULLUP_BOTH
move.b %d2,(%a1)
moveq #59,%d0
2:
dbf %d0,2b
.endm
.text
.even
.globl send_frame
send_frame:
move.w %d3,-(%sp)
| Direct link I/O wire access
lea 0x60000E,%a1
| Compute checksum
| TODO: compute checksum incrementally !
move.w %d0,%d3
lea 12(%a0),%a0
sub.w #12+1,%d0 | len
| TODO: handle improper lengths
moveq #0,%d1 | val
moveq #0,%d2 | accumulator for checksum
loop_checksum:
move.b (%a0)+,%d1
add.w %d1,%d2
dbf %d0,loop_checksum
| Write checksum in little-endian form
move.b %d2,(%a0)
lsr.w #8,%d2
move.b %d2,1(%a0)
| Jamming phase: ~9.8ms
PULLDOWN_CLOCK_PULLUP_DATA
| dbf timings: 10 CPU clock cycles when cc false and branch taken, i.e. <~ 1 us @ ~12 MHz.
| We need to loop ~12K times.
move.w #12000-1,%d0
loop_jamming:
dbf %d0,loop_jamming
PULLUP_BOTH
| Get back to the beginning of the frame
suba.w %d3,%a0
| Add checksum length
addq.w #2-1,%d3
loop_send_bytes:
bsr.s send_byte
dbf %d3,loop_send_bytes
| TODO for directed frames: actually listen for the checksum...
| move.w #(182+60+50+8*(20+40+60)),%d0
|loop_wait_checksum:
| dbf %d0,loop_wait_checksum
| TODO: ACK/NAK the checksum if it's a directed frame
| lea ack(%pc),%a0
| bsr.s send_byte
move.w (%sp)+,%d3
rts
.text
.even
send_byte:
move.w %d3,-(%sp)
| Both high for 52 + 110 µs
PULLUP_BOTH
move.w #182-1,%d0
loop1_byte:
dbf %d0,loop1_byte
| Both low for 52 µs
PULLDOWN_BOTH
moveq #60-1,%d0
loop2_byte:
dbf %d0,loop2_byte
| Both high for 43 µs
PULLUP_BOTH
moveq #50-1,%d0
loop3_byte:
dbf %d0,loop3_byte
move.b (%a0)+,%d1
moveq #8-1,%d3
loop_send_bit:
| From bit 7 (MSB) down to bit 0 (LSB)
rol.b #1,%d1 | Leftmost bit goes to C
| We want the data line to have the same state as the input bit, so we want the DATA_WRITE_BIT to be not(input bit)
| if carry clear (i.e. input bit is 0) then pull down (i.e. set bit) else pull up (i.e. clear bit)
| if carry set (i.e. input bit is 1) then pull up (i.e. clear bit) else pull down (i.e. set bit)
| Sxx is [if condition xx = true then 0xFF -> dest else 0 -> dest]
scc %d2
SEND_BIT
dbf %d3,loop_send_bit
move.w (%sp)+,%d3
rts
|
|ack:
| .byte 0xAA
| .even
");
//! Where all the fun starts...
void _main(void) {
short saved_int5_rate = PRG_getRate();
HANDLE cert_handle;
unsigned long cert_len;
CFILE context;
CERT_FIELD field;
unsigned short i;
uint8_t calc_id[5];
int1_ticks = 0,
int5_ticks = 0;
// Retrieve unique calculator ID, the proper (but large and slow) way.
// The improper way, with very little chance of false positives, would be searching for 0A 15 <5 bytes> 0A 2D 40.
FL_getCert(&cert_handle, &cert_len, FALSE);
if (cert_handle != H_NULL && cert_len > 0) {
unsigned char *ptr = HeapDeref(cert_handle);
copen (&context, ptr, cert_len);
// Root cert field of the Certificate memory.
if (cfindfield (&context, 0x330, &field)) {
copensub (&context, &field);
// Serial number field.
if (cfindfield (&context, 0xA10, &field)) {
copensub(&context, &field);
memcpy(calc_id, context.Pos, 5);
}
}
HeapFree(cert_handle);
}
saved_int_1 = GetIntVec(AUTO_INT_1);
SetIntVec(AUTO_INT_1, MyInt1);
saved_int_5 = GetIntVec(AUTO_INT_5);
SetIntVec(AUTO_INT_5, MyInt5);
// Disable all linking interrupts
pokeIO(0x60000C, 0x60);
// Setup frame
memcpy(frame, calc_id, 5); // Sender ID
_memset(frame+5, 0, 5); // Receiver ID, 0 for broadcast
frame[10] = 0x01; // Length, little endian 0x0001
frame[11] = 0x00;
frame[12] = 0x01; // Data: 0x01: first part of the handshake used in Flourish & Netpong.
// Let's fire AUTO_INT_5 at ~109.95 Hz (very close to the 110 Hz used by CALCnet)
/*PRG_setStart(257 - 149);
PRG_setRate(0);
// Check AUTO_INT_5 frequency against AUTO_INT_1 frequency (well-defined to 256 Hz on HW1).
while (!(_rowread(0xF000))) {
if ((int1_ticks % 1024) == 0) {
printf_xy(0, 0, "%" PRIu32 " %" PRIu32, int1_ticks, int5_ticks);
}
}
PRG_setRate(saved_int5_rate);*/
while (!(_rowread(0xF000)));
SetIntVec(AUTO_INT_1, saved_int_1);
SetIntVec(AUTO_INT_5, saved_int_5);
OSLinkReset();
GKeyFlush();
}
Compiled with a Makefile that reads as follows:
Code:
$ cat Makefile
all: calcnet.c
<tab>tigcc -Os -Wall -W -Wwrite-strings -Wshadow -mregparm=5 -fomit-frame-pointer -ffunction-sections -fdata-sections -fmerge-all-constants --optimize-code --cut-ranges --reorder-sections --merge-constants -Wa,--all-relocs -mno-bss -o calcnet calcnet.c
This version/Makefile doesn't crash in TiEmu. If I can find my 92+ and some batteries for it, I'll test out your code and check it out on my "oscilloscope". I still need to get mine working with the proper timings and such.
christop wrote:
KermMartian wrote:
It us indeed highest bit first. The link port port data bit on the TI-83 series is in a low bit, which is why I mention that I flip the byte and then rotate right one bit at a time.
Thanks for confirming. So flipping the byte was just an implementation detail as a kind of optimization, then?
I debooged and fine-tuned the timing in my calcnet driver. Apparently you have to give the link port a bit of time after changing the bit level (especially after releasing a line) before reading it next, otherwise it will give a false low reading.
Also, the timings are far different from what I calculated them to be. Do you know if the "OUT (LINKPORT),A" and "IN A,(LINKPORT)" instructions take longer on the TI-8x calcs than the Z80 docs say they should? The docs I have say they each take 11 cycles.
Anywho, here's my second test program:
http://www.mediafire.com/file/5q04fhk7ywo2zzd/testcn2.86p
Let me know if this one works.
I didn't change the jamming signal length, so let's see if that has any effect. It's actually only about 10.3ms long, since it starts about 0.8ms after an interrupt (10.3+0.8=11.1, which is the length of 2 interrupts). Given the different interrupt rate of the 83+/84+, it'll probably work out anyway.
Also, the timings are far different from what I calculated them to be. Do you know if the "OUT (LINKPORT),A" and "IN A,(LINKPORT)" instructions take longer on the TI-8x calcs than the Z80 docs say they should? The docs I have say they each take 11 cycles.
Anywho, here's my second test program:
http://www.mediafire.com/file/5q04fhk7ywo2zzd/testcn2.86p
Let me know if this one works.
I didn't change the jamming signal length, so let's see if that has any effect. It's actually only about 10.3ms long, since it starts about 0.8ms after an interrupt (10.3+0.8=11.1, which is the length of 2 interrupts). Given the different interrupt rate of the 83+/84+, it'll probably work out anyway.
Oooh, you don't have a second calculator to test it with? I think I only have my TI-85 at home; my TI-86 is AWoL uptown somewhere.
No, sadly, I only have a TI-86 and a TI-92+. I had a TI-89 for about a year in high school but someone stole it. That calculator was teh awexome.
Besides, I don't have the receiver code debugged yet, so it's kind of moot. I want to make sure my code works with the "official" DCS code on a network.
Besides, I don't have the receiver code debugged yet, so it's kind of moot. I want to make sure my code works with the "official" DCS code on a network.
I can test it tomorrow when I have some time, its a little late today for me to be pulling out all my calcs to play around with.
"Always code as if the person who will maintain your code is a maniac serial killer that knows where you live" -Unknown
"If you've done something right no one will know that you've done anything at all" -Futurama
<Michael_V> or create a Borg collective and call it The 83+
<Michael_V> Lower your slide cases and prepare to be silent linked. Memory clears are futile.
TheStorm wrote:
I can test it tomorrow when I have some time, its a little late today for me to be pulling out all my calcs to play around with.
Very much appreciated, Jonimus. I checked, and an 86 is indeed missing from my current collection. I hope to be able to remedy that sad state of affairs sooner rather than later. - Lionel Debroux
- Minor Calculator Deity (Posts: 1324)
- 22 Mar 2011 01:37:29 am
- Last edited by Lionel Debroux on 22 Mar 2011 01:40:51 am; edited 1 time in total
Neither the 84+SE running OS 2.41, nor the 83+SE running OS 1.18, can detect the 86 running the testcn2 program, in 1:1 connection through a working cable.
Dots are moving at the bottom left of both screens, though.
Dots are moving at the bottom left of both screens, though.
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
» Go to Registration page
Page 5 of 9
» 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
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