mirror of
https://github.com/dkgrizzly/GreenSCSI.git
synced 2025-02-16 04:30:38 +00:00
RAW disk support and LittleFS support
This commit is contained in:
parent
c5c4c51667
commit
d420244da9
91
src/cmd.ino
91
src/cmd.ino
@ -24,6 +24,7 @@ int scriptlevel = -1;
|
||||
char cmd_prefix[256] = "/";
|
||||
|
||||
extern uint8_t mbr_bin[];
|
||||
uint8_t zero[512];
|
||||
|
||||
void cmdDisplay() {
|
||||
if(cmd_prefix[0] != 0) {
|
||||
@ -723,7 +724,7 @@ void changeDirectory(int argc, char **argv) {
|
||||
goto e_invalidpath;
|
||||
}
|
||||
|
||||
if(!strcmp(new_prefix, "/") || !strcmp(new_prefix, "/tgts") || !strcmp(new_prefix, "/vdevs")
|
||||
if(!strcmp(new_prefix, "/") || !strcmp(new_prefix, "/tgts") || !strcmp(new_prefix, "/vdevs") || !strcmp(new_prefix, "/nv") || !strcmp(new_prefix, "/raw")
|
||||
|| !strcmp(new_prefix, "/sd") || !strcmp(new_prefix, "/diag")|| !strcmp(new_prefix, "/diag/sd")
|
||||
) {
|
||||
strcpy(cmd_prefix, new_prefix);
|
||||
@ -863,6 +864,7 @@ void showDirectory(int argc, char **argv) {
|
||||
printDirectory(0, 0, "/ ", " [...]");
|
||||
printDirectory(1, 0, "diag/ ", " [...]");
|
||||
printDirectory(1, 0, "sd/ ", " [...]");
|
||||
printDirectory(1, 0, "raw/ ", " [...]");
|
||||
sprintf(tmp_right, " [%d Target%s]", NUM_SCSIID, (NUM_SCSIID != 1) ? "s" : "");
|
||||
printDirectory(1, 0, "tgts/ ", tmp_right);
|
||||
sprintf(tmp_right, " [%d Storage Object%s]", m_vdevcnt, (m_vdevcnt != 1) ? "s" : "");
|
||||
@ -874,6 +876,33 @@ void showDirectory(int argc, char **argv) {
|
||||
printDirectory(1, 0, "sd/ ", " [...]");
|
||||
return;
|
||||
}
|
||||
if(!strcmp(local_prefix, "/raw")) {
|
||||
mbr_t *mbr = (mbr_t *)cardMBR;
|
||||
printDirectory(0, 0, "/raw/ ", " [...]");
|
||||
|
||||
sd.card()->readSector(0, cardMBR);
|
||||
|
||||
for(uint8_t partIndex = 0; partIndex < 4; partIndex++) {
|
||||
sprintf(tmp_left, "part%d", partIndex);
|
||||
switch(mbr->part[partIndex].type) {
|
||||
case 0x04:
|
||||
case 0x06:
|
||||
case 0x0B:
|
||||
case 0x0C:
|
||||
case 0x0E:
|
||||
printDirectory(1, 0, tmp_left, "[FAT Filesystem]");
|
||||
break;
|
||||
case 0x07:
|
||||
printDirectory(1, 0, tmp_left, "[EXFAT/NTFS Filesystem]");
|
||||
break;
|
||||
case 0x87:
|
||||
sprintf(tmp_right, "[Emulated %dMB Drive]", (int)(mbr->part[partIndex].totalSectors / 2048));
|
||||
printDirectory(1, 0, tmp_left, tmp_right);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(!strcmp(local_prefix, "/diag/sd")) {
|
||||
printDirectory(0, 0, "/diag/sd/ ", " [...]");
|
||||
|
||||
@ -996,6 +1025,31 @@ void showDirectory(int argc, char **argv) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(!strcmp(local_prefix, "/nv") || !strncmp(local_prefix, "/nv/", 4)) {
|
||||
File root = lfs.open("/");
|
||||
while(true) {
|
||||
File entry = root.openNextFile();
|
||||
|
||||
if(! entry) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!entry.isDirectory()) {
|
||||
sprintf(tmp_left, "%s ", entry.name());
|
||||
if(entry.size() >= 8192) {
|
||||
sprintf(tmp_right, " [%llu KB]", entry.size() >> 10);
|
||||
} else {
|
||||
sprintf(tmp_right, " [%llu Bytes]", entry.size());
|
||||
}
|
||||
printDirectory(1, 0, tmp_left, tmp_right);
|
||||
|
||||
}
|
||||
|
||||
entry.close();
|
||||
}
|
||||
|
||||
root.close();
|
||||
}
|
||||
if(!strcmp(local_prefix, "/sd") || !strncmp(local_prefix, "/sd/", 4)) {
|
||||
char name[MAX_FILE_PATH+1];
|
||||
SdFile root;
|
||||
@ -1217,15 +1271,15 @@ void makeimagecmd(int argc, char **argv) {
|
||||
memset(zero, 0, 512);
|
||||
|
||||
while(fileSize) {
|
||||
if((fileSize & 0x7FFF) == 0)
|
||||
if((fileSize & 0x1FFF) == 0)
|
||||
Serial.printf(".");
|
||||
if((fileSize & 0x3FFFFF) == 0)
|
||||
if((fileSize & 0x7FFFF) == 0)
|
||||
Serial.printf("\r\n");
|
||||
file.write(zero, 512);
|
||||
fileSize -= 512;
|
||||
}
|
||||
Serial.printf("\r\n");
|
||||
|
||||
|
||||
file.close();
|
||||
|
||||
return;
|
||||
@ -1250,7 +1304,9 @@ void catcmd(int argc, char **argv) {
|
||||
}
|
||||
|
||||
fixupPath(tmp_path, argv[1]);
|
||||
if(!strncmp(filename, "/sd/", 4)) {
|
||||
if(!strncmp(filename, "/nv/", 4)) {
|
||||
filename += 3;
|
||||
} else if(!strncmp(filename, "/sd/", 4)) {
|
||||
filename += 3;
|
||||
} else {
|
||||
errorlevel = -1;
|
||||
@ -1394,6 +1450,14 @@ void setcmd(int argc, char **argv) {
|
||||
if((param_name) && !strcasecmp(param_name, "/quirks")) {
|
||||
if(argc<3) {
|
||||
Serial.printf("0x%02x\r\n", h->m_quirks);
|
||||
} if(!strcasecmp(argv[2], "SASI") || !strcasecmp(argv[2], "+SASI")) {
|
||||
h->m_quirks |= QUIRKS_SASI;
|
||||
} if(!strcasecmp(argv[2], "-SASI")) {
|
||||
h->m_quirks &= ~QUIRKS_SASI;
|
||||
} if(!strcasecmp(argv[2], "APPLE") || !strcasecmp(argv[2], "+APPLE")) {
|
||||
h->m_quirks |= QUIRKS_APPLE;
|
||||
} if(!strcasecmp(argv[2], "-APPLE")) {
|
||||
h->m_quirks &= ~QUIRKS_APPLE;
|
||||
} else {
|
||||
h->m_quirks = strtol(argv[2], NULL, 0);
|
||||
}
|
||||
@ -1593,6 +1657,14 @@ void mountcmd(int argc, char **argv) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(!strncmp(tmp_path, "/raw/", 5)) {
|
||||
if(OpenDiskImage(h, tmp_path, 512)) {
|
||||
strcpy(h->m_filename, tmp_path);
|
||||
h->m_enabled = true;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
h->m_fileSize = 0;
|
||||
h->m_blocksize = 0;
|
||||
@ -1770,6 +1842,14 @@ void saveconfig(int argc, char **argv) {
|
||||
config_file.close();
|
||||
}
|
||||
|
||||
char helponSelfTest[] =
|
||||
"\r\n"
|
||||
"selftest\r\n"
|
||||
"\r\n"
|
||||
" Use the selftest command to check for miswired boards and shorts.\r\n"
|
||||
"\r\n"
|
||||
;
|
||||
|
||||
char helponSave[] =
|
||||
"\r\n"
|
||||
"saveconfig\r\n"
|
||||
@ -1907,6 +1987,7 @@ char helponHelp[] =
|
||||
|
||||
Commands_t GlobalCommands[] = {
|
||||
// Command Valid From Path Req. Params Short Help Long Help Handler Dispatch
|
||||
{ "selftest", "/", 0, "Execute Self Test.", helponSelfTest, SelfTest, NULL },
|
||||
{ "cd", "/", 1, "change current directory", NULL, changeDirectory, NULL },
|
||||
{ "sl", "/", 0, NULL, NULL, slcmd, NULL },
|
||||
{ "dir", "/", 0, NULL, NULL, punishDirectory, NULL },
|
||||
|
@ -14,7 +14,7 @@
|
||||
// SCSI config
|
||||
#define NUM_SCSIID 8 // Maximum number of supported SCSI-IDs (The minimum is 1)
|
||||
#define NUM_SCSILUN 8 // Maximum number of LUNs supported (The minimum is 1)
|
||||
#define NUM_VDEV 8 // Maximum number of VDEVs supported (The minimum is 1)
|
||||
#define NUM_VDEV 16 // Maximum number of VDEVs supported (The minimum is 1)
|
||||
|
||||
#define READ_PARITY_CHECK 0 // Perform read parity check (unverified)
|
||||
|
||||
|
22
src/disk.ino
22
src/disk.ino
@ -10,7 +10,7 @@ byte checkBlockCommand(uint32_t adds, uint32_t len)
|
||||
if(!m_sel) {
|
||||
return STATUS_CHECK;
|
||||
}
|
||||
if(!m_sel->m_file.isOpen()) {
|
||||
if(!m_sel->m_rawPart && !m_sel->m_file.isOpen()) {
|
||||
m_sel->m_sense.m_key = NOT_READY; // Not ready
|
||||
m_sel->m_sense.m_code = LUN_NOT_READY; // Logical Unit Not Ready, Manual Intervention Required
|
||||
m_sel->m_sense.m_key_specific[0] = 0x03;
|
||||
@ -53,7 +53,7 @@ void ReadCapacityCommandHandler() {
|
||||
m_phase = PHASE_STATUSIN;
|
||||
return;
|
||||
}
|
||||
if(!m_sel->m_file.isOpen()) {
|
||||
if(!m_sel->m_rawPart && !m_sel->m_file.isOpen()) {
|
||||
m_sts |= STATUS_CHECK;
|
||||
m_sel->m_sense.m_key = NOT_READY; // Not ready
|
||||
m_sel->m_sense.m_code = LUN_NOT_READY; // Logical Unit Not Ready, Manual Intervention Required
|
||||
@ -111,7 +111,11 @@ uint8_t onReadCommand(uint32_t adds, uint32_t len)
|
||||
if(sts) return sts;
|
||||
|
||||
LED_ON();
|
||||
writeDataPhaseSD(adds, len);
|
||||
if(m_sel->m_rawPart) {
|
||||
writeDataPhaseRaw(adds, len);
|
||||
} else {
|
||||
writeDataPhaseSD(adds, len);
|
||||
}
|
||||
LED_OFF();
|
||||
return 0x00; //sts
|
||||
}
|
||||
@ -132,7 +136,11 @@ uint8_t onWriteCommand(uint32_t adds, uint32_t len)
|
||||
if(sts) return sts;
|
||||
|
||||
LED_ON();
|
||||
readDataPhaseSD(adds, len);
|
||||
if(m_sel->m_rawPart) {
|
||||
readDataPhaseRaw(adds, len);
|
||||
} else {
|
||||
readDataPhaseSD(adds, len);
|
||||
}
|
||||
LED_OFF();
|
||||
return 0; //sts
|
||||
}
|
||||
@ -153,7 +161,11 @@ uint8_t onVerifyCommand(uint32_t adds, uint32_t len)
|
||||
if(sts) return sts;
|
||||
|
||||
LED_ON();
|
||||
verifyDataPhaseSD(adds, len);
|
||||
if(m_sel->m_rawPart) {
|
||||
verifyDataPhaseRaw(adds, len);
|
||||
} else {
|
||||
verifyDataPhaseSD(adds, len);
|
||||
}
|
||||
LED_OFF();
|
||||
return 0; //sts
|
||||
}
|
||||
|
@ -40,15 +40,16 @@ void RequestSenseCommandHandler() {
|
||||
};
|
||||
|
||||
if(!m_sel) {
|
||||
// Image file absent
|
||||
buf[2] = 0x02; // NOT_READY
|
||||
buf[12] = 0x25; // Logical Unit Not Supported
|
||||
buf[2] = 2; // Not ready
|
||||
buf[12] = LUN_NOT_READY; // Logical Unit Not Ready, Manual Intervention Required
|
||||
buf[13] = 0x03;
|
||||
} else {
|
||||
buf[2] = m_sel->m_sense.m_key;
|
||||
buf[12] = m_sel->m_sense.m_code;
|
||||
buf[13] = m_sel->m_sense.m_key_specific[0];
|
||||
buf[14] = m_sel->m_sense.m_key_specific[1];
|
||||
buf[15] = m_sel->m_sense.m_key_specific[2];
|
||||
|
||||
m_sel->m_sense.m_key = 0;
|
||||
m_sel->m_sense.m_code = 0;
|
||||
m_sel->m_sense.m_key_specific[0] = 0;
|
||||
@ -66,7 +67,7 @@ void TestUnitCommandHandler() {
|
||||
m_sts |= STATUS_CHECK;
|
||||
return;
|
||||
}
|
||||
if(!m_sel->m_file.isOpen()) {
|
||||
if(!m_sel->m_rawPart && !m_sel->m_file.isOpen()) {
|
||||
m_sts |= STATUS_CHECK;
|
||||
m_sel->m_sense.m_key = NOT_READY; // Not ready
|
||||
m_sel->m_sense.m_code = LUN_NOT_READY; // Logical Unit Not Ready, Manual Intervention Required
|
||||
@ -83,13 +84,14 @@ void RezeroUnitCommandHandler() {
|
||||
m_sts |= STATUS_CHECK;
|
||||
return;
|
||||
}
|
||||
if(!m_sel->m_file.isOpen()) {
|
||||
if(!m_sel->m_rawPart && !m_sel->m_file.isOpen()) {
|
||||
m_sts |= STATUS_CHECK;
|
||||
m_sel->m_sense.m_key = NOT_READY; // Not ready
|
||||
m_sel->m_sense.m_code = LUN_NOT_READY; // Logical Unit Not Ready, Manual Intervention Required
|
||||
m_sel->m_sense.m_key_specific[0] = 0x03;
|
||||
return;
|
||||
}
|
||||
|
||||
m_phase = PHASE_STATUSIN;
|
||||
}
|
||||
|
||||
@ -99,7 +101,7 @@ void FormatUnitCommandHandler() {
|
||||
m_sts |= STATUS_CHECK;
|
||||
return;
|
||||
}
|
||||
if(!m_sel->m_file.isOpen()) {
|
||||
if(!m_sel->m_rawPart && !m_sel->m_file.isOpen()) {
|
||||
m_sts |= STATUS_CHECK;
|
||||
m_sel->m_sense.m_key = NOT_READY; // Not ready
|
||||
m_sel->m_sense.m_code = LUN_NOT_READY; // Logical Unit Not Ready, Manual Intervention Required
|
||||
@ -116,7 +118,7 @@ void ReassignBlocksCommandHandler() {
|
||||
m_sts |= STATUS_CHECK;
|
||||
return;
|
||||
}
|
||||
if(!m_sel->m_file.isOpen()) {
|
||||
if(!m_sel->m_rawPart && !m_sel->m_file.isOpen()) {
|
||||
m_sts |= STATUS_CHECK;
|
||||
m_sel->m_sense.m_key = NOT_READY; // Not ready
|
||||
m_sel->m_sense.m_code = LUN_NOT_READY; // Logical Unit Not Ready, Manual Intervention Required
|
||||
@ -165,7 +167,7 @@ void ModeSenseCommandHandler()
|
||||
m_phase = PHASE_STATUSIN;
|
||||
return;
|
||||
}
|
||||
if(!m_sel->m_file.isOpen()) {
|
||||
if(!m_sel->m_rawPart && !m_sel->m_file.isOpen()) {
|
||||
m_sts |= STATUS_CHECK;
|
||||
m_sel->m_sense.m_key = NOT_READY; // Not ready
|
||||
m_sel->m_sense.m_code = LUN_NOT_READY; // Logical Unit Not Ready, Manual Intervention Required
|
||||
|
@ -40,6 +40,7 @@
|
||||
|
||||
#include <Arduino.h> // For Platform.IO
|
||||
#include <SPI.h>
|
||||
#include <LittleFS.h>
|
||||
#include <SdFat.h>
|
||||
#include "sdios.h"
|
||||
#include "config.h"
|
||||
@ -48,6 +49,25 @@
|
||||
|
||||
// SDFAT
|
||||
SdFs sd;
|
||||
LittleFS_Program lfs;
|
||||
|
||||
|
||||
struct part_s {
|
||||
uint8_t boot;
|
||||
uint8_t beginCHS[3];
|
||||
uint8_t type;
|
||||
uint8_t endCHS[3];
|
||||
uint32_t firstSector;
|
||||
uint32_t totalSectors;
|
||||
} __attribute__((packed));
|
||||
typedef struct part_s part_t;
|
||||
//-----------------------------------------------------------------------------
|
||||
struct mbr_s {
|
||||
uint8_t bootCode[446];
|
||||
part_t part[4];
|
||||
uint8_t signature[2];
|
||||
} __attribute__((packed));
|
||||
typedef struct mbr_s mbr_t;
|
||||
|
||||
boolean debuglog = 0;
|
||||
|
||||
@ -194,6 +214,8 @@ typedef struct VirtualDevice_s
|
||||
FsFile m_file; // File object
|
||||
uint64_t m_fileSize; // File size
|
||||
size_t m_blocksize; // SCSI BLOCK size
|
||||
uint32_t m_firstSector; // First sector for partition
|
||||
boolean m_rawPart; // Raw Partition (True) or Image File (False)
|
||||
#if SUPPORT_TAPE
|
||||
size_t m_filemarks; // Tape position counter (file marks since BOM)
|
||||
#endif
|
||||
@ -225,6 +247,8 @@ uint16_t default_quirks = (SUPPORT_SASI_DEFAULT ? QUIRKS_SASI : 0) | (SUPPO
|
||||
uint16_t ledbits = 0;
|
||||
uint8_t ledbit = 0;
|
||||
|
||||
uint8_t cardMBR[512];
|
||||
|
||||
typedef enum {
|
||||
PHASE_BUSFREE = 0,
|
||||
PHASE_SELECTION,
|
||||
@ -236,7 +260,7 @@ typedef enum {
|
||||
phase_t m_phase = PHASE_BUSFREE;
|
||||
|
||||
// Log File
|
||||
#define VERSION "1.2-20211204"
|
||||
#define VERSION "1.4-20230513"
|
||||
#if DEBUG == 2
|
||||
#define LOG_FILENAME "LOG.txt"
|
||||
FsFile LOG_FILE;
|
||||
@ -280,6 +304,59 @@ boolean OpenImage(VirtualDevice_t *h, const char *image_name)
|
||||
*/
|
||||
boolean OpenDiskImage(VirtualDevice_t *h, const char *image_name, int blocksize)
|
||||
{
|
||||
if(!strncmp(image_name, "/tgts/", 6)) {
|
||||
LOGN("/tgts/ path is not supported for disk images.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!strncmp(image_name, "/vdevs/", 7)) {
|
||||
LOGN("/vdevs/ path is not supported for disk images.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!strncmp(image_name, "/diag/", 6)) {
|
||||
LOGN("/diag/ path is not supported for disk images.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!strncmp(image_name, "/nv/", 4)) {
|
||||
LOGN("/nv/ path is not supported for disk images.");
|
||||
return false;
|
||||
}
|
||||
|
||||
h->m_rawPart = false;
|
||||
|
||||
if(!strncmp(image_name, "/raw/part", 9)) {
|
||||
int partIndex = image_name[9] - '0';
|
||||
mbr_t *mbr = (mbr_t *)cardMBR;
|
||||
if((partIndex < 0) || (partIndex > 3)) {
|
||||
LOGN("partition index is outside the allowed range.");
|
||||
return false;
|
||||
}
|
||||
|
||||
sd.card()->readSector(0, cardMBR);
|
||||
if(mbr->part[partIndex].type != 0x87) {
|
||||
LOGN("partition is of the wrong type.");
|
||||
return false;
|
||||
}
|
||||
|
||||
h->m_blocksize = blocksize;
|
||||
h->m_fileSize = ((uint64_t)mbr->part[partIndex].totalSectors) * ((uint64_t)512);
|
||||
h->m_rawPart = true;
|
||||
h->m_firstSector = mbr->part[partIndex].firstSector;
|
||||
|
||||
LOG(" Imagefile: ");
|
||||
LOG(image_name);
|
||||
LOG(" / ");
|
||||
LOG(h->m_fileSize / h->m_blocksize);
|
||||
LOG(" sectors / ");
|
||||
LOG(h->m_fileSize / 1024);
|
||||
LOG(" KiB / ");
|
||||
LOG(h->m_fileSize / 1024 / 1024);
|
||||
LOGN(" MiB");
|
||||
return true; // File opened
|
||||
}
|
||||
|
||||
if(!strncmp(image_name, "/sd/", 4))
|
||||
image_name += 3;
|
||||
|
||||
@ -320,6 +397,29 @@ boolean OpenDiskImage(VirtualDevice_t *h, const char *image_name, int blocksize)
|
||||
*/
|
||||
boolean OpenTapeImage(VirtualDevice_t *h, const char *image_name)
|
||||
{
|
||||
if(!strncmp(image_name, "/tgts/", 6)) {
|
||||
LOGN("/tgts/ path is not supported for tape images.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!strncmp(image_name, "/vdevs/", 7)) {
|
||||
LOGN("/vdevs/ path is not supported for tape images.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!strncmp(image_name, "/diag/", 6)) {
|
||||
LOGN("/diag/ path is not supported for tape images.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!strncmp(image_name, "/nv/", 4)) {
|
||||
LOGN("/nv/ path is not supported for tape images.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!strncmp(image_name, "/sd/", 4))
|
||||
image_name += 3;
|
||||
|
||||
h->m_fileSize = 0;
|
||||
h->m_blocksize = 0;
|
||||
h->m_filemarks = 0;
|
||||
@ -406,6 +506,9 @@ void setup()
|
||||
|
||||
LED_ON();
|
||||
|
||||
// Filesystems
|
||||
lfs.begin(256 * 1024); // 256KB of program memory to be used as nonvolatile storage
|
||||
|
||||
if(!sd.begin(SdioConfig(FIFO_SDIO))) {
|
||||
#if DEBUG > 0
|
||||
Serial.println("SD initialization failed!");
|
||||
@ -420,10 +523,14 @@ void setup()
|
||||
//HD image file open
|
||||
scsi_id_mask = 0x00;
|
||||
|
||||
// If greenscsi.cfg exists, run it
|
||||
// If greenscsi.cfg exists, run it (try first from SD, otherwise from flash)
|
||||
if(sd.exists("/greenscsi.cfg")) {
|
||||
execscript((char*)"/sd/greenscsi.cfg");
|
||||
execLoop();
|
||||
} else
|
||||
if(lfs.exists("/greenscsi.cfg")) {
|
||||
execscript((char*)"/nv/greenscsi.cfg");
|
||||
execLoop();
|
||||
}
|
||||
|
||||
// Scan for images if we haven't defined any targets yet.
|
||||
@ -911,3 +1018,235 @@ void BusFreePhaseHandler() {
|
||||
// Reset back to waiting for selection phase.
|
||||
m_phase = PHASE_SELECTION;
|
||||
}
|
||||
|
||||
typedef struct SelfTestPins_s {
|
||||
int A;
|
||||
int B;
|
||||
int pA;
|
||||
int pB;
|
||||
char nA[4];
|
||||
char nB[4];
|
||||
} SelfTestPins_t;
|
||||
|
||||
SelfTestPins_t SelfTestPins[] = {
|
||||
{ IO, DB0, 50, 2, "I/O", "DB0" },
|
||||
{ IO, DB0, 48, 4, "REQ", "DB1" },
|
||||
{ IO, DB0, 46, 6, "C/D", "DB2" },
|
||||
{ IO, DB0, 44, 8, "SEL", "DB3" },
|
||||
{ IO, DB0, 42, 10, "MSG", "DB4" },
|
||||
{ IO, DB0, 50, 12, "RST", "DB5" },
|
||||
{ IO, DB0, 38, 14, "ACK", "DB6" },
|
||||
{ IO, DB0, 36, 16, "BSY", "DB7" },
|
||||
{ IO, DB0, 32, 18, "ATN", "DBP" },
|
||||
};
|
||||
|
||||
void SelfTest(int argc, char **argv) {
|
||||
int i, x;
|
||||
char c;
|
||||
|
||||
Serial.printf("Are you sure you wish to run the self test? ");
|
||||
for(;;) {
|
||||
if (Serial.available()) {
|
||||
c = Serial.read();
|
||||
switch(c) {
|
||||
default:
|
||||
return;
|
||||
case 'y': case 'Y':
|
||||
goto ConnectHarness;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConnectHarness:
|
||||
// Clear any extra characters
|
||||
while (Serial.available()) {
|
||||
c = Serial.read();
|
||||
}
|
||||
|
||||
// Disable normal operation and prepare the self test.
|
||||
detachInterrupt(RST);
|
||||
detachInterrupt(SEL);
|
||||
|
||||
Serial.printf("Self Test starting...\r\n");
|
||||
|
||||
// Delay for 3 seconds
|
||||
delay(3000);
|
||||
|
||||
while (Serial.available()) {
|
||||
c = Serial.read();
|
||||
}
|
||||
|
||||
Serial.printf("Connect the Loopback test adapter and press Enter.");
|
||||
for(;;) {
|
||||
if (Serial.available()) {
|
||||
c = Serial.read();
|
||||
switch(c) {
|
||||
case 0xA: case 0xD:
|
||||
goto ExecuteSelfTest;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExecuteSelfTest:
|
||||
// Clear any extra characters
|
||||
while (Serial.available()) {
|
||||
c = Serial.read();
|
||||
}
|
||||
|
||||
// All pins input
|
||||
for(i = 0; i < 9; i++) {
|
||||
pinMode(SelfTestPins[i].A, INPUT_PULLUP);
|
||||
pinMode(SelfTestPins[i].B, INPUT_PULLUP);
|
||||
}
|
||||
|
||||
for(i = 0; i < 9; i++) {
|
||||
// Test A -> B
|
||||
pinMode(SelfTestPins[i].A, OUTPUT_OPENDRAIN);
|
||||
digitalWrite(SelfTestPins[i].A, LOW);
|
||||
|
||||
delay(10);
|
||||
|
||||
if(digitalRead(SelfTestPins[i].B) != LOW) {
|
||||
Serial.printf("Self Test Failed. Pin %d (%s) was unable to pull Pin %d (%s) LOW.\r\n", SelfTestPins[i].pA, SelfTestPins[i].nA, SelfTestPins[i].pB, SelfTestPins[i].nB);
|
||||
pinMode(SelfTestPins[i].A, INPUT_PULLUP);
|
||||
return;
|
||||
}
|
||||
|
||||
for(x = 0; x < 9; x++) {
|
||||
if(x != i) {
|
||||
if(digitalRead(SelfTestPins[x].A) == LOW) {
|
||||
Serial.printf("Self Test Failed. Pin %d (%s) is shorted to Pin %d (%s).\r\n", SelfTestPins[i].pA, SelfTestPins[i].nA, SelfTestPins[x].pA, SelfTestPins[x].nA);
|
||||
pinMode(SelfTestPins[i].A, INPUT_PULLUP);
|
||||
return;
|
||||
}
|
||||
if(digitalRead(SelfTestPins[x].B) == LOW) {
|
||||
Serial.printf("Self Test Failed. Pin %d (%s) is shorted to Pin %d (%s).\r\n", SelfTestPins[i].pA, SelfTestPins[i].nA, SelfTestPins[x].pB, SelfTestPins[x].nB);
|
||||
pinMode(SelfTestPins[i].A, INPUT_PULLUP);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pinMode(SelfTestPins[i].A, INPUT_PULLUP);
|
||||
|
||||
delay(10);
|
||||
|
||||
// Test B -> A
|
||||
pinMode(SelfTestPins[i].B, OUTPUT_OPENDRAIN);
|
||||
digitalWrite(SelfTestPins[i].B, LOW);
|
||||
|
||||
delay(10);
|
||||
|
||||
if(digitalRead(SelfTestPins[i].A) != LOW) {
|
||||
Serial.printf("Self Test Failed. Pin %d (%s) was unable to pull Pin %d (%s) LOW.\r\n", SelfTestPins[i].pB, SelfTestPins[i].nB, SelfTestPins[i].pA, SelfTestPins[i].nA);
|
||||
pinMode(SelfTestPins[i].B, INPUT_PULLUP);
|
||||
return;
|
||||
}
|
||||
|
||||
for(x = 0; x < 9; x++) {
|
||||
if(x != i) {
|
||||
if(digitalRead(SelfTestPins[x].A) == LOW) {
|
||||
Serial.printf("Self Test Failed. Pin %d (%s) is shorted to Pin %d (%s).\r\n", SelfTestPins[i].pB, SelfTestPins[i].nB, SelfTestPins[x].pA, SelfTestPins[x].nA);
|
||||
pinMode(SelfTestPins[i].B, INPUT_PULLUP);
|
||||
return;
|
||||
}
|
||||
if(digitalRead(SelfTestPins[x].B) == LOW) {
|
||||
Serial.printf("Self Test Failed. Pin %d (%s) is shorted to Pin %d (%s).\r\n", SelfTestPins[i].pB, SelfTestPins[i].nB, SelfTestPins[x].pB, SelfTestPins[x].nB);
|
||||
pinMode(SelfTestPins[i].B, INPUT_PULLUP);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pinMode(SelfTestPins[i].B, INPUT_PULLUP);
|
||||
|
||||
delay(10);
|
||||
}
|
||||
|
||||
while (Serial.available()) {
|
||||
c = Serial.read();
|
||||
}
|
||||
|
||||
Serial.printf("Disconnect the Loopback test adapter and press Enter.");
|
||||
for(;;) {
|
||||
if (Serial.available()) {
|
||||
c = Serial.read();
|
||||
switch(c) {
|
||||
case 0xA: case 0xD:
|
||||
goto DisconnectHarness;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DisconnectHarness:
|
||||
// Clear any extra characters
|
||||
while (Serial.available()) {
|
||||
c = Serial.read();
|
||||
}
|
||||
|
||||
for(i = 0; i < 9; i++) {
|
||||
// Test A -> B
|
||||
pinMode(SelfTestPins[i].A, OUTPUT_OPENDRAIN);
|
||||
digitalWrite(SelfTestPins[i].A, LOW);
|
||||
|
||||
delay(10);
|
||||
|
||||
if(digitalRead(SelfTestPins[i].B) == LOW) {
|
||||
Serial.printf("Self Test Failed. Pin %d (%s) is shorted to Pin %d (%s).\r\n", SelfTestPins[i].pA, SelfTestPins[i].nA, SelfTestPins[i].pB, SelfTestPins[i].nB);
|
||||
pinMode(SelfTestPins[i].A, INPUT_PULLUP);
|
||||
return;
|
||||
}
|
||||
|
||||
// Test B -> A
|
||||
pinMode(SelfTestPins[i].B, OUTPUT_OPENDRAIN);
|
||||
digitalWrite(SelfTestPins[i].B, LOW);
|
||||
|
||||
delay(10);
|
||||
|
||||
if(digitalRead(SelfTestPins[i].A) == LOW) {
|
||||
Serial.printf("Self Test Failed. Pin %d (%s) is shorted to Pin %d (%s).\r\n", SelfTestPins[i].pB, SelfTestPins[i].nB, SelfTestPins[i].pA, SelfTestPins[i].nA);
|
||||
pinMode(SelfTestPins[i].B, INPUT_PULLUP);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//SelfTestComplete:
|
||||
// Clear any extra characters
|
||||
while (Serial.available()) {
|
||||
c = Serial.read();
|
||||
}
|
||||
|
||||
Serial.printf("Self Test Passed.\r\n");
|
||||
|
||||
// On success, restore normal operation
|
||||
// Input port
|
||||
pinMode(ATN, INPUT_PULLUP);
|
||||
pinMode(ACK, INPUT_PULLUP);
|
||||
pinMode(RST, INPUT_PULLUP);
|
||||
pinMode(SEL, INPUT_PULLUP);
|
||||
|
||||
// Output port
|
||||
pinModeFastSlew(BSY, OUTPUT_OPENDRAIN);
|
||||
pinModeFastSlew(MSG, OUTPUT_OPENDRAIN);
|
||||
pinModeFastSlew(CD, OUTPUT_OPENDRAIN);
|
||||
pinModeFastSlew(IO, OUTPUT_OPENDRAIN);
|
||||
pinModeFastSlew(REQ, OUTPUT_OPENDRAIN);
|
||||
|
||||
pinModeFastSlew(DB0, OUTPUT_OPENDRAIN);
|
||||
pinModeFastSlew(DB1, OUTPUT_OPENDRAIN);
|
||||
pinModeFastSlew(DB2, OUTPUT_OPENDRAIN);
|
||||
pinModeFastSlew(DB3, OUTPUT_OPENDRAIN);
|
||||
pinModeFastSlew(DB4, OUTPUT_OPENDRAIN);
|
||||
pinModeFastSlew(DB5, OUTPUT_OPENDRAIN);
|
||||
pinModeFastSlew(DB6, OUTPUT_OPENDRAIN);
|
||||
pinModeFastSlew(DB7, OUTPUT_OPENDRAIN);
|
||||
pinModeFastSlew(DB8, OUTPUT_OPENDRAIN);
|
||||
|
||||
// Turn off the output port
|
||||
SCSI_TARGET_INACTIVE();
|
||||
|
||||
attachInterrupt(RST, onBusReset, FALLING);
|
||||
attachInterrupt(SEL, SelectionPhaseISR, FALLING);
|
||||
|
||||
LED_OFF();
|
||||
}
|
@ -497,6 +497,10 @@ void OpticalReadCapacityCommandHandler() {
|
||||
LOGN("[ReadCapacity]");
|
||||
if(!m_sel) {
|
||||
m_sts |= STATUS_CHECK; // Image file absent
|
||||
m_sel->m_sense.m_key_specific[0] = 0x04;
|
||||
m_sel->m_sense.m_key_specific[1] = 0x03;
|
||||
m_sel->m_sense.m_key_specific[2] = 0x00;
|
||||
m_sel->m_sense.m_key_specific[3] = 0x00;
|
||||
m_phase = PHASE_STATUSIN;
|
||||
return;
|
||||
}
|
||||
|
135
src/scsibus.ino
135
src/scsibus.ino
@ -211,6 +211,55 @@ void writeDataPhaseSD(uint32_t adds, uint32_t len)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Data in phase.
|
||||
* Send len block while reading from SD card.
|
||||
*/
|
||||
void writeDataPhaseRaw(uint32_t adds, uint32_t len)
|
||||
{
|
||||
#if READ_SPEED_OPTIMIZE_RAW
|
||||
uint32_t bigread = (MAX_BLOCKSIZE / m_sel->m_blocksize);
|
||||
#endif
|
||||
uint32_t i = 0;
|
||||
|
||||
//LOGN("DATAIN PHASE(RAW)");
|
||||
uint32_t pos = ((adds * m_sel->m_blocksize) / 512) + m_sel->m_firstSector;
|
||||
|
||||
SET_MSG_INACTIVE();
|
||||
SET_CD_INACTIVE();
|
||||
SET_IO_ACTIVE();
|
||||
|
||||
while(i < len) {
|
||||
// Asynchronous reads will make it faster ...
|
||||
#if READ_SPEED_OPTIMIZE_RAW
|
||||
if((len-i) >= bigread) {
|
||||
sd.card()->readSectors(pos, m_buf, (MAX_BLOCKSIZE / 512));
|
||||
writeHandshakeBlock(m_buf, MAX_BLOCKSIZE);
|
||||
i += bigread;
|
||||
pos += (MAX_BLOCKSIZE / 512);
|
||||
} else {
|
||||
sd.card()->readSectors(pos, m_buf, ((m_sel->m_blocksize * (len-i)) / 512));
|
||||
writeHandshakeBlock(m_buf, m_sel->m_blocksize * (len-i));
|
||||
i = len;
|
||||
}
|
||||
#else
|
||||
sd.card()->readSectors(pos, m_buf, (m_sel->m_blocksize / 512));
|
||||
pos++;
|
||||
for(unsigned int j = 0; j < m_sel->m_blocksize; j++) {
|
||||
if(m_isBusReset) {
|
||||
m_phase = PHASE_BUSFREE;
|
||||
return;
|
||||
}
|
||||
writeHandshake(m_buf[j]);
|
||||
}
|
||||
#endif
|
||||
if(m_isBusReset) {
|
||||
m_phase = PHASE_BUSFREE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Data out phase.
|
||||
* len block read
|
||||
@ -275,6 +324,50 @@ void readDataPhaseSD(uint32_t adds, uint32_t len)
|
||||
m_sel->m_file.flush();
|
||||
}
|
||||
|
||||
/*
|
||||
* Data out phase.
|
||||
* Write to SD card while reading len block.
|
||||
*/
|
||||
void readDataPhaseRaw(uint32_t adds, uint32_t len)
|
||||
{
|
||||
#if WRITE_SPEED_OPTIMIZE
|
||||
uint32_t bigread = (MAX_BLOCKSIZE / m_sel->m_blocksize);
|
||||
#endif
|
||||
uint32_t i = 0;
|
||||
|
||||
//LOGN("DATAOUT PHASE(RAW)");
|
||||
uint32_t pos = ((adds * m_sel->m_blocksize) / 512) + m_sel->m_firstSector;
|
||||
|
||||
SET_MSG_INACTIVE();
|
||||
SET_CD_INACTIVE();
|
||||
SET_IO_INACTIVE();
|
||||
|
||||
while(i < len) {
|
||||
#if WRITE_SPEED_OPTIMIZE
|
||||
if((len-i) >= bigread) {
|
||||
readHandshakeBlock(m_buf, MAX_BLOCKSIZE);
|
||||
sd.card()->writeSectors(pos, m_buf, (MAX_BLOCKSIZE / 512));
|
||||
i += bigread;
|
||||
pos += (MAX_BLOCKSIZE / 512);
|
||||
} else {
|
||||
readHandshakeBlock(m_buf, m_sel->m_blocksize * (len-i));
|
||||
sd.card()->writeSectors(pos, m_buf, ((m_sel->m_blocksize * (len-i)) / 512));
|
||||
i = len;
|
||||
}
|
||||
#else
|
||||
for(unsigned int j = 0; j < m_sel->m_blocksize; j++) {
|
||||
if(m_isBusReset) {
|
||||
return;
|
||||
}
|
||||
m_buf[j] = readHandshake();
|
||||
}
|
||||
sd.card()->writeSectors(pos, m_buf, (m_sel->m_blocksize / 512));
|
||||
i++;
|
||||
pos += (m_sel->m_blocksize / 512);
|
||||
#endif
|
||||
}
|
||||
m_sel->m_file.flush();
|
||||
}
|
||||
|
||||
/*
|
||||
* Data out phase.
|
||||
@ -287,12 +380,54 @@ void verifyDataPhaseSD(uint32_t adds, uint32_t len)
|
||||
#endif
|
||||
uint32_t i = 0;
|
||||
|
||||
//LOGN("DATAOUT PHASE(SD)");
|
||||
uint32_t pos = adds * m_sel->m_blocksize;
|
||||
m_sel->m_file.seek(pos);
|
||||
SET_MSG_INACTIVE();
|
||||
SET_CD_INACTIVE();
|
||||
SET_IO_INACTIVE();
|
||||
|
||||
while(i < len) {
|
||||
#if WRITE_SPEED_OPTIMIZE
|
||||
if((len-i) >= bigread) {
|
||||
readHandshakeBlock(m_buf, MAX_BLOCKSIZE);
|
||||
//m_sel->m_file.verify(m_buf, MAX_BLOCKSIZE);
|
||||
i += bigread;
|
||||
} else {
|
||||
readHandshakeBlock(m_buf, m_sel->m_blocksize * (len-i));
|
||||
//m_sel->m_file.verify(m_buf, m_sel->m_blocksize * (len-i));
|
||||
i = len;
|
||||
}
|
||||
#else
|
||||
for(unsigned int j = 0; j < m_sel->m_blocksize; j++) {
|
||||
if(m_isBusReset) {
|
||||
return;
|
||||
}
|
||||
m_buf[j] = readHandshake();
|
||||
}
|
||||
//m_sel->m_file.verify(m_buf, m_sel->m_blocksize);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Data out phase.
|
||||
* Verify SD card while reading len block.
|
||||
*/
|
||||
void verifyDataPhaseRaw(uint32_t adds, uint32_t len)
|
||||
{
|
||||
#if WRITE_SPEED_OPTIMIZE
|
||||
uint32_t bigread = (MAX_BLOCKSIZE / m_sel->m_blocksize);
|
||||
#endif
|
||||
uint32_t i = 0;
|
||||
|
||||
//LOGN("DATAOUT PHASE(RAW)");
|
||||
uint32_t pos = ((adds * m_sel->m_blocksize) / 512) + m_sel->m_firstSector;
|
||||
SET_MSG_INACTIVE();
|
||||
SET_CD_INACTIVE();
|
||||
SET_IO_INACTIVE();
|
||||
|
||||
while(i < len) {
|
||||
#if WRITE_SPEED_OPTIMIZE
|
||||
if((len-i) >= bigread) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user