Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
227 changes: 195 additions & 32 deletions Firmware/Hub-Mega2560/Hub-Mega2560.ino
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ char urlVer[] = "http://8bit-unity.com/Hub-Version.txt";
const char* cmdString[] =
{"SYS_ERROR","SYS_RESET","SYS_NOTIF", "SYS_SCAN", "SYS_CONNECT","SYS_IP", "SYS_MOUSE","SYS_VERSION","SYS_UPDATE","",
"DIR_LS", "DIR_MK", "DIR_RM", "DIR_CD", "", "", "", "", "", "",
"FILE_OPEN","FILE_SEEK","FILE_READ", "FILE_WRITE","FILE_CLOSE", "", "", "", "", "",
"", "FILE_OPEN","FILE_SEEK", "FILE_READ", "FILE_WRITE", "FILE_CLOSE","", "", "", "",
"UDP_OPEN", "UDP_RECV", "UDP_SEND", "UDP_CLOSE", "UDP_SLOT", "", "", "", "", "",
"TCP_OPEN", "TCP_RECV", "TCP_SEND", "TCP_CLOSE", "TCP_SLOT", "", "", "", "", "",
"WEB_OPEN", "WEB_RECV", "WEB_HEADER","WEB_BODY", "WEB_SEND", "WEB_CLOSE","", "", "", "",
Expand All @@ -93,9 +93,12 @@ const char* fail = "Update failed! ";
#define MODE_C64 4
#define MODE_NES 5
#define MODE_ORIC 6
#define MODE_LYNX 7
#define HUB_MODES 8
const char* modeString[HUB_MODES] = {"Please setup", "Apple //", "Atari 8bit", "BBC Micro", "C64/C128", "NES", "Oric", "Lynx"};
#define MODE_LYNXOLD 7
#define MODE_LYNXNEW 8
#define HUB_MODES 9
const char* modeString[HUB_MODES] = {
"Please setup", "Apple //", "Atari 8bit", "BBC Micro", "C64/C128", "NES", "Oric",
"Lynx(old)", "Lynx(new)"};
byte hubMode = MODE_NONE;

// COMM Params
Expand Down Expand Up @@ -550,6 +553,10 @@ volatile unsigned long interruptTimer = 0;
unsigned long timerIO = millis();
#endif

// For Lynx(new), we use two interfaces and name them according to function
#define LynxSerialRecv Serial1
#define LynxSerialSend Serial2

void setupCOM() {
// Setup COM Connection
switch (hubMode) {
Expand All @@ -572,14 +579,26 @@ void setupCOM() {
PORTH &= ~_BV(PH1); // Pin 16 LOW == READY
attachInterrupt(digitalPinToInterrupt(18), c64Interrupt, FALLING);
break;
case MODE_LYNX:
case MODE_LYNXOLD:
// Setup Serial 2 on pins 16/17
Serial2.begin(62500, SERIAL_8N2); // Lynx comm (Bauds 62500, 41666, 9600)
while (!Serial2) { }
Serial2.setTimeout(30);
Serial2.flush();
Serial2.readString();
break;
case MODE_LYNXNEW:
// Issue with parity:
// In the hub code on the lynx, parity for receiving is checked!
// But the Lynx cannot create correct parity.
// The code here cannot use different setting for send and recv in one interface
// Thus we need two to make it workin hardware
LynxSerialRecv.begin(62500, SERIAL_8N2); // recv // Lynx comm (Bauds 62500, 41666, 9600)
LynxSerialSend.begin(62500, SERIAL_8O1); // send // Lynx comm (Bauds 62500, 41666, 9600)
LynxSerialRecv.setTimeout(30);
LynxSerialSend.flush();
LynxSerialRecv.readString();// why need readstring?
break;
case MODE_NES:
pinMode(18, INPUT_PULLUP); // STROBE (PC)
pinMode(16, INPUT_PULLUP); // R/W STATE
Expand Down Expand Up @@ -851,26 +870,26 @@ void c64Interrupt() {
}

////////////////////////////////
// LYNX Communication //
// LYNX Communication (old) //
////////////////////////////////

unsigned char lynxBitPeriod = 16; // Bauds: 62500=16 / 41666=24 / 9600=104
unsigned long lynxTimer;

void lynxOutputMode(void) {
void lynxOldOutputMode(void) {
// Switch pin to output
PORTD |= B00000100;
DDRD |= B00000100;
lynxTimer = micros();
lynxTimer = micros();
while (micros()-lynxTimer < lynxBitPeriod);
}

void lynxInputMode(void) {
void lynxOldInputMode(void) {
// Switch pin to input
DDRD &= B11111011;
}

void lynxWrite(char value) {
void lynxOldWrite(char value) {
unsigned char i, parity = 0, mask = 1;

// Start Bit
Expand Down Expand Up @@ -904,13 +923,13 @@ void lynxWrite(char value) {
}
}

void lynxProcessCOM() {
void lynxOldProcessCOM() {
// Have we got data?
if (!Serial2.available()) { comCode = COM_ERR_NODATA; return; }

// Get Header
if (!Serial2.readBytes((unsigned char*)&comInHeader, 1)) { comCode = COM_ERR_HEADER; return; }
#ifdef __DEBUG_IO__
#ifdef __DEBUG_IO__
inRec++;
#endif

Expand All @@ -919,15 +938,15 @@ void lynxProcessCOM() {

// Get Command
if (!Serial2.readBytes((unsigned char*)&comInCMD, 1)) { comCode = COM_ERR_TRUNCAT; return; }
#ifdef __DEBUG_IO__
#ifdef __DEBUG_IO__
inRec++;
#endif

// Send or Receive?
if (comInHeader == 85) {
// Get RecvID
if (!Serial2.readBytes((unsigned char*)&comInID, 1)) { comCode = COM_ERR_TRUNCAT; return; }
#ifdef __DEBUG_IO__
#ifdef __DEBUG_IO__
inRec++;
#endif

Expand All @@ -937,49 +956,145 @@ void lynxProcessCOM() {

// Send DATA
//delayMicroseconds(6*lynxBitPeriod); // Bauds: 62500=6* / 41666=8* / 9600=2*
lynxOutputMode();
lynxOldOutputMode();
for (unsigned char i=0; i<comOutLen; i++) {
lynxWrite(comOutBuffer[i]);
#ifdef __DEBUG_IO__
lynxOldWrite(comOutBuffer[i]);
#ifdef __DEBUG_IO__
outRec++;
#endif
}
#endif
}

} else {
// Get Length
if (!Serial2.readBytes((unsigned char*)&comInLen, 1)) { comCode = COM_ERR_TRUNCAT; return; }
#ifdef __DEBUG_IO__
#ifdef __DEBUG_IO__
inRec++;
#endif

// Get Buffer+Checksum
if (!Serial2.readBytes((unsigned char*)comInBuffer, comInLen+1)) { comCode = COM_ERR_TRUNCAT; return; }
#ifdef __DEBUG_IO__
#ifdef __DEBUG_IO__
inRec += comInLen+1;
#endif

// Check Data Integrity
if (checkPacket()) {
if (checkPacket()) {
// Send ACKNOW and process CMD
lynxOutputMode();
lynxWrite(85);
lynxOldOutputMode();
lynxOldWrite(85);
comProcessCMD();
} else {
// Send NG
lynxOutputMode();
lynxWrite(0);
lynxOldOutputMode();
lynxOldWrite(0);
}
#ifdef __DEBUG_IO__
#ifdef __DEBUG_IO__
outRec++;
#endif
#endif
}

// Return pin to input and clear data sent to self
lynxInputMode();
lynxOldInputMode();
while (Serial2.available())
Serial2.read();
}

////////////////////////////////
// LYNX Communication (new) //
////////////////////////////////


void lynxNewOutputMode(void) {
// Switch pin to output ...
// with diode this is nop
}

void lynxNewInputMode(void) {
LynxSerialSend.flush(); // wait until everything send
// Switch pin to input
// with diode this is nop
}

void lynxNewWrite(char value) {
LynxSerialSend.write(value);
}

void lynxNewProcessCOM() {
// Have we got data?
if (!LynxSerialRecv.available()) { comCode = COM_ERR_NODATA; return; }

// Get Header
if (!LynxSerialRecv.readBytes((unsigned char*)&comInHeader, 1)) { comCode = COM_ERR_HEADER; return; }
#ifdef __DEBUG_IO__
inRec++;
#endif

// Check Header
if (comInHeader != 170 && comInHeader != 85) { comCode = COM_ERR_HEADER; return; }

// Get Command
if (!LynxSerialRecv.readBytes((unsigned char*)&comInCMD, 1)) { comCode = COM_ERR_TRUNCAT; return; }
#ifdef __DEBUG_IO__
inRec++;
#endif

// Send or Receive?
if (comInHeader == 85) {
// Get RecvID
if (!LynxSerialRecv.readBytes((unsigned char*)&comInID, 1)) { comCode = COM_ERR_TRUNCAT; return; }
#ifdef __DEBUG_IO__
inRec++;
#endif

// Process packets
popPacket(comInID);
preparePacket();

// Send DATA
//delayMicroseconds(6*lynxBitPeriod); // Bauds: 62500=6* / 41666=8* / 9600=2*
lynxNewOutputMode();
for (unsigned char i=0; i<comOutLen; i++) {
lynxNewWrite(comOutBuffer[i]);
#ifdef __DEBUG_IO__
outRec++;
#endif
}

} else {
// Get Length
if (!LynxSerialRecv.readBytes((unsigned char*)&comInLen, 1)) { comCode = COM_ERR_TRUNCAT; return; }
#ifdef __DEBUG_IO__
inRec++;
#endif

// Get Buffer+Checksum
if (!LynxSerialRecv.readBytes((unsigned char*)comInBuffer, comInLen+1)) { comCode = COM_ERR_TRUNCAT; return; }
#ifdef __DEBUG_IO__
inRec += comInLen+1;
#endif

// Check Data Integrity
if (checkPacket()) {
// Send ACKNOW and process CMD
lynxNewOutputMode();
lynxNewWrite(85);
comProcessCMD();
} else {
// Send NG
lynxNewOutputMode();
lynxNewWrite(0);
}
#ifdef __DEBUG_IO__
outRec++;
#endif
}

// Return pin to input and clear data sent to self
lynxNewInputMode();
while (LynxSerialRecv.available())
LynxSerialRecv.read();
}

/////////////////////////////////
// NES Communication //
/////////////////////////////////
Expand Down Expand Up @@ -1396,6 +1511,50 @@ void comProcessCMD() {
pushPacket(HUB_SYS_IP, -1);
break;

case HUB_DIR_LS: // Todo: Implement for root directory /microSD
{
unsigned char skip = comInBuffer[0];
unsigned char count = 0;
length = 1;

// TODO: we may want to start a different dir if CD is implemented
File dir = SD.open("/");
while (true) {
File entry = dir.openNextFile();
if (!entry) {
// no more files
break;
}
if (!entry.isDirectory()){
// skip any dir; TODO: change when CD is implemented
if( skip!=0){
// skip entries as requested
skip--;
}else{
unsigned int slen=strlen(entry.name());
if( length+slen+3>255){
// printf("Buffer length exceeded!");
break;
}
memcpy(&serBuffer[length], entry.name(), slen);
length += slen;
serBuffer[length++] = 0;
serBuffer[length++] = (unsigned char)(entry.size() & 0xff);
serBuffer[length++] = (unsigned char)((entry.size() >> 8)&0xff);
count++;
}
}

entry.close();
}
dir.close();
serBuffer[0] = count;
serLen = length;
}

pushPacket(HUB_DIR_LS, -1);
break;

case HUB_FILE_OPEN:
// Check if file was previously opened
if (hubFile[comInBuffer[0]])
Expand All @@ -1418,7 +1577,7 @@ void comProcessCMD() {
// Send back file size
length = hubFile[comInBuffer[0]].size();
memcpy(serBuffer, (char*)&length, 4); serLen = 4;
pushPacket(HUB_FILE_OPEN, comInBuffer[0]);
pushPacket(HUB_FILE_OPEN, -1);
break;

case HUB_FILE_SEEK:
Expand Down Expand Up @@ -2493,9 +2652,13 @@ void loop() {
espProcessCMD();

// Process COM I/O
if (hubMode == MODE_LYNX) {
if (hubMode == MODE_LYNXOLD) {
// Process Lynx Communication (asynchronously)
lynxOldProcessCOM();
} else
if (hubMode == MODE_LYNXNEW) {
// Process Lynx Communication (asynchronously)
lynxProcessCOM();
lynxNewProcessCOM();
} else
if (hubMode == MODE_ATARI || hubMode == MODE_C64 || hubMode == MODE_NES || hubMode == MODE_ORIC) {
// Check if data burst stalled (allow extra time for VBI/DLI interrupts)
Expand Down