apple1-videocard-lib/demos/sdcard/apple1_sdcard/apple1_sdcard.ino

479 lines
13 KiB
C++

// 1 per SD card normale, 0 per SDFat
#include <Regexp.h>
#define USE_SD_H 0
#include <SPI.h>
#if USE_SD_H
#include <SD.h>
#else
#include "SdFat.h"
SdFat SD;
#endif
#define SD_CS_PIN SS
/*
+-----------+ +-----------------+
| | | ARDUINO |
| VIA 6522 | | NANO |
| | | |
| PA0 |<------ bit 0 ------>| D2 | +-------\
| PA1 |<------ bit 1 ------>| D3 D10 |----- SS ------>| \
| PA2 |<------ bit 2 ------>| D4 D11 |----- MOSI ---->| SD |
| PA3 |<------ bit 3 ------>| D5 D12 |<---- MISO -----| CARD |
| PA4 |<------ bit 4 ------>| D6 D13 |----- SCK ----->| |
| PA5 |<------ bit 5 ------>| D7 | +--------+
| PA6 |<------ bit 6 ------>| D8 |
| PA7 |<------ bit 7 ------>| D9 |
| | | |
| PB7 |<---- MCU_STROBE ----| D14/A0 |
| PB0 |--- CPU_STROBE ----->| D15/A1 |
| | | |
+-----------+ +-----------------+
*/
// pin definitions
#define BIT0 2
#define BIT1 3
#define BIT2 4
#define BIT3 5
#define BIT4 6
#define BIT5 7
#define BIT6 8
#define BIT7 9
/* 10,11,12,13 reserved for SD card */
#define MCU_STROBE 14
#define CPU_STROBE 15
// indicates that a timeout occurred during wait()
int TIMEOUT = 0;
void wait(int pin, int value) {
unsigned long start_time = millis();
unsigned long elapsed;
if(TIMEOUT) return;
while(digitalRead(pin) != value) {
elapsed = millis() - start_time;
if(elapsed > 500) {
TIMEOUT = 1;
break;
}
}
}
const int DIR_INPUT = 0;
const int DIR_OUTPUT = 1;
int last_dir; // remember last data port pins direction
void set_data_port_direction(int dir) {
// check if no need to set pins
if(dir == last_dir) return;
if(dir == DIR_INPUT) {
pinMode(BIT0, INPUT);
pinMode(BIT1, INPUT);
pinMode(BIT2, INPUT);
pinMode(BIT3, INPUT);
pinMode(BIT4, INPUT);
pinMode(BIT5, INPUT);
pinMode(BIT6, INPUT);
pinMode(BIT7, INPUT);
}
else {
pinMode(BIT0, OUTPUT);
pinMode(BIT1, OUTPUT);
pinMode(BIT2, OUTPUT);
pinMode(BIT3, OUTPUT);
pinMode(BIT4, OUTPUT);
pinMode(BIT5, OUTPUT);
pinMode(BIT6, OUTPUT);
pinMode(BIT7, OUTPUT);
}
// remember direction
last_dir = dir;
}
int receive_byte_from_cpu() {
// set data port pins as INPUT pins
set_data_port_direction(DIR_INPUT);
// both strobes are 0
// CPU deposits data byte and sets strobe high
wait(CPU_STROBE, HIGH);
// read the data byte
int data =
(digitalRead(BIT0) << 0) |
(digitalRead(BIT1) << 1) |
(digitalRead(BIT2) << 2) |
(digitalRead(BIT3) << 3) |
(digitalRead(BIT4) << 4) |
(digitalRead(BIT5) << 5) |
(digitalRead(BIT6) << 6) |
(digitalRead(BIT7) << 7);
// after reading the byte, MCU sets strobe high
digitalWrite(MCU_STROBE, HIGH);
// CPU now sets strobe low
wait(CPU_STROBE, LOW);
// and MCU sets strobe low
digitalWrite(MCU_STROBE, LOW);
return data;
}
void send_byte_to_cpu(int data) {
// set data port pins as OUTPUT pins
set_data_port_direction(DIR_OUTPUT);
// both strobes are 0
// put byte on the data port
digitalWrite(BIT0, data & 1);
digitalWrite(BIT1, data & 2);
digitalWrite(BIT2, data & 4);
digitalWrite(BIT3, data & 8);
digitalWrite(BIT4, data & 16);
digitalWrite(BIT5, data & 32);
digitalWrite(BIT6, data & 64);
digitalWrite(BIT7, data & 128);
// after depositing data byte, MCU sets strobe high
digitalWrite(MCU_STROBE, HIGH);
// wait for CPU to set strobe high
wait(CPU_STROBE, HIGH);
// tells CPU byte we are finished
digitalWrite(MCU_STROBE, LOW);
// wait for CPU to set strobe low
wait(CPU_STROBE, LOW);
}
// *********************************************************************************************
// *********************************************************************************************
// *********************************************************************************************
// *********************************************************************************************
// *********************************************************************************************
// *********************************************************************************************
// *********************************************************************************************
// *********************************************************************************************
void setup() {
// debug on serial
Serial.begin(9600);
#if USE_SD_H
Serial.println(F("SDCARD library: SD.h"));
#else // USE_SD_H
Serial.println(F("SDCARD library: SDFat.h"));
#endif // USE_SD_H
// initialize SD card
if (!SD.begin(SD_CS_PIN)) Serial.println("SD card initialization failed");
else Serial.println("SD card initialized");
// control pins setup
pinMode(CPU_STROBE, INPUT);
pinMode(MCU_STROBE, OUTPUT);
digitalWrite(MCU_STROBE, LOW);
// data pins setup
last_dir = -1; // no previous data direction
set_data_port_direction(DIR_INPUT);
MatchState ms;
char buf [100] = { F("The quick brown fox jumps over the lazy wolf") };
ms.Target (buf);
char result = ms.Match ("f.x");
if(result >0) {
Serial.println("match!");
}
}
const int CMD_READ = 0;
const int CMD_WRITE = 1;
const int CMD_DIR = 2;
const int ERR_RESPONSE = 255;
const int OK_RESPONSE = 0;
char filename[64];
// **************************************************************************************
// **************************************************************************************
// ********************************* DIR ***********************************************
// **************************************************************************************
// **************************************************************************************
void printDirectory(File dir, int numTabs) {
while (true) {
if(TIMEOUT) break;
File entry = dir.openNextFile();
if (! entry) {
// no more files
break;
}
// indentazione delle sottodirectory
for (uint8_t i = 0; i < numTabs; i++) {
Serial.print('\t');
send_byte_to_cpu(32);
send_byte_to_cpu(32);
send_byte_to_cpu(32);
}
// nome del file
char *msg;
#if USE_SD_H
msg = entry.name();
#else
entry.getName(filename, 64);
msg = filename;
#endif
Serial.print(msg);
for(int t=0; t<strlen(msg); t++) {
send_byte_to_cpu(msg[t]);
}
if (entry.isDirectory()) {
Serial.println("/");
send_byte_to_cpu('/');
send_byte_to_cpu('\r');
printDirectory(entry, numTabs + 1);
} else {
// files have sizes, directories do not
Serial.print("\t\t");
send_byte_to_cpu(' ');
send_byte_to_cpu(' ');
/*
// file size
Serial.println(entry.size(), DEC);
msg = itoa(entry.size());
for(int t=0; t<strlen(msg); t++) {
send_byte_to_cpu(msg[t]);
}
*/
send_byte_to_cpu('\r');
}
entry.close();
}
}
// **************************************************************************************
// **************************************************************************************
// ********************************* CMD_READ ******************************************
// **************************************************************************************
// **************************************************************************************
void comando_read() {
Serial.println("command CMD_READ received from CPU");
// reads filename as 0 terminated string
receive_string_from_cpu(filename);
if(TIMEOUT) return;
Serial.print("file to read: ");
Serial.println(filename);
if(!SD.exists(filename)) {
Serial.println("error opening file");
send_byte_to_cpu(ERR_RESPONSE);
send_string_to_cpu("?FILE NOT FOUND");
return;
}
// open the file
File myFile = SD.open(filename);
if(!myFile) {
Serial.println("error opening file");
send_byte_to_cpu(ERR_RESPONSE);
send_string_to_cpu("?CAN'T OPEN FILE");
return;
}
Serial.println("file opened on the SD card");
// ok response
send_byte_to_cpu(OK_RESPONSE);
if(TIMEOUT) return;
Serial.println("ok response sent to CPU");
// sends size as low and high byte
int size = myFile.size();
send_byte_to_cpu(size & 0xFF);
send_byte_to_cpu((size >> 8) & 0xFF);
if(TIMEOUT) return;
Serial.println("file size sent to CPU");
int bytes_sent = 0;
while(myFile.available() && !TIMEOUT) {
send_byte_to_cpu(myFile.read());
if(!TIMEOUT) bytes_sent++;
}
myFile.close();
if(TIMEOUT) {
Serial.print("timeout, bytes sent: ");
Serial.println(bytes_sent);
return;
}
Serial.println("file read ok");
}
void send_string_to_cpu(char *msg) {
while(1) {
int c = *msg++;
send_byte_to_cpu(c);
if(TIMEOUT) break;
if(c==0) break;
}
}
void receive_string_from_cpu(char *msg) {
while(1) {
int c = receive_byte_from_cpu();
if(TIMEOUT) break;
*msg++ = c;
if(c==0) break;
}
}
// **************************************************************************************
// **************************************************************************************
// ********************************* CMD_WRITE *****************************************
// **************************************************************************************
// **************************************************************************************
int receive_word_from_cpu() {
int lo = receive_byte_from_cpu();
int hi = receive_byte_from_cpu();
int data = lo | (hi << 8);
return data;
}
void comando_write() {
Serial.println("command CMD_WRITE received from CPU");
// reads filename as 0 terminated string
receive_string_from_cpu(filename);
if(TIMEOUT) return;
Serial.print("file to write: ");
Serial.println(filename);
if(SD.exists(filename)) {
Serial.println("file already exist");
send_byte_to_cpu(ERR_RESPONSE);
send_string_to_cpu("?ALREADY EXISTS");
return;
}
// open the file
File myFile = SD.open(filename, FILE_WRITE);
if(!myFile) {
Serial.println("error opening file for write");
send_byte_to_cpu(ERR_RESPONSE);
send_string_to_cpu("?CAN'T CREATE FILE");
return;
}
Serial.println("file opened for write on the SD card");
// ok response
send_byte_to_cpu(OK_RESPONSE);
if(TIMEOUT) return;
Serial.println("first ok response sent to CPU");
// get file size low and high byte
int size = receive_word_from_cpu();
if(TIMEOUT) return;
Serial.print("received file size: ");
Serial.println(size);
int error = 0;
for(int t=0;t<size;t++) {
int data = receive_byte_from_cpu();
if(TIMEOUT) break;
int n = myFile.write((unsigned char)data);
if(n!=1) error = 1;
}
// close the file
myFile.close();
if(TIMEOUT) return;
// report write issues
if(error) {
Serial.println("file write error");
send_byte_to_cpu(ERR_RESPONSE);
if(TIMEOUT) return;
send_string_to_cpu("?WRITE ERROR");
return;
}
Serial.println("file read ok");
send_byte_to_cpu(OK_RESPONSE);
}
// **************************************************************************************
// **************************************************************************************
// ********************************* LOOP **********************************************
// **************************************************************************************
// **************************************************************************************
void loop() {
TIMEOUT = 0;
int data = receive_byte_from_cpu();
if(TIMEOUT) return;
if(data == CMD_READ) {
comando_read();
if(TIMEOUT) Serial.println("TIMEOUT during CMD_READ");
}
else if(data == CMD_WRITE) {
comando_write();
if(TIMEOUT) Serial.println("TIMEOUT during CMD_WRITE");
}
else if(data == CMD_DIR) {
Serial.println("command DIR received from CPU");
File root = SD.open("/");
printDirectory(root, 0);
root.close();
// terminates
send_byte_to_cpu(0);
if(TIMEOUT) Serial.println("TIMEOUT during DIR");
Serial.println("command DIR ended");
}
else {
Serial.print("unknown command ");
Serial.print(data);
Serial.println(" received");
}
}