The Oric connects to the 8bit-Hub through the printer port. The trick consists of switching PORT A to input/output mode when receiving/sending data. The code does this 20 times per second, which gives a theoretical bandwidth of 5 KB/s (20*256 bytes).
The system works correctly, and it is possible to pass UDP/TCP packets to 8bit-OS and 8bit-Slicks. But after a few minutes (I would 5-10), the VIA stops toggling PORT A (the humming sound stops). A soft reset (through the CUMANA Reborn) fixes the issue, and gives another few minutes of PORT A communication. So it looks like a software issue is at play (rather than hardware).
I wonder if there is need for some register to be reset? I am pasting the CC65 Hub communication code here, hoping for some insights from veteran members... The main points of interest are the UpdateHub(), SendByte() and ReceiveByte().
Code: Select all
unsigned char tick;
unsigned char hubState[7] = { COM_ERR_OFFLINE, 255, 255, 255, 255, 80, 100 };
unsigned char sendID = 0, sendLen = 0, sendHub[256];
unsigned char recvID = 0, recvLen = 0, recvHub[256];
unsigned char packetID = 0;
unsigned char QueueHub(unsigned char packetCmd, unsigned char* packetBuffer, unsigned char packetLen)
{
unsigned char i;
// Check if there is enough space in buffer
if (packetLen > 255-sendLen)
return 0;
// Add to send buffer
if (++packetID > 15) { packetID = 1; }
sendHub[sendLen++] = packetID;
sendHub[sendLen++] = packetLen+1;
sendHub[sendLen++] = packetCmd;
for (i=0; i<packetLen; i++)
sendHub[sendLen++] = packetBuffer[i];
return 1;
}
void SendByte(unsigned char value)
{
// Send 1 byte to HUB
POKE(0x0301, value); // Write to Printer Port
POKE(0x0300, 175); // Send STROBE (falling signal)
tick++; tick++; tick++; // Wait 3 cycles
POKE(0x0300, 255); // Reset STROBE
}
unsigned char RecvByte(unsigned char* value)
{
// Recv 1 byte from HUB
unsigned char i = 255;
while (1) { // Countdown i to 0
if (PEEK(0x030d)&2) { *value = PEEK(0x0301); break; } // Look for ACKNOW on CA1 then read Printer Port
if (!i--) return 0;
}
return 1;
}
void RecvHub()
{
unsigned char i, len, ID, packetLen;
unsigned char header, footer, checksum;
SendByte(85); // Ask Hub to send us some Data
POKE(0x0303, 0); // Set Port A as Input
i = PEEK(0x0301); // Reset ORA
// Check header
if (!RecvByte(&header) || header != 170) {
if (hubState[0] != COM_ERR_OFFLINE) { hubState[0] = COM_ERR_HEADER; }
return;
}
// Get packet ID
if (!RecvByte(&ID)) { hubState[0] = COM_ERR_TRUNCAT; return; }
// Read joystick/mouse data
for (i=1; i<7; i++) {
if (!RecvByte(&hubState[i])) { hubState[0] = COM_ERR_TRUNCAT; return; }
}
// Get buffer length
if (!RecvByte(&len)) { hubState[0] = COM_ERR_TRUNCAT; return; }
// Read buffer data
for (i=0; i<len; i++) {
if (!RecvByte(&recvHub[i])) { hubState[0] = COM_ERR_TRUNCAT; return; }
}
// Get footer
if (!RecvByte(&footer)) { hubState[0] = COM_ERR_TRUNCAT; return; }
// Verify checkum
checksum = ID;
for (i=1; i<7; i++) { checksum += hubState[i]; }
for (i=0; i<len; i++) { checksum += recvHub[i]; }
if (footer != checksum) {
hubState[0] = COM_ERR_CORRUPT;
return;
}
hubState[0] = COM_ERR_OK;
// Check packet reception
if (ID != recvID) {
// Check ID against last packet sent
if ((ID & 0x0f) == sendID) {
// Shift any remaining data
packetLen = sendHub[1]+2;
if (packetLen < sendLen) {
memcpy(&sendHub[0], &sendHub[packetLen], sendLen-packetLen);
sendLen -= packetLen;
} else {
sendLen = 0;
}
}
// Check ID against last packet received
if (len && ((ID & 0xf0) != (recvID & 0xf0)))
recvLen = len;
// Update ID
recvID = ID;
}
}
void SendHub()
{
unsigned char i, checksum, packetLen;
// Send Header
SendByte(170);
// Send Packet ID
if (sendLen) { sendID = sendHub[0]; }
checksum = (recvID & 0xf0) + sendID;
SendByte(checksum);
// Send Packet Data (if any)
if (sendLen) {
packetLen = sendHub[1];
SendByte(packetLen);
for (i=2; i<packetLen+2; i++) {
SendByte(sendHub[i]);
checksum += sendHub[i];
}
} else {
SendByte(0);
}
// Send footer
SendByte(checksum);
}
clock_t updateClock;
void UpdateHub()
{
unsigned char i;
// Throttle requests to respect refresh rate
if (clock() < updateClock)
return;
updateClock = clock()+HUB_REFRESH_RATE;
// Was hub already initialized?
if (hubState[0] == COM_ERR_OFFLINE) {
// Queue reset command
if (sendHub[0] != HUB_SYS_RESET) {
recvID = 0; recvLen = 0;
sendID = 0; sendLen = 0;
QueueHub(HUB_SYS_RESET, 0, 0);
}
}
__asm__("sei"); // Disable interrupts
// Process HUB I/O
SendHub();
RecvHub();
POKE(0x0303, 255); // Set port A as Output
__asm__("cli"); // Resume interrupts
}