Obsługa protokołu SIO przez urządzenie peryferyjne
From Atariki
Dane jest urządzenie peryferyjne o identyfikatorze $40 obsługujące rozkaz 'W' ($57), dla którego odbiera 8 bajtów danych i realizuje jakąś operację.
Kod dla Atari
lda #$40 sta DDEVIC ;$300 lda #$01 sta DUNIT ;$301 lda #'W' sta DCMND ;$302 lda #$80 sta DSTATS ;$303 lda #<buffer sta DBUFA ;$304 lda #>buffer sta DBUFA+1 lda #$07 sta DTIMLO ;$306 lda #<8 sta DBUFL ;$308 lda #>8 sta DBUFL+1 lda #$00 sta DAUX1 ;$30A lda #$00 sta DAUX2 ;$30B jsr SIOV ;$E459 bmi ?error
Kod dla mikrokontolera AVR (Arduino)
/*
SIO CMD structure:
Byte:
RxBuffer[0] - SIO device identifier and unit number
RxBuffer[1] - COMMAND, for future use,
RxBuffer[2] - DAUX1, for future use,
RxBuffer[3] - DAUX2, for future use,
RxBuffer[4] - checksum.
SIO DATA structure:
RxBuffer[0] - data,
RxBuffer[1] - data,
...
...
RxBuffer[RxDataSize-1] - data,
RxBuffer[RxDataSize] - checksum.
*/
/* Arduino hardware settings */
#define PIN_SIOCOMMAND 2 // ATARI SIO-COMMAND Pin
#define SIO Serial1 // ATARI SIO-Serial interface
// ----------------------------------------
/* Global define */
#define RxCmdSize 4 // size of command frame (w/o checksum byte)
#define RxDataSize 8 // size of data frame (w/o checksum byte)
#define DEVICE_ID 0x40 // SIO device identifier and unit number
#define COMMAND_ID 'W' // SIO operation command
/* Global Variable */
uint8_t RxBuffer[8+1];
uint8_t RxSum;
void setup()
{
pinMode(PIN_SIOCOMMAND, INPUT_PULLUP);
SIO.begin(19200);
}
void loop()
{
while (1)
{
//wait for COMMAND line is LOW
while (digitalRead(PIN_SIOCOMMAND) != 0) ;
//receive command frame and calculate checksum
RxSum = ReceiveData(RxBuffer, RxCmdSize+1);
//wait for COMMAND line is HIGH
while (digitalRead(PIN_SIOCOMMAND) == 0) ;
//verify device identifier
if (RxBuffer[0] == DEVICE_ID)
{
//check command checksum
if (RxSum == RxBuffer[RxCmdSize])
{
//check command identifier
if (RxBuffer[1] == COMMAND_ID)
{
//-- check or process auxiliary bytes RxBuffer[2] and RxBuffer[3] when needed
//...
//...
//-- end of aux data processing ----------------------------------------
//send ACK and continue receive data
delayMicroseconds(1000);
SIO.write('A');
SIO.flush();
//receive data frame
RxSum = ReceiveData(RxBuffer, RxDataSize+1);
if (RxSum == RxBuffer[RxDataSize])
{
//send ACK
delayMicroseconds(1000);
SIO.write('A');
SIO.flush();
//-- start operation according to received command and data
//...
//...
//-- end of operation ----------------------------------------
//then send operation COMPLETE
delayMicroseconds(250);
SIO.write('C');
SIO.flush();
}
else
{
//send NAK because of wrong data frame checksum
delayMicroseconds(1000);
SIO.write('N');
SIO.flush();
//then send operation ERROR
delayMicroseconds(250);
SIO.write('E');
SIO.flush();
}
}
else
{
//send NAK because of not supported command
delayMicroseconds(1000);
SIO.write('N');
SIO.flush();
}
}
else
{
//send NAK because of wrong command frame checksum
delayMicroseconds(1000);
SIO.write('N');
SIO.flush();
}
}
}
}
//functions
uint8_t ReceiveData(uint8_t *buffer, uint8_t length)
{
u8 cnt = 0;
int sum = 0;
cnt = SIO.readBytes(buffer,length);
if (cnt == length)
{
for (cnt = 0; cnt < length-1; cnt++)
{
sum += buffer[cnt];
if (sum >= 256)
{
sum = (sum - 256) + 1; // add carry into sum
}
}
}
return sum;
}
