runcpm-pico/abstraction_arduino.h

521 lines
11 KiB
C

#ifndef ABSTRACT_H
#define ABSTRACT_H
#ifdef PROFILE
#define printf(a, b) Serial.println(b)
#endif
// #if defined ARDUINO_SAM_DUE || defined ADAFRUIT_GRAND_CENTRAL_M4
#define HostOS 0x01
// #endif
#if defined CORE_TEENSY
#define HostOS 0x04
#endif
#if defined ESP32
#define HostOS 0x05
#endif
#if defined _STM32_DEF_
#define HostOS 0x06
#endif
/* Memory abstraction functions */
/*===============================================================================*/
bool _RamLoad(char* filename, uint16 address) {
File32 f;
bool result = false;
if (f = SD.open(filename, FILE_READ)) {
while (f.available())
_RamWrite(address++, f.read());
f.close();
result = true;
}
return(result);
}
/* Filesystem (disk) abstraction fuctions */
/*===============================================================================*/
File32 rootdir, userdir;
#define FOLDERCHAR '/'
typedef struct {
uint8 dr;
uint8 fn[8];
uint8 tp[3];
uint8 ex, s1, s2, rc;
uint8 al[16];
uint8 cr, r0, r1, r2;
} CPM_FCB;
typedef struct {
uint8 dr;
uint8 fn[8];
uint8 tp[3];
uint8 ex, s1, s2, rc;
uint8 al[16];
} CPM_DIRENTRY;
static DirFat_t fileDirEntry;
bool _sys_exists(uint8* filename) {
return(SD.exists((const char *)filename));
}
File32 _sys_fopen_w(uint8* filename) {
return(SD.open((char*)filename, O_CREAT | O_WRITE));
}
int _sys_fputc(uint8 ch, File32& f) {
return(f.write(ch));
}
void _sys_fflush(File32& f) {
f.flush();
}
void _sys_fclose(File32& f) {
f.close();
}
int _sys_select(uint8* disk) {
uint8 result = FALSE;
File32 f;
digitalWrite(LED, HIGH ^ LEDinv);
if (f = SD.open((char*)disk, O_READ)) {
if (f.isDirectory())
result = TRUE;
f.close();
}
digitalWrite(LED, LOW ^ LEDinv);
return(result);
}
long _sys_filesize(uint8* filename) {
long l = -1;
File32 f;
digitalWrite(LED, HIGH ^ LEDinv);
if (f = SD.open((char*)filename, O_RDONLY)) {
l = f.size();
f.close();
}
digitalWrite(LED, LOW ^ LEDinv);
return(l);
}
int _sys_openfile(uint8* filename) {
File32 f;
int result = 0;
digitalWrite(LED, HIGH ^ LEDinv);
f = SD.open((char*)filename, O_READ);
if (f) {
f.dirEntry(&fileDirEntry);
f.close();
result = 1;
}
digitalWrite(LED, LOW ^ LEDinv);
return(result);
}
int _sys_makefile(uint8* filename) {
File32 f;
int result = 0;
digitalWrite(LED, HIGH ^ LEDinv);
f = SD.open((char*)filename, O_CREAT | O_WRITE);
if (f) {
f.close();
result = 1;
}
digitalWrite(LED, LOW ^ LEDinv);
return(result);
}
int _sys_deletefile(uint8* filename) {
digitalWrite(LED, HIGH ^ LEDinv);
return(SD.remove((char*)filename));
digitalWrite(LED, LOW ^ LEDinv);
}
int _sys_renamefile(uint8* filename, uint8* newname) {
File32 f;
int result = 0;
digitalWrite(LED, HIGH ^ LEDinv);
f = SD.open((char*)filename, O_WRITE | O_APPEND);
if (f) {
if (f.rename((char*)newname)) {
f.close();
result = 1;
}
}
digitalWrite(LED, LOW ^ LEDinv);
return(result);
}
#ifdef DEBUGLOG
void _sys_logbuffer(uint8* buffer) {
#ifdef CONSOLELOG
puts((char*)buffer);
#else
File32 f;
uint8 s = 0;
while (*(buffer + s)) // Computes buffer size
++s;
if (f = SD.open(LogName, O_CREAT | O_APPEND | O_WRITE)) {
f.write(buffer, s);
f.flush();
f.close();
}
#endif
}
#endif
bool _sys_extendfile(char* fn, unsigned long fpos)
{
uint8 result = true;
File32 f;
unsigned long i;
digitalWrite(LED, HIGH ^ LEDinv);
if (f = SD.open(fn, O_WRITE | O_APPEND)) {
if (fpos > f.size()) {
for (i = 0; i < f.size() - fpos; ++i) {
if (f.write((uint8)0) != 1) {
result = false;
break;
}
}
}
f.close();
} else {
result = false;
}
digitalWrite(LED, LOW ^ LEDinv);
return(result);
}
uint8 _sys_readseq(uint8* filename, long fpos) {
uint8 result = 0xff;
File32 f;
uint8 bytesread;
uint8 dmabuf[BlkSZ];
uint8 i;
digitalWrite(LED, HIGH ^ LEDinv);
f = SD.open((char*)filename, O_READ);
if (f) {
if (f.seek(fpos)) {
for (i = 0; i < BlkSZ; ++i)
dmabuf[i] = 0x1a;
bytesread = f.read(&dmabuf[0], BlkSZ);
if (bytesread) {
for (i = 0; i < BlkSZ; ++i)
_RamWrite(dmaAddr + i, dmabuf[i]);
}
result = bytesread ? 0x00 : 0x01;
} else {
result = 0x01;
}
f.close();
} else {
result = 0x10;
}
digitalWrite(LED, LOW ^ LEDinv);
return(result);
}
uint8 _sys_writeseq(uint8* filename, long fpos) {
uint8 result = 0xff;
File32 f;
digitalWrite(LED, HIGH ^ LEDinv);
if (_sys_extendfile((char*)filename, fpos))
f = SD.open((char*)filename, O_RDWR);
if (f) {
if (f.seek(fpos)) {
if (f.write(_RamSysAddr(dmaAddr), BlkSZ))
result = 0x00;
} else {
result = 0x01;
}
f.close();
} else {
result = 0x10;
}
digitalWrite(LED, LOW ^ LEDinv);
return(result);
}
uint8 _sys_readrand(uint8* filename, long fpos) {
uint8 result = 0xff;
File32 f;
uint8 bytesread;
uint8 dmabuf[BlkSZ];
uint8 i;
long extSize;
digitalWrite(LED, HIGH ^ LEDinv);
f = SD.open((char*)filename, O_READ);
if (f) {
if (f.seek(fpos)) {
for (i = 0; i < BlkSZ; ++i)
dmabuf[i] = 0x1a;
bytesread = f.read(&dmabuf[0], BlkSZ);
if (bytesread) {
for (i = 0; i < BlkSZ; ++i)
_RamWrite(dmaAddr + i, dmabuf[i]);
}
result = bytesread ? 0x00 : 0x01;
} else {
if (fpos >= 65536L * BlkSZ) {
result = 0x06; // seek past 8MB (largest file size in CP/M)
} else {
extSize = f.size();
// round file size up to next full logical extent
extSize = ExtSZ * ((extSize / ExtSZ) + ((extSize % ExtSZ) ? 1 : 0));
if (fpos < extSize)
result = 0x01; // reading unwritten data
else
result = 0x04; // seek to unwritten extent
}
}
f.close();
} else {
result = 0x10;
}
digitalWrite(LED, LOW ^ LEDinv);
return(result);
}
uint8 _sys_writerand(uint8* filename, long fpos) {
uint8 result = 0xff;
File32 f;
digitalWrite(LED, HIGH ^ LEDinv);
if (_sys_extendfile((char*)filename, fpos)) {
f = SD.open((char*)filename, O_RDWR);
}
if (f) {
if (f.seek(fpos)) {
if (f.write(_RamSysAddr(dmaAddr), BlkSZ))
result = 0x00;
} else {
result = 0x06;
}
f.close();
} else {
result = 0x10;
}
digitalWrite(LED, LOW ^ LEDinv);
return(result);
}
static uint8 findNextDirName[13];
static uint16 fileRecords = 0;
static uint16 fileExtents = 0;
static uint16 fileExtentsUsed = 0;
static uint16 firstFreeAllocBlock;
uint8 _findnext(uint8 isdir) {
File32 f;
uint8 result = 0xff;
bool isfile;
uint32 bytes;
digitalWrite(LED, HIGH ^ LEDinv);
if (allExtents && fileRecords) {
_mockupDirEntry();
result = 0;
} else {
while (f = userdir.openNextFile()) {
f.getName((char*)&findNextDirName[0], 13);
isfile = !f.isDirectory();
bytes = f.size();
f.dirEntry(&fileDirEntry);
f.close();
if (!isfile)
continue;
_HostnameToFCBname(findNextDirName, fcbname);
if (match(fcbname, pattern)) {
if (isdir) {
// account for host files that aren't multiples of the block size
// by rounding their bytes up to the next multiple of blocks
if (bytes & (BlkSZ - 1)) {
bytes = (bytes & ~(BlkSZ - 1)) + BlkSZ;
}
fileRecords = bytes / BlkSZ;
fileExtents = fileRecords / BlkEX + ((fileRecords & (BlkEX - 1)) ? 1 : 0);
fileExtentsUsed = 0;
firstFreeAllocBlock = firstBlockAfterDir;
_mockupDirEntry();
} else {
fileRecords = 0;
fileExtents = 0;
fileExtentsUsed = 0;
firstFreeAllocBlock = firstBlockAfterDir;
}
_RamWrite(tmpFCB, filename[0] - '@');
_HostnameToFCB(tmpFCB, findNextDirName);
result = 0x00;
break;
}
}
}
digitalWrite(LED, LOW ^ LEDinv);
return(result);
}
uint8 _findfirst(uint8 isdir) {
uint8 path[4] = { '?', FOLDERCHAR, '?', 0 };
path[0] = filename[0];
path[2] = filename[2];
if (userdir)
userdir.close();
userdir = SD.open((char*)path); // Set directory search to start from the first position
_HostnameToFCBname(filename, pattern);
fileRecords = 0;
fileExtents = 0;
fileExtentsUsed = 0;
return(_findnext(isdir));
}
uint8 _findnextallusers(uint8 isdir) {
uint8 result = 0xFF;
char dirname[13];
bool done = false;
while (!done) {
while (!userdir) {
userdir = rootdir.openNextFile();
if (!userdir) {
done = true;
break;
}
userdir.getName(dirname, sizeof dirname);
if (userdir.isDirectory() && strlen(dirname) == 1 && isxdigit(dirname[0])) {
currFindUser = dirname[0] <= '9' ? dirname[0] - '0' : toupper(dirname[0]) - 'A' + 10;
break;
}
userdir.close();
}
if (userdir) {
result = _findnext(isdir);
if (result) {
userdir.close();
} else {
done = true;
}
} else {
result = 0xFF;
done = true;
}
}
return result;
}
uint8 _findfirstallusers(uint8 isdir) {
uint8 path[2] = { '?', 0 };
path[0] = filename[0];
if (rootdir)
rootdir.close();
if (userdir)
userdir.close();
rootdir = SD.open((char*)path); // Set directory search to start from the first position
strcpy((char*)pattern, "???????????");
if (!rootdir)
return 0xFF;
fileRecords = 0;
fileExtents = 0;
fileExtentsUsed = 0;
return(_findnextallusers(isdir));
}
uint8 _Truncate(char* filename, uint8 rc) {
File32 f;
int result = 0;
digitalWrite(LED, HIGH ^ LEDinv);
f = SD.open((char*)filename, O_WRITE | O_APPEND);
if (f) {
if (f.truncate(rc * BlkSZ)) {
f.close();
result = 1;
}
}
digitalWrite(LED, LOW ^ LEDinv);
return(result);
}
void _MakeUserDir() {
uint8 dFolder = cDrive + 'A';
uint8 uFolder = toupper(tohex(userCode));
uint8 path[4] = { dFolder, FOLDERCHAR, uFolder, 0 };
digitalWrite(LED, HIGH ^ LEDinv);
SD.mkdir((char*)path);
digitalWrite(LED, LOW ^ LEDinv);
}
uint8 _sys_makedisk(uint8 drive) {
uint8 result = 0;
if (drive < 1 || drive>16) {
result = 0xff;
} else {
uint8 dFolder = drive + '@';
uint8 disk[2] = { dFolder, 0 };
digitalWrite(LED, HIGH ^ LEDinv);
if (!SD.mkdir((char*)disk)) {
result = 0xfe;
} else {
uint8 path[4] = { dFolder, FOLDERCHAR, '0', 0 };
SD.mkdir((char*)path);
}
digitalWrite(LED, LOW ^ LEDinv);
}
return(result);
}
/* Hardware abstraction functions */
/*===============================================================================*/
void _HardwareOut(const uint32 Port, const uint32 Value) {
}
uint32 _HardwareIn(const uint32 Port) {
return 0;
}
/* Console abstraction functions */
/*===============================================================================*/
int _kbhit(void) {
return(Serial.available());
}
uint8 _getch(void) {
while (!Serial.available());
return(Serial.read());
}
uint8 _getche(void) {
uint8 ch = _getch();
Serial.write(ch);
return(ch);
}
void _putch(uint8 ch) {
Serial.write(ch);
}
void _clrscr(void) {
Serial.print("\e[H\e[J");
}
#endif