mirror of
https://github.com/nippur72/apple1-videocard-lib.git
synced 2024-12-22 13:30:38 +00:00
tagged file names (LOAD, RUN, SAVE, DIR)
This commit is contained in:
parent
ee8a7e3308
commit
8f345b801e
@ -36,7 +36,7 @@ in Verilog syntax: data = { PORTB[1:0], PORTD[7:2] };
|
||||
|
||||
*/
|
||||
|
||||
#define FASTWRITE 1
|
||||
// #define FASTWRITE 1
|
||||
|
||||
#ifdef FASTWRITE
|
||||
#define get_cpu_strobe ((PORTC >> 1) & 1)
|
||||
@ -47,7 +47,8 @@ in Verilog syntax: data = { PORTB[1:0], PORTD[7:2] };
|
||||
#endif
|
||||
|
||||
|
||||
#include <Regexp.h>
|
||||
// #include <Regexp.h>
|
||||
|
||||
#include <SPI.h>
|
||||
#include "SdFat.h"
|
||||
|
||||
@ -210,6 +211,7 @@ void send_byte_to_cpu(int data) {
|
||||
const int CMD_READ = 0;
|
||||
const int CMD_WRITE = 1;
|
||||
const int CMD_DIR = 2;
|
||||
const int CMD_LOAD = 4;
|
||||
const int CMD_DEL = 11;
|
||||
const int CMD_LS = 12;
|
||||
const int CMD_CD = 13;
|
||||
@ -218,8 +220,9 @@ const int CMD_PWD = 19;
|
||||
const int CMD_RMDIR = 15;
|
||||
const int CMD_TEST = 20;
|
||||
|
||||
const int ERR_RESPONSE = 255;
|
||||
const int OK_RESPONSE = 0;
|
||||
const int ERR_RESPONSE = 255;
|
||||
const int WAIT_RESPONSE = 1;
|
||||
const int OK_RESPONSE = 0;
|
||||
|
||||
char filename[64];
|
||||
char tmp[64];
|
||||
@ -260,6 +263,8 @@ void setup() {
|
||||
last_dir = -1; // no previous data direction
|
||||
set_data_port_direction(DIR_INPUT);
|
||||
|
||||
/*
|
||||
// regex disabled for now
|
||||
MatchState ms;
|
||||
char buf [100] = { "The quick " };
|
||||
ms.Target (buf);
|
||||
@ -267,6 +272,7 @@ void setup() {
|
||||
if(result >0) {
|
||||
Serial.println("match!");
|
||||
}
|
||||
*/
|
||||
|
||||
// set working directory to root
|
||||
strcpy(cd_path, "/");
|
||||
@ -400,6 +406,7 @@ void print_dir_entry(File dir, int list_files, int command) {
|
||||
|
||||
// send file size or directory
|
||||
entry.getName(filename, 64);
|
||||
strtoupper(filename);
|
||||
|
||||
if((list_files == 0 && entry.isDirectory()) || (list_files == 1 && !entry.isDirectory())) {
|
||||
if(entry.isDirectory()) {
|
||||
@ -429,16 +436,42 @@ void print_dir_entry(File dir, int list_files, int command) {
|
||||
send_byte_to_cpu('\r');
|
||||
}
|
||||
else {
|
||||
// BUG the following line does not work
|
||||
// sprintf(tmp, "%5d %s", entry.size(), filename);
|
||||
// use this instead
|
||||
|
||||
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", entry.size());
|
||||
sprintf(tmp, "%6d ", entry.size());
|
||||
print_string_to_cpu(tmp);
|
||||
Serial.println(tmp);
|
||||
Serial.print(tmp);
|
||||
|
||||
print_string_to_cpu(type);
|
||||
Serial.print(type);
|
||||
|
||||
print_string_to_cpu(address);
|
||||
Serial.println(address);
|
||||
|
||||
send_byte_to_cpu('\r');
|
||||
}
|
||||
@ -616,6 +649,173 @@ void comando_write() {
|
||||
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
|
||||
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"
|
||||
|
||||
char file_path[64];
|
||||
char file_name[64];
|
||||
|
||||
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
|
||||
//
|
||||
int 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
|
||||
File dir = SD.open(strlen(file_path)==0 ? cd_path : file_path);
|
||||
|
||||
if(!dir) return 0;
|
||||
|
||||
Serial.println(F("dir opened"));
|
||||
|
||||
// scan all the directory
|
||||
while(1) {
|
||||
|
||||
send_byte_to_cpu(WAIT_RESPONSE);
|
||||
if(TIMEOUT) return 0;
|
||||
|
||||
File F = dir.openNextFile();
|
||||
|
||||
// end of directory
|
||||
if(!F) {
|
||||
dir.close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// copy filename in dest and closes it
|
||||
F.getName(dest, 64);
|
||||
strtoupper(dest);
|
||||
F.close();
|
||||
|
||||
Serial.println(F("file entry:"));
|
||||
Serial.println(dest);
|
||||
|
||||
// verify the match
|
||||
if(strncmp(file_name, dest, strlen(filename))==0) {
|
||||
Serial.println(F("it is matching!"));
|
||||
// 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
|
||||
}
|
||||
dir.close();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// **************************************************************************************
|
||||
// **************************************************************************************
|
||||
// ********************************* CMD_DEL ********************************************
|
||||
@ -867,6 +1067,7 @@ void loop() {
|
||||
|
||||
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();
|
||||
|
@ -6,30 +6,109 @@
|
||||
|
||||
// global cmd
|
||||
|
||||
void comando_load() {
|
||||
void comando_load_bas() {
|
||||
|
||||
// send command byte
|
||||
send_byte_to_MCU(CMD_READ);
|
||||
send_byte_to_MCU(CMD_LOAD);
|
||||
if(TIMEOUT) return;
|
||||
|
||||
// send filename
|
||||
send_string_to_MCU(filename);
|
||||
if(TIMEOUT) return;
|
||||
|
||||
// response
|
||||
byte response = receive_byte_from_MCU();
|
||||
if(TIMEOUT) return;
|
||||
// wait for OK response, MCU sends many WAIT_RESPONSE to avoid TIMEOUT
|
||||
while(1) {
|
||||
byte response = receive_byte_from_MCU();
|
||||
if(TIMEOUT) return;
|
||||
|
||||
if(response == ERR_RESPONSE) {
|
||||
// error with file, print message
|
||||
print_string_response();
|
||||
return;
|
||||
if(response == ERR_RESPONSE) {
|
||||
// error with file, print message
|
||||
print_string_response();
|
||||
return;
|
||||
}
|
||||
if(response == OK_RESPONSE) break;
|
||||
}
|
||||
|
||||
// get matching file name
|
||||
receive_string_from_MCU(filename);
|
||||
woz_puts("FOUND ");
|
||||
woz_puts(filename);
|
||||
woz_putc('\r');
|
||||
|
||||
byte filetype = 0;
|
||||
token_ptr = filename;
|
||||
while(1) {
|
||||
if(*token_ptr == '#') {
|
||||
if(token_ptr[1] == '0' && token_ptr[2] == '6') { filetype = 0x06; break; }
|
||||
if(token_ptr[1] == 'F' && token_ptr[2] == '1') { filetype = 0xF1; break; }
|
||||
}
|
||||
if(*token_ptr == 0) break;
|
||||
token_ptr++;
|
||||
}
|
||||
|
||||
// calculate start address for 0x06 binary file
|
||||
if(filetype == 0x06) {
|
||||
token_ptr+=2;
|
||||
hex_to_word(token_ptr);
|
||||
start_address = tmpword;
|
||||
}
|
||||
|
||||
// get file length in tmpword
|
||||
receive_word_from_mcu();
|
||||
if(TIMEOUT) return;
|
||||
|
||||
if(filetype != 0x06 && filetype != 0xF1) {
|
||||
woz_puts("?INVALID FILE NAME TAG #");
|
||||
for(word t=0;t!=tmpword;t++) receive_byte_from_MCU(); // empty buffer
|
||||
return;
|
||||
}
|
||||
|
||||
woz_puts("LOADING\r");
|
||||
|
||||
if(filetype == 0x06) {
|
||||
// 0x06 BINARY FILE format
|
||||
|
||||
// get file bytes
|
||||
token_ptr = (byte *) start_address;
|
||||
for(word t=0;t!=tmpword;t++) {
|
||||
byte data = receive_byte_from_MCU();
|
||||
if(TIMEOUT) return;
|
||||
*token_ptr++ = data;
|
||||
|
||||
#ifdef LOADING_DOTS
|
||||
if(((byte)t) == 0) woz_putc('.');
|
||||
#endif
|
||||
}
|
||||
|
||||
// decrease by one for display result
|
||||
token_ptr--;
|
||||
|
||||
// print feedback to user
|
||||
woz_putc('\r');
|
||||
woz_puts(filename);
|
||||
woz_putc('\r');
|
||||
woz_print_hexword(start_address);
|
||||
woz_putc('.');
|
||||
woz_print_hexword((word)token_ptr);
|
||||
woz_puts(" (");
|
||||
utoa(tmpword, filename, 10); // use filename as string buffer
|
||||
woz_puts(filename);
|
||||
woz_puts(" BYTES)\rOK");
|
||||
|
||||
// executes machine language program at start address
|
||||
if(cmd == CMD_RUN) {
|
||||
woz_putc('\r');
|
||||
tmpword = start_address;
|
||||
asm {
|
||||
jmp (tmpword)
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// 0xF1 BASIC FILE TYPE
|
||||
|
||||
// get file bytes
|
||||
token_ptr = (byte *) 0;
|
||||
for(word t=0;t!=tmpword;t++) {
|
||||
@ -37,7 +116,9 @@ void comando_load() {
|
||||
if(TIMEOUT) return;
|
||||
|
||||
if((t==0 && data!=0x41) || (t==1 && data!=0x31)) {
|
||||
woz_puts("?NOT CFFA1/PRODOS FORMAT");
|
||||
woz_puts("?UNKNOWN FILE FORMAT");
|
||||
t=t+1;
|
||||
for(;t!=tmpword;t++) receive_byte_from_MCU(); // empty buffer
|
||||
return;
|
||||
}
|
||||
else if(t<0x004a) {
|
||||
@ -81,14 +162,15 @@ void bas_file_info() {
|
||||
// print feedback to user
|
||||
woz_putc('\r');
|
||||
woz_puts(filename);
|
||||
woz_puts(": ");
|
||||
woz_putc('\r');
|
||||
bas_info();
|
||||
woz_puts("\rOK");
|
||||
}
|
||||
|
||||
void bas_info() {
|
||||
woz_puts("LOMEM=");
|
||||
woz_puts("(LOMEM=");
|
||||
woz_print_hexword((word) *BASIC_LOMEM);
|
||||
woz_puts(" HIMEM=");
|
||||
woz_print_hexword((word) *BASIC_HIMEM);
|
||||
woz_putc(')');
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ void comando_read() {
|
||||
// print feedback to user
|
||||
woz_putc('\r');
|
||||
woz_puts(filename);
|
||||
woz_puts(": ");
|
||||
woz_putc('\r');
|
||||
woz_print_hexword(start_address);
|
||||
woz_putc('.');
|
||||
woz_print_hexword((word)token_ptr);
|
||||
|
@ -1,11 +1,20 @@
|
||||
// global len
|
||||
|
||||
void comando_save() {
|
||||
void comando_save_bas() {
|
||||
|
||||
if(((word) *BASIC_HIMEM) < ((word) *BASIC_LOMEM)) {
|
||||
woz_puts("?NO BASIC PROGRAM");
|
||||
return;
|
||||
}
|
||||
|
||||
// send command byte
|
||||
send_byte_to_MCU(CMD_WRITE);
|
||||
if(TIMEOUT) return;
|
||||
|
||||
strcat(filename, "#F1");
|
||||
tmpword = (word) *BASIC_LOMEM;
|
||||
append_hex_tmpword(filename);
|
||||
|
||||
// send filename
|
||||
send_string_to_MCU(filename);
|
||||
if(TIMEOUT) return;
|
||||
@ -19,6 +28,8 @@ void comando_save() {
|
||||
return;
|
||||
}
|
||||
|
||||
woz_puts("SAVING\r");
|
||||
|
||||
// send file size
|
||||
//tmpword = ((word) *BASIC_HIMEM) - ((word)*BASIC_LOMEM) + 512;
|
||||
// in assembly:
|
||||
|
@ -60,7 +60,7 @@ void comando_write() {
|
||||
// print feedback to user
|
||||
woz_putc('\r');
|
||||
woz_puts(filename);
|
||||
woz_puts(": ");
|
||||
woz_puts(":\r");
|
||||
woz_print_hexword(start_address);
|
||||
woz_putc('.');
|
||||
woz_print_hexword(end_address);
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
byte **const BASIC_LOMEM = (byte **) 0x004a; // lomem pointer used by integer BASIC
|
||||
byte **const BASIC_HIMEM = (byte **) 0x004c; // himem pointer used by integer BASIC
|
||||
@ -15,8 +15,9 @@ byte *const filename = (byte *) (KEYBUFSTART+KEYBUFLEN+6 ); // [33] stores a
|
||||
byte *const hex1 = (byte *) (KEYBUFSTART+KEYBUFLEN+6+33 ); // [5] stores a hex parameter
|
||||
byte *const hex2 = (byte *) (KEYBUFSTART+KEYBUFLEN+6+33+5); // [5] stores a hex parameter
|
||||
|
||||
const byte OK_RESPONSE = 0x00;
|
||||
const byte ERR_RESPONSE = 0xFF;
|
||||
const byte OK_RESPONSE = 0x00;
|
||||
const byte WAIT_RESPONSE = 0x01;
|
||||
const byte ERR_RESPONSE = 0xFF;
|
||||
|
||||
// command constants, which are also byte commands to send to the MCU
|
||||
const byte CMD_READ = 0;
|
||||
@ -127,6 +128,27 @@ void hex_to_word(byte *str) {
|
||||
if(i>4 || i==0) hex_to_word_ok = 0;
|
||||
}
|
||||
|
||||
void strcat(char *dest, char *src) {
|
||||
while(*dest) dest++;
|
||||
while(*src) *dest++ = *src++;
|
||||
*dest = 0;
|
||||
}
|
||||
|
||||
void append_hex_digit(char *dest, byte digit) {
|
||||
while(*dest) dest++;
|
||||
if(digit<10) digit += '0';
|
||||
else digit += 'A' - 10;
|
||||
*dest++ = digit;
|
||||
*dest = 0;
|
||||
}
|
||||
|
||||
void append_hex_tmpword(char *dest) {
|
||||
append_hex_digit(dest, *((byte *)&tmpword+1) >> 4);
|
||||
append_hex_digit(dest, *((byte *)&tmpword+1) & 0x0F);
|
||||
append_hex_digit(dest, *((byte *)&tmpword+0) >> 4);
|
||||
append_hex_digit(dest, *((byte *)&tmpword+0) & 0x0F);
|
||||
}
|
||||
|
||||
#include "cmd_read.h"
|
||||
#include "cmd_write.h"
|
||||
#include "cmd_load.h"
|
||||
@ -238,7 +260,7 @@ void console() {
|
||||
woz_puts("?MISSING FILENAME");
|
||||
continue;
|
||||
}
|
||||
comando_load();
|
||||
comando_load_bas();
|
||||
}
|
||||
else if(cmd == CMD_SAVE) {
|
||||
get_token(filename, 32); // parse filename
|
||||
@ -246,7 +268,33 @@ void console() {
|
||||
woz_puts("?MISSING FILENAME");
|
||||
continue;
|
||||
}
|
||||
comando_save();
|
||||
//comando_save();
|
||||
|
||||
get_token(hex1, 4);
|
||||
if(hex1[0] != 0) {
|
||||
// it's SAVE binary file
|
||||
hex_to_word(hex1);
|
||||
if(!hex_to_word_ok) {
|
||||
woz_puts("?BAD ADDRESS");
|
||||
continue;
|
||||
}
|
||||
start_address = tmpword;
|
||||
|
||||
strcat(filename, "#06");
|
||||
append_hex_tmpword(filename);
|
||||
|
||||
get_token(hex2, 4);
|
||||
hex_to_word(hex2);
|
||||
if(!hex_to_word_ok) {
|
||||
woz_puts("?BAD ADDRESS");
|
||||
continue;
|
||||
}
|
||||
end_address = tmpword;
|
||||
comando_write();
|
||||
}
|
||||
else {
|
||||
comando_save_bas();
|
||||
}
|
||||
}
|
||||
else if(cmd == CMD_TYPE) {
|
||||
get_token(filename, 32); // parse filename
|
||||
|
@ -121,6 +121,16 @@ void send_string_to_MCU(char *msg) {
|
||||
}
|
||||
}
|
||||
|
||||
// receive a string sent by the MCU
|
||||
void receive_string_from_MCU(char *dest) {
|
||||
while(1) {
|
||||
byte data = receive_byte_from_MCU();
|
||||
*dest++ = data;
|
||||
if(TIMEOUT) break;
|
||||
if(data == 0) break; // string terminator
|
||||
}
|
||||
}
|
||||
|
||||
// print a string sent by the MCU
|
||||
void print_string_response() {
|
||||
while(1) {
|
||||
|
Loading…
Reference in New Issue
Block a user