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

1085 lines
30 KiB
C++

/*
+-----------+ +-----------------+
| | | 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 |
| | | |
+-----------+ +-----------------+
*/
/*
PORT ASSIGNMENT FOR FAST READ/WRITE
===================================
BIT 0: PORTD[2]
BIT 1: PORTD[3]
BIT 2: PORTD[4]
BIT 3: PORTD[5]
BIT 4: PORTD[6]
BIT 5: PORTD[7]
BIT 6: PORTB[0]
BIT 7: PORTB[1]
MCU_STROBE: PORTC[0]
CPU_STROBE: PORTC[1]
in Verilog syntax: data = { PORTB[1:0], PORTD[7:2] };
*/
// FASTWRITE not working (yet)
// #define FASTWRITE 1
#ifdef FASTWRITE
#define get_cpu_strobe ((PORTC >> 1) & 1)
#define set_mcu_strobe(c) PORTC = (PORTC & 0xFE) | (c)
#else
#define get_cpu_strobe digitalRead(CPU_STROBE)
#define set_mcu_strobe(c) digitalWrite(MCU_STROBE,(c))
#endif
#include <SPI.h>
#include "SdFat.h"
SdFat SD;
#define SD_CS_PIN SS
// 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_cpu_strobe()
byte TIMEOUT = 0;
void wait_cpu_strobe(byte value) {
unsigned long start_time = millis();
unsigned long elapsed;
if(TIMEOUT) return;
while(get_cpu_strobe != value) {
elapsed = millis() - start_time;
if(elapsed > 500) {
TIMEOUT = 1;
break;
}
}
}
const byte DIR_INPUT = 0;
const byte DIR_OUTPUT = 1;
byte last_dir; // remember last data port pins direction
void set_data_port_direction(byte 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;
}
byte 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
#ifdef FASTWRITE
byte data = ((PORTB & 0x03)<<6) | (PORTD >> 2); // data = { PORTB[1:0], PORTD[7:2] }
#else
byte 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);
#endif
// after reading the byte, MCU sets strobe high
set_mcu_strobe(HIGH);
// CPU now sets strobe low
wait_cpu_strobe(LOW);
// and MCU sets strobe low
set_mcu_strobe(LOW);
return data;
}
void send_byte_to_cpu(byte data) {
// set data port pins as OUTPUT pins
set_data_port_direction(DIR_OUTPUT);
// both strobes are 0
// put byte on the data port
#ifdef FASTWRITE
PORTB = (PORTB & 0xFC) | ((data >> 6) & 0x03); // PORTB[1:0] = data[7:6];
PORTD = (PORTD & 0x03) | (data << 2); // PORTD[7:2] = data[5:0];
#else
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);
#endif
// after depositing data byte, MCU sets strobe high
set_mcu_strobe(HIGH);
// wait for CPU to set strobe high
wait_cpu_strobe(HIGH);
// tells CPU byte we are finished
set_mcu_strobe(LOW);
// wait for CPU to set strobe low
wait_cpu_strobe(LOW);
}
// *********************************************************************************************
// *********************************************************************************************
// *********************************************************************************************
// *********************************************************************************************
// *********************************************************************************************
// *********************************************************************************************
// *********************************************************************************************
// *********************************************************************************************
const byte CMD_READ = 0;
const byte CMD_WRITE = 1;
const byte CMD_DIR = 2;
const byte CMD_LOAD = 4;
const byte CMD_DEL = 11;
const byte CMD_LS = 12;
const byte CMD_CD = 13;
const byte CMD_MKDIR = 14;
const byte CMD_PWD = 19;
const byte CMD_RMDIR = 15;
const byte CMD_TEST = 20;
const byte CMD_MOUNT = 21;
const byte ERR_RESPONSE = 255;
const byte WAIT_RESPONSE = 1;
const byte OK_RESPONSE = 0;
// @buffer
char filename[64];
char tmp[32];
char cd_path[64];
// fixed messages
const char *FILE_NOT_FOUND = "?FILE NOT FOUND";
const char *CANT_OPEN_FILE = "?CAN'T OPEN FILE";
const char *ALREADY_EXISTS = "?FILE ALREADY EXISTS";
const char *CANT_CREATE_FILE = "?CAN'T CREATE FILE";
const char *WRITE_ERROR = "?WRITE ERROR";
const char *CANT_DELETE_FILE = "?CAN'T DELETE FILE";
const char *FILE_DELETED = " DELETED";
const char *DIR_NOT_FOUND = "?DIR NOT FOUND";
const char *CANT_REMOVE_DIR = "?CAN'T REMOVE DIR";
const char *DIR_REMOVED = " (DIR) REMOVED";
const char *DIR_ALREADY_EXISTS = "?DIR ALREADY EXISTS";
const char *CANT_MAKE_DIR = "?CAN'T MAKE DIR";
const char *DIR_CREATED = " (DIR) CREATED";
const char *CANT_CD_DIR = "?CAN'T CHANGE DIR";
const char *NOT_A_DIRECTORY = "?NOT A DIRECTORY";
const char *MOUNT_OK = "MOUNTING SDCARD...\rOK";
const char *MOUNT_FAILED = "?SD CARD ERROR";
// file structures used to operate with the SD card
File myFile;
File myDir;
void setup() {
// debug on serial
Serial.begin(9600);
Serial.println(F("SDCARD library: SDFat.h"));
mount_sdcard();
// 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);
// set working directory to root
strcpy(cd_path, "/");
}
bool mount_sdcard() {
// initialize SD card
if(!SD.begin(SD_CS_PIN)) {
Serial.println(F("SD card initialization failed"));
return false;
}
else {
Serial.println(F("SD card initialized"));
return true;
}
}
// **************************************************************************************
// **************************************************************************************
// ********************************* @CMD_DIR ******************************************
// **************************************************************************************
// **************************************************************************************
byte list_files;
void comando_dir(byte command) {
Serial.println(F("command DIR received from CPU"));
// reads filename as 0 terminated string
receive_string_from_cpu(filename);
if(TIMEOUT) return;
Serial.print(F("dir to read: "));
Serial.println(filename);
if(filename[0]==0) {
// no argument given, use cd_path
strcpy(filename, cd_path);
}
myDir = SD.open(filename);
if(!myDir) {
Serial.println(F("dir not found"));
send_byte_to_cpu(ERR_RESPONSE);
send_string_to_cpu(DIR_NOT_FOUND);
return;
}
// dir opened OK
send_byte_to_cpu(OK_RESPONSE);
list_files = 0; // starts listing dirs (0) then files (1)
while(true) {
byte c = receive_byte_from_cpu();
if(TIMEOUT) {
Serial.println(F("timeout while receiving 'next line' byte"));
break;
} else if(c == WAIT_RESPONSE) {
// do nothing, just keep listening
continue;
} else if(c == ERR_RESPONSE) {
// user asked to abort dir listing
Serial.println(F("dir interrupted by the user"));
break;
} else if(c == OK_RESPONSE) {
if(!send_next_dir_line(command)) {
Serial.println(F("dir terminated"));
break;
}
}
}
myDir.close();
}
byte send_next_dir_line(byte command) {
// user wants a new line of dir listing
while(1) {
myFile = myDir.openNextFile();
if(!myFile) {
if(list_files==0) {
list_files++;
myDir.rewind();
continue;
}
else {
// no more lines to send
myDir.close();
send_byte_to_cpu(ERR_RESPONSE);
return 0; // no more lines
}
}
if(myFile.isDirectory() && list_files == 0) break;
if(!myFile.isDirectory() && list_files == 1) break;
}
// send the text line
send_byte_to_cpu(OK_RESPONSE);
send_directory_entry(command);
myFile.close();
return 1; // more lines to send
}
void send_directory_entry(byte command) {
myFile.getName(filename, 64);
strtoupper(filename);
if(myFile.isDirectory()) {
if(command != CMD_DIR) {
sprintf(tmp, "(DIR) %s\r", filename);
print_string_to_cpu(tmp);
Serial.println(tmp);
}
else {
sprintf(tmp, "%-15s (DIR)\r", filename);
print_string_to_cpu(tmp);
Serial.println(tmp);
}
}
else {
if(command != CMD_DIR) {
// BUG the following line does not work
// sprintf(tmp, "%5d %s", entry.size(), filename);
// use this instead
sprintf(tmp, "%5d ", myFile.size());
print_string_to_cpu(tmp);
Serial.print(tmp);
print_string_to_cpu(filename);
Serial.println(filename);
send_byte_to_cpu('\r');
}
else {
char type[5];
char address[5];
strcpy(type,"");
strcpy(address, "");
char *x = strchr(filename, '#');
if(x != NULL) {
*x++ = 0;
if(x[0]=='0' && x[1]=='6') {
strcpy(type,"BIN ");
strcpy(address,x+2);
}
else if(x[0]=='F' && x[1]=='1') {
strcpy(type,"BAS ");
strcpy(address,x+2);
}
else {
strcpy(type,"??? ");
}
}
sprintf(tmp, "%-15s", filename);
print_string_to_cpu(tmp);
Serial.print(filename);
sprintf(tmp, "%6d ", myFile.size());
print_string_to_cpu(tmp);
Serial.print(tmp);
print_string_to_cpu(type);
Serial.print(type);
if(type[0]!=0) {
send_byte_to_cpu('$');
Serial.print("$");
}
print_string_to_cpu(address);
Serial.println(address);
send_byte_to_cpu('\r');
}
}
}
// **************************************************************************************
// **************************************************************************************
// ********************************* CMD_READ ******************************************
// **************************************************************************************
// **************************************************************************************
void comando_read() {
Serial.println(F("command CMD_READ received from CPU"));
// reads filename as 0 terminated string
receive_string_from_cpu(filename);
if(TIMEOUT) return;
Serial.print(F("file to read: "));
Serial.println(filename);
if(!SD.exists(filename)) {
Serial.println(F("error opening file"));
send_byte_to_cpu(ERR_RESPONSE);
send_string_to_cpu(FILE_NOT_FOUND);
return;
}
// open the file
myFile = SD.open(filename);
if(!myFile) {
Serial.println(F("error opening file"));
send_byte_to_cpu(ERR_RESPONSE);
send_string_to_cpu(CANT_OPEN_FILE);
return;
}
Serial.println(F("file opened on the SD card"));
// ok response
send_byte_to_cpu(OK_RESPONSE);
if(TIMEOUT) return;
Serial.println(F("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(F("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(F("timeout, bytes sent: "));
Serial.println(bytes_sent);
return;
}
Serial.println(F("file read ok"));
}
void send_string_to_cpu(char *msg) {
while(1) {
byte c = *msg++;
send_byte_to_cpu(c);
if(TIMEOUT) break;
if(c==0) break;
}
}
// come send_string_to_cpu ma senza lo zero finale
void print_string_to_cpu(char *msg) {
while(1) {
byte c = *msg++;
if(c==0) break;
send_byte_to_cpu(c);
if(TIMEOUT) break;
}
}
void receive_string_from_cpu(char *msg) {
while(1) {
byte c = receive_byte_from_cpu();
if(TIMEOUT) break;
*msg++ = c;
if(c==0) break;
}
}
// **************************************************************************************
// **************************************************************************************
// ********************************* CMD_WRITE *****************************************
// **************************************************************************************
// **************************************************************************************
int receive_word_from_cpu() {
byte lo = receive_byte_from_cpu();
byte hi = receive_byte_from_cpu();
int data = lo | (hi << 8);
return data;
}
void comando_write() {
Serial.println(F("command CMD_WRITE received from CPU"));
// reads filename as 0 terminated string
receive_string_from_cpu(filename);
if(TIMEOUT) return;
Serial.print(F("file to write: "));
Serial.println(filename);
if(SD.exists(filename)) {
Serial.println(F("file already exist"));
send_byte_to_cpu(ERR_RESPONSE);
send_string_to_cpu(ALREADY_EXISTS);
return;
}
// open the file
myFile = SD.open(filename, FILE_WRITE);
if(!myFile) {
Serial.println(F("error opening file for write"));
send_byte_to_cpu(ERR_RESPONSE);
send_string_to_cpu(CANT_CREATE_FILE);
return;
}
Serial.println(F("file opened for write on the SD card"));
// ok response
send_byte_to_cpu(OK_RESPONSE);
if(TIMEOUT) return;
Serial.println(F("first ok response sent to CPU"));
// get file size low and high byte
int size = receive_word_from_cpu();
if(TIMEOUT) return;
Serial.print(F("received file size: "));
Serial.println(size);
byte error = 0;
for(int t=0;t<size;t++) {
byte 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(F("file write error"));
send_byte_to_cpu(ERR_RESPONSE);
if(TIMEOUT) return;
send_string_to_cpu(WRITE_ERROR);
return;
}
Serial.println(F("file read ok"));
send_byte_to_cpu(OK_RESPONSE);
}
// **************************************************************************************
// **************************************************************************************
// ********************************* CMD_LOAD ******************************************
// **************************************************************************************
// **************************************************************************************
void comando_load() {
Serial.println(F("command CMD_LOAD received from CPU"));
// reads filename as 0 terminated string
receive_string_from_cpu(filename);
if(TIMEOUT) return;
Serial.print(F("file to read: "));
Serial.println(filename);
// if a matching file name is found, use it
if(matchname(filename, tmp)==1) {
Serial.print(F("found matching file: "));
Serial.println(tmp);
strcpy(filename, tmp);
}
if(!SD.exists(filename)) {
Serial.println(F("error opening file"));
send_byte_to_cpu(ERR_RESPONSE);
send_string_to_cpu(FILE_NOT_FOUND);
return;
}
// open the file
myFile = SD.open(filename);
if(!myFile) {
Serial.println(F("error opening file"));
send_byte_to_cpu(ERR_RESPONSE);
send_string_to_cpu(CANT_OPEN_FILE);
return;
}
Serial.println(F("file opened on the SD card"));
// ok response
send_byte_to_cpu(OK_RESPONSE);
if(TIMEOUT) return;
Serial.println(F("ok response sent to CPU"));
// sends matched filename
send_string_to_cpu(filename);
// 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(F("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(F("timeout, bytes sent: "));
Serial.println(bytes_sent);
return;
}
Serial.println(F("file read ok"));
}
void strtoupper(char *str){
int len = strlen(str), i;
for(i=0;i<len;i++)
if(str[i]>='a' && str[i]<='z')
str[i] = str[i]-'a'+'A';
}
// splits filename into file_path and file_name
// e.g. "root/myfolder/pluto" => "root/myfolder" , "pluto"
// "myfolder/pluto" => "myfolder", "pluto"
// "pluto" => "", "pluto"
// "/pluto" => "/", "pluto"
// @buffer
char file_path[64];
char file_name[32];
void split_path(char *filename) {
strcpy(file_path, filename);
for(int t=strlen(file_path)-1;t>0;t--) {
if(file_path[t] == '/') {
file_path[t] = 0;
strcpy(file_name, &file_path[t+1]);
if(t==0) strcpy(file_path, "/"); // case of root folder
return;
}
}
strcpy(file_path, "");
strcpy(file_name, filename);
}
//
// returns in dest the first file that matches (starts with) "filename"
// returns 1 if matching file is found
// returns 0 if no matching file is found
//
byte matchname(char *filename, char *dest) {
// split filename into file_path and file_name
split_path(filename);
Serial.print(F("after split file_path="));
Serial.print(file_path);
Serial.print(F(", file_name="));
Serial.println(file_name);
if(strlen(file_path)==0) Serial.println(F("scanning the current directory"));
else Serial.println(F("scanning the file_path directory"));
// open the directory containing the file
myDir = SD.open(strlen(file_path)==0 ? cd_path : file_path);
if(!myDir) return 0;
Serial.println(F("dir opened"));
// scans twice: scanmode=0 for exact match, scanmode=1 for partial match
for(byte scanmode=0;scanmode<=1;scanmode++) {
if(scanmode==0) Serial.println(F("scanning for exact match..."));
if(scanmode==1) Serial.println(F("scanning for partial match..."));
// scan all the directory
while(1) {
send_byte_to_cpu(WAIT_RESPONSE);
if(TIMEOUT) return 0;
myFile = myDir.openNextFile();
// end of directory
if(!myFile) {
if(scanmode == 0) {
// exact match not found, rewind the directory and scan fot partial match
myDir.rewind();
break;
}
else if(scanmode == 1) {
// match not found even with partial match, return error
myDir.close();
return 0;
}
}
// copy filename in dest and closes it
myFile.getName(dest, 64);
strtoupper(dest);
myFile.close();
Serial.print(F("file entry: "));
Serial.println(dest);
// verify the match
int len = strlen(filename);
bool match_found = strncmp(file_name, dest, len) == 0;
// enforce exact match
if(scanmode == 0) match_found = match_found && dest[strlen(filename)] == '#';
if(match_found) {
if(scanmode==0) Serial.println(F("found an exact match"));
if(scanmode==1) Serial.println(F("found a partial match"));
// matching, dest already contains the matched file name
// if file_path is empty then it's current directory, do nothing
// else file_path needs to be combined with file name
if(file_path[0]!=0) {
Serial.println(F("not on current dir, joining paths"));
strcpy(filename, dest);
if(file_path[0]=='/' && file_path[1]==0) sprintf(dest,"/%s", filename); // case of root folder
else sprintf(dest,"%s/%s", file_path, filename); // case of normal nested folder
}
myDir.close();
return 1;
}
}
}
}
// **************************************************************************************
// **************************************************************************************
// ********************************* CMD_DEL ********************************************
// **************************************************************************************
// **************************************************************************************
void comando_del() {
Serial.println(F("command DEL received from CPU"));
// reads filename as 0 terminated string
receive_string_from_cpu(filename);
if(TIMEOUT) return;
Serial.print(F("file to delete: "));
Serial.println(filename);
if(!SD.exists(filename)) {
Serial.println(F("file does not exist"));
send_string_to_cpu(FILE_NOT_FOUND);
return;
}
if(TIMEOUT) return;
// open the file for deletion
myFile = SD.open(filename, FILE_WRITE);
if(!myFile) {
Serial.println(F("error opening file for deletion"));
send_string_to_cpu(CANT_DELETE_FILE);
myFile.close();
return;
}
if(TIMEOUT) return;
if(!myFile.remove()) {
Serial.println(F("error removing file"));
send_string_to_cpu(CANT_DELETE_FILE);
myFile.close();
return;
}
// close the file
myFile.close();
print_string_to_cpu(filename);
send_string_to_cpu(FILE_DELETED);
Serial.println(F("file deleted"));
}
// **************************************************************************************
// **************************************************************************************
// ********************************* CMD_RMDIR ******************************************
// **************************************************************************************
// **************************************************************************************
void comando_rmdir() {
Serial.println(F("command RMDIR received from CPU"));
// reads filename as 0 terminated string
receive_string_from_cpu(filename);
if(TIMEOUT) return;
Serial.print(F("directory to delete: "));
Serial.println(filename);
if(TIMEOUT) return;
// check if the directory exists
if(!SD.exists(filename)) {
Serial.println(F("dir does not exist"));
send_string_to_cpu(DIR_NOT_FOUND);
return;
}
// removes the directory
if(!SD.rmdir(filename)) {
Serial.println(F("error removing dir"));
send_string_to_cpu(CANT_REMOVE_DIR);
return;
}
print_string_to_cpu(filename);
send_string_to_cpu(DIR_REMOVED);
Serial.println(F("dir removed"));
}
// **************************************************************************************
// **************************************************************************************
// ********************************* CMD_MKDIR ******************************************
// **************************************************************************************
// **************************************************************************************
void comando_mkdir() {
Serial.println(F("command MKDIR received from CPU"));
// reads filename as 0 terminated string
receive_string_from_cpu(filename);
if(TIMEOUT) return;
Serial.print(F("directory to create: "));
Serial.println(filename);
if(TIMEOUT) return;
// check if the directory exists
if(SD.exists(filename)) {
Serial.println(F("dir already exist"));
send_string_to_cpu(DIR_ALREADY_EXISTS);
return;
}
// removes the directory
if(!SD.mkdir(filename)) {
Serial.println(F("error creating"));
send_string_to_cpu(CANT_MAKE_DIR);
return;
}
print_string_to_cpu(filename);
send_string_to_cpu(DIR_CREATED);
Serial.println(F("dir created"));
}
// **************************************************************************************
// **************************************************************************************
// ********************************* @CMD_CD ********************************************
// **************************************************************************************
// **************************************************************************************
void comando_cd() {
Serial.println(F("command CD received from CPU"));
// reads filename as 0 terminated string
receive_string_from_cpu(filename);
if(TIMEOUT) return;
Serial.print(F("directory to change to: "));
Serial.println(filename);
if(TIMEOUT) return;
// CD without arguments
if(filename[0] == 0) {
// ok response
send_byte_to_cpu(OK_RESPONSE);
return;
}
// CD ..
if(filename[0] == '.' && filename[1] == '.' && filename[2] == 0) {
strcpy(filename, cd_path);
for(int t=strlen(filename)-1;t>=1;t--) {
byte c = filename[t];
filename[t] = 0;
if(c == '/') break;
}
}
// CD /
if(filename[0] == '/' && filename[1] == 0) {
// changes to the root directory
if(SD.chdir()) {
// set root working directory
strcpy(cd_path, filename);
Serial.print(F("dir changed to:"));
Serial.println(cd_path);
send_byte_to_cpu(OK_RESPONSE);
return;
}
else {
Serial.println(F("error changing dir"));
send_byte_to_cpu(ERR_RESPONSE);
send_string_to_cpu(CANT_CD_DIR);
return;
}
}
// CD dirname
if(SD.chdir(filename)) {
// update working directory
if(filename[0] == '/') {
strcpy(cd_path, filename); // path is absolute, replace cwd
}
else {
// path is relative, append to cwd
if(cd_path[0] == '/' && cd_path[1] == 0) {
cd_path[0] = 0; // avoid the double slash ("//DIR") when cwd is root
}
sprintf(tmp, "%s/%s", cd_path, filename);
strcpy(cd_path, tmp);
}
Serial.print(F("dir changed to:"));
Serial.println(cd_path);
send_byte_to_cpu(OK_RESPONSE);
return;
}
// errors
send_byte_to_cpu(ERR_RESPONSE);
// check if the directory exists
if(!SD.exists(filename)) {
Serial.println(F("dir not found"));
send_string_to_cpu(DIR_NOT_FOUND);
return;
}
myFile = SD.open(filename);
bool isDir = myFile.isDirectory();
myFile.close();
if(!isDir) {
Serial.println(F("not a directory"));
send_string_to_cpu(NOT_A_DIRECTORY);
}
else {
Serial.println(F("error changing dir"));
send_string_to_cpu(CANT_CD_DIR);
}
}
// **************************************************************************************
// **************************************************************************************
// ********************************* @CMD_PWD *******************************************
// **************************************************************************************
// **************************************************************************************
void comando_pwd() {
Serial.println(F("command PWD received from CPU"));
send_string_to_cpu(cd_path);
}
// **************************************************************************************
// **************************************************************************************
// ********************************* LOOP **********************************************
// **************************************************************************************
// **************************************************************************************
void loop() {
TIMEOUT = 0;
byte data = receive_byte_from_cpu();
if(TIMEOUT) return;
unsigned long start_time = millis();
if(data == CMD_READ) comando_read();
else if(data == CMD_WRITE) comando_write();
else if(data == CMD_LOAD) comando_load();
else if(data == CMD_DEL) comando_del();
else if(data == CMD_RMDIR) comando_rmdir();
else if(data == CMD_MKDIR) comando_mkdir();
else if(data == CMD_CD) comando_cd();
else if(data == CMD_PWD) comando_pwd();
else if(data == CMD_DIR) comando_dir(data);
else if(data == CMD_LS) comando_dir(data);
else if(data == CMD_TEST) {
while(!TIMEOUT) {
byte data = receive_byte_from_cpu();
send_byte_to_cpu(data ^ 0xFF);
}
}
else if(data == CMD_MOUNT) {
bool mount = mount_sdcard();
if(mount) send_string_to_cpu(MOUNT_OK);
else send_string_to_cpu(MOUNT_FAILED);
}
else {
Serial.print(F("unknown command "));
Serial.print(data);
Serial.println(F(" received"));
}
Serial.print(F("command processing time: "));
Serial.println(millis() - start_time);
if(TIMEOUT) Serial.println(F("TIMEOUT during command"));
}