| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323 | #ifndef __BLUESCSI_H__#define __BLUESCSI_H__#include <Arduino.h> // For Platform.IO#include <SdFat.h>// SCSI config#define MAX_SCSIID  7          // Maximum number of supported SCSI-IDs (The minimum is 0)#define MAX_SCSILUN 8          // Maximum number of LUNs supported     (The minimum is 0)#define NUM_SCSIID  MAX_SCSIID // Number of enabled SCSI IDs#define NUM_SCSILUN 1          // Number of enabled LUNs#define READ_PARITY_CHECK 0    // Perform read parity check (unverified)#define DEFAULT_SCSI_ID 1#define DEFAULT_SCSI_LUN 0#define SCSI_BUF_SIZE 512      // Size of the SCSI Buffer#define HDD_BLOCK_SIZE 512#define OPTICAL_BLOCK_SIZE 2048// HDD format#define MAX_BLOCKSIZE 4096     // Maximum BLOCK size// SDFAT#define SD1_CONFIG SdSpiConfig(PA4, DEDICATED_SPI, SD_SCK_MHZ(SPI_FULL_SPEED), &SPI)// LED ERRORS#define ERROR_FALSE_INIT  3#define ERROR_NO_SDCARD   5#if DEBUG#define LOG(XX)     Serial.print(XX)#define LOGHEX(XX)  Serial.print(XX, HEX)#define LOGN(XX)    Serial.println(XX)#define LOGHEXN(XX) Serial.println(XX, HEX)#else#define LOG(XX)     //Serial.print(XX)#define LOGHEX(XX)  //Serial.print(XX, HEX)#define LOGN(XX)    //Serial.println(XX)#define LOGHEXN(XX) //Serial.println(XX, HEX)#endif#define active   1#define inactive 0#define high 0#define low 1#define isHigh(XX) ((XX) == high)#define isLow(XX) ((XX) != high)#define gpio_mode(pin,val) gpio_set_mode(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit, val);#define gpio_write(pin,val) gpio_write_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit, val)#define gpio_read(pin) gpio_read_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit)//#define DB0       PB8     // SCSI:DB0//#define DB1       PB9     // SCSI:DB1//#define DB2       PB10    // SCSI:DB2//#define DB3       PB11    // SCSI:DB3//#define DB4       PB12    // SCSI:DB4//#define DB5       PB13    // SCSI:DB5//#define DB6       PB14    // SCSI:DB6//#define DB7       PB15    // SCSI:DB7//#define DBP       PB0     // SCSI:DBP#define ATN       PA8      // SCSI:ATN#define BSY       PA9      // SCSI:BSY#define ACK       PA10     // SCSI:ACK#define RST       PA15     // SCSI:RST#define MSG       PB3      // SCSI:MSG#define SEL       PB4      // SCSI:SEL#define CD        PB5      // SCSI:C/D#define REQ       PB6      // SCSI:REQ#define IO        PB7      // SCSI:I/O#define SD_CS     PA4      // SDCARD:CS#define LED       PC13     // LED#define LED2      PA0      // External LED// Image Set Selector#ifdef XCVR#define IMAGE_SELECT1   PC14#define IMAGE_SELECT2   PC15#else#define IMAGE_SELECT1   PA1#define IMAGE_SELECT2   PB1#endif// GPIO register port#define PAREG GPIOA->regs#define PBREG GPIOB->regs#define PCREG GPIOC->regs// LED control#define LED_ON()  PCREG->BSRR = 0b00100000000000000000000000000000; PAREG->BSRR = 0b00000000000000000000000000000001;#define LED_OFF() PCREG->BSRR = 0b00000000000000000010000000000000; PAREG->BSRR = 0b00000000000000010000000000000000;// Virtual pin (Arduio compatibility is slow, so make it MCU-dependent)#define PA(BIT)       (BIT)#define PB(BIT)       (BIT+16)// Virtual pin decoding#define GPIOREG(VPIN)    ((VPIN)>=16?PBREG:PAREG)#define BITMASK(VPIN) (1<<((VPIN)&15))#define vATN       PA(8)      // SCSI:ATN#define vBSY       PA(9)      // SCSI:BSY#define vACK       PA(10)     // SCSI:ACK#define vRST       PA(15)     // SCSI:RST#define vMSG       PB(3)      // SCSI:MSG#define vSEL       PB(4)      // SCSI:SEL#define vCD        PB(5)      // SCSI:C/D#define vREQ       PB(6)      // SCSI:REQ#define vIO        PB(7)      // SCSI:I/O#define vSD_CS     PA(4)      // SDCARD:CS// SCSI output pin control: opendrain active LOW (direct pin drive)#define SCSI_OUT(VPIN,ACTIVE) { GPIOREG(VPIN)->BSRR = BITMASK(VPIN)<<((ACTIVE)?16:0); }// SCSI input pin check (inactive=0,avtive=1)#define SCSI_IN(VPIN) ((~GPIOREG(VPIN)->IDR>>(VPIN&15))&1)#define NOP(x) for(unsigned _nopcount = x; _nopcount; _nopcount--) { asm("NOP"); }/* SCSI Timing delays */// Due to limitations in timing granularity all of these are "very" rough estimates#define SCSI_BUS_SETTLE() NOP(30);                            // spec 400ns ours ~420us#define SCSI_DATA_RELEASE() NOP(30);                          // spec 400ns ours ~420us#define SCSI_HOLD_TIME() asm("NOP"); asm("NOP"); asm("NOP");  // spec 45ns ours ~42ns#define SCSI_DESKEW() // asm("NOP"); asm("NOP"); asm("NOP");     // spec 45ns ours ~42ns#define SCSI_CABLE_SKEW() // asm("NOP");                         // spec 10ns ours ~14ns#define SCSI_RESET_HOLD() asm("NOP"); asm("NOP");             // spec 25ns ours ~28ns#define SCSI_DISCONNECTION_DELAY() NOP(15);                   // spec 200ns ours ~210ns/* SCSI phases+=============-===============-==================================-============+|    Signal   |  Phase name   |       Direction of transfer      |  Comment   ||-------------|               |                                  |            || MSG|C/D|I/O |               |                                  |            ||----+---+----+---------------+----------------------------------+------------||  0 | 0 | 0  |  DATA OUT     |       Initiator to target     \  |  Data      ||  0 | 0 | 1  |  DATA IN      |       Initiator from target   /  |  phase     ||  0 | 1 | 0  |  COMMAND      |       Initiator to target        |            ||  0 | 1 | 1  |  STATUS       |       Initiator from target      |            ||  1 | 0 | 0  |  *            |                                  |            ||  1 | 0 | 1  |  *            |                                  |            ||  1 | 1 | 0  |  MESSAGE OUT  |       Initiator to target     \  |  Message   ||  1 | 1 | 1  |  MESSAGE IN   |       Initiator from target   /  |  phase     ||-----------------------------------------------------------------------------|| Key:  0 = False,  1 = True,  * = Reserved for future standardization        |+=============================================================================+ */// SCSI phase change as single write to port B#define SCSIPHASEMASK(MSGACTIVE, CDACTIVE, IOACTIVE) ((BITMASK(vMSG)<<((MSGACTIVE)?16:0)) | (BITMASK(vCD)<<((CDACTIVE)?16:0)) | (BITMASK(vIO)<<((IOACTIVE)?16:0)))#define SCSI_PHASE_DATAOUT SCSIPHASEMASK(inactive, inactive, inactive)#define SCSI_PHASE_DATAIN SCSIPHASEMASK(inactive, inactive, active)#define SCSI_PHASE_COMMAND SCSIPHASEMASK(inactive, active, inactive)#define SCSI_PHASE_STATUS SCSIPHASEMASK(inactive, active, active)#define SCSI_PHASE_MESSAGEOUT SCSIPHASEMASK(active, active, inactive)#define SCSI_PHASE_MESSAGEIN SCSIPHASEMASK(active, active, active)#define SCSI_PHASE_CHANGE(MASK) { PBREG->BSRR = (MASK); }#ifdef XCVR#define TR_TARGET        PA1   // Target Transceiver Control Pin#define TR_DBP           PA2   // Data Pins Transceiver Control Pin#define TR_INITIATOR     PA3   // Initiator Transciever Control Pin#define vTR_TARGET       PA(1) // Target Transceiver Control Pin#define vTR_DBP          PA(2) // Data Pins Transceiver Control Pin#define vTR_INITIATOR    PA(3) // Initiator Transciever Control Pin#define TR_INPUT 1#define TR_OUTPUT 0// Transceiver control definitions#define TRANSCEIVER_IO_SET(VPIN,TR_INPUT) { GPIOREG(VPIN)->BSRR = BITMASK(VPIN) << ((TR_INPUT) ? 16 : 0); }// Turn on the output only for BSY#define SCSI_BSY_ACTIVE()      {  gpio_mode(BSY, GPIO_OUTPUT_PP); SCSI_OUT(vBSY, active) }#define SCSI_TARGET_ACTIVE()   { gpio_mode(REQ, GPIO_OUTPUT_PP); gpio_mode(MSG, GPIO_OUTPUT_PP); gpio_mode(CD, GPIO_OUTPUT_PP); gpio_mode(IO, GPIO_OUTPUT_PP); gpio_mode(BSY, GPIO_OUTPUT_PP);  TRANSCEIVER_IO_SET(vTR_TARGET,TR_OUTPUT);}// BSY,REQ,MSG,CD,IO Turn off output, BSY is the last input#define SCSI_TARGET_INACTIVE() { pinMode(REQ, INPUT); pinMode(MSG, INPUT); pinMode(CD, INPUT); pinMode(IO, INPUT); pinMode(BSY, INPUT); TRANSCEIVER_IO_SET(vTR_TARGET,TR_INPUT); }#define DB_MODE_OUT 1  // push-pull mode#define DB_MODE_IN  4  // floating inputs#else// GPIO mode// IN , FLOAT      : 4// IN , PU/PD      : 8// OUT, PUSH/PULL  : 3// OUT, OD         : 1#define DB_MODE_OUT 3//#define DB_MODE_OUT 7#define DB_MODE_IN  8// Turn on the output only for BSY#define SCSI_BSY_ACTIVE()      { gpio_mode(BSY, GPIO_OUTPUT_OD); SCSI_OUT(vBSY,  active) }// BSY,REQ,MSG,CD,IO Turn on the output (no change required for OD)#define SCSI_TARGET_ACTIVE()   { if (DB_MODE_OUT != 7) gpio_mode(REQ, GPIO_OUTPUT_PP); }// BSY,REQ,MSG,CD,IO Turn off output, BSY is the last input#define SCSI_TARGET_INACTIVE() { if (DB_MODE_OUT == 7) SCSI_OUT(vREQ,inactive) else { if (DB_MODE_IN == 8) gpio_mode(REQ, GPIO_INPUT_PU) else gpio_mode(REQ, GPIO_INPUT_FLOATING)} PBREG->BSRR = 0b000000000000000011101000; SCSI_OUT(vBSY,inactive); gpio_mode(BSY, GPIO_INPUT_PU); }#endif// Put DB and DP in output mode#define SCSI_DB_OUTPUT() { PBREG->CRL=(PBREG->CRL &0xfffffff0)|DB_MODE_OUT; PBREG->CRH = 0x11111111*DB_MODE_OUT; }// Put DB and DP in input mode#define SCSI_DB_INPUT()  { PBREG->CRL=(PBREG->CRL &0xfffffff0)|DB_MODE_IN ; PBREG->CRH = 0x11111111*DB_MODE_IN; }// HDDiamge file#define HDIMG_ID_POS  2                 // Position to embed ID number#define HDIMG_LUN_POS 3                 // Position to embed LUN numbers#define HDIMG_BLK_POS 5                 // Position to embed block size numbers#define MAX_FILE_PATH 32                // Maximum file name length/* *  Data byte to BSRR register setting value and parity table*/// Parity bit generation#define PTY(V)   (1^((V)^((V)>>1)^((V)>>2)^((V)>>3)^((V)>>4)^((V)>>5)^((V)>>6)^((V)>>7))&1)// Data byte to BSRR register setting value conversion table// BSRR[31:24] =  DB[7:0]// BSRR[   16] =  PTY(DB)// BSRR[15: 8] = ~DB[7:0]// BSRR[    0] = ~PTY(DB)// Set DBP, set REQ = inactive#define DBP(D)    ((((((uint32_t)(D)<<8)|PTY(D))*0x00010001)^0x0000ff01)|BITMASK(vREQ))//#define DBP(D)    ((((((uint32_t)(D)<<8)|PTY(D))*0x00010001)^0x0000ff01))//#define DBP8(D)   DBP(D),DBP(D+1),DBP(D+2),DBP(D+3),DBP(D+4),DBP(D+5),DBP(D+6),DBP(D+7)//#define DBP32(D)  DBP8(D),DBP8(D+8),DBP8(D+16),DBP8(D+24)// BSRR register control value that simultaneously performs DB set, DP set, and REQ = H (inactrive)uint32_t db_bsrr[256];// Parity bit acquisition#define PARITY(DB) (db_bsrr[DB]&1)// Macro cleaning//#undef DBP32//#undef DBP8//#undef DBP//#undef PTY// #define GET_CDB6_LBA(x) ((x[2] & 01f) << 16) | (x[3] << 8) | x[4]#define READ_DATA_BUS() (byte)((~(uint32_t)GPIOB->regs->IDR)>>8)enum SCSI_DEVICE_TYPE{  SCSI_DEVICE_HDD,  SCSI_DEVICE_OPTICAL,};#define CDROM_RAW_SECTORSIZE    2352#define CDROM_COMMON_SECTORSIZE 2048struct SCSI_INQUIRY_DATA{  union  {  struct {    // bitfields are in REVERSE order for ARM    // byte 0    byte peripheral_device_type:5;    byte peripheral_qualifier:3;    // byte 1    byte reserved_byte2:7;    byte rmb:1;    // byte 2    byte ansi_version:3;    byte always_zero_byte3:5;    // byte 3    byte response_format:4;    byte reserved_byte4:2;    byte tiop:1;    byte always_zero_byte4:1;    // byte 4    byte additional_length;    // byte 5-6    byte reserved_byte5;    byte reserved_byte6;    // byte 7    byte sync:1;    byte always_zero_byte7_more:4;    byte always_zero_byte7:3;    // byte 8-15    char vendor[8];    // byte 16-31    char product[16];    // byte 32-35    char revision[4];    // byte 36    byte release;    // 37-46    char revision_date[10];  };  // raw bytes  byte raw[64];  };};// HDD imagetypedef __attribute__((aligned(4))) struct _SCSI_DEVICE{	FsFile        *m_file;                 // File object	uint64_t      m_fileSize;             // File size	uint16_t      m_blocksize;            // SCSI BLOCK size  uint8_t       m_type;                 // SCSI device type  uint32_t      m_blockcount;           // blockcount  bool          m_raw;                  // Raw disk  SCSI_INQUIRY_DATA *inquiry_block;      // SCSI information  uint8_t       m_senseKey;               // Sense key  uint16_t      m_additional_sense_code;  // ASC/ASCQ   bool          m_mode2;                  // MODE2 CDROM} SCSI_DEVICE;#endif
 |