diff --git a/src/cmd.ino b/src/cmd.ino index ffa60fd..f76ec1d 100755 --- a/src/cmd.ino +++ b/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 }, diff --git a/src/config.h b/src/config.h index c1814e4..9ed28d4 100755 --- a/src/config.h +++ b/src/config.h @@ -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) diff --git a/src/disk.ino b/src/disk.ino index d23f0e2..71c5f5f 100755 --- a/src/disk.ino +++ b/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 } diff --git a/src/general.ino b/src/general.ino index f62f5df..87f59df 100755 --- a/src/general.ino +++ b/src/general.ino @@ -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 diff --git a/src/greenscsi.ino b/src/greenscsi.ino index 69b62f1..ece87d5 100755 --- a/src/greenscsi.ino +++ b/src/greenscsi.ino @@ -40,6 +40,7 @@ #include // For Platform.IO #include +#include #include #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(); +} \ No newline at end of file diff --git a/src/optical.ino b/src/optical.ino index 97c470e..788d284 100755 --- a/src/optical.ino +++ b/src/optical.ino @@ -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; } diff --git a/src/scsibus.ino b/src/scsibus.ino index 1cfc8b0..82c99e0 100755 --- a/src/scsibus.ino +++ b/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) {