- Sending/Receiving Data Through the I/O Port (method)
- 09 Jan 2014 01:21:55 am
- Last edited by amihart on 18 Jan 2014 02:26:12 pm; edited 4 times in total
So, I've been trying to figure out how to send/receive data through the I/O port, and I've sort of come up with a way. It's probably not original but it seems to work.
Basically, on the cable, you have the tip and the ring. Either can be high, low, or one or the other. This creates 4 different states that the cable can be in.
To send these states out the I/O port, we simply use "out" and send it through port 0.
Most people would write a state like this:
Code:
However, with my method I am using to send data, the state itself doesn't really matter, just the fact that there are 4 of them. So you could replace that for this for simplicity:
Code:
The four different states are 00000001, 00000010, 00000011, and 00000000, but again, we can just refer to them as 0, 1, 2, and 3 for simplicity.
You can read what is being sent out through the I/O cable with "in":
Code:
When you send one of these values out the I/O cable, the inverse happens on the other side. What I mean by this is if you were to send a "00000010" the receiver would read a "00000001". I've noticed this from experimentation. I'm not very good with hardware so I am unsure the mechanics behind why, but just know that it is inverted.
In much simpler terms, the inversion is like so:
Code:
If a 1 is sent out the I/O port, the receiver will read a 2. If a 2 is sent, a 1. 3, 0. And 0, 3.
Now to transfer data, what I have done is taken advantage of the first three states and laid the last one aside as a "terminating" state. Basically, if the sender sends a 0 (default position), then it knows the message is done being sent.
The logic I've used to send data basically has the receiver go into a sort of "receiving" mode where it logs the current state and waits for a state change. Once there is a state change, it uses that to determine whether a 0 or 1 is being sent, or whether the message is over.
The logic in pseudo-code works like this:
Code:
The first state before the arrow is the previous state.
The one after the arrow is the new one.
The default state is 3 and all transmissions start on 3.
If the sender sends a new state out the I/O port then that state change can be turned into a byte with the logic above.
For example, if the sender were to do something like this:
Code:
Since these are all inverted, the receiver would receive 1,2,0,2,0,2,0,1,3.
Since the default state is 3, that means the receiver is going through states like this:
Code:
If we use the logic above in the various if statements, we can see that this would correspond to:
Code:
If the receiver were to record all these state changes, he could put all these bits together into 1 byte and get 01010100, or, the letter T.
Anywho, that's how I managed to send a byte through the I/O port.
Here's my library so far:
http://pastebin.com/8YpUbSvx
Sorry if you think it's messy and not optimized. I'm not that far into Assembly.
Here is an example of using my library to send the letter "T" from my TI-84+CSE to my TI-84+:
Sending program:
Code:
Code:
I'm not sure why, but I've noticed that sometimes bits are dropped in the library I'm working on. Like, if I were to send "1111" over, it may come over as "1101" or "1011". I'm unsure of why. But bits never seem to be gained, so I've created a slower but safer way of sending data were it sends it three times then compares them, so if you get something like "1101", "1001", and "0111" then it knows it's supposed to be "1111".
The call that sends and receives it three times have "Safe" after it. Such as, "ReceiveDataSafe" and "SendDataSafe" are much more accurate than "SendData" and "ReceiveData", but are also much slower.
The data gets sent over as a string of ones and zeros. But I'm working on a compression routine that will compress that all into bytes. Currently, the "CompressData" routine just compresses the first byte in the string to a byte.
I'm also working on a routine that will decompress the data. That way, you can send bytes over.
Basically, on the cable, you have the tip and the ring. Either can be high, low, or one or the other. This creates 4 different states that the cable can be in.
To send these states out the I/O port, we simply use "out" and send it through port 0.
Most people would write a state like this:
Code:
ld a, %00000010
out (0), a ; send a through port 0 (I/O port)
However, with my method I am using to send data, the state itself doesn't really matter, just the fact that there are 4 of them. So you could replace that for this for simplicity:
Code:
ld a, 2
out (0), a
The four different states are 00000001, 00000010, 00000011, and 00000000, but again, we can just refer to them as 0, 1, 2, and 3 for simplicity.
You can read what is being sent out through the I/O cable with "in":
Code:
in a, (0)
call AToString ; custom
bcall(_PutS)
When you send one of these values out the I/O cable, the inverse happens on the other side. What I mean by this is if you were to send a "00000010" the receiver would read a "00000001". I've noticed this from experimentation. I'm not very good with hardware so I am unsure the mechanics behind why, but just know that it is inverted.
In much simpler terms, the inversion is like so:
Code:
1 -> 2
2 -> 1
3 -> 0
0 -> 3
If a 1 is sent out the I/O port, the receiver will read a 2. If a 2 is sent, a 1. 3, 0. And 0, 3.
Now to transfer data, what I have done is taken advantage of the first three states and laid the last one aside as a "terminating" state. Basically, if the sender sends a 0 (default position), then it knows the message is done being sent.
The logic I've used to send data basically has the receiver go into a sort of "receiving" mode where it logs the current state and waits for a state change. Once there is a state change, it uses that to determine whether a 0 or 1 is being sent, or whether the message is over.
The logic in pseudo-code works like this:
Code:
Receiving Side:
if (0) -> (1)
then bit=0
if (0) -> (2)
then bit=1
if (1) -> (0)
then bit=0
if (1) -> (2)
then bit=1
if (2) -> (0)
then bit=0
if (2) -> (1)
then bit=1
if (anything) -> (3)
then finish
if (3) -> (1)
then bit=0
if (3) -> (2)
then bit=1
if (3) -> (0)
then finish
The first state before the arrow is the previous state.
The one after the arrow is the new one.
The default state is 3 and all transmissions start on 3.
If the sender sends a new state out the I/O port then that state change can be turned into a byte with the logic above.
For example, if the sender were to do something like this:
Code:
(psuedo-code)
out -> 2
out -> 1
out -> 3
out -> 1
out -> 3
out -> 1
out -> 3
out -> 2
out -> 0
Since these are all inverted, the receiver would receive 1,2,0,2,0,2,0,1,3.
Since the default state is 3, that means the receiver is going through states like this:
Code:
3->1->2->0->2->0->2->0->1->3
If we use the logic above in the various if statements, we can see that this would correspond to:
Code:
3->1 = 0
1->2 = 1
2->0 = 0
0->2 = 1
2->0 = 0
0->2 = 1
2->0 = 0
0->1 = 0
0->3 = End
If the receiver were to record all these state changes, he could put all these bits together into 1 byte and get 01010100, or, the letter T.
Anywho, that's how I managed to send a byte through the I/O port.
Here's my library so far:
http://pastebin.com/8YpUbSvx
Sorry if you think it's messy and not optimized. I'm not that far into Assembly.
Here is an example of using my library to send the letter "T" from my TI-84+CSE to my TI-84+:
Sending program:
Code:
#include "ti84pluscse.inc"
.org userMem-2
.db $EF, $69
start:
call FindData
ld (hl), '0' \ inc hl
ld (hl), '1' \ inc hl
ld (hl), '0' \ inc hl
ld (hl), '1' \ inc hl
ld (hl), '0' \ inc hl
ld (hl), '1' \ inc hl
ld (hl), '0' \ inc hl
ld (hl), '0' \ inc hl
call SendDataSafe
ret
#include "transfer.h"
Code:
#include "ti83plus.inc"
.org userMem-2
.db $BB,$6D
start:
call ReceiveDataSafe
call CompressData
call FindDataCompressed
ld a, (hl)
bcall(_PutC)
bcall(_NewLine)
#include "transfer.h"
I'm not sure why, but I've noticed that sometimes bits are dropped in the library I'm working on. Like, if I were to send "1111" over, it may come over as "1101" or "1011". I'm unsure of why. But bits never seem to be gained, so I've created a slower but safer way of sending data were it sends it three times then compares them, so if you get something like "1101", "1001", and "0111" then it knows it's supposed to be "1111".
The call that sends and receives it three times have "Safe" after it. Such as, "ReceiveDataSafe" and "SendDataSafe" are much more accurate than "SendData" and "ReceiveData", but are also much slower.
The data gets sent over as a string of ones and zeros. But I'm working on a compression routine that will compress that all into bytes. Currently, the "CompressData" routine just compresses the first byte in the string to a byte.
I'm also working on a routine that will decompress the data. That way, you can send bytes over.