-201501?? 4.1.1
+20150420 4.2.2
+ - Improved compatibility with older SCSI1 hosts.
+
+20150123 4.1.1
- Fix MODE SENSE bug when the allocation length is less than the
page size.
- Add WRITE BUFFER and WRITE AND VERIFY support.
Features
In-built active terminator.
- Can optional supply terminator power back to the SCSI bus
Emulates up to 4 SCSI devices
Supports sector sizes from 64 bytes to 8192 bytes
Firmware updatable over USB
SCSI cable reversed on S3200
There are compatibility problems with the Akai MPC3000. It works (slowly) with the alternate Vailixi OS with multi-sector transfers disabled.
EMU Emulator E4X with EOS 3.00b and E6400 (classic) with Eos 4.01
+ EMU E6400 w/ EOS2.80f
+ EMU Emax2
Ensoniq ASR-X, ASR-10 (from v3.4, 2GB size limit)
ASR-20 Requires TERMPWR jumper.
ASR-X resets when writing to devices > 2Gb.
Reftek RT-72A Seismic datalogger.
http://www.iris.iris.edu/passcal/Reftek/72A-R-005-00.1.pdf
http://www.iris.iris.edu/passcal/Manual/rtfm.s3a.13.html
+ Konami Simpson's Bowling arcade machine
+ http://forums.arcade-museum.com/showthread.php?p=3027446
\r
#include <string.h>\r
\r
-static const uint16_t FIRMWARE_VERSION = 0x0411;\r
+static const uint16_t FIRMWARE_VERSION = 0x0422;\r
\r
enum USB_ENDPOINTS\r
{\r
static int usbDebugEpState;\r
static int usbReady;\r
\r
+uint8_t DEFAULT_CONFIG[256]\r
+ __attribute__ ((section(".DEFAULT_CONFIG"))) =\r
+{\r
+ CONFIG_TARGET_ENABLED,\r
+ CONFIG_FIXED,\r
+ 0,\r
+ 0,\r
+ 0, 0, 0, 0,\r
+ 0xff, 0xff, 0x3f, 0x00, // 4194303, 2GB - 1 sector\r
+ 0x00, 0x02, //512\r
+ 63, 0,\r
+ 255, 0,\r
+ ' ', 'c', 'o', 'd', 'e', 's', 'r', 'c',\r
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'S', 'C', 'S', 'I', '2', 'S', 'D',\r
+ ' ', '4', '.', '2',\r
+ '1','2','3','4','5','6','7','8','1','2','3','4','5','6','7','8'\r
+};\r
+// otherwise linker removes unused section.\r
+volatile uint8_t trickLinker;\r
+\r
void configInit()\r
{\r
+ trickLinker = DEFAULT_CONFIG[0];\r
+\r
// The USB block will be powered by an internal 3.3V regulator.\r
// The PSoC must be operating between 4.6V and 5V for the regulator\r
// to work.\r
\r
hidPacket_send(response, sizeof(response));\r
}\r
+\r
+\r
+static void\r
+scsiTestCommand()\r
+{\r
+ int resultCode = scsiSelfTest();\r
+ uint8_t response[] =\r
+ {\r
+ resultCode == 0 ? CONFIG_STATUS_GOOD : CONFIG_STATUS_ERR,\r
+ resultCode\r
+ };\r
+ hidPacket_send(response, sizeof(response));\r
+}\r
+\r
static void\r
processCommand(const uint8_t* cmd, size_t cmdSize)\r
{\r
sdInfoCommand();\r
break;\r
\r
+ case CONFIG_SCSITEST:\r
+ scsiTestCommand();\r
+ break;\r
+\r
case CONFIG_NONE: // invalid\r
default:\r
break;\r
{\r
if (scsiDev.parityError &&\r
(scsiDev.target->cfg->flags & CONFIG_ENABLE_PARITY) &&\r
- !scsiDev.compatMode)\r
+ (scsiDev.compatMode >= COMPAT_SCSI2))\r
{\r
scsiDev.target->sense.code = ABORTED_COMMAND;\r
scsiDev.target->sense.asc = SCSI_PARITY_ERROR;\r
static void doModeSense(\r
int sixByteCmd, int dbd, int pc, int pageCode, int allocLength)\r
{\r
- if (pc == 0x03) // Saved Values not supported.\r
+ ////////////// Mode Parameter Header\r
+ ////////////////////////////////////\r
+\r
+ // Skip the Mode Data Length, we set that last.\r
+ int idx = 1;\r
+ if (!sixByteCmd) ++idx;\r
+\r
+ uint8_t mediumType = 0;\r
+ uint8_t deviceSpecificParam = 0;\r
+ uint8_t density = 0;\r
+ switch (scsiDev.target->cfg->deviceType == CONFIG_OPTICAL)\r
{\r
- scsiDev.status = CHECK_CONDITION;\r
- scsiDev.target->sense.code = ILLEGAL_REQUEST;\r
- scsiDev.target->sense.asc = SAVING_PARAMETERS_NOT_SUPPORTED;\r
- scsiDev.phase = STATUS;\r
+ case CONFIG_FIXED:\r
+ case CONFIG_REMOVEABLE:\r
+ mediumType = 0; // We should support various floppy types here!\r
+ // Contains cache bits (0) and a Write-Protect bit.\r
+ deviceSpecificParam =\r
+ (blockDev.state & DISK_WP) ? 0x80 : 0;\r
+ density = 0; // reserved for direct access\r
+ break;\r
+\r
+ case CONFIG_FLOPPY_14MB:\r
+ mediumType = 0x1E; // 90mm/3.5"\r
+ deviceSpecificParam =\r
+ (blockDev.state & DISK_WP) ? 0x80 : 0;\r
+ density = 0; // reserved for direct access\r
+ break;\r
+\r
+ case CONFIG_OPTICAL:\r
+ mediumType = 0x02; // 120mm CDROM, data only.\r
+ deviceSpecificParam = 0;\r
+ density = 0x01; // User data only, 2048bytes per sector.\r
+ break;\r
+\r
+ };\r
+\r
+ scsiDev.data[idx++] = mediumType;\r
+ scsiDev.data[idx++] = deviceSpecificParam;\r
+\r
+ if (sixByteCmd)\r
+ {\r
+ if (dbd)\r
+ {\r
+ scsiDev.data[idx++] = 0; // No block descriptor\r
+ }\r
+ else\r
+ {\r
+ // One block descriptor of length 8 bytes.\r
+ scsiDev.data[idx++] = 8;\r
+ }\r
}\r
else\r
{\r
- ////////////// Mode Parameter Header\r
- ////////////////////////////////////\r
-\r
- // Skip the Mode Data Length, we set that last.\r
- int idx = 1;\r
- if (!sixByteCmd) ++idx;\r
-\r
- uint8_t mediumType = 0;\r
- uint8_t deviceSpecificParam = 0;\r
- uint8_t density = 0;\r
- switch (scsiDev.target->cfg->deviceType == CONFIG_OPTICAL)\r
- {\r
- case CONFIG_FIXED:\r
- case CONFIG_REMOVEABLE:\r
- mediumType = 0; // We should support various floppy types here!\r
- // Contains cache bits (0) and a Write-Protect bit.\r
- deviceSpecificParam =\r
- (blockDev.state & DISK_WP) ? 0x80 : 0;\r
- density = 0; // reserved for direct access\r
- break;\r
-\r
- case CONFIG_FLOPPY_14MB:\r
- mediumType = 0x1E; // 90mm/3.5"\r
- deviceSpecificParam =\r
- (blockDev.state & DISK_WP) ? 0x80 : 0;\r
- density = 0; // reserved for direct access\r
- break;\r
-\r
- case CONFIG_OPTICAL:\r
- mediumType = 0x02; // 120mm CDROM, data only.\r
- deviceSpecificParam = 0;\r
- density = 0x01; // User data only, 2048bytes per sector.\r
- break;\r
-\r
- };\r
-\r
- scsiDev.data[idx++] = mediumType;\r
- scsiDev.data[idx++] = deviceSpecificParam;\r
-\r
- if (sixByteCmd)\r
+ scsiDev.data[idx++] = 0; // Reserved\r
+ scsiDev.data[idx++] = 0; // Reserved\r
+ if (dbd)\r
{\r
- if (dbd)\r
- {\r
- scsiDev.data[idx++] = 0; // No block descriptor\r
- }\r
- else\r
- {\r
- // One block descriptor of length 8 bytes.\r
- scsiDev.data[idx++] = 8;\r
- }\r
+ scsiDev.data[idx++] = 0; // No block descriptor\r
+ scsiDev.data[idx++] = 0; // No block descriptor\r
}\r
else\r
{\r
- scsiDev.data[idx++] = 0; // Reserved\r
- scsiDev.data[idx++] = 0; // Reserved\r
- if (dbd)\r
- {\r
- scsiDev.data[idx++] = 0; // No block descriptor\r
- scsiDev.data[idx++] = 0; // No block descriptor\r
- }\r
- else\r
- {\r
- // One block descriptor of length 8 bytes.\r
- scsiDev.data[idx++] = 0;\r
- scsiDev.data[idx++] = 8;\r
- }\r
+ // One block descriptor of length 8 bytes.\r
+ scsiDev.data[idx++] = 0;\r
+ scsiDev.data[idx++] = 8;\r
}\r
+ }\r
\r
- ////////////// Block Descriptor\r
- ////////////////////////////////////\r
- if (!dbd)\r
- {\r
- scsiDev.data[idx++] = density;\r
- // Number of blocks\r
- // Zero == all remaining blocks shall have the medium\r
- // characteristics specified.\r
- scsiDev.data[idx++] = 0;\r
- scsiDev.data[idx++] = 0;\r
- scsiDev.data[idx++] = 0;\r
+ ////////////// Block Descriptor\r
+ ////////////////////////////////////\r
+ if (!dbd)\r
+ {\r
+ scsiDev.data[idx++] = density;\r
+ // Number of blocks\r
+ // Zero == all remaining blocks shall have the medium\r
+ // characteristics specified.\r
+ scsiDev.data[idx++] = 0;\r
+ scsiDev.data[idx++] = 0;\r
+ scsiDev.data[idx++] = 0;\r
+\r
+ scsiDev.data[idx++] = 0; // reserved\r
+\r
+ // Block length\r
+ uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;\r
+ scsiDev.data[idx++] = bytesPerSector >> 16;\r
+ scsiDev.data[idx++] = bytesPerSector >> 8;\r
+ scsiDev.data[idx++] = bytesPerSector & 0xFF;\r
+ }\r
\r
- scsiDev.data[idx++] = 0; // reserved\r
+ int pageFound = 0;\r
\r
- // Block length\r
- uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;\r
- scsiDev.data[idx++] = bytesPerSector >> 16;\r
- scsiDev.data[idx++] = bytesPerSector >> 8;\r
- scsiDev.data[idx++] = bytesPerSector & 0xFF;\r
- }\r
+ if (pageCode == 0x01 || pageCode == 0x3F)\r
+ {\r
+ pageFound = 1;\r
+ pageIn(pc, idx, ReadWriteErrorRecoveryPage, sizeof(ReadWriteErrorRecoveryPage));\r
+ idx += sizeof(ReadWriteErrorRecoveryPage);\r
+ }\r
\r
- int pageFound = 0;\r
+ if (pageCode == 0x02 || pageCode == 0x3F)\r
+ {\r
+ pageFound = 1;\r
+ pageIn(pc, idx, DisconnectReconnectPage, sizeof(DisconnectReconnectPage));\r
+ idx += sizeof(DisconnectReconnectPage);\r
+ }\r
\r
- if (pageCode == 0x01 || pageCode == 0x3F)\r
+ if (pageCode == 0x03 || pageCode == 0x3F)\r
+ {\r
+ pageFound = 1;\r
+ pageIn(pc, idx, FormatDevicePage, sizeof(FormatDevicePage));\r
+ if (pc != 0x01)\r
{\r
- pageFound = 1;\r
- pageIn(pc, idx, ReadWriteErrorRecoveryPage, sizeof(ReadWriteErrorRecoveryPage));\r
- idx += sizeof(ReadWriteErrorRecoveryPage);\r
+ // Fill out the configured bytes-per-sector\r
+ uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;\r
+ scsiDev.data[idx+12] = bytesPerSector >> 8;\r
+ scsiDev.data[idx+13] = bytesPerSector & 0xFF;\r
}\r
-\r
- if (pageCode == 0x02 || pageCode == 0x3F)\r
+ else\r
{\r
- pageFound = 1;\r
- pageIn(pc, idx, DisconnectReconnectPage, sizeof(DisconnectReconnectPage));\r
- idx += sizeof(DisconnectReconnectPage);\r
+ // Set a mask for the changeable values.\r
+ scsiDev.data[idx+12] = 0xFF;\r
+ scsiDev.data[idx+13] = 0xFF;\r
}\r
\r
- if (pageCode == 0x03 || pageCode == 0x3F)\r
- {\r
- pageFound = 1;\r
- pageIn(pc, idx, FormatDevicePage, sizeof(FormatDevicePage));\r
- if (pc != 0x01)\r
- {\r
- // Fill out the configured bytes-per-sector\r
- uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;\r
- scsiDev.data[idx+12] = bytesPerSector >> 8;\r
- scsiDev.data[idx+13] = bytesPerSector & 0xFF;\r
- }\r
- else\r
- {\r
- // Set a mask for the changeable values.\r
- scsiDev.data[idx+12] = 0xFF;\r
- scsiDev.data[idx+13] = 0xFF;\r
- }\r
+ idx += sizeof(FormatDevicePage);\r
+ }\r
\r
- idx += sizeof(FormatDevicePage);\r
- }\r
+ if (pageCode == 0x04 || pageCode == 0x3F)\r
+ {\r
+ pageFound = 1;\r
+ pageIn(pc, idx, RigidDiskDriveGeometry, sizeof(RigidDiskDriveGeometry));\r
\r
- if (pageCode == 0x04 || pageCode == 0x3F)\r
+ if (pc != 0x01)\r
{\r
- pageFound = 1;\r
- pageIn(pc, idx, RigidDiskDriveGeometry, sizeof(RigidDiskDriveGeometry));\r
-\r
- if (pc != 0x01)\r
- {\r
- // Need to fill out the number of cylinders.\r
- uint32 cyl;\r
- uint8 head;\r
- uint32 sector;\r
- LBA2CHS(\r
- getScsiCapacity(\r
- scsiDev.target->cfg->sdSectorStart,\r
- scsiDev.target->liveCfg.bytesPerSector,\r
- scsiDev.target->cfg->scsiSectors),\r
- &cyl,\r
- &head,\r
- §or);\r
-\r
- scsiDev.data[idx+2] = cyl >> 16;\r
- scsiDev.data[idx+3] = cyl >> 8;\r
- scsiDev.data[idx+4] = cyl;\r
-\r
- memcpy(&scsiDev.data[idx+6], &scsiDev.data[idx+2], 3);\r
- memcpy(&scsiDev.data[idx+9], &scsiDev.data[idx+2], 3);\r
- }\r
-\r
- idx += sizeof(RigidDiskDriveGeometry);\r
+ // Need to fill out the number of cylinders.\r
+ uint32 cyl;\r
+ uint8 head;\r
+ uint32 sector;\r
+ LBA2CHS(\r
+ getScsiCapacity(\r
+ scsiDev.target->cfg->sdSectorStart,\r
+ scsiDev.target->liveCfg.bytesPerSector,\r
+ scsiDev.target->cfg->scsiSectors),\r
+ &cyl,\r
+ &head,\r
+ §or);\r
+\r
+ scsiDev.data[idx+2] = cyl >> 16;\r
+ scsiDev.data[idx+3] = cyl >> 8;\r
+ scsiDev.data[idx+4] = cyl;\r
+\r
+ memcpy(&scsiDev.data[idx+6], &scsiDev.data[idx+2], 3);\r
+ memcpy(&scsiDev.data[idx+9], &scsiDev.data[idx+2], 3);\r
}\r
\r
- // DON'T output the following pages for SCSI1 hosts. They get upset when\r
- // we have more data to send than the allocation length provided.\r
- // (ie. Try not to output any more pages below this comment)\r
+ idx += sizeof(RigidDiskDriveGeometry);\r
+ }\r
\r
+ // DON'T output the following pages for SCSI1 hosts. They get upset when\r
+ // we have more data to send than the allocation length provided.\r
+ // (ie. Try not to output any more pages below this comment)\r
\r
- if (!scsiDev.compatMode && (pageCode == 0x08 || pageCode == 0x3F))\r
- {\r
- pageFound = 1;\r
- pageIn(pc, idx, CachingPage, sizeof(CachingPage));\r
- idx += sizeof(CachingPage);\r
- }\r
\r
- if (!scsiDev.compatMode && (pageCode == 0x0A || pageCode == 0x3F))\r
- {\r
- pageFound = 1;\r
- pageIn(pc, idx, ControlModePage, sizeof(ControlModePage));\r
- idx += sizeof(ControlModePage);\r
- }\r
+ if ((scsiDev.compatMode >= COMPAT_SCSI2) &&\r
+ (pageCode == 0x08 || pageCode == 0x3F))\r
+ {\r
+ pageFound = 1;\r
+ pageIn(pc, idx, CachingPage, sizeof(CachingPage));\r
+ idx += sizeof(CachingPage);\r
+ }\r
\r
- if ((\r
- (scsiDev.target->cfg->quirks == CONFIG_QUIRKS_APPLE) ||\r
- (idx + sizeof(AppleVendorPage) <= allocLength)\r
- ) &&\r
- (pageCode == 0x30 || pageCode == 0x3F))\r
- {\r
- pageFound = 1;\r
- pageIn(pc, idx, AppleVendorPage, sizeof(AppleVendorPage));\r
- idx += sizeof(AppleVendorPage);\r
- }\r
+ if ((scsiDev.compatMode >= COMPAT_SCSI2)\r
+ && (pageCode == 0x0A || pageCode == 0x3F))\r
+ {\r
+ pageFound = 1;\r
+ pageIn(pc, idx, ControlModePage, sizeof(ControlModePage));\r
+ idx += sizeof(ControlModePage);\r
+ }\r
+\r
+ if ((\r
+ (scsiDev.target->cfg->quirks == CONFIG_QUIRKS_APPLE) ||\r
+ (idx + sizeof(AppleVendorPage) <= allocLength)\r
+ ) &&\r
+ (pageCode == 0x30 || pageCode == 0x3F))\r
+ {\r
+ pageFound = 1;\r
+ pageIn(pc, idx, AppleVendorPage, sizeof(AppleVendorPage));\r
+ idx += sizeof(AppleVendorPage);\r
+ }\r
\r
- if (!pageFound)\r
+ if (!pageFound)\r
+ {\r
+ // Unknown Page Code\r
+ pageFound = 0;\r
+ scsiDev.status = CHECK_CONDITION;\r
+ scsiDev.target->sense.code = ILLEGAL_REQUEST;\r
+ scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;\r
+ scsiDev.phase = STATUS;\r
+ }\r
+ else\r
+ {\r
+ // Go back and fill out the mode data length\r
+ if (sixByteCmd)\r
{\r
- // Unknown Page Code\r
- pageFound = 0;\r
- scsiDev.status = CHECK_CONDITION;\r
- scsiDev.target->sense.code = ILLEGAL_REQUEST;\r
- scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;\r
- scsiDev.phase = STATUS;\r
+ // Cannot currently exceed limits. yay\r
+ scsiDev.data[0] = idx - 1;\r
}\r
else\r
{\r
- // Go back and fill out the mode data length\r
- if (sixByteCmd)\r
- {\r
- // Cannot currently exceed limits. yay\r
- scsiDev.data[0] = idx - 1;\r
- }\r
- else\r
- {\r
- scsiDev.data[0] = ((idx - 2) >> 8);\r
- scsiDev.data[1] = (idx - 2);\r
- }\r
-\r
- scsiDev.dataLen = idx > allocLength ? allocLength : idx;\r
- scsiDev.phase = DATA_IN;\r
+ scsiDev.data[0] = ((idx - 2) >> 8);\r
+ scsiDev.data[1] = (idx - 2);\r
}\r
+\r
+ scsiDev.dataLen = idx > allocLength ? allocLength : idx;\r
+ scsiDev.phase = DATA_IN;\r
}\r
}\r
\r
+\r
// Callback after the DATA OUT phase is complete.\r
static void doModeSelect(void)\r
{\r
{\r
// This delay probably isn't needed for most SCSI hosts, but it won't\r
// hurt either. It's possible some of the samplers needed this delay.\r
- if (scsiDev.compatMode)\r
+ if (scsiDev.compatMode < COMPAT_SCSI2)\r
{\r
CyDelayUs(2);\r
}\r
\r
if (scsiDev.parityError &&\r
(scsiDev.target->cfg->flags & CONFIG_ENABLE_PARITY) &&\r
- !scsiDev.compatMode)\r
+ (scsiDev.compatMode >= COMPAT_SCSI2))\r
{\r
scsiDev.target->sense.code = ABORTED_COMMAND;\r
scsiDev.target->sense.asc = SCSI_PARITY_ERROR;\r
}\r
else if (scsiDev.parityError &&\r
(scsiDev.target->cfg->flags & CONFIG_ENABLE_PARITY) &&\r
- !scsiDev.compatMode)\r
+ (scsiDev.compatMode >= COMPAT_SCSI2))\r
{\r
scsiDev.target->sense.code = ABORTED_COMMAND;\r
scsiDev.target->sense.asc = SCSI_PARITY_ERROR;\r
scsiDev.atnFlag = 0;\r
scsiDev.resetFlag = 0;\r
scsiDev.lun = -1;\r
+ scsiDev.compatMode = COMPAT_UNKNOWN;\r
\r
if (scsiDev.target)\r
{\r
scsiDev.phase = SELECTION;\r
scsiDev.lun = -1;\r
scsiDev.discPriv = 0;\r
- scsiDev.compatMode = 0;\r
\r
scsiDev.initiatorId = -1;\r
scsiDev.target = NULL;\r
\r
static void process_SelectionPhase()\r
{\r
+ if (scsiDev.compatMode < COMPAT_SCSI2)\r
+ {\r
+ // Required for some older SCSI1 devices using a 5380 chip.\r
+ CyDelayUs(100);\r
+ }\r
+\r
int sel = SCSI_ReadFilt(SCSI_Filt_SEL);\r
int bsy = SCSI_ReadFilt(SCSI_Filt_BSY);\r
\r
if (!scsiDev.atnFlag)\r
{\r
target->unitAttention = 0;\r
- scsiDev.compatMode = 1;\r
+ scsiDev.compatMode = COMPAT_SCSI1;\r
+ }\r
+ else if (scsiDev.compatMode == COMPAT_UNKNOWN)\r
+ {\r
+ scsiDev.compatMode = COMPAT_SCSI2;\r
}\r
\r
// We've been selected!\r
\r
if (scsiDev.parityError &&\r
(scsiDev.target->cfg->flags & CONFIG_ENABLE_PARITY) &&\r
- !scsiDev.compatMode)\r
+ (scsiDev.compatMode >= COMPAT_SCSI2))\r
{\r
// Skip the remaining message bytes, and then start the MESSAGE_OUT\r
// phase again from the start. The initiator will re-send the\r
scsiDev.resetFlag = 1;\r
scsiDev.phase = BUS_FREE;\r
scsiDev.target = NULL;\r
+ scsiDev.compatMode = COMPAT_UNKNOWN;\r
\r
int i;\r
for (i = 0; i < MAX_SCSI_TARGETS; ++i)\r
MSG_LINKED_COMMAND_COMPLETE_WITH_FLAG = 0x0B
} SCSI_MESSAGE;
+typedef enum
+{
+ COMPAT_UNKNOWN,
+ COMPAT_SCSI1,
+ COMPAT_SCSI2
+} SCSI_COMPAT_MODE;
+
// Maximum value for bytes-per-sector.
#define MAX_SECTOR_SIZE 8192
#define MIN_SECTOR_SIZE 64
uint8 cdbLen; // 6, 10, or 12 byte message.
int8 lun; // Target lun, set by IDENTIFY message.
uint8 discPriv; // Disconnect priviledge.
- uint8_t compatMode; // true for SCSI1 and SASI hosts.
+ uint8_t compatMode; // SCSI_COMPAT_MODE
// Only let the reserved initiator talk to us.
// A 3rd party may be sending the RESERVE/RELEASE commands
\r
SCSI_RST_ISR_StartEx(scsiResetISR);\r
}\r
+\r
+// 1 = DBx error\r
+// 2 = Parity error\r
+// 4 = MSG error\r
+// 8 = CD error\r
+// 16 = IO error\r
+// 32 = other error\r
+int scsiSelfTest()\r
+{\r
+ int result = 0;\r
+\r
+ // TEST DBx and DBp\r
+ int i;\r
+ SCSI_Out_Ctl_Write(1); // Write bits manually.\r
+ SCSI_CTL_PHASE_Write(__scsiphase_io); // Needed for parity generation\r
+ for (i = 0; i < 256; ++i)\r
+ {\r
+ SCSI_Out_Bits_Write(i);\r
+ scsiDeskewDelay();\r
+ if (scsiReadDBxPins() != (i & 0xff))\r
+ {\r
+ result |= 1;\r
+ }\r
+ if (Lookup_OddParity[i & 0xff] != SCSI_ReadPin(SCSI_In_DBP))\r
+ {\r
+ result |= 2;\r
+ }\r
+ }\r
+ SCSI_Out_Ctl_Write(0); // Write bits normally.\r
+\r
+ // TEST MSG, CD, IO\r
+ for (i = 0; i < 8; ++i)\r
+ {\r
+ SCSI_CTL_PHASE_Write(i);\r
+ scsiDeskewDelay();\r
+\r
+ if (SCSI_ReadPin(SCSI_In_MSG) != !!(i & __scsiphase_msg))\r
+ {\r
+ result |= 4;\r
+ }\r
+ if (SCSI_ReadPin(SCSI_In_CD) != !!(i & __scsiphase_cd))\r
+ {\r
+ result |= 8;\r
+ }\r
+ if (SCSI_ReadPin(SCSI_In_IO) != !!(i & __scsiphase_io))\r
+ {\r
+ result |= 16;\r
+ }\r
+ }\r
+ SCSI_CTL_PHASE_Write(0);\r
+\r
+ uint32_t signalsOut[] = { SCSI_Out_ATN, SCSI_Out_BSY, SCSI_Out_RST, SCSI_Out_SEL };\r
+ uint32_t signalsIn[] = { SCSI_Filt_ATN, SCSI_Filt_BSY, SCSI_Filt_RST, SCSI_Filt_SEL };\r
+\r
+ for (i = 0; i < 4; ++i)\r
+ {\r
+ SCSI_SetPin(signalsOut[i]);\r
+ scsiDeskewDelay();\r
+\r
+ int j;\r
+ for (j = 0; j < 4; ++j)\r
+ {\r
+ if (i == j)\r
+ {\r
+ if (! SCSI_ReadFilt(signalsIn[j]))\r
+ {\r
+ result |= 32;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if (SCSI_ReadFilt(signalsIn[j]))\r
+ {\r
+ result |= 32;\r
+ }\r
+ }\r
+ }\r
+ SCSI_ClearPin(signalsOut[i]);\r
+ }\r
+ return result;\r
+}\r
+\r
+\r
#pragma GCC pop_options\r
void scsiEnterPhase(int phase);
+int scsiSelfTest(void);
+
#endif
#define USBFS_arb_int__INTC_CLR_PD_REG CYREG_NVIC_CLRPEND0\r
#define USBFS_arb_int__INTC_MASK 0x400000u\r
#define USBFS_arb_int__INTC_NUMBER 22u\r
-#define USBFS_arb_int__INTC_PRIOR_NUM 7u\r
+#define USBFS_arb_int__INTC_PRIOR_NUM 6u\r
#define USBFS_arb_int__INTC_PRIOR_REG CYREG_NVIC_PRI_22\r
#define USBFS_arb_int__INTC_SET_EN_REG CYREG_NVIC_SETENA0\r
#define USBFS_arb_int__INTC_SET_PD_REG CYREG_NVIC_SETPEND0\r
.set USBFS_arb_int__INTC_CLR_PD_REG, CYREG_NVIC_CLRPEND0\r
.set USBFS_arb_int__INTC_MASK, 0x400000\r
.set USBFS_arb_int__INTC_NUMBER, 22\r
-.set USBFS_arb_int__INTC_PRIOR_NUM, 7\r
+.set USBFS_arb_int__INTC_PRIOR_NUM, 6\r
.set USBFS_arb_int__INTC_PRIOR_REG, CYREG_NVIC_PRI_22\r
.set USBFS_arb_int__INTC_SET_EN_REG, CYREG_NVIC_SETENA0\r
.set USBFS_arb_int__INTC_SET_PD_REG, CYREG_NVIC_SETPEND0\r
USBFS_arb_int__INTC_CLR_PD_REG EQU CYREG_NVIC_CLRPEND0\r
USBFS_arb_int__INTC_MASK EQU 0x400000\r
USBFS_arb_int__INTC_NUMBER EQU 22\r
-USBFS_arb_int__INTC_PRIOR_NUM EQU 7\r
+USBFS_arb_int__INTC_PRIOR_NUM EQU 6\r
USBFS_arb_int__INTC_PRIOR_REG EQU CYREG_NVIC_PRI_22\r
USBFS_arb_int__INTC_SET_EN_REG EQU CYREG_NVIC_SETENA0\r
USBFS_arb_int__INTC_SET_PD_REG EQU CYREG_NVIC_SETPEND0\r
USBFS_arb_int__INTC_CLR_PD_REG EQU CYREG_NVIC_CLRPEND0\r
USBFS_arb_int__INTC_MASK EQU 0x400000\r
USBFS_arb_int__INTC_NUMBER EQU 22\r
-USBFS_arb_int__INTC_PRIOR_NUM EQU 7\r
+USBFS_arb_int__INTC_PRIOR_NUM EQU 6\r
USBFS_arb_int__INTC_PRIOR_REG EQU CYREG_NVIC_PRI_22\r
USBFS_arb_int__INTC_SET_EN_REG EQU CYREG_NVIC_SETENA0\r
USBFS_arb_int__INTC_SET_PD_REG EQU CYREG_NVIC_SETPEND0\r
const uint8 cy_meta_loadable[] = {\r
0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,\r
0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,\r
- 0x00u, 0x00u, 0x00u, 0x00u, 0x5Cu, 0xD1u, 0x20u, 0x04u,\r
+ 0x00u, 0x00u, 0x00u, 0x00u, 0x5Cu, 0xD1u, 0x22u, 0x04u,\r
0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,\r
0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,\r
0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,\r
<name_val_pair name="c9323d49-d323-40b8-9b59-cc008d68a989@Release@CortexM3@Linker@General@Enable printf Float" v="True" />\r
<name_val_pair name="c9323d49-d323-40b8-9b59-cc008d68a989@Release@CortexM3@Linker@Optimization@Optimization Level" v="Size" />\r
<name_val_pair name="c9323d49-d323-40b8-9b59-cc008d68a989@Release@CortexM3@Linker@Optimization@Remove Unused Functions" v="True" />\r
-<name_val_pair name="c9323d49-d323-40b8-9b59-cc008d68a989@Release@CortexM3@Linker@Command Line@Command Line" v="" />\r
+<name_val_pair name="c9323d49-d323-40b8-9b59-cc008d68a989@Release@CortexM3@Linker@Command Line@Command Line" v="-Wl,--section-start=.DEFAULT_CONFIG=0x0001BC00" />\r
</name>\r
</platform>\r
<platform>\r
#define USBFS_arb_int__INTC_CLR_PD_REG CYREG_NVIC_CLRPEND0
#define USBFS_arb_int__INTC_MASK 0x400000u
#define USBFS_arb_int__INTC_NUMBER 22u
-#define USBFS_arb_int__INTC_PRIOR_NUM 7u
+#define USBFS_arb_int__INTC_PRIOR_NUM 6u
#define USBFS_arb_int__INTC_PRIOR_REG CYREG_NVIC_PRI_22
#define USBFS_arb_int__INTC_SET_EN_REG CYREG_NVIC_SETENA0
#define USBFS_arb_int__INTC_SET_PD_REG CYREG_NVIC_SETPEND0
#define SD_RX_DMA__DRQ_CTL CYREG_IDMUX_DRQ_CTL0
#define SD_RX_DMA__DRQ_NUMBER 2u
#define SD_RX_DMA__NUMBEROF_TDS 0u
-#define SD_RX_DMA__PRIORITY 2u
+#define SD_RX_DMA__PRIORITY 0u
#define SD_RX_DMA__TERMIN_EN 0u
#define SD_RX_DMA__TERMIN_SEL 0u
#define SD_RX_DMA__TERMOUT0_EN 1u
#define SD_TX_DMA__DRQ_CTL CYREG_IDMUX_DRQ_CTL0
#define SD_TX_DMA__DRQ_NUMBER 3u
#define SD_TX_DMA__NUMBEROF_TDS 0u
-#define SD_TX_DMA__PRIORITY 2u
+#define SD_TX_DMA__PRIORITY 1u
#define SD_TX_DMA__TERMIN_EN 0u
#define SD_TX_DMA__TERMIN_SEL 0u
#define SD_TX_DMA__TERMOUT0_EN 1u
.set USBFS_arb_int__INTC_CLR_PD_REG, CYREG_NVIC_CLRPEND0
.set USBFS_arb_int__INTC_MASK, 0x400000
.set USBFS_arb_int__INTC_NUMBER, 22
-.set USBFS_arb_int__INTC_PRIOR_NUM, 7
+.set USBFS_arb_int__INTC_PRIOR_NUM, 6
.set USBFS_arb_int__INTC_PRIOR_REG, CYREG_NVIC_PRI_22
.set USBFS_arb_int__INTC_SET_EN_REG, CYREG_NVIC_SETENA0
.set USBFS_arb_int__INTC_SET_PD_REG, CYREG_NVIC_SETPEND0
.set SD_RX_DMA__DRQ_CTL, CYREG_IDMUX_DRQ_CTL0
.set SD_RX_DMA__DRQ_NUMBER, 2
.set SD_RX_DMA__NUMBEROF_TDS, 0
-.set SD_RX_DMA__PRIORITY, 2
+.set SD_RX_DMA__PRIORITY, 0
.set SD_RX_DMA__TERMIN_EN, 0
.set SD_RX_DMA__TERMIN_SEL, 0
.set SD_RX_DMA__TERMOUT0_EN, 1
.set SD_TX_DMA__DRQ_CTL, CYREG_IDMUX_DRQ_CTL0
.set SD_TX_DMA__DRQ_NUMBER, 3
.set SD_TX_DMA__NUMBEROF_TDS, 0
-.set SD_TX_DMA__PRIORITY, 2
+.set SD_TX_DMA__PRIORITY, 1
.set SD_TX_DMA__TERMIN_EN, 0
.set SD_TX_DMA__TERMIN_SEL, 0
.set SD_TX_DMA__TERMOUT0_EN, 1
USBFS_arb_int__INTC_CLR_PD_REG EQU CYREG_NVIC_CLRPEND0
USBFS_arb_int__INTC_MASK EQU 0x400000
USBFS_arb_int__INTC_NUMBER EQU 22
-USBFS_arb_int__INTC_PRIOR_NUM EQU 7
+USBFS_arb_int__INTC_PRIOR_NUM EQU 6
USBFS_arb_int__INTC_PRIOR_REG EQU CYREG_NVIC_PRI_22
USBFS_arb_int__INTC_SET_EN_REG EQU CYREG_NVIC_SETENA0
USBFS_arb_int__INTC_SET_PD_REG EQU CYREG_NVIC_SETPEND0
SD_RX_DMA__DRQ_CTL EQU CYREG_IDMUX_DRQ_CTL0
SD_RX_DMA__DRQ_NUMBER EQU 2
SD_RX_DMA__NUMBEROF_TDS EQU 0
-SD_RX_DMA__PRIORITY EQU 2
+SD_RX_DMA__PRIORITY EQU 0
SD_RX_DMA__TERMIN_EN EQU 0
SD_RX_DMA__TERMIN_SEL EQU 0
SD_RX_DMA__TERMOUT0_EN EQU 1
SD_TX_DMA__DRQ_CTL EQU CYREG_IDMUX_DRQ_CTL0
SD_TX_DMA__DRQ_NUMBER EQU 3
SD_TX_DMA__NUMBEROF_TDS EQU 0
-SD_TX_DMA__PRIORITY EQU 2
+SD_TX_DMA__PRIORITY EQU 1
SD_TX_DMA__TERMIN_EN EQU 0
SD_TX_DMA__TERMIN_SEL EQU 0
SD_TX_DMA__TERMOUT0_EN EQU 1
USBFS_arb_int__INTC_CLR_PD_REG EQU CYREG_NVIC_CLRPEND0
USBFS_arb_int__INTC_MASK EQU 0x400000
USBFS_arb_int__INTC_NUMBER EQU 22
-USBFS_arb_int__INTC_PRIOR_NUM EQU 7
+USBFS_arb_int__INTC_PRIOR_NUM EQU 6
USBFS_arb_int__INTC_PRIOR_REG EQU CYREG_NVIC_PRI_22
USBFS_arb_int__INTC_SET_EN_REG EQU CYREG_NVIC_SETENA0
USBFS_arb_int__INTC_SET_PD_REG EQU CYREG_NVIC_SETPEND0
SD_RX_DMA__DRQ_CTL EQU CYREG_IDMUX_DRQ_CTL0
SD_RX_DMA__DRQ_NUMBER EQU 2
SD_RX_DMA__NUMBEROF_TDS EQU 0
-SD_RX_DMA__PRIORITY EQU 2
+SD_RX_DMA__PRIORITY EQU 0
SD_RX_DMA__TERMIN_EN EQU 0
SD_RX_DMA__TERMIN_SEL EQU 0
SD_RX_DMA__TERMOUT0_EN EQU 1
SD_TX_DMA__DRQ_CTL EQU CYREG_IDMUX_DRQ_CTL0
SD_TX_DMA__DRQ_NUMBER EQU 3
SD_TX_DMA__NUMBEROF_TDS EQU 0
-SD_TX_DMA__PRIORITY EQU 2
+SD_TX_DMA__PRIORITY EQU 1
SD_TX_DMA__TERMIN_EN EQU 0
SD_TX_DMA__TERMIN_SEL EQU 0
SD_TX_DMA__TERMOUT0_EN EQU 1
const uint8 cy_meta_loadable[] = {
0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
- 0x00u, 0x00u, 0x00u, 0x00u, 0x5Cu, 0xD1u, 0x10u, 0x04u,
+ 0x00u, 0x00u, 0x00u, 0x00u, 0x5Cu, 0xD1u, 0x22u, 0x04u,
0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
<name_val_pair name="c9323d49-d323-40b8-9b59-cc008d68a989@Release@CortexM3@Linker@General@Enable printf Float" v="True" />
<name_val_pair name="c9323d49-d323-40b8-9b59-cc008d68a989@Release@CortexM3@Linker@Optimization@Optimization Level" v="Size" />
<name_val_pair name="c9323d49-d323-40b8-9b59-cc008d68a989@Release@CortexM3@Linker@Optimization@Remove Unused Functions" v="True" />
-<name_val_pair name="c9323d49-d323-40b8-9b59-cc008d68a989@Release@CortexM3@Linker@Command Line@Command Line" v="" />
+<name_val_pair name="c9323d49-d323-40b8-9b59-cc008d68a989@Release@CortexM3@Linker@Command Line@Command Line" v="-Wl,--section-start=.DEFAULT_CONFIG=0x0001BC00" />
</name>
</platform>
<platform>
// Response:
// uint8_t[16] CSD
// uint8_t[16] CID
- CONFIG_SDINFO
+ CONFIG_SDINFO,
+
+ // Command content:
+ // uint8_t CONFIG_SCSITEST
+ // Response:
+ // CONFIG_STATUS
+ // uint8_t result code (0 = passed)
+ CONFIG_SCSITEST
} CONFIG_COMMAND;
typedef enum
using namespace SCSI2SD;
-ADD QUIRKS MODES
namespace
{
// Endian conversion routines.
config.headsPerCylinder = 255;
memcpy(config.vendor, " codesrc", 8);
memcpy(config.prodId, " SCSI2SD", 16);
- memcpy(config.revision, " 4.0", 4);
+ memcpy(config.revision, " 4.2", 4);
memcpy(config.serial, "1234567812345678", 16);
// Reserved fields, already set to 0
return std::vector<uint8_t>(begin, begin + sizeof(config));
}
+/*
wxXmlNode*
ConfigUtil::toXML(const TargetConfig& config)
{
{
}
+*/
export CC CXX
-all: $(BUILD)/scsi2sd-util$(EXE)
+all: $(BUILD)/scsi2sd-util$(EXE) $(BUILD)/scsi2sd-monitor$(EXE)
CYAPI = \
$(BUILD)/cybtldr_api2.o \
OBJ = \
$(CYAPI) $(HIDAPI) \
- $(BUILD)/scsi2sd-util.o \
$(BUILD)/ConfigUtil.o \
$(BUILD)/Firmware.o \
$(BUILD)/TargetPanel.o \
$(BUILD)/SCSI2SD_HID.o \
$(BUILD)/hidpacket.o \
+EXEOBJ = \
+ $(BUILD)/scsi2sd-util.o \
+ $(BUILD)/scsi2sd-monitor.o \
+
+
$(OBJ): $(BUILD)/zlib/buildstamp
+$(EXEOBJ): $(BUILD)/zlib/buildstamp
$(BUILD)/zlib/buildstamp:
mkdir -p $(dir $@)
( \
touch $@
$(OBJ): $(BUILD)/wx.buildstamp
+$(EXEOBJ): $(BUILD)/wx.buildstamp
$(BUILD)/wx.buildstamp: $(BUILD)/zlib/buildstamp
mkdir -p $(dir $@)
( \
touch $@
$(OBJ): $(BUILD)/libzipper/buildstamp
+$(EXEOBJ): $(BUILD)/libzipper/buildstamp
$(BUILD)/libzipper/buildstamp: $(BUILD)/zlib/buildstamp
mkdir -p $(dir $@)
( \
mkdir -p $(dir $@)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) `$(BUILD)/wx-config --cxxflags` $< -c -o $@
-$(BUILD)/scsi2sd-util$(EXE): $(OBJ)
+$(BUILD)/scsi2sd-util$(EXE): $(OBJ) $(BUILD)/scsi2sd-util.o
+ mkdir -p $(dir $@)
+ $(CXX) $(CXXFLAGS) $^ $(LDFLAGS) `$(BUILD)/wx-config --libs` -o $@
+
+$(BUILD)/scsi2sd-monitor$(EXE): $(OBJ) $(BUILD)/scsi2sd-monitor.o
mkdir -p $(dir $@)
$(CXX) $(CXXFLAGS) $^ $(LDFLAGS) `$(BUILD)/wx-config --libs` -o $@
std::vector<uint8_t> out;
try
{
- sendHIDPacket(cmd, out, 1);
+ sendHIDPacket(cmd, out, 16);
}
catch (std::runtime_error& e)
{
std::vector<uint8_t> out;
try
{
- sendHIDPacket(cmd, out, 1);
+ sendHIDPacket(cmd, out, 16);
}
catch (std::runtime_error& e)
{
return result;
}
+bool
+HID::scsiSelfTest()
+{
+ std::vector<uint8_t> cmd { CONFIG_SCSITEST };
+ std::vector<uint8_t> out;
+ try
+ {
+ sendHIDPacket(cmd, out, 2);
+ }
+ catch (std::runtime_error& e)
+ {
+ return false;
+ }
+ return (out.size() >= 1) && (out[0] == CONFIG_STATUS_GOOD);
+}
+
+
void
HID::sendHIDPacket(
const std::vector<uint8_t>& cmd,
std::vector<uint8_t> getSD_CSD();
std::vector<uint8_t> getSD_CID();
+ bool scsiSelfTest();
+
void enterBootloader();
void readFlashRow(int array, int row, std::vector<uint8_t>& out);
--- /dev/null
+// Copyright (C) 2015 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of SCSI2SD.
+//
+// SCSI2SD is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// SCSI2SD is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
+
+
+// For compilers that support precompilation, includes "wx/wx.h".
+#include <wx/wxprec.h>
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+
+#include <wx/filedlg.h>
+#include <wx/filefn.h>
+#include <wx/filename.h>
+#include <wx/log.h>
+#include <wx/notebook.h>
+#include <wx/progdlg.h>
+#include <wx/utils.h>
+#include <wx/windowptr.h>
+#include <wx/thread.h>
+
+#include <zipper.hh>
+
+#include "ConfigUtil.hh"
+#include "TargetPanel.hh"
+#include "SCSI2SD_Bootloader.hh"
+#include "SCSI2SD_HID.hh"
+#include "Firmware.hh"
+
+#include <algorithm>
+#include <iomanip>
+#include <vector>
+#include <set>
+#include <sstream>
+
+#if __cplusplus >= 201103L
+#include <cstdint>
+#include <memory>
+using std::shared_ptr;
+#else
+#include <stdint.h>
+#include <tr1/memory>
+using std::tr1::shared_ptr;
+#endif
+
+#define MIN_FIRMWARE_VERSION 0x0400
+
+using namespace SCSI2SD;
+
+namespace
+{
+
+static uint8_t sdCrc7(uint8_t* chr, uint8_t cnt, uint8_t crc)
+{
+ uint8_t a;
+ for(a = 0; a < cnt; a++)
+ {
+ uint8_t data = chr[a];
+ uint8_t i;
+ for(i = 0; i < 8; i++)
+ {
+ crc <<= 1;
+ if ((data & 0x80) ^ (crc & 0x80))
+ {
+ crc ^= 0x09;
+ }
+ data <<= 1;
+ }
+ }
+ return crc & 0x7F;
+}
+
+class TimerLock
+{
+public:
+ TimerLock(wxTimer* timer) :
+ myTimer(timer),
+ myInterval(myTimer->GetInterval())
+ {
+ myTimer->Stop();
+ };
+
+ virtual ~TimerLock()
+ {
+ if (myTimer && myInterval > 0)
+ {
+ myTimer->Start(myInterval);
+ }
+ }
+private:
+ wxTimer* myTimer;
+ int myInterval;
+};
+
+class AppFrame : public wxFrame
+{
+public:
+ AppFrame() :
+ wxFrame(NULL, wxID_ANY, "scsi2sd-monitor", wxPoint(50, 50), wxSize(250, 150))
+ {
+ wxFlexGridSizer *fgs = new wxFlexGridSizer(3, 2, 9, 25);
+
+ fgs->Add(new wxStaticText(this, wxID_ANY, wxT("SCSI2SD Device:")));
+ myBoardText = new wxStaticText(this, wxID_ANY, wxT(""));
+ fgs->Add(myBoardText);
+ fgs->Add(new wxStaticText(this, wxID_ANY, wxT("SD Test:")));
+ mySDText = new wxStaticText(this, wxID_ANY, wxT(""));
+ fgs->Add(mySDText);
+ fgs->Add(new wxStaticText(this, wxID_ANY, wxT("SCSI Test:")));
+ mySCSIText = new wxStaticText(this, wxID_ANY, wxT(""));
+ fgs->Add(mySCSIText);
+
+ wxBoxSizer* hbox = new wxBoxSizer(wxHORIZONTAL);
+ hbox->Add(fgs, 1, wxALL | wxEXPAND, 15);
+ this->SetSizer(hbox);
+ Centre();
+
+ //Fit(); // Needed to reduce window size on Windows
+ //FitInside(); // Needed on Linux to prevent status bar overlap
+
+ myTimer = new wxTimer(this, ID_Timer);
+ myTimer->Start(1000);
+ }
+
+private:
+ wxTimer* myTimer;
+ shared_ptr<HID> myHID;
+ shared_ptr<Bootloader> myBootloader;
+
+ wxStaticText* myBoardText;
+ wxStaticText* mySDText;
+ wxStaticText* mySCSIText;
+
+ enum
+ {
+ ID_ConfigDefaults = wxID_HIGHEST + 1,
+ ID_Timer
+ };
+
+ void evaluate()
+ {
+ if (myHID)
+ {
+ std::stringstream msg;
+ msg << "Ready, " <<
+ myHID->getFirmwareVersionStr();
+ myBoardText->SetLabelText(msg.str());
+
+
+ std::vector<uint8_t> csd(myHID->getSD_CSD());
+ std::vector<uint8_t> cid(myHID->getSD_CID());
+
+ bool sdGood = false;
+ for (size_t i = 0; i < 16; ++i)
+ {
+ if (csd[i] != 0)
+ {
+ sdGood = true;
+ //break;
+ }
+ }
+
+ sdGood = sdGood &&
+ (sdCrc7(&csd[0], 15, 0) == (csd[15] >> 1)) &&
+ (sdCrc7(&cid[0], 15, 0) == (cid[15] >> 1));
+
+ if (sdGood)
+ {
+ mySDText->SetLabelText("OK");
+ }
+ else
+ {
+ mySDText->SetLabelText("FAIL");
+ }
+
+ if (myHID->scsiSelfTest())
+ {
+ mySCSIText->SetLabelText("OK");
+ }
+ else
+ {
+ mySCSIText->SetLabelText("FAIL");
+ }
+ }
+ else
+ {
+ if (myBootloader)
+ {
+ myBoardText->SetLabelText("Bootloader");
+ }
+ else
+ {
+ myBoardText->SetLabelText("Missing");
+ }
+ mySDText->SetLabelText("-");
+ mySCSIText->SetLabelText("-");
+ }
+ }
+
+ void OnID_Timer(wxTimerEvent& event)
+ {
+ // Check if we are connected to the HID device.
+ // AND/or bootloader device.
+ try
+ {
+ if (myBootloader)
+ {
+ // Verify the USB HID connection is valid
+ if (!myBootloader->ping())
+ {
+ myBootloader.reset();
+ }
+ }
+
+ if (!myBootloader)
+ {
+ myBootloader.reset(Bootloader::Open());
+ }
+
+ if (myHID && !myHID->ping())
+ {
+ // Verify the USB HID connection is valid
+std::cerr << "RESET!" << std::endl;
+ myHID.reset();
+ }
+
+ if (!myHID)
+ {
+ myHID.reset(HID::Open());
+
+ }
+ }
+ catch (std::runtime_error& e)
+ {
+ std::cerr << e.what() << std::endl;
+ }
+
+ evaluate();
+ }
+
+ // Note: Don't confuse this with the wxApp::OnExit virtual method
+ void OnExitEvt(wxCommandEvent& event)
+ {
+ Close(true);
+ }
+
+ wxDECLARE_EVENT_TABLE();
+};
+
+wxBEGIN_EVENT_TABLE(AppFrame, wxFrame)
+ EVT_MENU(wxID_EXIT, AppFrame::OnExitEvt)
+
+ EVT_TIMER(AppFrame::ID_Timer, AppFrame::OnID_Timer)
+
+wxEND_EVENT_TABLE()
+
+
+
+class App : public wxApp
+{
+public:
+ virtual bool OnInit()
+ {
+ AppFrame* frame = new AppFrame();
+ frame->Show(true);
+ SetTopWindow(frame);
+ return true;
+ }
+};
+} // namespace
+
+// Main Method
+wxIMPLEMENT_APP(App);
+
+
namespace
{
+static uint8_t sdCrc7(uint8_t* chr, uint8_t cnt, uint8_t crc)
+{
+ uint8_t a;
+ for(a = 0; a < cnt; a++)
+ {
+ uint8_t data = chr[a];
+ uint8_t i;
+ for(i = 0; i < 8; i++)
+ {
+ crc <<= 1;
+ if ((data & 0x80) ^ (crc & 0x80))
+ {
+ crc ^= 0x09;
+ }
+ data <<= 1;
+ }
+ }
+ return crc & 0x7F;
+}
+
class TimerLock
{
public:
"Log SCSI data",
"Log SCSI commands");
+ mySelfTestChk = menuDebug->AppendCheckItem(
+ ID_SelfTest,
+ "SCSI Standalone Self-Test",
+ "SCSI Standalone Self-Test");
+
wxMenu *menuHelp = new wxMenu();
menuHelp->Append(wxID_ABOUT);
wxButton* myLoadButton;
wxButton* mySaveButton;
wxMenuItem* mySCSILogChk;
+ wxMenuItem* mySelfTestChk;
wxTimer* myTimer;
shared_ptr<HID> myHID;
shared_ptr<Bootloader> myBootloader;
ID_BtnLoad,
ID_BtnSave,
ID_LogWindow,
- ID_SCSILog
+ ID_SCSILog,
+ ID_SelfTest
};
void OnID_ConfigDefaults(wxCommandEvent& event)
myHID->getSDCapacity() << std::endl;
sdinfo << "SD CSD Register: ";
+ if (sdCrc7(&csd[0], 15, 0) != (csd[15] >> 1))
+ {
+ sdinfo << "BADCRC ";
+ }
for (size_t i = 0; i < csd.size(); ++i)
{
sdinfo <<
}
sdinfo << std::endl;
sdinfo << "SD CID Register: ";
+ if (sdCrc7(&cid[0], 15, 0) != (cid[15] >> 1))
+ {
+ sdinfo << "BADCRC ";
+ }
for (size_t i = 0; i < cid.size(); ++i)
{
sdinfo <<
wxLogMessage(this, "%s", sdinfo.str());
+ if (mySelfTestChk->IsChecked())
+ {
+ std::stringstream scsiInfo;
+ scsiInfo << "SCSI Self-Test: " <<
+ (myHID->scsiSelfTest() ? "Passed" : "FAIL");
+ wxLogMessage(this, "%s", scsiInfo.str());
+ }
+
if (!myInitialConfig)
{
wxCommandEvent loadEvent(wxEVT_NULL, ID_BtnLoad);