Add Marlin firmware. Has initial configuration for CoreXY and 1 servo.
Update CAD file with improved clearances for Pilot G2 cartridge clearances after first print.
This commit is contained in:
678
Marlin Firmware/Marlin/src/sd/Sd2Card.cpp
Normal file
678
Marlin Firmware/Marlin/src/sd/Sd2Card.cpp
Normal file
@ -0,0 +1,678 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Arduino Sd2Card Library
|
||||
* Copyright (c) 2009 by William Greiman
|
||||
* Updated with backports of the latest SdFat library from the same author
|
||||
*
|
||||
* This file is part of the Arduino Sd2Card Library
|
||||
*/
|
||||
|
||||
#include "../inc/MarlinConfig.h"
|
||||
|
||||
#if NEED_SD2CARD_SPI
|
||||
|
||||
/* Enable FAST CRC computations - You can trade speed for FLASH space if
|
||||
* needed by disabling the following define */
|
||||
#define FAST_CRC 1
|
||||
|
||||
#include "Sd2Card.h"
|
||||
|
||||
#include "../MarlinCore.h"
|
||||
|
||||
#if ENABLED(SD_CHECK_AND_RETRY)
|
||||
static bool crcSupported = true;
|
||||
|
||||
#ifdef FAST_CRC
|
||||
static const uint8_t crctab7[] PROGMEM = {
|
||||
0x00,0x09,0x12,0x1B,0x24,0x2D,0x36,0x3F,0x48,0x41,0x5A,0x53,0x6C,0x65,0x7E,0x77,
|
||||
0x19,0x10,0x0B,0x02,0x3D,0x34,0x2F,0x26,0x51,0x58,0x43,0x4A,0x75,0x7C,0x67,0x6E,
|
||||
0x32,0x3B,0x20,0x29,0x16,0x1F,0x04,0x0D,0x7A,0x73,0x68,0x61,0x5E,0x57,0x4C,0x45,
|
||||
0x2B,0x22,0x39,0x30,0x0F,0x06,0x1D,0x14,0x63,0x6A,0x71,0x78,0x47,0x4E,0x55,0x5C,
|
||||
0x64,0x6D,0x76,0x7F,0x40,0x49,0x52,0x5B,0x2C,0x25,0x3E,0x37,0x08,0x01,0x1A,0x13,
|
||||
0x7D,0x74,0x6F,0x66,0x59,0x50,0x4B,0x42,0x35,0x3C,0x27,0x2E,0x11,0x18,0x03,0x0A,
|
||||
0x56,0x5F,0x44,0x4D,0x72,0x7B,0x60,0x69,0x1E,0x17,0x0C,0x05,0x3A,0x33,0x28,0x21,
|
||||
0x4F,0x46,0x5D,0x54,0x6B,0x62,0x79,0x70,0x07,0x0E,0x15,0x1C,0x23,0x2A,0x31,0x38,
|
||||
0x41,0x48,0x53,0x5A,0x65,0x6C,0x77,0x7E,0x09,0x00,0x1B,0x12,0x2D,0x24,0x3F,0x36,
|
||||
0x58,0x51,0x4A,0x43,0x7C,0x75,0x6E,0x67,0x10,0x19,0x02,0x0B,0x34,0x3D,0x26,0x2F,
|
||||
0x73,0x7A,0x61,0x68,0x57,0x5E,0x45,0x4C,0x3B,0x32,0x29,0x20,0x1F,0x16,0x0D,0x04,
|
||||
0x6A,0x63,0x78,0x71,0x4E,0x47,0x5C,0x55,0x22,0x2B,0x30,0x39,0x06,0x0F,0x14,0x1D,
|
||||
0x25,0x2C,0x37,0x3E,0x01,0x08,0x13,0x1A,0x6D,0x64,0x7F,0x76,0x49,0x40,0x5B,0x52,
|
||||
0x3C,0x35,0x2E,0x27,0x18,0x11,0x0A,0x03,0x74,0x7D,0x66,0x6F,0x50,0x59,0x42,0x4B,
|
||||
0x17,0x1E,0x05,0x0C,0x33,0x3A,0x21,0x28,0x5F,0x56,0x4D,0x44,0x7B,0x72,0x69,0x60,
|
||||
0x0E,0x07,0x1C,0x15,0x2A,0x23,0x38,0x31,0x46,0x4F,0x54,0x5D,0x62,0x6B,0x70,0x79
|
||||
};
|
||||
|
||||
static uint8_t CRC7(const uint8_t *data, uint8_t n) {
|
||||
uint8_t crc = 0;
|
||||
while (n > 0) {
|
||||
crc = pgm_read_byte(&crctab7[ (crc << 1) ^ *data++ ]);
|
||||
n--;
|
||||
}
|
||||
return (crc << 1) | 1;
|
||||
}
|
||||
#else
|
||||
static uint8_t CRC7(const uint8_t *data, uint8_t n) {
|
||||
uint8_t crc = 0;
|
||||
LOOP_L_N(i, n) {
|
||||
uint8_t d = data[i];
|
||||
d ^= crc << 1;
|
||||
if (d & 0x80) d ^= 9;
|
||||
crc = d ^ (crc & 0x78) ^ (crc << 4) ^ ((crc >> 3) & 15);
|
||||
crc &= 0x7F;
|
||||
}
|
||||
crc = (crc << 1) ^ (crc << 4) ^ (crc & 0x70) ^ ((crc >> 3) & 0x0F);
|
||||
return crc | 1;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Send command and return error code. Return zero for OK
|
||||
uint8_t DiskIODriver_SPI_SD::cardCommand(const uint8_t cmd, const uint32_t arg) {
|
||||
|
||||
#if ENABLED(SDCARD_COMMANDS_SPLIT)
|
||||
if (cmd != CMD12) chipDeselect();
|
||||
#endif
|
||||
|
||||
// Select card
|
||||
chipSelect();
|
||||
|
||||
// Wait up to 300 ms if busy
|
||||
waitNotBusy(SD_WRITE_TIMEOUT);
|
||||
|
||||
uint8_t *pa = (uint8_t *)(&arg);
|
||||
|
||||
#if ENABLED(SD_CHECK_AND_RETRY)
|
||||
|
||||
// Form message
|
||||
uint8_t d[6] = {(uint8_t) (cmd | 0x40), pa[3], pa[2], pa[1], pa[0] };
|
||||
|
||||
// Add crc
|
||||
d[5] = CRC7(d, 5);
|
||||
|
||||
// Send message
|
||||
LOOP_L_N(k, 6) spiSend(d[k]);
|
||||
|
||||
#else
|
||||
// Send command
|
||||
spiSend(cmd | 0x40);
|
||||
|
||||
// Send argument
|
||||
for (int8_t i = 3; i >= 0; i--) spiSend(pa[i]);
|
||||
|
||||
// Send CRC - correct for CMD0 with arg zero or CMD8 with arg 0X1AA
|
||||
spiSend(cmd == CMD0 ? 0X95 : 0X87);
|
||||
#endif
|
||||
|
||||
// Skip stuff byte for stop read
|
||||
if (cmd == CMD12) spiRec();
|
||||
|
||||
// Wait for response
|
||||
for (uint8_t i = 0; ((status_ = spiRec()) & 0x80) && i != 0xFF; i++) { /* Intentionally left empty */ }
|
||||
return status_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the size of an SD flash memory card.
|
||||
*
|
||||
* \return The number of 512 byte data blocks in the card
|
||||
* or zero if an error occurs.
|
||||
*/
|
||||
uint32_t DiskIODriver_SPI_SD::cardSize() {
|
||||
csd_t csd;
|
||||
if (!readCSD(&csd)) return 0;
|
||||
if (csd.v1.csd_ver == 0) {
|
||||
uint8_t read_bl_len = csd.v1.read_bl_len;
|
||||
uint16_t c_size = (csd.v1.c_size_high << 10)
|
||||
| (csd.v1.c_size_mid << 2) | csd.v1.c_size_low;
|
||||
uint8_t c_size_mult = (csd.v1.c_size_mult_high << 1)
|
||||
| csd.v1.c_size_mult_low;
|
||||
return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7);
|
||||
}
|
||||
else if (csd.v2.csd_ver == 1) {
|
||||
uint32_t c_size = ((uint32_t)csd.v2.c_size_high << 16)
|
||||
| (csd.v2.c_size_mid << 8) | csd.v2.c_size_low;
|
||||
return (c_size + 1) << 10;
|
||||
}
|
||||
else {
|
||||
error(SD_CARD_ERROR_BAD_CSD);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void DiskIODriver_SPI_SD::chipDeselect() {
|
||||
extDigitalWrite(chipSelectPin_, HIGH);
|
||||
spiSend(0xFF); // Ensure MISO goes high impedance
|
||||
}
|
||||
|
||||
void DiskIODriver_SPI_SD::chipSelect() {
|
||||
spiInit(spiRate_);
|
||||
extDigitalWrite(chipSelectPin_, LOW);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase a range of blocks.
|
||||
*
|
||||
* \param[in] firstBlock The address of the first block in the range.
|
||||
* \param[in] lastBlock The address of the last block in the range.
|
||||
*
|
||||
* \note This function requests the SD card to do a flash erase for a
|
||||
* range of blocks. The data on the card after an erase operation is
|
||||
* either 0 or 1, depends on the card vendor. The card must support
|
||||
* single block erase.
|
||||
*
|
||||
* \return true for success, false for failure.
|
||||
*/
|
||||
bool DiskIODriver_SPI_SD::erase(uint32_t firstBlock, uint32_t lastBlock) {
|
||||
if (ENABLED(SDCARD_READONLY)) return false;
|
||||
|
||||
csd_t csd;
|
||||
if (!readCSD(&csd)) goto FAIL;
|
||||
|
||||
// check for single block erase
|
||||
if (!csd.v1.erase_blk_en) {
|
||||
// erase size mask
|
||||
uint8_t m = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low;
|
||||
if ((firstBlock & m) != 0 || ((lastBlock + 1) & m) != 0) {
|
||||
// error card can't erase specified area
|
||||
error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK);
|
||||
goto FAIL;
|
||||
}
|
||||
}
|
||||
if (type_ != SD_CARD_TYPE_SDHC) { firstBlock <<= 9; lastBlock <<= 9; }
|
||||
if (cardCommand(CMD32, firstBlock) || cardCommand(CMD33, lastBlock) || cardCommand(CMD38, 0)) {
|
||||
error(SD_CARD_ERROR_ERASE);
|
||||
goto FAIL;
|
||||
}
|
||||
if (!waitNotBusy(SD_ERASE_TIMEOUT)) {
|
||||
error(SD_CARD_ERROR_ERASE_TIMEOUT);
|
||||
goto FAIL;
|
||||
}
|
||||
chipDeselect();
|
||||
return true;
|
||||
FAIL:
|
||||
chipDeselect();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if card supports single block erase.
|
||||
*
|
||||
* \return true if single block erase is supported.
|
||||
* false if single block erase is not supported.
|
||||
*/
|
||||
bool DiskIODriver_SPI_SD::eraseSingleBlockEnable() {
|
||||
csd_t csd;
|
||||
return readCSD(&csd) ? csd.v1.erase_blk_en : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize an SD flash memory card.
|
||||
*
|
||||
* \param[in] sckRateID SPI clock rate selector. See setSckRate().
|
||||
* \param[in] chipSelectPin SD chip select pin number.
|
||||
*
|
||||
* \return true for success, false for failure.
|
||||
* The reason for failure can be determined by calling errorCode() and errorData().
|
||||
*/
|
||||
bool DiskIODriver_SPI_SD::init(const uint8_t sckRateID, const pin_t chipSelectPin) {
|
||||
#if IS_TEENSY_35_36 || IS_TEENSY_40_41
|
||||
chipSelectPin_ = BUILTIN_SDCARD;
|
||||
const uint8_t ret = SDHC_CardInit();
|
||||
type_ = SDHC_CardGetType();
|
||||
return (ret == 0);
|
||||
#endif
|
||||
|
||||
errorCode_ = type_ = 0;
|
||||
chipSelectPin_ = chipSelectPin;
|
||||
// 16-bit init start time allows over a minute
|
||||
const millis_t init_timeout = millis() + SD_INIT_TIMEOUT;
|
||||
uint32_t arg;
|
||||
|
||||
watchdog_refresh(); // In case init takes too long
|
||||
|
||||
// Set pin modes
|
||||
#if ENABLED(ZONESTAR_12864OLED)
|
||||
if (chipSelectPin_ != DOGLCD_CS) {
|
||||
SET_OUTPUT(DOGLCD_CS);
|
||||
WRITE(DOGLCD_CS, HIGH);
|
||||
}
|
||||
#else
|
||||
extDigitalWrite(chipSelectPin_, HIGH); // For some CPUs pinMode can write the wrong data so init desired data value first
|
||||
pinMode(chipSelectPin_, OUTPUT); // Solution for #8746 by @benlye
|
||||
#endif
|
||||
spiBegin();
|
||||
|
||||
// Set SCK rate for initialization commands
|
||||
spiRate_ = SPI_SD_INIT_RATE;
|
||||
spiInit(spiRate_);
|
||||
|
||||
// Must supply min of 74 clock cycles with CS high.
|
||||
LOOP_L_N(i, 10) spiSend(0xFF);
|
||||
|
||||
watchdog_refresh(); // In case init takes too long
|
||||
|
||||
// Command to go idle in SPI mode
|
||||
while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) {
|
||||
if (ELAPSED(millis(), init_timeout)) {
|
||||
error(SD_CARD_ERROR_CMD0);
|
||||
goto FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLED(SD_CHECK_AND_RETRY)
|
||||
crcSupported = (cardCommand(CMD59, 1) == R1_IDLE_STATE);
|
||||
#endif
|
||||
|
||||
watchdog_refresh(); // In case init takes too long
|
||||
|
||||
// check SD version
|
||||
for (;;) {
|
||||
if (cardCommand(CMD8, 0x1AA) == (R1_ILLEGAL_COMMAND | R1_IDLE_STATE)) {
|
||||
type(SD_CARD_TYPE_SD1);
|
||||
break;
|
||||
}
|
||||
|
||||
// Get the last byte of r7 response
|
||||
LOOP_L_N(i, 4) status_ = spiRec();
|
||||
if (status_ == 0xAA) {
|
||||
type(SD_CARD_TYPE_SD2);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ELAPSED(millis(), init_timeout)) {
|
||||
error(SD_CARD_ERROR_CMD8);
|
||||
goto FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
watchdog_refresh(); // In case init takes too long
|
||||
|
||||
// Initialize card and send host supports SDHC if SD2
|
||||
arg = type() == SD_CARD_TYPE_SD2 ? 0x40000000 : 0;
|
||||
while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) {
|
||||
// Check for timeout
|
||||
if (ELAPSED(millis(), init_timeout)) {
|
||||
error(SD_CARD_ERROR_ACMD41);
|
||||
goto FAIL;
|
||||
}
|
||||
}
|
||||
// If SD2 read OCR register to check for SDHC card
|
||||
if (type() == SD_CARD_TYPE_SD2) {
|
||||
if (cardCommand(CMD58, 0)) {
|
||||
error(SD_CARD_ERROR_CMD58);
|
||||
goto FAIL;
|
||||
}
|
||||
if ((spiRec() & 0xC0) == 0xC0) type(SD_CARD_TYPE_SDHC);
|
||||
// Discard rest of ocr - contains allowed voltage range
|
||||
LOOP_L_N(i, 3) spiRec();
|
||||
}
|
||||
chipDeselect();
|
||||
|
||||
ready = true;
|
||||
return setSckRate(sckRateID);
|
||||
|
||||
FAIL:
|
||||
chipDeselect();
|
||||
ready = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 512 byte block from an SD card.
|
||||
*
|
||||
* \param[in] blockNumber Logical block to be read.
|
||||
* \param[out] dst Pointer to the location that will receive the data.
|
||||
* \return true for success, false for failure.
|
||||
*/
|
||||
bool DiskIODriver_SPI_SD::readBlock(uint32_t blockNumber, uint8_t *dst) {
|
||||
#if IS_TEENSY_35_36 || IS_TEENSY_40_41
|
||||
return 0 == SDHC_CardReadBlock(dst, blockNumber);
|
||||
#endif
|
||||
|
||||
if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; // Use address if not SDHC card
|
||||
|
||||
#if ENABLED(SD_CHECK_AND_RETRY)
|
||||
uint8_t retryCnt = 3;
|
||||
for (;;) {
|
||||
if (cardCommand(CMD17, blockNumber))
|
||||
error(SD_CARD_ERROR_CMD17);
|
||||
else if (readData(dst, 512))
|
||||
return true;
|
||||
|
||||
chipDeselect();
|
||||
if (!--retryCnt) break;
|
||||
|
||||
cardCommand(CMD12, 0); // Try sending a stop command, ignore the result.
|
||||
errorCode_ = 0;
|
||||
}
|
||||
return false;
|
||||
#else
|
||||
if (cardCommand(CMD17, blockNumber)) {
|
||||
error(SD_CARD_ERROR_CMD17);
|
||||
chipDeselect();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return readData(dst, 512);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Read one data block in a multiple block read sequence
|
||||
*
|
||||
* \param[in] dst Pointer to the location for the data to be read.
|
||||
*
|
||||
* \return true for success, false for failure.
|
||||
*/
|
||||
bool DiskIODriver_SPI_SD::readData(uint8_t *dst) {
|
||||
chipSelect();
|
||||
return readData(dst, 512);
|
||||
}
|
||||
|
||||
#if ENABLED(SD_CHECK_AND_RETRY)
|
||||
#ifdef FAST_CRC
|
||||
static const uint16_t crctab16[] PROGMEM = {
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
|
||||
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
|
||||
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
|
||||
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
|
||||
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
|
||||
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
|
||||
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
|
||||
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
|
||||
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
|
||||
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
|
||||
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
|
||||
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
|
||||
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
|
||||
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
|
||||
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
|
||||
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
|
||||
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
|
||||
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
|
||||
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
|
||||
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
|
||||
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
|
||||
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
|
||||
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
|
||||
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
|
||||
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
|
||||
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
|
||||
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
|
||||
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
|
||||
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
|
||||
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
|
||||
};
|
||||
// faster CRC-CCITT
|
||||
// uses the x^16,x^12,x^5,x^1 polynomial.
|
||||
static uint16_t CRC_CCITT(const uint8_t *data, size_t n) {
|
||||
uint16_t crc = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
crc = pgm_read_word(&crctab16[(crc >> 8 ^ data[i]) & 0xFF]) ^ (crc << 8);
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
#else
|
||||
// slower CRC-CCITT
|
||||
// uses the x^16,x^12,x^5,x^1 polynomial.
|
||||
static uint16_t CRC_CCITT(const uint8_t *data, size_t n) {
|
||||
uint16_t crc = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
crc = (uint8_t)(crc >> 8) | (crc << 8);
|
||||
crc ^= data[i];
|
||||
crc ^= (uint8_t)(crc & 0xFF) >> 4;
|
||||
crc ^= crc << 12;
|
||||
crc ^= (crc & 0xFF) << 5;
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
#endif
|
||||
#endif // SD_CHECK_AND_RETRY
|
||||
|
||||
bool DiskIODriver_SPI_SD::readData(uint8_t *dst, const uint16_t count) {
|
||||
bool success = false;
|
||||
|
||||
const millis_t read_timeout = millis() + SD_READ_TIMEOUT;
|
||||
while ((status_ = spiRec()) == 0xFF) { // Wait for start block token
|
||||
if (ELAPSED(millis(), read_timeout)) {
|
||||
error(SD_CARD_ERROR_READ_TIMEOUT);
|
||||
goto FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
if (status_ == DATA_START_BLOCK) {
|
||||
spiRead(dst, count); // Transfer data
|
||||
|
||||
const uint16_t recvCrc = (spiRec() << 8) | spiRec();
|
||||
#if ENABLED(SD_CHECK_AND_RETRY)
|
||||
success = !crcSupported || recvCrc == CRC_CCITT(dst, count);
|
||||
if (!success) error(SD_CARD_ERROR_READ_CRC);
|
||||
#else
|
||||
success = true;
|
||||
UNUSED(recvCrc);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
error(SD_CARD_ERROR_READ);
|
||||
|
||||
FAIL:
|
||||
chipDeselect();
|
||||
return success;
|
||||
}
|
||||
|
||||
/** read CID or CSR register */
|
||||
bool DiskIODriver_SPI_SD::readRegister(const uint8_t cmd, void *buf) {
|
||||
uint8_t *dst = reinterpret_cast<uint8_t*>(buf);
|
||||
if (cardCommand(cmd, 0)) {
|
||||
error(SD_CARD_ERROR_READ_REG);
|
||||
chipDeselect();
|
||||
return false;
|
||||
}
|
||||
return readData(dst, 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a read multiple blocks sequence.
|
||||
*
|
||||
* \param[in] blockNumber Address of first block in sequence.
|
||||
*
|
||||
* \note This function is used with readData() and readStop() for optimized
|
||||
* multiple block reads. SPI chipSelect must be low for the entire sequence.
|
||||
*
|
||||
* \return true for success, false for failure.
|
||||
*/
|
||||
bool DiskIODriver_SPI_SD::readStart(uint32_t blockNumber) {
|
||||
if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9;
|
||||
|
||||
const bool success = !cardCommand(CMD18, blockNumber);
|
||||
if (!success) error(SD_CARD_ERROR_CMD18);
|
||||
chipDeselect();
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* End a read multiple blocks sequence.
|
||||
*
|
||||
* \return true for success, false for failure.
|
||||
*/
|
||||
bool DiskIODriver_SPI_SD::readStop() {
|
||||
chipSelect();
|
||||
const bool success = !cardCommand(CMD12, 0);
|
||||
if (!success) error(SD_CARD_ERROR_CMD12);
|
||||
chipDeselect();
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the SPI clock rate.
|
||||
*
|
||||
* \param[in] sckRateID A value in the range [0, 6].
|
||||
*
|
||||
* The SPI clock will be set to F_CPU/pow(2, 1 + sckRateID). The maximum
|
||||
* SPI rate is F_CPU/2 for \a sckRateID = 0 and the minimum rate is F_CPU/128
|
||||
* for \a scsRateID = 6.
|
||||
*
|
||||
* \return The value one, true, is returned for success and the value zero,
|
||||
* false, is returned for an invalid value of \a sckRateID.
|
||||
*/
|
||||
bool DiskIODriver_SPI_SD::setSckRate(const uint8_t sckRateID) {
|
||||
const bool success = (sckRateID <= 6);
|
||||
if (success) spiRate_ = sckRateID; else error(SD_CARD_ERROR_SCK_RATE);
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for card to become not-busy
|
||||
* \param[in] timeout_ms Timeout to abort.
|
||||
* \return true for success, false for timeout.
|
||||
*/
|
||||
bool DiskIODriver_SPI_SD::waitNotBusy(const millis_t timeout_ms) {
|
||||
const millis_t wait_timeout = millis() + timeout_ms;
|
||||
while (spiRec() != 0xFF) if (ELAPSED(millis(), wait_timeout)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void DiskIODriver_SPI_SD::error(const uint8_t code) { errorCode_ = code; }
|
||||
|
||||
/**
|
||||
* Write a 512 byte block to an SD card.
|
||||
*
|
||||
* \param[in] blockNumber Logical block to be written.
|
||||
* \param[in] src Pointer to the location of the data to be written.
|
||||
* \return true for success, false for failure.
|
||||
*/
|
||||
bool DiskIODriver_SPI_SD::writeBlock(uint32_t blockNumber, const uint8_t *src) {
|
||||
if (ENABLED(SDCARD_READONLY)) return false;
|
||||
|
||||
#if IS_TEENSY_35_36 || IS_TEENSY_40_41
|
||||
return 0 == SDHC_CardWriteBlock(src, blockNumber);
|
||||
#endif
|
||||
|
||||
bool success = false;
|
||||
if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; // Use address if not SDHC card
|
||||
if (!cardCommand(CMD24, blockNumber)) {
|
||||
if (writeData(DATA_START_BLOCK, src)) {
|
||||
if (waitNotBusy(SD_WRITE_TIMEOUT)) { // Wait for flashing to complete
|
||||
success = !(cardCommand(CMD13, 0) || spiRec()); // Response is r2 so get and check two bytes for nonzero
|
||||
if (!success) error(SD_CARD_ERROR_WRITE_PROGRAMMING);
|
||||
}
|
||||
else
|
||||
error(SD_CARD_ERROR_WRITE_TIMEOUT);
|
||||
}
|
||||
}
|
||||
else
|
||||
error(SD_CARD_ERROR_CMD24);
|
||||
|
||||
chipDeselect();
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write one data block in a multiple block write sequence
|
||||
* \param[in] src Pointer to the location of the data to be written.
|
||||
* \return true for success, false for failure.
|
||||
*/
|
||||
bool DiskIODriver_SPI_SD::writeData(const uint8_t *src) {
|
||||
if (ENABLED(SDCARD_READONLY)) return false;
|
||||
|
||||
bool success = true;
|
||||
chipSelect();
|
||||
// Wait for previous write to finish
|
||||
if (!waitNotBusy(SD_WRITE_TIMEOUT) || !writeData(WRITE_MULTIPLE_TOKEN, src)) {
|
||||
error(SD_CARD_ERROR_WRITE_MULTIPLE);
|
||||
success = false;
|
||||
}
|
||||
chipDeselect();
|
||||
return success;
|
||||
}
|
||||
|
||||
// Send one block of data for write block or write multiple blocks
|
||||
bool DiskIODriver_SPI_SD::writeData(const uint8_t token, const uint8_t *src) {
|
||||
if (ENABLED(SDCARD_READONLY)) return false;
|
||||
|
||||
const uint16_t crc = TERN(SD_CHECK_AND_RETRY, CRC_CCITT(src, 512), 0xFFFF);
|
||||
spiSendBlock(token, src);
|
||||
spiSend(crc >> 8);
|
||||
spiSend(crc & 0xFF);
|
||||
|
||||
status_ = spiRec();
|
||||
if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) {
|
||||
error(SD_CARD_ERROR_WRITE);
|
||||
chipDeselect();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a write multiple blocks sequence.
|
||||
*
|
||||
* \param[in] blockNumber Address of first block in sequence.
|
||||
* \param[in] eraseCount The number of blocks to be pre-erased.
|
||||
*
|
||||
* \note This function is used with writeData() and writeStop()
|
||||
* for optimized multiple block writes.
|
||||
*
|
||||
* \return true for success, false for failure.
|
||||
*/
|
||||
bool DiskIODriver_SPI_SD::writeStart(uint32_t blockNumber, const uint32_t eraseCount) {
|
||||
if (ENABLED(SDCARD_READONLY)) return false;
|
||||
|
||||
bool success = false;
|
||||
if (!cardAcmd(ACMD23, eraseCount)) { // Send pre-erase count
|
||||
if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; // Use address if not SDHC card
|
||||
success = !cardCommand(CMD25, blockNumber);
|
||||
if (!success) error(SD_CARD_ERROR_CMD25);
|
||||
}
|
||||
else
|
||||
error(SD_CARD_ERROR_ACMD23);
|
||||
|
||||
chipDeselect();
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* End a write multiple blocks sequence.
|
||||
*
|
||||
* \return true for success, false for failure.
|
||||
*/
|
||||
bool DiskIODriver_SPI_SD::writeStop() {
|
||||
if (ENABLED(SDCARD_READONLY)) return false;
|
||||
|
||||
bool success = false;
|
||||
chipSelect();
|
||||
if (waitNotBusy(SD_WRITE_TIMEOUT)) {
|
||||
spiSend(STOP_TRAN_TOKEN);
|
||||
success = waitNotBusy(SD_WRITE_TIMEOUT);
|
||||
}
|
||||
else
|
||||
error(SD_CARD_ERROR_STOP_TRAN);
|
||||
|
||||
chipDeselect();
|
||||
return success;
|
||||
}
|
||||
|
||||
#endif // NEED_SD2CARD_SPI
|
197
Marlin Firmware/Marlin/src/sd/Sd2Card.h
Normal file
197
Marlin Firmware/Marlin/src/sd/Sd2Card.h
Normal file
@ -0,0 +1,197 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief Sd2Card class for V2 SD/SDHC cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* Arduino Sd2Card Library
|
||||
* Copyright (c) 2009 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino Sd2Card Library
|
||||
*/
|
||||
|
||||
#include "SdFatConfig.h"
|
||||
#include "SdInfo.h"
|
||||
#include "disk_io_driver.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
uint16_t const SD_INIT_TIMEOUT = 2000, // (ms) Init timeout
|
||||
SD_ERASE_TIMEOUT = 10000, // (ms) Erase timeout
|
||||
SD_READ_TIMEOUT = 300, // (ms) Read timeout
|
||||
SD_WRITE_TIMEOUT = 600; // (ms) Write timeout
|
||||
|
||||
// SD card errors
|
||||
typedef enum : uint8_t {
|
||||
SD_CARD_ERROR_CMD0 = 0x01, // Timeout error for command CMD0 (initialize card in SPI mode)
|
||||
SD_CARD_ERROR_CMD8 = 0x02, // CMD8 was not accepted - not a valid SD card
|
||||
SD_CARD_ERROR_CMD12 = 0x03, // Card returned an error response for CMD12 (write stop)
|
||||
SD_CARD_ERROR_CMD17 = 0x04, // Card returned an error response for CMD17 (read block)
|
||||
SD_CARD_ERROR_CMD18 = 0x05, // Card returned an error response for CMD18 (read multiple block)
|
||||
SD_CARD_ERROR_CMD24 = 0x06, // Card returned an error response for CMD24 (write block)
|
||||
SD_CARD_ERROR_CMD25 = 0x07, // WRITE_MULTIPLE_BLOCKS command failed
|
||||
SD_CARD_ERROR_CMD58 = 0x08, // Card returned an error response for CMD58 (read OCR)
|
||||
SD_CARD_ERROR_ACMD23 = 0x09, // SET_WR_BLK_ERASE_COUNT failed
|
||||
SD_CARD_ERROR_ACMD41 = 0x0A, // ACMD41 initialization process timeout
|
||||
SD_CARD_ERROR_BAD_CSD = 0x0B, // Card returned a bad CSR version field
|
||||
SD_CARD_ERROR_ERASE = 0x0C, // Erase block group command failed
|
||||
SD_CARD_ERROR_ERASE_SINGLE_BLOCK = 0x0D, // Card not capable of single block erase
|
||||
SD_CARD_ERROR_ERASE_TIMEOUT = 0x0E, // Erase sequence timed out
|
||||
SD_CARD_ERROR_READ = 0x0F, // Card returned an error token instead of read data
|
||||
SD_CARD_ERROR_READ_REG = 0x10, // Read CID or CSD failed
|
||||
SD_CARD_ERROR_READ_TIMEOUT = 0x11, // Timeout while waiting for start of read data
|
||||
SD_CARD_ERROR_STOP_TRAN = 0x12, // Card did not accept STOP_TRAN_TOKEN
|
||||
SD_CARD_ERROR_WRITE = 0x13, // Card returned an error token as a response to a write operation
|
||||
SD_CARD_ERROR_WRITE_BLOCK_ZERO = 0x14, // REMOVE - not used ... attempt to write protected block zero
|
||||
SD_CARD_ERROR_WRITE_MULTIPLE = 0x15, // Card did not go ready for a multiple block write
|
||||
SD_CARD_ERROR_WRITE_PROGRAMMING = 0x16, // Card returned an error to a CMD13 status check after a write
|
||||
SD_CARD_ERROR_WRITE_TIMEOUT = 0x17, // Timeout occurred during write programming
|
||||
SD_CARD_ERROR_SCK_RATE = 0x18, // Incorrect rate selected
|
||||
SD_CARD_ERROR_INIT_NOT_CALLED = 0x19, // Init() not called
|
||||
// 0x1A is unused now, it was: card returned an error for CMD59 (CRC_ON_OFF)
|
||||
SD_CARD_ERROR_READ_CRC = 0x1B // Invalid read CRC
|
||||
} sd_error_code_t;
|
||||
|
||||
// card types
|
||||
uint8_t const SD_CARD_TYPE_SD1 = 1, // Standard capacity V1 SD card
|
||||
SD_CARD_TYPE_SD2 = 2, // Standard capacity V2 SD card
|
||||
SD_CARD_TYPE_SDHC = 3; // High Capacity SD card
|
||||
|
||||
/**
|
||||
* Define SOFTWARE_SPI to use bit-bang SPI
|
||||
*/
|
||||
#if EITHER(MEGA_SOFT_SPI, USE_SOFTWARE_SPI)
|
||||
#define SOFTWARE_SPI
|
||||
#endif
|
||||
|
||||
#if IS_TEENSY_35_36 || IS_TEENSY_40_41
|
||||
#include "NXP_SDHC.h"
|
||||
#define BUILTIN_SDCARD 254
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \class Sd2Card
|
||||
* \brief Raw access to SD and SDHC flash memory cards.
|
||||
*/
|
||||
class DiskIODriver_SPI_SD : public DiskIODriver {
|
||||
public:
|
||||
|
||||
DiskIODriver_SPI_SD() : errorCode_(SD_CARD_ERROR_INIT_NOT_CALLED), type_(0) {}
|
||||
|
||||
bool erase(uint32_t firstBlock, uint32_t lastBlock);
|
||||
bool eraseSingleBlockEnable();
|
||||
|
||||
/**
|
||||
* Set SD error code.
|
||||
* \param[in] code value for error code.
|
||||
*/
|
||||
void error(const uint8_t code);
|
||||
|
||||
/**
|
||||
* \return error code for last error. See Sd2Card.h for a list of error codes.
|
||||
*/
|
||||
inline int errorCode() const { return errorCode_; }
|
||||
|
||||
/** \return error data for last error. */
|
||||
inline int errorData() const { return status_; }
|
||||
|
||||
/**
|
||||
* Initialize an SD flash memory card with default clock rate and chip
|
||||
* select pin. See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin).
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool init(const uint8_t sckRateID, const pin_t chipSelectPin) override;
|
||||
|
||||
bool setSckRate(const uint8_t sckRateID);
|
||||
|
||||
/**
|
||||
* Return the card type: SD V1, SD V2 or SDHC
|
||||
* \return 0 - SD V1, 1 - SD V2, or 3 - SDHC.
|
||||
*/
|
||||
int type() const { return type_; }
|
||||
|
||||
/**
|
||||
* Read a card's CID register. The CID contains card identification
|
||||
* information such as Manufacturer ID, Product name, Product serial
|
||||
* number and Manufacturing date.
|
||||
*
|
||||
* \param[out] cid pointer to area for returned data.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool readCID(cid_t *cid) { return readRegister(CMD10, cid); }
|
||||
|
||||
/**
|
||||
* Read a card's CSD register. The CSD contains Card-Specific Data that
|
||||
* provides information regarding access to the card's contents.
|
||||
*
|
||||
* \param[out] csd pointer to area for returned data.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
inline bool readCSD(csd_t *csd) override { return readRegister(CMD9, csd); }
|
||||
|
||||
bool readData(uint8_t *dst) override;
|
||||
bool readStart(uint32_t blockNumber) override;
|
||||
bool readStop() override;
|
||||
|
||||
bool writeData(const uint8_t *src) override;
|
||||
bool writeStart(const uint32_t blockNumber, const uint32_t eraseCount) override;
|
||||
bool writeStop() override;
|
||||
|
||||
bool readBlock(uint32_t block, uint8_t *dst) override;
|
||||
bool writeBlock(uint32_t blockNumber, const uint8_t *src) override;
|
||||
|
||||
uint32_t cardSize() override;
|
||||
|
||||
bool isReady() override { return ready; };
|
||||
|
||||
void idle() override {}
|
||||
|
||||
private:
|
||||
bool ready = false;
|
||||
uint8_t chipSelectPin_,
|
||||
errorCode_,
|
||||
spiRate_,
|
||||
status_,
|
||||
type_;
|
||||
|
||||
// private functions
|
||||
inline uint8_t cardAcmd(const uint8_t cmd, const uint32_t arg) {
|
||||
cardCommand(CMD55, 0);
|
||||
return cardCommand(cmd, arg);
|
||||
}
|
||||
uint8_t cardCommand(const uint8_t cmd, const uint32_t arg);
|
||||
|
||||
bool readData(uint8_t *dst, const uint16_t count);
|
||||
bool readRegister(const uint8_t cmd, void *buf);
|
||||
void chipDeselect();
|
||||
void chipSelect();
|
||||
inline void type(const uint8_t value) { type_ = value; }
|
||||
bool waitNotBusy(const millis_t timeout_ms);
|
||||
bool writeData(const uint8_t token, const uint8_t *src);
|
||||
};
|
55
Marlin Firmware/Marlin/src/sd/Sd2Card_sdio.h
Normal file
55
Marlin Firmware/Marlin/src/sd/Sd2Card_sdio.h
Normal file
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../inc/MarlinConfig.h"
|
||||
|
||||
#include "SdInfo.h"
|
||||
#include "disk_io_driver.h"
|
||||
|
||||
bool SDIO_Init();
|
||||
bool SDIO_ReadBlock(uint32_t block, uint8_t *dst);
|
||||
bool SDIO_WriteBlock(uint32_t block, const uint8_t *src);
|
||||
|
||||
class DiskIODriver_SDIO : public DiskIODriver {
|
||||
public:
|
||||
bool init(const uint8_t sckRateID=0, const pin_t chipSelectPin=0) override { return SDIO_Init(); }
|
||||
|
||||
bool readCSD(csd_t *csd) override { return false; }
|
||||
|
||||
bool readStart(const uint32_t block) override { return false; }
|
||||
bool readData(uint8_t *dst) override { return false; }
|
||||
bool readStop() override { return false; }
|
||||
|
||||
bool writeStart(const uint32_t block, const uint32_t) override { return false; }
|
||||
bool writeData(const uint8_t *src) override { return false; }
|
||||
bool writeStop() override { return false; }
|
||||
|
||||
bool readBlock(uint32_t block, uint8_t *dst) override { return SDIO_ReadBlock(block, dst); }
|
||||
bool writeBlock(uint32_t block, const uint8_t *src) override { return SDIO_WriteBlock(block, src); }
|
||||
|
||||
uint32_t cardSize() override { return 0; }
|
||||
|
||||
bool isReady() override { return true; }
|
||||
|
||||
void idle() override {}
|
||||
};
|
1830
Marlin Firmware/Marlin/src/sd/SdBaseFile.cpp
Normal file
1830
Marlin Firmware/Marlin/src/sd/SdBaseFile.cpp
Normal file
File diff suppressed because it is too large
Load Diff
384
Marlin Firmware/Marlin/src/sd/SdBaseFile.h
Normal file
384
Marlin Firmware/Marlin/src/sd/SdBaseFile.h
Normal file
@ -0,0 +1,384 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* sd/SdBaseFile.h
|
||||
*
|
||||
* Arduino SdFat Library
|
||||
* Copyright (c) 2009 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino Sd2Card Library
|
||||
*/
|
||||
|
||||
#include "SdFatConfig.h"
|
||||
#include "SdVolume.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* \struct filepos_t
|
||||
* \brief internal type for istream
|
||||
* do not use in user apps
|
||||
*/
|
||||
struct filepos_t {
|
||||
uint32_t position; // stream byte position
|
||||
uint32_t cluster; // cluster of position
|
||||
filepos_t() : position(0), cluster(0) {}
|
||||
};
|
||||
|
||||
// use the gnu style oflag in open()
|
||||
uint8_t const O_READ = 0x01, // open() oflag for reading
|
||||
O_RDONLY = O_READ, // open() oflag - same as O_IN
|
||||
O_WRITE = 0x02, // open() oflag for write
|
||||
O_WRONLY = O_WRITE, // open() oflag - same as O_WRITE
|
||||
O_RDWR = (O_READ | O_WRITE), // open() oflag for reading and writing
|
||||
O_ACCMODE = (O_READ | O_WRITE), // open() oflag mask for access modes
|
||||
O_APPEND = 0x04, // The file offset shall be set to the end of the file prior to each write.
|
||||
O_SYNC = 0x08, // Synchronous writes - call sync() after each write
|
||||
O_TRUNC = 0x10, // Truncate the file to zero length
|
||||
O_AT_END = 0x20, // Set the initial position at the end of the file
|
||||
O_CREAT = 0x40, // Create the file if nonexistent
|
||||
O_EXCL = 0x80; // If O_CREAT and O_EXCL are set, open() shall fail if the file exists
|
||||
|
||||
// SdBaseFile class static and const definitions
|
||||
|
||||
// flags for ls()
|
||||
uint8_t const LS_DATE = 1, // ls() flag to print modify date
|
||||
LS_SIZE = 2, // ls() flag to print file size
|
||||
LS_R = 4; // ls() flag for recursive list of subdirectories
|
||||
|
||||
|
||||
// flags for timestamp
|
||||
uint8_t const T_ACCESS = 1, // Set the file's last access date
|
||||
T_CREATE = 2, // Set the file's creation date and time
|
||||
T_WRITE = 4; // Set the file's write date and time
|
||||
|
||||
// values for type_
|
||||
uint8_t const FAT_FILE_TYPE_CLOSED = 0, // This file has not been opened.
|
||||
FAT_FILE_TYPE_NORMAL = 1, // A normal file
|
||||
FAT_FILE_TYPE_ROOT_FIXED = 2, // A FAT12 or FAT16 root directory
|
||||
FAT_FILE_TYPE_ROOT32 = 3, // A FAT32 root directory
|
||||
FAT_FILE_TYPE_SUBDIR = 4, // A subdirectory file
|
||||
FAT_FILE_TYPE_MIN_DIR = FAT_FILE_TYPE_ROOT_FIXED; // Test value for directory type
|
||||
|
||||
/**
|
||||
* date field for FAT directory entry
|
||||
* \param[in] year [1980,2107]
|
||||
* \param[in] month [1,12]
|
||||
* \param[in] day [1,31]
|
||||
*
|
||||
* \return Packed date for dir_t entry.
|
||||
*/
|
||||
static inline uint16_t FAT_DATE(uint16_t year, uint8_t month, uint8_t day) { return (year - 1980) << 9 | month << 5 | day; }
|
||||
|
||||
/**
|
||||
* year part of FAT directory date field
|
||||
* \param[in] fatDate Date in packed dir format.
|
||||
*
|
||||
* \return Extracted year [1980,2107]
|
||||
*/
|
||||
static inline uint16_t FAT_YEAR(uint16_t fatDate) { return 1980 + (fatDate >> 9); }
|
||||
|
||||
/**
|
||||
* month part of FAT directory date field
|
||||
* \param[in] fatDate Date in packed dir format.
|
||||
*
|
||||
* \return Extracted month [1,12]
|
||||
*/
|
||||
static inline uint8_t FAT_MONTH(uint16_t fatDate) { return (fatDate >> 5) & 0xF; }
|
||||
|
||||
/**
|
||||
* day part of FAT directory date field
|
||||
* \param[in] fatDate Date in packed dir format.
|
||||
*
|
||||
* \return Extracted day [1,31]
|
||||
*/
|
||||
static inline uint8_t FAT_DAY(uint16_t fatDate) { return fatDate & 0x1F; }
|
||||
|
||||
/**
|
||||
* time field for FAT directory entry
|
||||
* \param[in] hour [0,23]
|
||||
* \param[in] minute [0,59]
|
||||
* \param[in] second [0,59]
|
||||
*
|
||||
* \return Packed time for dir_t entry.
|
||||
*/
|
||||
static inline uint16_t FAT_TIME(uint8_t hour, uint8_t minute, uint8_t second) { return hour << 11 | minute << 5 | second >> 1; }
|
||||
|
||||
/**
|
||||
* hour part of FAT directory time field
|
||||
* \param[in] fatTime Time in packed dir format.
|
||||
*
|
||||
* \return Extracted hour [0,23]
|
||||
*/
|
||||
static inline uint8_t FAT_HOUR(uint16_t fatTime) { return fatTime >> 11; }
|
||||
|
||||
/**
|
||||
* minute part of FAT directory time field
|
||||
* \param[in] fatTime Time in packed dir format.
|
||||
*
|
||||
* \return Extracted minute [0,59]
|
||||
*/
|
||||
static inline uint8_t FAT_MINUTE(uint16_t fatTime) { return (fatTime >> 5) & 0x3F; }
|
||||
|
||||
/**
|
||||
* second part of FAT directory time field
|
||||
* Note second/2 is stored in packed time.
|
||||
*
|
||||
* \param[in] fatTime Time in packed dir format.
|
||||
*
|
||||
* \return Extracted second [0,58]
|
||||
*/
|
||||
static inline uint8_t FAT_SECOND(uint16_t fatTime) { return 2 * (fatTime & 0x1F); }
|
||||
|
||||
// Default date for file timestamps is 1 Jan 2000
|
||||
uint16_t const FAT_DEFAULT_DATE = ((2000 - 1980) << 9) | (1 << 5) | 1;
|
||||
// Default time for file timestamp is 1 am
|
||||
uint16_t const FAT_DEFAULT_TIME = (1 << 11);
|
||||
|
||||
/**
|
||||
* \class SdBaseFile
|
||||
* \brief Base class for SdFile with Print and C++ streams.
|
||||
*/
|
||||
class SdBaseFile {
|
||||
public:
|
||||
SdBaseFile() : writeError(false), type_(FAT_FILE_TYPE_CLOSED) {}
|
||||
SdBaseFile(const char *path, uint8_t oflag);
|
||||
~SdBaseFile() { if (isOpen()) close(); }
|
||||
|
||||
/**
|
||||
* writeError is set to true if an error occurs during a write().
|
||||
* Set writeError to false before calling print() and/or write() and check
|
||||
* for true after calls to print() and/or write().
|
||||
*/
|
||||
bool writeError;
|
||||
|
||||
// helpers for stream classes
|
||||
|
||||
/**
|
||||
* get position for streams
|
||||
* \param[out] pos struct to receive position
|
||||
*/
|
||||
void getpos(filepos_t *pos);
|
||||
|
||||
/**
|
||||
* set position for streams
|
||||
* \param[out] pos struct with value for new position
|
||||
*/
|
||||
void setpos(filepos_t *pos);
|
||||
|
||||
bool close();
|
||||
bool contiguousRange(uint32_t *bgnBlock, uint32_t *endBlock);
|
||||
bool createContiguous(SdBaseFile *dirFile,
|
||||
const char *path, uint32_t size);
|
||||
/**
|
||||
* \return The current cluster number for a file or directory.
|
||||
*/
|
||||
uint32_t curCluster() const { return curCluster_; }
|
||||
|
||||
/**
|
||||
* \return The current position for a file or directory.
|
||||
*/
|
||||
uint32_t curPosition() const { return curPosition_; }
|
||||
|
||||
/**
|
||||
* \return Current working directory
|
||||
*/
|
||||
static SdBaseFile *cwd() { return cwd_; }
|
||||
|
||||
/**
|
||||
* Set the date/time callback function
|
||||
*
|
||||
* \param[in] dateTime The user's call back function. The callback
|
||||
* function is of the form:
|
||||
*
|
||||
* \code
|
||||
* void dateTime(uint16_t *date, uint16_t *time) {
|
||||
* uint16_t year;
|
||||
* uint8_t month, day, hour, minute, second;
|
||||
*
|
||||
* // User gets date and time from GPS or real-time clock here
|
||||
*
|
||||
* // return date using FAT_DATE macro to format fields
|
||||
* *date = FAT_DATE(year, month, day);
|
||||
*
|
||||
* // return time using FAT_TIME macro to format fields
|
||||
* *time = FAT_TIME(hour, minute, second);
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* Sets the function that is called when a file is created or when
|
||||
* a file's directory entry is modified by sync(). All timestamps,
|
||||
* access, creation, and modify, are set when a file is created.
|
||||
* sync() maintains the last access date and last modify date/time.
|
||||
*
|
||||
* See the timestamp() function.
|
||||
*/
|
||||
static void dateTimeCallback(
|
||||
void (*dateTime)(uint16_t *date, uint16_t *time)) {
|
||||
dateTime_ = dateTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel the date/time callback function.
|
||||
*/
|
||||
static void dateTimeCallbackCancel() { dateTime_ = 0; }
|
||||
bool dirEntry(dir_t *dir);
|
||||
static void dirName(const dir_t& dir, char *name);
|
||||
bool exists(const char *name);
|
||||
int16_t fgets(char *str, int16_t num, char *delim = 0);
|
||||
|
||||
/**
|
||||
* \return The total number of bytes in a file or directory.
|
||||
*/
|
||||
uint32_t fileSize() const { return fileSize_; }
|
||||
|
||||
/**
|
||||
* \return The first cluster number for a file or directory.
|
||||
*/
|
||||
uint32_t firstCluster() const { return firstCluster_; }
|
||||
|
||||
/**
|
||||
* \return True if this is a directory else false.
|
||||
*/
|
||||
bool isDir() const { return type_ >= FAT_FILE_TYPE_MIN_DIR; }
|
||||
|
||||
/**
|
||||
* \return True if this is a normal file else false.
|
||||
*/
|
||||
bool isFile() const { return type_ == FAT_FILE_TYPE_NORMAL; }
|
||||
|
||||
/**
|
||||
* \return True if this is an open file/directory else false.
|
||||
*/
|
||||
bool isOpen() const { return type_ != FAT_FILE_TYPE_CLOSED; }
|
||||
|
||||
/**
|
||||
* \return True if this is a subdirectory else false.
|
||||
*/
|
||||
bool isSubDir() const { return type_ == FAT_FILE_TYPE_SUBDIR; }
|
||||
|
||||
/**
|
||||
* \return True if this is the root directory.
|
||||
*/
|
||||
bool isRoot() const { return type_ == FAT_FILE_TYPE_ROOT_FIXED || type_ == FAT_FILE_TYPE_ROOT32; }
|
||||
|
||||
bool getDosName(char * const name);
|
||||
void ls(uint8_t flags = 0, uint8_t indent = 0);
|
||||
|
||||
bool mkdir(SdBaseFile *dir, const char *path, bool pFlag = true);
|
||||
bool open(SdBaseFile *dirFile, uint16_t index, uint8_t oflag);
|
||||
bool open(SdBaseFile *dirFile, const char *path, uint8_t oflag);
|
||||
bool open(const char *path, uint8_t oflag = O_READ);
|
||||
bool openNext(SdBaseFile *dirFile, uint8_t oflag);
|
||||
bool openRoot(SdVolume *vol);
|
||||
int peek();
|
||||
static void printFatDate(uint16_t fatDate);
|
||||
static void printFatTime(uint16_t fatTime);
|
||||
bool printName();
|
||||
int16_t read();
|
||||
int16_t read(void *buf, uint16_t nbyte);
|
||||
int8_t readDir(dir_t *dir, char *longFilename);
|
||||
static bool remove(SdBaseFile *dirFile, const char *path);
|
||||
bool remove();
|
||||
|
||||
/**
|
||||
* Set the file's current position to zero.
|
||||
*/
|
||||
void rewind() { seekSet(0); }
|
||||
bool rename(SdBaseFile *dirFile, const char *newPath);
|
||||
bool rmdir();
|
||||
bool rmRfStar();
|
||||
|
||||
/**
|
||||
* Set the files position to current position + \a pos. See seekSet().
|
||||
* \param[in] offset The new position in bytes from the current position.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool seekCur(const int32_t offset) { return seekSet(curPosition_ + offset); }
|
||||
|
||||
/**
|
||||
* Set the files position to end-of-file + \a offset. See seekSet().
|
||||
* \param[in] offset The new position in bytes from end-of-file.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool seekEnd(const int32_t offset = 0) { return seekSet(fileSize_ + offset); }
|
||||
bool seekSet(const uint32_t pos);
|
||||
bool sync();
|
||||
bool timestamp(SdBaseFile *file);
|
||||
bool timestamp(uint8_t flag, uint16_t year, uint8_t month, uint8_t day,
|
||||
uint8_t hour, uint8_t minute, uint8_t second);
|
||||
|
||||
/**
|
||||
* Type of file. Use isFile() or isDir() instead of type() if possible.
|
||||
*
|
||||
* \return The file or directory type.
|
||||
*/
|
||||
uint8_t type() const { return type_; }
|
||||
bool truncate(uint32_t size);
|
||||
|
||||
/**
|
||||
* \return SdVolume that contains this file.
|
||||
*/
|
||||
SdVolume* volume() const { return vol_; }
|
||||
int16_t write(const void *buf, uint16_t nbyte);
|
||||
|
||||
private:
|
||||
friend class SdFat; // allow SdFat to set cwd_
|
||||
static SdBaseFile *cwd_; // global pointer to cwd dir
|
||||
|
||||
// data time callback function
|
||||
static void (*dateTime_)(uint16_t *date, uint16_t *time);
|
||||
|
||||
// bits defined in flags_
|
||||
static uint8_t const F_OFLAG = (O_ACCMODE | O_APPEND | O_SYNC), // should be 0x0F
|
||||
F_FILE_DIR_DIRTY = 0x80; // sync of directory entry required
|
||||
|
||||
// private data
|
||||
uint8_t flags_; // See above for definition of flags_ bits
|
||||
uint8_t fstate_; // error and eof indicator
|
||||
uint8_t type_; // type of file see above for values
|
||||
uint32_t curCluster_; // cluster for current file position
|
||||
uint32_t curPosition_; // current file position in bytes from beginning
|
||||
uint32_t dirBlock_; // block for this files directory entry
|
||||
uint8_t dirIndex_; // index of directory entry in dirBlock
|
||||
uint32_t fileSize_; // file size in bytes
|
||||
uint32_t firstCluster_; // first cluster of file
|
||||
SdVolume *vol_; // volume where file is located
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL - Don't use!
|
||||
*/
|
||||
//bool openParent(SdBaseFile *dir);
|
||||
|
||||
// private functions
|
||||
bool addCluster();
|
||||
bool addDirCluster();
|
||||
dir_t* cacheDirEntry(uint8_t action);
|
||||
int8_t lsPrintNext(uint8_t flags, uint8_t indent);
|
||||
static bool make83Name(const char *str, uint8_t *name, const char **ptr);
|
||||
bool mkdir(SdBaseFile *parent, const uint8_t dname[11]);
|
||||
bool open(SdBaseFile *dirFile, const uint8_t dname[11], uint8_t oflag);
|
||||
bool openCachedEntry(uint8_t cacheIndex, uint8_t oflags);
|
||||
dir_t* readDirCache();
|
||||
};
|
112
Marlin Firmware/Marlin/src/sd/SdFatConfig.h
Normal file
112
Marlin Firmware/Marlin/src/sd/SdFatConfig.h
Normal file
@ -0,0 +1,112 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* sd/SdFatConfig.h
|
||||
*
|
||||
* Arduino SdFat Library
|
||||
* Copyright (c) 2009 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino Sd2Card Library
|
||||
*/
|
||||
|
||||
#include "../inc/MarlinConfig.h"
|
||||
|
||||
/**
|
||||
* To use multiple SD cards set USE_MULTIPLE_CARDS nonzero.
|
||||
*
|
||||
* Using multiple cards costs 400 - 500 bytes of flash.
|
||||
*
|
||||
* Each card requires about 550 bytes of SRAM so use of a Mega is recommended.
|
||||
*/
|
||||
#define USE_MULTIPLE_CARDS 0 //TODO? ENABLED(MULTI_VOLUME)
|
||||
|
||||
/**
|
||||
* Call flush for endl if ENDL_CALLS_FLUSH is nonzero
|
||||
*
|
||||
* The standard for iostreams is to call flush. This is very costly for
|
||||
* SdFat. Each call to flush causes 2048 bytes of I/O to the SD.
|
||||
*
|
||||
* SdFat has a single 512 byte buffer for SD I/O so it must write the current
|
||||
* data block to the SD, read the directory block from the SD, update the
|
||||
* directory entry, write the directory block to the SD and read the data
|
||||
* block back into the buffer.
|
||||
*
|
||||
* The SD flash memory controller is not designed for this many rewrites
|
||||
* so performance may be reduced by more than a factor of 100.
|
||||
*
|
||||
* If ENDL_CALLS_FLUSH is zero, you must call flush and/or close to force
|
||||
* all data to be written to the SD.
|
||||
*/
|
||||
#define ENDL_CALLS_FLUSH 0
|
||||
|
||||
/**
|
||||
* Allow FAT12 volumes if FAT12_SUPPORT is nonzero.
|
||||
* FAT12 has not been well tested.
|
||||
*/
|
||||
#define FAT12_SUPPORT 0
|
||||
|
||||
/**
|
||||
* SPI init rate for SD initialization commands. Must be 5 (F_CPU/64)
|
||||
* or 6 (F_CPU/128).
|
||||
*/
|
||||
#define SPI_SD_INIT_RATE 5
|
||||
|
||||
/**
|
||||
* Set the SS pin high for hardware SPI. If SS is chip select for another SPI
|
||||
* device this will disable that device during the SD init phase.
|
||||
*/
|
||||
#define SET_SPI_SS_HIGH 1
|
||||
|
||||
/**
|
||||
* Define MEGA_SOFT_SPI nonzero to use software SPI on Mega Arduinos.
|
||||
* Pins used are SS 10, MOSI 11, MISO 12, and SCK 13.
|
||||
*
|
||||
* MEGA_SOFT_SPI allows an unmodified Adafruit GPS Shield to be used
|
||||
* on Mega Arduinos. Software SPI works well with GPS Shield V1.1
|
||||
* but many SD cards will fail with GPS Shield V1.0.
|
||||
*/
|
||||
#define MEGA_SOFT_SPI 0
|
||||
|
||||
// Set USE_SOFTWARE_SPI nonzero to ALWAYS use Software SPI.
|
||||
#define USE_SOFTWARE_SPI 0
|
||||
|
||||
/**
|
||||
* The __cxa_pure_virtual function is an error handler that is invoked when
|
||||
* a pure virtual function is called.
|
||||
*/
|
||||
#define USE_CXA_PURE_VIRTUAL 1
|
||||
|
||||
/**
|
||||
* Defines for 8.3 and long (vfat) filenames
|
||||
*/
|
||||
|
||||
#define FILENAME_LENGTH 13 // Number of UTF-16 characters per entry
|
||||
|
||||
// UTF-8 may use up to 3 bytes to represent single UTF-16 code point.
|
||||
// We discard 3-byte characters allowing only 2-bytes
|
||||
// or 1-byte if UTF_FILENAME_SUPPORT disabled.
|
||||
#define LONG_FILENAME_CHARSIZE TERN(UTF_FILENAME_SUPPORT, 2, 1)
|
||||
|
||||
// Total bytes needed to store a single long filename
|
||||
#define LONG_FILENAME_LENGTH (FILENAME_LENGTH * LONG_FILENAME_CHARSIZE * MAX_VFAT_ENTRIES + 1)
|
609
Marlin Firmware/Marlin/src/sd/SdFatStructs.h
Normal file
609
Marlin Firmware/Marlin/src/sd/SdFatStructs.h
Normal file
@ -0,0 +1,609 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* sd/SdFatStructs.h
|
||||
*
|
||||
* Arduino SdFat Library
|
||||
* Copyright (c) 2009 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino Sd2Card Library
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define PACKED __attribute__((__packed__))
|
||||
|
||||
/**
|
||||
* mostly from Microsoft document fatgen103.doc
|
||||
* https://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
|
||||
*/
|
||||
|
||||
uint8_t const BOOTSIG0 = 0x55, // Value for byte 510 of boot block or MBR
|
||||
BOOTSIG1 = 0xAA, // Value for byte 511 of boot block or MBR
|
||||
EXTENDED_BOOT_SIG = 0x29; // Value for bootSignature field int FAT/FAT32 boot sector
|
||||
|
||||
/**
|
||||
* \struct partitionTable
|
||||
* \brief MBR partition table entry
|
||||
*
|
||||
* A partition table entry for a MBR formatted storage device.
|
||||
* The MBR partition table has four entries.
|
||||
*/
|
||||
struct partitionTable {
|
||||
/**
|
||||
* Boot Indicator . Indicates whether the volume is the active
|
||||
* partition. Legal values include: 0x00. Do not use for booting.
|
||||
* 0x80 Active partition.
|
||||
*/
|
||||
uint8_t boot;
|
||||
/**
|
||||
* Head part of Cylinder-head-sector address of the first block in
|
||||
* the partition. Legal values are 0-255. Only used in old PC BIOS.
|
||||
*/
|
||||
uint8_t beginHead;
|
||||
/**
|
||||
* Sector part of Cylinder-head-sector address of the first block in
|
||||
* the partition. Legal values are 1-63. Only used in old PC BIOS.
|
||||
*/
|
||||
unsigned beginSector : 6;
|
||||
/** High bits cylinder for first block in partition. */
|
||||
unsigned beginCylinderHigh : 2;
|
||||
/**
|
||||
* Combine beginCylinderLow with beginCylinderHigh. Legal values
|
||||
* are 0-1023. Only used in old PC BIOS.
|
||||
*/
|
||||
uint8_t beginCylinderLow;
|
||||
/**
|
||||
* Partition type. See defines that begin with PART_TYPE_ for
|
||||
* some Microsoft partition types.
|
||||
*/
|
||||
uint8_t type;
|
||||
/**
|
||||
* head part of cylinder-head-sector address of the last sector in the
|
||||
* partition. Legal values are 0-255. Only used in old PC BIOS.
|
||||
*/
|
||||
uint8_t endHead;
|
||||
/**
|
||||
* Sector part of cylinder-head-sector address of the last sector in
|
||||
* the partition. Legal values are 1-63. Only used in old PC BIOS.
|
||||
*/
|
||||
unsigned endSector : 6;
|
||||
/** High bits of end cylinder */
|
||||
unsigned endCylinderHigh : 2;
|
||||
/**
|
||||
* Combine endCylinderLow with endCylinderHigh. Legal values
|
||||
* are 0-1023. Only used in old PC BIOS.
|
||||
*/
|
||||
uint8_t endCylinderLow;
|
||||
|
||||
uint32_t firstSector; // Logical block address of the first block in the partition.
|
||||
uint32_t totalSectors; // Length of the partition, in blocks.
|
||||
} PACKED;
|
||||
|
||||
typedef struct partitionTable part_t; // Type name for partitionTable
|
||||
|
||||
/**
|
||||
* \struct masterBootRecord
|
||||
*
|
||||
* \brief Master Boot Record
|
||||
*
|
||||
* The first block of a storage device that is formatted with a MBR.
|
||||
*/
|
||||
struct masterBootRecord {
|
||||
uint8_t codeArea[440]; // Code Area for master boot program.
|
||||
uint32_t diskSignature; // Optional Windows NT disk signature. May contain boot code.
|
||||
uint16_t usuallyZero; // Usually zero but may be more boot code.
|
||||
part_t part[4]; // Partition tables.
|
||||
uint8_t mbrSig0; // First MBR signature byte. Must be 0x55
|
||||
uint8_t mbrSig1; // Second MBR signature byte. Must be 0xAA
|
||||
} PACKED;
|
||||
/** Type name for masterBootRecord */
|
||||
typedef struct masterBootRecord mbr_t;
|
||||
|
||||
/**
|
||||
* \struct fat_boot
|
||||
*
|
||||
* \brief Boot sector for a FAT12/FAT16 volume.
|
||||
*/
|
||||
struct fat_boot {
|
||||
/**
|
||||
* The first three bytes of the boot sector must be valid,
|
||||
* executable x 86-based CPU instructions. This includes a
|
||||
* jump instruction that skips the next nonexecutable bytes.
|
||||
*/
|
||||
uint8_t jump[3];
|
||||
/**
|
||||
* This is typically a string of characters that identifies
|
||||
* the operating system that formatted the volume.
|
||||
*/
|
||||
char oemId[8];
|
||||
/**
|
||||
* The size of a hardware sector. Valid decimal values for this
|
||||
* field are 512, 1024, 2048, and 4096. For most disks used in
|
||||
* the United States, the value of this field is 512.
|
||||
*/
|
||||
uint16_t bytesPerSector;
|
||||
/**
|
||||
* Number of sectors per allocation unit. This value must be a
|
||||
* power of 2 that is greater than 0. The legal values are
|
||||
* 1, 2, 4, 8, 16, 32, 64, and 128. 128 should be avoided.
|
||||
*/
|
||||
uint8_t sectorsPerCluster;
|
||||
/**
|
||||
* The number of sectors preceding the start of the first FAT,
|
||||
* including the boot sector. The value of this field is always 1.
|
||||
*/
|
||||
uint16_t reservedSectorCount;
|
||||
/**
|
||||
* The number of copies of the FAT on the volume.
|
||||
* The value of this field is always 2.
|
||||
*/
|
||||
uint8_t fatCount;
|
||||
/**
|
||||
* For FAT12 and FAT16 volumes, this field contains the count of
|
||||
* 32-byte directory entries in the root directory. For FAT32 volumes,
|
||||
* this field must be set to 0. For FAT12 and FAT16 volumes, this
|
||||
* value should always specify a count that when multiplied by 32
|
||||
* results in a multiple of bytesPerSector. FAT16 volumes should
|
||||
* use the value 512.
|
||||
*/
|
||||
uint16_t rootDirEntryCount;
|
||||
/**
|
||||
* This field is the old 16-bit total count of sectors on the volume.
|
||||
* This count includes the count of all sectors in all four regions
|
||||
* of the volume. This field can be 0; if it is 0, then totalSectors32
|
||||
* must be nonzero. For FAT32 volumes, this field must be 0. For
|
||||
* FAT12 and FAT16 volumes, this field contains the sector count, and
|
||||
* totalSectors32 is 0 if the total sector count fits
|
||||
* (is less than 0x10000).
|
||||
*/
|
||||
uint16_t totalSectors16;
|
||||
/**
|
||||
* This dates back to the old MS-DOS 1.x media determination and is
|
||||
* no longer usually used for anything. 0xF8 is the standard value
|
||||
* for fixed (nonremovable) media. For removable media, 0xF0 is
|
||||
* frequently used. Legal values are 0xF0 or 0xF8-0xFF.
|
||||
*/
|
||||
uint8_t mediaType;
|
||||
/**
|
||||
* Count of sectors occupied by one FAT on FAT12/FAT16 volumes.
|
||||
* On FAT32 volumes this field must be 0, and sectorsPerFat32
|
||||
* contains the FAT size count.
|
||||
*/
|
||||
uint16_t sectorsPerFat16;
|
||||
|
||||
uint16_t sectorsPerTrack; // Sectors per track for interrupt 0x13. Not used otherwise.
|
||||
uint16_t headCount; // Number of heads for interrupt 0x13. Not used otherwise.
|
||||
|
||||
/**
|
||||
* Count of hidden sectors preceding the partition that contains this
|
||||
* FAT volume. This field is generally only relevant for media
|
||||
* visible on interrupt 0x13.
|
||||
*/
|
||||
uint32_t hidddenSectors;
|
||||
/**
|
||||
* This field is the new 32-bit total count of sectors on the volume.
|
||||
* This count includes the count of all sectors in all four regions
|
||||
* of the volume. This field can be 0; if it is 0, then
|
||||
* totalSectors16 must be nonzero.
|
||||
*/
|
||||
uint32_t totalSectors32;
|
||||
/**
|
||||
* Related to the BIOS physical drive number. Floppy drives are
|
||||
* identified as 0x00 and physical hard disks are identified as
|
||||
* 0x80, regardless of the number of physical disk drives.
|
||||
* Typically, this value is set prior to issuing an INT 13h BIOS
|
||||
* call to specify the device to access. The value is only
|
||||
* relevant if the device is a boot device.
|
||||
*/
|
||||
uint8_t driveNumber;
|
||||
|
||||
uint8_t reserved1; // used by Windows NT - should be zero for FAT
|
||||
uint8_t bootSignature; // 0x29 if next three fields are valid
|
||||
|
||||
/**
|
||||
* A random serial number created when formatting a disk,
|
||||
* which helps to distinguish between disks.
|
||||
* Usually generated by combining date and time.
|
||||
*/
|
||||
uint32_t volumeSerialNumber;
|
||||
/**
|
||||
* A field once used to store the volume label. The volume label
|
||||
* is now stored as a special file in the root directory.
|
||||
*/
|
||||
char volumeLabel[11];
|
||||
/**
|
||||
* A field with a value of either FAT, FAT12 or FAT16,
|
||||
* depending on the disk format.
|
||||
*/
|
||||
char fileSystemType[8];
|
||||
|
||||
uint8_t bootCode[448]; // X86 boot code
|
||||
uint8_t bootSectorSig0; // must be 0x55
|
||||
uint8_t bootSectorSig1; // must be 0xAA
|
||||
} PACKED;
|
||||
|
||||
typedef struct fat_boot fat_boot_t; // Type name for FAT Boot Sector
|
||||
|
||||
/**
|
||||
* \struct fat32_boot
|
||||
*
|
||||
* \brief Boot sector for a FAT32 volume.
|
||||
*/
|
||||
struct fat32_boot {
|
||||
/**
|
||||
* The first three bytes of the boot sector must be valid,
|
||||
* executable x 86-based CPU instructions. This includes a
|
||||
* jump instruction that skips the next nonexecutable bytes.
|
||||
*/
|
||||
uint8_t jump[3];
|
||||
/**
|
||||
* This is typically a string of characters that identifies
|
||||
* the operating system that formatted the volume.
|
||||
*/
|
||||
char oemId[8];
|
||||
/**
|
||||
* The size of a hardware sector. Valid decimal values for this
|
||||
* field are 512, 1024, 2048, and 4096. For most disks used in
|
||||
* the United States, the value of this field is 512.
|
||||
*/
|
||||
uint16_t bytesPerSector;
|
||||
/**
|
||||
* Number of sectors per allocation unit. This value must be a
|
||||
* power of 2 that is greater than 0. The legal values are
|
||||
* 1, 2, 4, 8, 16, 32, 64, and 128. 128 should be avoided.
|
||||
*/
|
||||
uint8_t sectorsPerCluster;
|
||||
/**
|
||||
* The number of sectors preceding the start of the first FAT,
|
||||
* including the boot sector. Must not be zero
|
||||
*/
|
||||
uint16_t reservedSectorCount;
|
||||
/**
|
||||
* The number of copies of the FAT on the volume.
|
||||
* The value of this field is always 2.
|
||||
*/
|
||||
uint8_t fatCount;
|
||||
/**
|
||||
* FAT12/FAT16 only. For FAT32 volumes, this field must be set to 0.
|
||||
*/
|
||||
uint16_t rootDirEntryCount;
|
||||
/**
|
||||
* For FAT32 volumes, this field must be 0.
|
||||
*/
|
||||
uint16_t totalSectors16;
|
||||
/**
|
||||
* This dates back to the old MS-DOS 1.x media determination and is
|
||||
* no longer usually used for anything. 0xF8 is the standard value
|
||||
* for fixed (nonremovable) media. For removable media, 0xF0 is
|
||||
* frequently used. Legal values are 0xF0 or 0xF8-0xFF.
|
||||
*/
|
||||
uint8_t mediaType;
|
||||
/**
|
||||
* On FAT32 volumes this field must be 0, and sectorsPerFat32
|
||||
* contains the FAT size count.
|
||||
*/
|
||||
uint16_t sectorsPerFat16;
|
||||
|
||||
uint16_t sectorsPerTrack; // Sectors per track for interrupt 0x13. Not used otherwise.
|
||||
uint16_t headCount; // Number of heads for interrupt 0x13. Not used otherwise.
|
||||
|
||||
/**
|
||||
* Count of hidden sectors preceding the partition that contains this
|
||||
* FAT volume. This field is generally only relevant for media
|
||||
* visible on interrupt 0x13.
|
||||
*/
|
||||
uint32_t hidddenSectors;
|
||||
/**
|
||||
* Contains the total number of sectors in the FAT32 volume.
|
||||
*/
|
||||
uint32_t totalSectors32;
|
||||
/**
|
||||
* Count of sectors occupied by one FAT on FAT32 volumes.
|
||||
*/
|
||||
uint32_t sectorsPerFat32;
|
||||
/**
|
||||
* This field is only defined for FAT32 media and does not exist on
|
||||
* FAT12 and FAT16 media.
|
||||
* Bits 0-3 -- Zero-based number of active FAT.
|
||||
* Only valid if mirroring is disabled.
|
||||
* Bits 4-6 -- Reserved.
|
||||
* Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs.
|
||||
* -- 1 means only one FAT is active; it is the one referenced
|
||||
* in bits 0-3.
|
||||
* Bits 8-15 -- Reserved.
|
||||
*/
|
||||
uint16_t fat32Flags;
|
||||
/**
|
||||
* FAT32 version. High byte is major revision number.
|
||||
* Low byte is minor revision number. Only 0.0 define.
|
||||
*/
|
||||
uint16_t fat32Version;
|
||||
/**
|
||||
* Cluster number of the first cluster of the root directory for FAT32.
|
||||
* This usually 2 but not required to be 2.
|
||||
*/
|
||||
uint32_t fat32RootCluster;
|
||||
/**
|
||||
* Sector number of FSINFO structure in the reserved area of the
|
||||
* FAT32 volume. Usually 1.
|
||||
*/
|
||||
uint16_t fat32FSInfo;
|
||||
/**
|
||||
* If nonzero, indicates the sector number in the reserved area
|
||||
* of the volume of a copy of the boot record. Usually 6.
|
||||
* No value other than 6 is recommended.
|
||||
*/
|
||||
uint16_t fat32BackBootBlock;
|
||||
/**
|
||||
* Reserved for future expansion. Code that formats FAT32 volumes
|
||||
* should always set all of the bytes of this field to 0.
|
||||
*/
|
||||
uint8_t fat32Reserved[12];
|
||||
/**
|
||||
* Related to the BIOS physical drive number. Floppy drives are
|
||||
* identified as 0x00 and physical hard disks are identified as
|
||||
* 0x80, regardless of the number of physical disk drives.
|
||||
* Typically, this value is set prior to issuing an INT 13h BIOS
|
||||
* call to specify the device to access. The value is only
|
||||
* relevant if the device is a boot device.
|
||||
*/
|
||||
uint8_t driveNumber;
|
||||
|
||||
uint8_t reserved1; // Used by Windows NT - should be zero for FAT
|
||||
uint8_t bootSignature; // 0x29 if next three fields are valid
|
||||
|
||||
/**
|
||||
* A random serial number created when formatting a disk,
|
||||
* which helps to distinguish between disks.
|
||||
* Usually generated by combining date and time.
|
||||
*/
|
||||
uint32_t volumeSerialNumber;
|
||||
/**
|
||||
* A field once used to store the volume label. The volume label
|
||||
* is now stored as a special file in the root directory.
|
||||
*/
|
||||
char volumeLabel[11];
|
||||
/**
|
||||
* A text field with a value of FAT32.
|
||||
*/
|
||||
char fileSystemType[8];
|
||||
|
||||
uint8_t bootCode[420]; // X86 boot code
|
||||
uint8_t bootSectorSig0; // must be 0x55
|
||||
uint8_t bootSectorSig1; // must be 0xAA
|
||||
|
||||
} PACKED;
|
||||
|
||||
typedef struct fat32_boot fat32_boot_t; // Type name for FAT32 Boot Sector
|
||||
|
||||
uint32_t const FSINFO_LEAD_SIG = 0x41615252, // 'AaRR' Lead signature for a FSINFO sector
|
||||
FSINFO_STRUCT_SIG = 0x61417272; // 'aArr' Struct signature for a FSINFO sector
|
||||
|
||||
/**
|
||||
* \struct fat32_fsinfo
|
||||
*
|
||||
* \brief FSINFO sector for a FAT32 volume.
|
||||
*/
|
||||
struct fat32_fsinfo {
|
||||
uint32_t leadSignature; // must be 0x52, 0x52, 0x61, 0x41 'RRaA'
|
||||
uint8_t reserved1[480]; // must be zero
|
||||
uint32_t structSignature; // must be 0x72, 0x72, 0x41, 0x61 'rrAa'
|
||||
/**
|
||||
* Contains the last known free cluster count on the volume.
|
||||
* If the value is 0xFFFFFFFF, then the free count is unknown
|
||||
* and must be computed. Any other value can be used, but is
|
||||
* not necessarily correct. It should be range checked at least
|
||||
* to make sure it is <= volume cluster count.
|
||||
*/
|
||||
uint32_t freeCount;
|
||||
/**
|
||||
* This is a hint for the FAT driver. It indicates the cluster
|
||||
* number at which the driver should start looking for free clusters.
|
||||
* If the value is 0xFFFFFFFF, then there is no hint and the driver
|
||||
* should start looking at cluster 2.
|
||||
*/
|
||||
uint32_t nextFree;
|
||||
|
||||
uint8_t reserved2[12]; // must be zero
|
||||
uint8_t tailSignature[4]; // must be 0x00, 0x00, 0x55, 0xAA
|
||||
} PACKED;
|
||||
|
||||
typedef struct fat32_fsinfo fat32_fsinfo_t; // Type name for FAT32 FSINFO Sector
|
||||
|
||||
// End Of Chain values for FAT entries
|
||||
uint16_t const FAT12EOC = 0xFFF, // FAT12 end of chain value used by Microsoft.
|
||||
FAT12EOC_MIN = 0xFF8, // Minimum value for FAT12 EOC. Use to test for EOC.
|
||||
FAT16EOC = 0xFFFF, // FAT16 end of chain value used by Microsoft.
|
||||
FAT16EOC_MIN = 0xFFF8; // Minimum value for FAT16 EOC. Use to test for EOC.
|
||||
uint32_t const FAT32EOC = 0x0FFFFFFF, // FAT32 end of chain value used by Microsoft.
|
||||
FAT32EOC_MIN = 0x0FFFFFF8, // Minimum value for FAT32 EOC. Use to test for EOC.
|
||||
FAT32MASK = 0x0FFFFFFF; // Mask a for FAT32 entry. Entries are 28 bits.
|
||||
|
||||
/**
|
||||
* \struct directoryEntry
|
||||
* \brief FAT short directory entry
|
||||
*
|
||||
* Short means short 8.3 name, not the entry size.
|
||||
*
|
||||
* Date Format. A FAT directory entry date stamp is a 16-bit field that is
|
||||
* basically a date relative to the MS-DOS epoch of 01/01/1980. Here is the
|
||||
* format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the
|
||||
* 16-bit word):
|
||||
*
|
||||
* Bits 9-15: Count of years from 1980, valid value range 0-127
|
||||
* inclusive (1980-2107).
|
||||
*
|
||||
* Bits 5-8: Month of year, 1 = January, valid value range 1-12 inclusive.
|
||||
*
|
||||
* Bits 0-4: Day of month, valid value range 1-31 inclusive.
|
||||
*
|
||||
* Time Format. A FAT directory entry time stamp is a 16-bit field that has
|
||||
* a granularity of 2 seconds. Here is the format (bit 0 is the LSB of the
|
||||
* 16-bit word, bit 15 is the MSB of the 16-bit word).
|
||||
*
|
||||
* Bits 11-15: Hours, valid value range 0-23 inclusive.
|
||||
*
|
||||
* Bits 5-10: Minutes, valid value range 0-59 inclusive.
|
||||
*
|
||||
* Bits 0-4: 2-second count, valid value range 0-29 inclusive (0 - 58 seconds).
|
||||
*
|
||||
* The valid time range is from Midnight 00:00:00 to 23:59:58.
|
||||
*/
|
||||
struct directoryEntry {
|
||||
/**
|
||||
* Short 8.3 name.
|
||||
*
|
||||
* The first eight bytes contain the file name with blank fill.
|
||||
* The last three bytes contain the file extension with blank fill.
|
||||
*/
|
||||
uint8_t name[11];
|
||||
/**
|
||||
* Entry attributes.
|
||||
*
|
||||
* The upper two bits of the attribute byte are reserved and should
|
||||
* always be set to 0 when a file is created and never modified or
|
||||
* looked at after that. See defines that begin with DIR_ATT_.
|
||||
*/
|
||||
uint8_t attributes;
|
||||
/**
|
||||
* Reserved for use by Windows NT. Set value to 0 when a file is
|
||||
* created and never modify or look at it after that.
|
||||
*/
|
||||
uint8_t reservedNT;
|
||||
/**
|
||||
* The granularity of the seconds part of creationTime is 2 seconds
|
||||
* so this field is a count of tenths of a second and it's valid
|
||||
* value range is 0-199 inclusive. (WHG note - seems to be hundredths)
|
||||
*/
|
||||
uint8_t creationTimeTenths;
|
||||
|
||||
uint16_t creationTime; // Time file was created.
|
||||
uint16_t creationDate; // Date file was created.
|
||||
|
||||
/**
|
||||
* Last access date. Note that there is no last access time, only
|
||||
* a date. This is the date of last read or write. In the case of
|
||||
* a write, this should be set to the same date as lastWriteDate.
|
||||
*/
|
||||
uint16_t lastAccessDate;
|
||||
/**
|
||||
* High word of this entry's first cluster number (always 0 for a
|
||||
* FAT12 or FAT16 volume).
|
||||
*/
|
||||
uint16_t firstClusterHigh;
|
||||
|
||||
uint16_t lastWriteTime; // Time of last write. File creation is considered a write.
|
||||
uint16_t lastWriteDate; // Date of last write. File creation is considered a write.
|
||||
uint16_t firstClusterLow; // Low word of this entry's first cluster number.
|
||||
uint32_t fileSize; // 32-bit unsigned holding this file's size in bytes.
|
||||
} PACKED;
|
||||
|
||||
/**
|
||||
* \struct directoryVFATEntry
|
||||
* \brief VFAT long filename directory entry
|
||||
*
|
||||
* directoryVFATEntries are found in the same list as normal directoryEntry.
|
||||
* But have the attribute field set to DIR_ATT_LONG_NAME.
|
||||
*
|
||||
* Long filenames are saved in multiple directoryVFATEntries.
|
||||
* Each entry containing 13 UTF-16 characters.
|
||||
*/
|
||||
struct directoryVFATEntry {
|
||||
/**
|
||||
* Sequence number. Consists of 2 parts:
|
||||
* bit 6: indicates first long filename block for the next file
|
||||
* bit 0-4: the position of this long filename block (first block is 1)
|
||||
*/
|
||||
uint8_t sequenceNumber;
|
||||
|
||||
uint16_t name1[5]; // First set of UTF-16 characters
|
||||
uint8_t attributes; // attributes (at the same location as in directoryEntry), always 0x0F
|
||||
uint8_t reservedNT; // Reserved for use by Windows NT. Always 0.
|
||||
uint8_t checksum; // Checksum of the short 8.3 filename, can be used to checked if the file system as modified by a not-long-filename aware implementation.
|
||||
uint16_t name2[6]; // Second set of UTF-16 characters
|
||||
uint16_t firstClusterLow; // firstClusterLow is always zero for longFilenames
|
||||
uint16_t name3[2]; // Third set of UTF-16 characters
|
||||
} PACKED;
|
||||
|
||||
// Definitions for directory entries
|
||||
//
|
||||
typedef struct directoryEntry dir_t; // Type name for directoryEntry
|
||||
typedef struct directoryVFATEntry vfat_t; // Type name for directoryVFATEntry
|
||||
|
||||
uint8_t const DIR_NAME_0xE5 = 0x05, // escape for name[0] = 0xE5
|
||||
DIR_NAME_DELETED = 0xE5, // name[0] value for entry that is free after being "deleted"
|
||||
DIR_NAME_FREE = 0x00, // name[0] value for entry that is free and no allocated entries follow
|
||||
DIR_ATT_READ_ONLY = 0x01, // file is read-only
|
||||
DIR_ATT_HIDDEN = 0x02, // File should hidden in directory listings
|
||||
DIR_ATT_SYSTEM = 0x04, // Entry is for a system file
|
||||
DIR_ATT_VOLUME_ID = 0x08, // Directory entry contains the volume label
|
||||
DIR_ATT_DIRECTORY = 0x10, // Entry is for a directory
|
||||
DIR_ATT_ARCHIVE = 0x20, // Old DOS archive bit for backup support
|
||||
DIR_ATT_LONG_NAME = 0x0F, // Test value for long name entry. Test is (d->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME.
|
||||
DIR_ATT_LONG_NAME_MASK = 0x3F, // Test mask for long name entry
|
||||
DIR_ATT_DEFINED_BITS = 0x3F; // defined attribute bits
|
||||
|
||||
/**
|
||||
* Directory entry is part of a long name
|
||||
* \param[in] dir Pointer to a directory entry.
|
||||
*
|
||||
* \return true if the entry is for part of a long name else false.
|
||||
*/
|
||||
static inline uint8_t DIR_IS_LONG_NAME(const dir_t *dir) {
|
||||
return (dir->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME;
|
||||
}
|
||||
|
||||
/** Mask for file/subdirectory tests */
|
||||
uint8_t const DIR_ATT_FILE_TYPE_MASK = (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY);
|
||||
|
||||
/**
|
||||
* Directory entry is for a file
|
||||
* \param[in] dir Pointer to a directory entry.
|
||||
*
|
||||
* \return true if the entry is for a normal file else false.
|
||||
*/
|
||||
static inline uint8_t DIR_IS_FILE(const dir_t *dir) {
|
||||
return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Directory entry is for a subdirectory
|
||||
* \param[in] dir Pointer to a directory entry.
|
||||
*
|
||||
* \return true if the entry is for a subdirectory else false.
|
||||
*/
|
||||
static inline uint8_t DIR_IS_SUBDIR(const dir_t *dir) {
|
||||
return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == DIR_ATT_DIRECTORY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Directory entry is for a file or subdirectory
|
||||
* \param[in] dir Pointer to a directory entry.
|
||||
*
|
||||
* \return true if the entry is for a normal file or subdirectory else false.
|
||||
*/
|
||||
static inline uint8_t DIR_IS_FILE_OR_SUBDIR(const dir_t *dir) {
|
||||
return (dir->attributes & DIR_ATT_VOLUME_ID) == 0;
|
||||
}
|
62
Marlin Firmware/Marlin/src/sd/SdFatUtil.cpp
Normal file
62
Marlin Firmware/Marlin/src/sd/SdFatUtil.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* sd/SdFatUtil.cpp
|
||||
*
|
||||
* Arduino SdFat Library
|
||||
* Copyright (c) 2008 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino Sd2Card Library
|
||||
*/
|
||||
|
||||
#include "../inc/MarlinConfig.h"
|
||||
|
||||
#if ENABLED(SDSUPPORT)
|
||||
|
||||
#include "SdFatUtil.h"
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* Amount of free RAM
|
||||
* \return The number of free bytes.
|
||||
*/
|
||||
#ifdef __arm__
|
||||
|
||||
extern "C" char* sbrk(int incr);
|
||||
int SdFatUtil::FreeRam() {
|
||||
char top;
|
||||
return &top - reinterpret_cast<char*>(sbrk(0));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
extern char* __brkval;
|
||||
extern char __bss_end;
|
||||
int SdFatUtil::FreeRam() {
|
||||
char top;
|
||||
return __brkval ? &top - __brkval : &top - &__bss_end;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif // SDSUPPORT
|
42
Marlin Firmware/Marlin/src/sd/SdFatUtil.h
Normal file
42
Marlin Firmware/Marlin/src/sd/SdFatUtil.h
Normal file
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* sd/SdFatUtil.h
|
||||
*
|
||||
* Arduino SdFat Library
|
||||
* Copyright (c) 2008 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino Sd2Card Library
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief Useful utility functions.
|
||||
*/
|
||||
|
||||
namespace SdFatUtil {
|
||||
int FreeRam();
|
||||
}
|
||||
|
||||
using namespace SdFatUtil; // NOLINT
|
102
Marlin Firmware/Marlin/src/sd/SdFile.cpp
Normal file
102
Marlin Firmware/Marlin/src/sd/SdFile.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* sd/SdFile.cpp
|
||||
*
|
||||
* Arduino SdFat Library
|
||||
* Copyright (c) 2009 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino Sd2Card Library
|
||||
*/
|
||||
|
||||
#include "../inc/MarlinConfig.h"
|
||||
|
||||
#if ENABLED(SDSUPPORT)
|
||||
|
||||
#include "SdFile.h"
|
||||
|
||||
/**
|
||||
* Create a file object and open it in the current working directory.
|
||||
*
|
||||
* \param[in] path A path with a valid 8.3 DOS name for a file to be opened.
|
||||
*
|
||||
* \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
|
||||
* OR of open flags. see SdBaseFile::open(SdBaseFile*, const char*, uint8_t).
|
||||
*/
|
||||
SdFile::SdFile(const char *path, uint8_t oflag) : SdBaseFile(path, oflag) { }
|
||||
|
||||
/**
|
||||
* Write data to an open file.
|
||||
*
|
||||
* \note Data is moved to the cache but may not be written to the
|
||||
* storage device until sync() is called.
|
||||
*
|
||||
* \param[in] buf Pointer to the location of the data to be written.
|
||||
*
|
||||
* \param[in] nbyte Number of bytes to write.
|
||||
*
|
||||
* \return For success write() returns the number of bytes written, always
|
||||
* \a nbyte. If an error occurs, write() returns -1. Possible errors
|
||||
* include write() is called before a file has been opened, write is called
|
||||
* for a read-only file, device is full, a corrupt file system or an I/O error.
|
||||
*/
|
||||
int16_t SdFile::write(const void *buf, uint16_t nbyte) { return SdBaseFile::write(buf, nbyte); }
|
||||
|
||||
/**
|
||||
* Write a byte to a file. Required by the Arduino Print class.
|
||||
* \param[in] b the byte to be written.
|
||||
* Use writeError to check for errors.
|
||||
*/
|
||||
#if ARDUINO >= 100
|
||||
size_t SdFile::write(uint8_t b) { return SdBaseFile::write(&b, 1); }
|
||||
#else
|
||||
void SdFile::write(uint8_t b) { SdBaseFile::write(&b, 1); }
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Write a string to a file. Used by the Arduino Print class.
|
||||
* \param[in] str Pointer to the string.
|
||||
* Use writeError to check for errors.
|
||||
*/
|
||||
void SdFile::write(const char *str) { SdBaseFile::write(str, strlen(str)); }
|
||||
|
||||
/**
|
||||
* Write a PROGMEM string to a file.
|
||||
* \param[in] str Pointer to the PROGMEM string.
|
||||
* Use writeError to check for errors.
|
||||
*/
|
||||
void SdFile::write_P(PGM_P str) {
|
||||
for (uint8_t c; (c = pgm_read_byte(str)); str++) write(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a PROGMEM string followed by CR/LF to a file.
|
||||
* \param[in] str Pointer to the PROGMEM string.
|
||||
* Use writeError to check for errors.
|
||||
*/
|
||||
void SdFile::writeln_P(PGM_P str) {
|
||||
write_P(str);
|
||||
write_P(PSTR("\r\n"));
|
||||
}
|
||||
|
||||
#endif // SDSUPPORT
|
56
Marlin Firmware/Marlin/src/sd/SdFile.h
Normal file
56
Marlin Firmware/Marlin/src/sd/SdFile.h
Normal file
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* sd/SdFile.h
|
||||
*
|
||||
* Arduino SdFat Library
|
||||
* Copyright (c) 2009 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino Sd2Card Library
|
||||
*/
|
||||
|
||||
#include "SdBaseFile.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* \class SdFile
|
||||
* \brief SdBaseFile with Print.
|
||||
*/
|
||||
class SdFile : public SdBaseFile {
|
||||
public:
|
||||
SdFile() {}
|
||||
SdFile(const char *name, uint8_t oflag);
|
||||
#if ARDUINO >= 100
|
||||
size_t write(uint8_t b);
|
||||
#else
|
||||
void write(uint8_t b);
|
||||
#endif
|
||||
|
||||
int16_t write(const void *buf, uint16_t nbyte);
|
||||
void write(const char *str);
|
||||
void write_P(PGM_P str);
|
||||
void writeln_P(PGM_P str);
|
||||
};
|
265
Marlin Firmware/Marlin/src/sd/SdInfo.h
Normal file
265
Marlin Firmware/Marlin/src/sd/SdInfo.h
Normal file
@ -0,0 +1,265 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* Arduino Sd2Card Library
|
||||
* Copyright (c) 2009 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino Sd2Card Library
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Based on the document:
|
||||
//
|
||||
// SD Specifications
|
||||
// Part 1
|
||||
// Physical Layer
|
||||
// Simplified Specification
|
||||
// Version 3.01
|
||||
// May 18, 2010
|
||||
//
|
||||
// https://www.sdcard.org/downloads/pls/index.html
|
||||
|
||||
// SD card commands
|
||||
uint8_t const CMD0 = 0x00, // GO_IDLE_STATE - init card in spi mode if CS low
|
||||
CMD8 = 0x08, // SEND_IF_COND - verify SD Memory Card interface operating condition
|
||||
CMD9 = 0x09, // SEND_CSD - read the Card Specific Data (CSD register)
|
||||
CMD10 = 0x0A, // SEND_CID - read the card identification information (CID register)
|
||||
CMD12 = 0x0C, // STOP_TRANSMISSION - end multiple block read sequence
|
||||
CMD13 = 0x0D, // SEND_STATUS - read the card status register
|
||||
CMD17 = 0x11, // READ_SINGLE_BLOCK - read a single data block from the card
|
||||
CMD18 = 0x12, // READ_MULTIPLE_BLOCK - read a multiple data blocks from the card
|
||||
CMD24 = 0x18, // WRITE_BLOCK - write a single data block to the card
|
||||
CMD25 = 0x19, // WRITE_MULTIPLE_BLOCK - write blocks of data until a STOP_TRANSMISSION
|
||||
CMD32 = 0x20, // ERASE_WR_BLK_START - sets the address of the first block to be erased
|
||||
CMD33 = 0x21, // ERASE_WR_BLK_END - sets the address of the last block of the continuous range to be erased
|
||||
CMD38 = 0x26, // ERASE - erase all previously selected blocks
|
||||
CMD55 = 0x37, // APP_CMD - escape for application specific command
|
||||
CMD58 = 0x3A, // READ_OCR - read the OCR register of a card
|
||||
CMD59 = 0x3B, // CRC_ON_OFF - enable or disable CRC checking
|
||||
ACMD23 = 0x17, // SET_WR_BLK_ERASE_COUNT - Set the number of write blocks to be pre-erased before writing
|
||||
ACMD41 = 0x29; // SD_SEND_OP_COMD - Sends host capacity support information and activates the card's initialization process
|
||||
|
||||
/** status for card in the ready state */
|
||||
uint8_t const R1_READY_STATE = 0x00;
|
||||
/** status for card in the idle state */
|
||||
uint8_t const R1_IDLE_STATE = 0x01;
|
||||
/** status bit for illegal command */
|
||||
uint8_t const R1_ILLEGAL_COMMAND = 0x04;
|
||||
/** start data token for read or write single block*/
|
||||
uint8_t const DATA_START_BLOCK = 0xFE;
|
||||
/** stop token for write multiple blocks*/
|
||||
uint8_t const STOP_TRAN_TOKEN = 0xFD;
|
||||
/** start data token for write multiple blocks*/
|
||||
uint8_t const WRITE_MULTIPLE_TOKEN = 0xFC;
|
||||
/** mask for data response tokens after a write block operation */
|
||||
uint8_t const DATA_RES_MASK = 0x1F;
|
||||
/** write data accepted token */
|
||||
uint8_t const DATA_RES_ACCEPTED = 0x05;
|
||||
|
||||
/** Card IDentification (CID) register */
|
||||
typedef struct CID {
|
||||
// byte 0
|
||||
/** Manufacturer ID */
|
||||
unsigned char mid;
|
||||
// byte 1-2
|
||||
/** OEM/Application ID */
|
||||
char oid[2];
|
||||
// byte 3-7
|
||||
/** Product name */
|
||||
char pnm[5];
|
||||
// byte 8
|
||||
/** Product revision least significant digit */
|
||||
unsigned char prv_m : 4;
|
||||
/** Product revision most significant digit */
|
||||
unsigned char prv_n : 4;
|
||||
// byte 9-12
|
||||
/** Product serial number */
|
||||
uint32_t psn;
|
||||
// byte 13
|
||||
/** Manufacturing date year low digit */
|
||||
unsigned char mdt_year_high : 4;
|
||||
/** not used */
|
||||
unsigned char reserved : 4;
|
||||
// byte 14
|
||||
/** Manufacturing date month */
|
||||
unsigned char mdt_month : 4;
|
||||
/** Manufacturing date year low digit */
|
||||
unsigned char mdt_year_low : 4;
|
||||
// byte 15
|
||||
/** not used always 1 */
|
||||
unsigned char always1 : 1;
|
||||
/** CRC7 checksum */
|
||||
unsigned char crc : 7;
|
||||
} cid_t;
|
||||
|
||||
/** CSD for version 1.00 cards */
|
||||
typedef struct CSDV1 {
|
||||
// byte 0
|
||||
unsigned char reserved1 : 6;
|
||||
unsigned char csd_ver : 2;
|
||||
// byte 1
|
||||
unsigned char taac;
|
||||
// byte 2
|
||||
unsigned char nsac;
|
||||
// byte 3
|
||||
unsigned char tran_speed;
|
||||
// byte 4
|
||||
unsigned char ccc_high;
|
||||
// byte 5
|
||||
unsigned char read_bl_len : 4;
|
||||
unsigned char ccc_low : 4;
|
||||
// byte 6
|
||||
unsigned char c_size_high : 2;
|
||||
unsigned char reserved2 : 2;
|
||||
unsigned char dsr_imp : 1;
|
||||
unsigned char read_blk_misalign : 1;
|
||||
unsigned char write_blk_misalign : 1;
|
||||
unsigned char read_bl_partial : 1;
|
||||
// byte 7
|
||||
unsigned char c_size_mid;
|
||||
// byte 8
|
||||
unsigned char vdd_r_curr_max : 3;
|
||||
unsigned char vdd_r_curr_min : 3;
|
||||
unsigned char c_size_low : 2;
|
||||
// byte 9
|
||||
unsigned char c_size_mult_high : 2;
|
||||
unsigned char vdd_w_cur_max : 3;
|
||||
unsigned char vdd_w_curr_min : 3;
|
||||
// byte 10
|
||||
unsigned char sector_size_high : 6;
|
||||
unsigned char erase_blk_en : 1;
|
||||
unsigned char c_size_mult_low : 1;
|
||||
// byte 11
|
||||
unsigned char wp_grp_size : 7;
|
||||
unsigned char sector_size_low : 1;
|
||||
// byte 12
|
||||
unsigned char write_bl_len_high : 2;
|
||||
unsigned char r2w_factor : 3;
|
||||
unsigned char reserved3 : 2;
|
||||
unsigned char wp_grp_enable : 1;
|
||||
// byte 13
|
||||
unsigned char reserved4 : 5;
|
||||
unsigned char write_partial : 1;
|
||||
unsigned char write_bl_len_low : 2;
|
||||
// byte 14
|
||||
unsigned char reserved5: 2;
|
||||
unsigned char file_format : 2;
|
||||
unsigned char tmp_write_protect : 1;
|
||||
unsigned char perm_write_protect : 1;
|
||||
unsigned char copy : 1;
|
||||
/** Indicates the file format on the card */
|
||||
unsigned char file_format_grp : 1;
|
||||
// byte 15
|
||||
unsigned char always1 : 1;
|
||||
unsigned char crc : 7;
|
||||
} csd1_t;
|
||||
|
||||
/** CSD for version 2.00 cards */
|
||||
typedef struct CSDV2 {
|
||||
// byte 0
|
||||
unsigned char reserved1 : 6;
|
||||
unsigned char csd_ver : 2;
|
||||
// byte 1
|
||||
/** fixed to 0x0E */
|
||||
unsigned char taac;
|
||||
// byte 2
|
||||
/** fixed to 0 */
|
||||
unsigned char nsac;
|
||||
// byte 3
|
||||
unsigned char tran_speed;
|
||||
// byte 4
|
||||
unsigned char ccc_high;
|
||||
// byte 5
|
||||
/** This field is fixed to 9h, which indicates READ_BL_LEN=512 Byte */
|
||||
unsigned char read_bl_len : 4;
|
||||
unsigned char ccc_low : 4;
|
||||
// byte 6
|
||||
/** not used */
|
||||
unsigned char reserved2 : 4;
|
||||
unsigned char dsr_imp : 1;
|
||||
/** fixed to 0 */
|
||||
unsigned char read_blk_misalign : 1;
|
||||
/** fixed to 0 */
|
||||
unsigned char write_blk_misalign : 1;
|
||||
/** fixed to 0 - no partial read */
|
||||
unsigned char read_bl_partial : 1;
|
||||
// byte 7
|
||||
/** not used */
|
||||
unsigned char reserved3 : 2;
|
||||
/** high part of card size */
|
||||
unsigned char c_size_high : 6;
|
||||
// byte 8
|
||||
/** middle part of card size */
|
||||
unsigned char c_size_mid;
|
||||
// byte 9
|
||||
/** low part of card size */
|
||||
unsigned char c_size_low;
|
||||
// byte 10
|
||||
/** sector size is fixed at 64 KB */
|
||||
unsigned char sector_size_high : 6;
|
||||
/** fixed to 1 - erase single is supported */
|
||||
unsigned char erase_blk_en : 1;
|
||||
/** not used */
|
||||
unsigned char reserved4 : 1;
|
||||
// byte 11
|
||||
unsigned char wp_grp_size : 7;
|
||||
/** sector size is fixed at 64 KB */
|
||||
unsigned char sector_size_low : 1;
|
||||
// byte 12
|
||||
/** write_bl_len fixed for 512 byte blocks */
|
||||
unsigned char write_bl_len_high : 2;
|
||||
/** fixed value of 2 */
|
||||
unsigned char r2w_factor : 3;
|
||||
/** not used */
|
||||
unsigned char reserved5 : 2;
|
||||
/** fixed value of 0 - no write protect groups */
|
||||
unsigned char wp_grp_enable : 1;
|
||||
// byte 13
|
||||
unsigned char reserved6 : 5;
|
||||
/** always zero - no partial block read*/
|
||||
unsigned char write_partial : 1;
|
||||
/** write_bl_len fixed for 512 byte blocks */
|
||||
unsigned char write_bl_len_low : 2;
|
||||
// byte 14
|
||||
unsigned char reserved7: 2;
|
||||
/** Do not use always 0 */
|
||||
unsigned char file_format : 2;
|
||||
unsigned char tmp_write_protect : 1;
|
||||
unsigned char perm_write_protect : 1;
|
||||
unsigned char copy : 1;
|
||||
/** Do not use always 0 */
|
||||
unsigned char file_format_grp : 1;
|
||||
// byte 15
|
||||
/** not used always 1 */
|
||||
unsigned char always1 : 1;
|
||||
/** checksum */
|
||||
unsigned char crc : 7;
|
||||
} csd2_t;
|
||||
|
||||
/** union of old and new style CSD register */
|
||||
union csd_t {
|
||||
csd1_t v1;
|
||||
csd2_t v2;
|
||||
};
|
405
Marlin Firmware/Marlin/src/sd/SdVolume.cpp
Normal file
405
Marlin Firmware/Marlin/src/sd/SdVolume.cpp
Normal file
@ -0,0 +1,405 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* sd/SdVolume.cpp
|
||||
*
|
||||
* Arduino SdFat Library
|
||||
* Copyright (c) 2009 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino Sd2Card Library
|
||||
*/
|
||||
|
||||
#include "../inc/MarlinConfig.h"
|
||||
|
||||
#if ENABLED(SDSUPPORT)
|
||||
|
||||
#include "SdVolume.h"
|
||||
|
||||
#include "../MarlinCore.h"
|
||||
|
||||
#if !USE_MULTIPLE_CARDS
|
||||
// raw block cache
|
||||
uint32_t SdVolume::cacheBlockNumber_; // current block number
|
||||
cache_t SdVolume::cacheBuffer_; // 512 byte cache for Sd2Card
|
||||
DiskIODriver *SdVolume::sdCard_; // pointer to SD card object
|
||||
bool SdVolume::cacheDirty_; // cacheFlush() will write block if true
|
||||
uint32_t SdVolume::cacheMirrorBlock_; // mirror block for second FAT
|
||||
#endif
|
||||
|
||||
// find a contiguous group of clusters
|
||||
bool SdVolume::allocContiguous(uint32_t count, uint32_t *curCluster) {
|
||||
if (ENABLED(SDCARD_READONLY)) return false;
|
||||
|
||||
// start of group
|
||||
uint32_t bgnCluster;
|
||||
// end of group
|
||||
uint32_t endCluster;
|
||||
// last cluster of FAT
|
||||
uint32_t fatEnd = clusterCount_ + 1;
|
||||
|
||||
// flag to save place to start next search
|
||||
bool setStart;
|
||||
|
||||
// set search start cluster
|
||||
if (*curCluster) {
|
||||
// try to make file contiguous
|
||||
bgnCluster = *curCluster + 1;
|
||||
|
||||
// don't save new start location
|
||||
setStart = false;
|
||||
}
|
||||
else {
|
||||
// start at likely place for free cluster
|
||||
bgnCluster = allocSearchStart_;
|
||||
|
||||
// save next search start if one cluster
|
||||
setStart = count == 1;
|
||||
}
|
||||
// end of group
|
||||
endCluster = bgnCluster;
|
||||
|
||||
// search the FAT for free clusters
|
||||
for (uint32_t n = 0;; n++, endCluster++) {
|
||||
// can't find space checked all clusters
|
||||
if (n >= clusterCount_) return false;
|
||||
|
||||
// past end - start from beginning of FAT
|
||||
if (endCluster > fatEnd) {
|
||||
bgnCluster = endCluster = 2;
|
||||
}
|
||||
uint32_t f;
|
||||
if (!fatGet(endCluster, &f)) return false;
|
||||
|
||||
if (f != 0) {
|
||||
// cluster in use try next cluster as bgnCluster
|
||||
bgnCluster = endCluster + 1;
|
||||
}
|
||||
else if ((endCluster - bgnCluster + 1) == count) {
|
||||
// done - found space
|
||||
break;
|
||||
}
|
||||
}
|
||||
// mark end of chain
|
||||
if (!fatPutEOC(endCluster)) return false;
|
||||
|
||||
// link clusters
|
||||
while (endCluster > bgnCluster) {
|
||||
if (!fatPut(endCluster - 1, endCluster)) return false;
|
||||
endCluster--;
|
||||
}
|
||||
if (*curCluster != 0) {
|
||||
// connect chains
|
||||
if (!fatPut(*curCluster, bgnCluster)) return false;
|
||||
}
|
||||
// return first cluster number to caller
|
||||
*curCluster = bgnCluster;
|
||||
|
||||
// remember possible next free cluster
|
||||
if (setStart) allocSearchStart_ = bgnCluster + 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SdVolume::cacheFlush() {
|
||||
#if DISABLED(SDCARD_READONLY)
|
||||
if (cacheDirty_) {
|
||||
if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_.data))
|
||||
return false;
|
||||
|
||||
// mirror FAT tables
|
||||
if (cacheMirrorBlock_) {
|
||||
if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data))
|
||||
return false;
|
||||
cacheMirrorBlock_ = 0;
|
||||
}
|
||||
cacheDirty_ = 0;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SdVolume::cacheRawBlock(uint32_t blockNumber, bool dirty) {
|
||||
if (cacheBlockNumber_ != blockNumber) {
|
||||
if (!cacheFlush()) return false;
|
||||
if (!sdCard_->readBlock(blockNumber, cacheBuffer_.data)) return false;
|
||||
cacheBlockNumber_ = blockNumber;
|
||||
}
|
||||
if (dirty) cacheDirty_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// return the size in bytes of a cluster chain
|
||||
bool SdVolume::chainSize(uint32_t cluster, uint32_t *size) {
|
||||
uint32_t s = 0;
|
||||
do {
|
||||
if (!fatGet(cluster, &cluster)) return false;
|
||||
s += 512UL << clusterSizeShift_;
|
||||
} while (!isEOC(cluster));
|
||||
*size = s;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fetch a FAT entry
|
||||
bool SdVolume::fatGet(uint32_t cluster, uint32_t *value) {
|
||||
uint32_t lba;
|
||||
if (cluster > (clusterCount_ + 1)) return false;
|
||||
if (FAT12_SUPPORT && fatType_ == 12) {
|
||||
uint16_t index = cluster;
|
||||
index += index >> 1;
|
||||
lba = fatStartBlock_ + (index >> 9);
|
||||
if (!cacheRawBlock(lba, CACHE_FOR_READ)) return false;
|
||||
index &= 0x1FF;
|
||||
uint16_t tmp = cacheBuffer_.data[index];
|
||||
index++;
|
||||
if (index == 512) {
|
||||
if (!cacheRawBlock(lba + 1, CACHE_FOR_READ)) return false;
|
||||
index = 0;
|
||||
}
|
||||
tmp |= cacheBuffer_.data[index] << 8;
|
||||
*value = cluster & 1 ? tmp >> 4 : tmp & 0xFFF;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fatType_ == 16)
|
||||
lba = fatStartBlock_ + (cluster >> 8);
|
||||
else if (fatType_ == 32)
|
||||
lba = fatStartBlock_ + (cluster >> 7);
|
||||
else
|
||||
return false;
|
||||
|
||||
if (lba != cacheBlockNumber_ && !cacheRawBlock(lba, CACHE_FOR_READ))
|
||||
return false;
|
||||
|
||||
*value = (fatType_ == 16) ? cacheBuffer_.fat16[cluster & 0xFF] : (cacheBuffer_.fat32[cluster & 0x7F] & FAT32MASK);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Store a FAT entry
|
||||
bool SdVolume::fatPut(uint32_t cluster, uint32_t value) {
|
||||
if (ENABLED(SDCARD_READONLY)) return false;
|
||||
|
||||
uint32_t lba;
|
||||
// error if reserved cluster
|
||||
if (cluster < 2) return false;
|
||||
|
||||
// error if not in FAT
|
||||
if (cluster > (clusterCount_ + 1)) return false;
|
||||
|
||||
if (FAT12_SUPPORT && fatType_ == 12) {
|
||||
uint16_t index = cluster;
|
||||
index += index >> 1;
|
||||
lba = fatStartBlock_ + (index >> 9);
|
||||
if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) return false;
|
||||
// mirror second FAT
|
||||
if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
|
||||
index &= 0x1FF;
|
||||
uint8_t tmp = value;
|
||||
if (cluster & 1) {
|
||||
tmp = (cacheBuffer_.data[index] & 0xF) | tmp << 4;
|
||||
}
|
||||
cacheBuffer_.data[index] = tmp;
|
||||
index++;
|
||||
if (index == 512) {
|
||||
lba++;
|
||||
index = 0;
|
||||
if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) return false;
|
||||
// mirror second FAT
|
||||
if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
|
||||
}
|
||||
tmp = value >> 4;
|
||||
if (!(cluster & 1)) {
|
||||
tmp = ((cacheBuffer_.data[index] & 0xF0)) | tmp >> 4;
|
||||
}
|
||||
cacheBuffer_.data[index] = tmp;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fatType_ == 16)
|
||||
lba = fatStartBlock_ + (cluster >> 8);
|
||||
else if (fatType_ == 32)
|
||||
lba = fatStartBlock_ + (cluster >> 7);
|
||||
else
|
||||
return false;
|
||||
|
||||
if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) return false;
|
||||
|
||||
// store entry
|
||||
if (fatType_ == 16)
|
||||
cacheBuffer_.fat16[cluster & 0xFF] = value;
|
||||
else
|
||||
cacheBuffer_.fat32[cluster & 0x7F] = value;
|
||||
|
||||
// mirror second FAT
|
||||
if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
|
||||
return true;
|
||||
}
|
||||
|
||||
// free a cluster chain
|
||||
bool SdVolume::freeChain(uint32_t cluster) {
|
||||
// clear free cluster location
|
||||
allocSearchStart_ = 2;
|
||||
|
||||
do {
|
||||
uint32_t next;
|
||||
if (!fatGet(cluster, &next)) return false;
|
||||
|
||||
// free cluster
|
||||
if (!fatPut(cluster, 0)) return false;
|
||||
|
||||
cluster = next;
|
||||
} while (!isEOC(cluster));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Volume free space in clusters.
|
||||
*
|
||||
* \return Count of free clusters for success or -1 if an error occurs.
|
||||
*/
|
||||
int32_t SdVolume::freeClusterCount() {
|
||||
uint32_t free = 0;
|
||||
uint16_t n;
|
||||
uint32_t todo = clusterCount_ + 2;
|
||||
|
||||
if (fatType_ == 16)
|
||||
n = 256;
|
||||
else if (fatType_ == 32)
|
||||
n = 128;
|
||||
else // put FAT12 here
|
||||
return -1;
|
||||
|
||||
for (uint32_t lba = fatStartBlock_; todo; todo -= n, lba++) {
|
||||
if (!cacheRawBlock(lba, CACHE_FOR_READ)) return -1;
|
||||
NOMORE(n, todo);
|
||||
if (fatType_ == 16) {
|
||||
for (uint16_t i = 0; i < n; i++)
|
||||
if (cacheBuffer_.fat16[i] == 0) free++;
|
||||
}
|
||||
else {
|
||||
for (uint16_t i = 0; i < n; i++)
|
||||
if (cacheBuffer_.fat32[i] == 0) free++;
|
||||
}
|
||||
#ifdef ESP32
|
||||
// Needed to reset the idle task watchdog timer on ESP32 as reading the complete FAT may easily
|
||||
// block for 10+ seconds. yield() is insufficient since it blocks lower prio tasks (e.g., idle).
|
||||
static millis_t nextTaskTime = 0;
|
||||
const millis_t ms = millis();
|
||||
if (ELAPSED(ms, nextTaskTime)) {
|
||||
vTaskDelay(1); // delay 1 tick (Minimum. Usually 10 or 1 ms depending on skdconfig.h)
|
||||
nextTaskTime = ms + 1000; // tickle the task manager again in 1 second
|
||||
}
|
||||
#endif // ESP32
|
||||
}
|
||||
return free;
|
||||
}
|
||||
|
||||
/** Initialize a FAT volume.
|
||||
*
|
||||
* \param[in] dev The SD card where the volume is located.
|
||||
*
|
||||
* \param[in] part The partition to be used. Legal values for \a part are
|
||||
* 1-4 to use the corresponding partition on a device formatted with
|
||||
* a MBR, Master Boot Record, or zero if the device is formatted as
|
||||
* a super floppy with the FAT boot sector in block zero.
|
||||
*
|
||||
* \return true for success, false for failure.
|
||||
* Reasons for failure include not finding a valid partition, not finding a valid
|
||||
* FAT file system in the specified partition or an I/O error.
|
||||
*/
|
||||
bool SdVolume::init(DiskIODriver* dev, uint8_t part) {
|
||||
uint32_t totalBlocks, volumeStartBlock = 0;
|
||||
fat32_boot_t *fbs;
|
||||
|
||||
sdCard_ = dev;
|
||||
fatType_ = 0;
|
||||
allocSearchStart_ = 2;
|
||||
cacheDirty_ = 0; // cacheFlush() will write block if true
|
||||
cacheMirrorBlock_ = 0;
|
||||
cacheBlockNumber_ = 0xFFFFFFFF;
|
||||
|
||||
// if part == 0 assume super floppy with FAT boot sector in block zero
|
||||
// if part > 0 assume mbr volume with partition table
|
||||
if (part) {
|
||||
if (part > 4) return false;
|
||||
if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) return false;
|
||||
part_t *p = &cacheBuffer_.mbr.part[part - 1];
|
||||
if ((p->boot & 0x7F) != 0 || p->totalSectors < 100 || p->firstSector == 0)
|
||||
return false; // not a valid partition
|
||||
volumeStartBlock = p->firstSector;
|
||||
}
|
||||
if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) return false;
|
||||
fbs = &cacheBuffer_.fbs32;
|
||||
if (fbs->bytesPerSector != 512 ||
|
||||
fbs->fatCount == 0 ||
|
||||
fbs->reservedSectorCount == 0 ||
|
||||
fbs->sectorsPerCluster == 0) {
|
||||
// not valid FAT volume
|
||||
return false;
|
||||
}
|
||||
fatCount_ = fbs->fatCount;
|
||||
blocksPerCluster_ = fbs->sectorsPerCluster;
|
||||
// determine shift that is same as multiply by blocksPerCluster_
|
||||
clusterSizeShift_ = 0;
|
||||
while (blocksPerCluster_ != _BV(clusterSizeShift_)) {
|
||||
// error if not power of 2
|
||||
if (clusterSizeShift_++ > 7) return false;
|
||||
}
|
||||
blocksPerFat_ = fbs->sectorsPerFat16 ?
|
||||
fbs->sectorsPerFat16 : fbs->sectorsPerFat32;
|
||||
|
||||
fatStartBlock_ = volumeStartBlock + fbs->reservedSectorCount;
|
||||
|
||||
// count for FAT16 zero for FAT32
|
||||
rootDirEntryCount_ = fbs->rootDirEntryCount;
|
||||
|
||||
// directory start for FAT16 dataStart for FAT32
|
||||
rootDirStart_ = fatStartBlock_ + fbs->fatCount * blocksPerFat_;
|
||||
|
||||
// data start for FAT16 and FAT32
|
||||
dataStartBlock_ = rootDirStart_ + ((32 * fbs->rootDirEntryCount + 511) / 512);
|
||||
|
||||
// total blocks for FAT16 or FAT32
|
||||
totalBlocks = fbs->totalSectors16 ?
|
||||
fbs->totalSectors16 : fbs->totalSectors32;
|
||||
|
||||
// total data blocks
|
||||
clusterCount_ = totalBlocks - (dataStartBlock_ - volumeStartBlock);
|
||||
|
||||
// divide by cluster size to get cluster count
|
||||
clusterCount_ >>= clusterSizeShift_;
|
||||
|
||||
// FAT type is determined by cluster count
|
||||
if (clusterCount_ < 4085) {
|
||||
fatType_ = 12;
|
||||
if (!FAT12_SUPPORT) return false;
|
||||
}
|
||||
else if (clusterCount_ < 65525)
|
||||
fatType_ = 16;
|
||||
else {
|
||||
rootDirStart_ = fbs->fat32RootCluster;
|
||||
fatType_ = 32;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // SDSUPPORT
|
201
Marlin Firmware/Marlin/src/sd/SdVolume.h
Normal file
201
Marlin Firmware/Marlin/src/sd/SdVolume.h
Normal file
@ -0,0 +1,201 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* sd/SdVolume.h
|
||||
*
|
||||
* Arduino SdFat Library
|
||||
* Copyright (c) 2009 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino Sd2Card Library
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../inc/MarlinConfigPre.h"
|
||||
|
||||
#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
|
||||
#include "usb_flashdrive/Sd2Card_FlashDrive.h"
|
||||
#endif
|
||||
|
||||
#if NEED_SD2CARD_SDIO
|
||||
#include "Sd2Card_sdio.h"
|
||||
#elif NEED_SD2CARD_SPI
|
||||
#include "Sd2Card.h"
|
||||
#endif
|
||||
|
||||
#include "SdFatConfig.h"
|
||||
#include "SdFatStructs.h"
|
||||
|
||||
//==============================================================================
|
||||
// SdVolume class
|
||||
|
||||
/**
|
||||
* \brief Cache for an SD data block
|
||||
*/
|
||||
union cache_t {
|
||||
uint8_t data[512]; // Used to access cached file data blocks.
|
||||
uint16_t fat16[256]; // Used to access cached FAT16 entries.
|
||||
uint32_t fat32[128]; // Used to access cached FAT32 entries.
|
||||
dir_t dir[16]; // Used to access cached directory entries.
|
||||
mbr_t mbr; // Used to access a cached Master Boot Record.
|
||||
fat_boot_t fbs; // Used to access to a cached FAT boot sector.
|
||||
fat32_boot_t fbs32; // Used to access to a cached FAT32 boot sector.
|
||||
fat32_fsinfo_t fsinfo; // Used to access to a cached FAT32 FSINFO sector.
|
||||
};
|
||||
|
||||
/**
|
||||
* \class SdVolume
|
||||
* \brief Access FAT16 and FAT32 volumes on SD and SDHC cards.
|
||||
*/
|
||||
class SdVolume {
|
||||
public:
|
||||
// Create an instance of SdVolume
|
||||
SdVolume() : fatType_(0) {}
|
||||
/**
|
||||
* Clear the cache and returns a pointer to the cache. Used by the WaveRP
|
||||
* recorder to do raw write to the SD card. Not for normal apps.
|
||||
* \return A pointer to the cache buffer or zero if an error occurs.
|
||||
*/
|
||||
cache_t* cacheClear() {
|
||||
if (!cacheFlush()) return 0;
|
||||
cacheBlockNumber_ = 0xFFFFFFFF;
|
||||
return &cacheBuffer_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a FAT volume. Try partition one first then try super
|
||||
* floppy format.
|
||||
*
|
||||
* \param[in] dev The DiskIODriver where the volume is located.
|
||||
*
|
||||
* \return true for success, false for failure.
|
||||
* Reasons for failure include not finding a valid partition, not finding
|
||||
* a valid FAT file system or an I/O error.
|
||||
*/
|
||||
bool init(DiskIODriver *dev) { return init(dev, 1) || init(dev, 0); }
|
||||
bool init(DiskIODriver *dev, uint8_t part);
|
||||
|
||||
// inline functions that return volume info
|
||||
uint8_t blocksPerCluster() const { return blocksPerCluster_; } //> \return The volume's cluster size in blocks.
|
||||
uint32_t blocksPerFat() const { return blocksPerFat_; } //> \return The number of blocks in one FAT.
|
||||
uint32_t clusterCount() const { return clusterCount_; } //> \return The total number of clusters in the volume.
|
||||
uint8_t clusterSizeShift() const { return clusterSizeShift_; } //> \return The shift count required to multiply by blocksPerCluster.
|
||||
uint32_t dataStartBlock() const { return dataStartBlock_; } //> \return The logical block number for the start of file data.
|
||||
uint8_t fatCount() const { return fatCount_; } //> \return The number of FAT structures on the volume.
|
||||
uint32_t fatStartBlock() const { return fatStartBlock_; } //> \return The logical block number for the start of the first FAT.
|
||||
uint8_t fatType() const { return fatType_; } //> \return The FAT type of the volume. Values are 12, 16 or 32.
|
||||
int32_t freeClusterCount();
|
||||
uint32_t rootDirEntryCount() const { return rootDirEntryCount_; } /** \return The number of entries in the root directory for FAT16 volumes. */
|
||||
|
||||
/**
|
||||
* \return The logical block number for the start of the root directory
|
||||
* on FAT16 volumes or the first cluster number on FAT32 volumes.
|
||||
*/
|
||||
uint32_t rootDirStart() const { return rootDirStart_; }
|
||||
|
||||
/**
|
||||
* DiskIODriver object for this volume
|
||||
* \return pointer to DiskIODriver object.
|
||||
*/
|
||||
DiskIODriver* sdCard() { return sdCard_; }
|
||||
|
||||
/**
|
||||
* Debug access to FAT table
|
||||
*
|
||||
* \param[in] n cluster number.
|
||||
* \param[out] v value of entry
|
||||
* \return true for success or false for failure
|
||||
*/
|
||||
bool dbgFat(uint32_t n, uint32_t *v) { return fatGet(n, v); }
|
||||
|
||||
private:
|
||||
// Allow SdBaseFile access to SdVolume private data.
|
||||
friend class SdBaseFile;
|
||||
|
||||
// value for dirty argument in cacheRawBlock to indicate read from cache
|
||||
static bool const CACHE_FOR_READ = false;
|
||||
// value for dirty argument in cacheRawBlock to indicate write to cache
|
||||
static bool const CACHE_FOR_WRITE = true;
|
||||
|
||||
#if USE_MULTIPLE_CARDS
|
||||
cache_t cacheBuffer_; // 512 byte cache for device blocks
|
||||
uint32_t cacheBlockNumber_; // Logical number of block in the cache
|
||||
DiskIODriver *sdCard_; // DiskIODriver object for cache
|
||||
bool cacheDirty_; // cacheFlush() will write block if true
|
||||
uint32_t cacheMirrorBlock_; // block number for mirror FAT
|
||||
#else
|
||||
static cache_t cacheBuffer_; // 512 byte cache for device blocks
|
||||
static uint32_t cacheBlockNumber_; // Logical number of block in the cache
|
||||
static DiskIODriver *sdCard_; // DiskIODriver object for cache
|
||||
static bool cacheDirty_; // cacheFlush() will write block if true
|
||||
static uint32_t cacheMirrorBlock_; // block number for mirror FAT
|
||||
#endif
|
||||
|
||||
uint32_t allocSearchStart_; // start cluster for alloc search
|
||||
uint8_t blocksPerCluster_; // cluster size in blocks
|
||||
uint32_t blocksPerFat_; // FAT size in blocks
|
||||
uint32_t clusterCount_; // clusters in one FAT
|
||||
uint8_t clusterSizeShift_; // shift to convert cluster count to block count
|
||||
uint32_t dataStartBlock_; // first data block number
|
||||
uint8_t fatCount_; // number of FATs on volume
|
||||
uint32_t fatStartBlock_; // start block for first FAT
|
||||
uint8_t fatType_; // volume type (12, 16, OR 32)
|
||||
uint16_t rootDirEntryCount_; // number of entries in FAT16 root dir
|
||||
uint32_t rootDirStart_; // root start block for FAT16, cluster for FAT32
|
||||
|
||||
bool allocContiguous(uint32_t count, uint32_t *curCluster);
|
||||
uint8_t blockOfCluster(uint32_t position) const { return (position >> 9) & (blocksPerCluster_ - 1); }
|
||||
uint32_t clusterStartBlock(uint32_t cluster) const { return dataStartBlock_ + ((cluster - 2) << clusterSizeShift_); }
|
||||
uint32_t blockNumber(uint32_t cluster, uint32_t position) const { return clusterStartBlock(cluster) + blockOfCluster(position); }
|
||||
|
||||
cache_t* cache() { return &cacheBuffer_; }
|
||||
uint32_t cacheBlockNumber() const { return cacheBlockNumber_; }
|
||||
|
||||
#if USE_MULTIPLE_CARDS
|
||||
bool cacheFlush();
|
||||
bool cacheRawBlock(uint32_t blockNumber, bool dirty);
|
||||
#else
|
||||
static bool cacheFlush();
|
||||
static bool cacheRawBlock(uint32_t blockNumber, bool dirty);
|
||||
#endif
|
||||
|
||||
// used by SdBaseFile write to assign cache to SD location
|
||||
void cacheSetBlockNumber(uint32_t blockNumber, bool dirty) {
|
||||
cacheDirty_ = dirty;
|
||||
cacheBlockNumber_ = blockNumber;
|
||||
}
|
||||
void cacheSetDirty() { cacheDirty_ |= CACHE_FOR_WRITE; }
|
||||
bool chainSize(uint32_t beginCluster, uint32_t *size);
|
||||
bool fatGet(uint32_t cluster, uint32_t *value);
|
||||
bool fatPut(uint32_t cluster, uint32_t value);
|
||||
bool fatPutEOC(uint32_t cluster) { return fatPut(cluster, 0x0FFFFFFF); }
|
||||
bool freeChain(uint32_t cluster);
|
||||
bool isEOC(uint32_t cluster) const {
|
||||
if (FAT12_SUPPORT && fatType_ == 12) return cluster >= FAT12EOC_MIN;
|
||||
if (fatType_ == 16) return cluster >= FAT16EOC_MIN;
|
||||
return cluster >= FAT32EOC_MIN;
|
||||
}
|
||||
bool readBlock(uint32_t block, uint8_t *dst) { return sdCard_->readBlock(block, dst); }
|
||||
bool writeBlock(uint32_t block, const uint8_t *dst) { return sdCard_->writeBlock(block, dst); }
|
||||
};
|
1302
Marlin Firmware/Marlin/src/sd/cardreader.cpp
Normal file
1302
Marlin Firmware/Marlin/src/sd/cardreader.cpp
Normal file
File diff suppressed because it is too large
Load Diff
365
Marlin Firmware/Marlin/src/sd/cardreader.h
Normal file
365
Marlin Firmware/Marlin/src/sd/cardreader.h
Normal file
@ -0,0 +1,365 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../inc/MarlinConfig.h"
|
||||
|
||||
#if ENABLED(SDSUPPORT)
|
||||
|
||||
extern const char M23_STR[], M24_STR[];
|
||||
|
||||
#if BOTH(SDCARD_SORT_ALPHA, SDSORT_DYNAMIC_RAM)
|
||||
#define SD_RESORT 1
|
||||
#endif
|
||||
|
||||
#if ENABLED(SDCARD_RATHERRECENTFIRST) && DISABLED(SDCARD_SORT_ALPHA)
|
||||
#define SD_ORDER(N,C) ((C) - 1 - (N))
|
||||
#else
|
||||
#define SD_ORDER(N,C) N
|
||||
#endif
|
||||
|
||||
#define MAX_DIR_DEPTH 10 // Maximum folder depth
|
||||
#define MAXDIRNAMELENGTH 8 // DOS folder name size
|
||||
#define MAXPATHNAMELENGTH (1 + (MAXDIRNAMELENGTH + 1) * (MAX_DIR_DEPTH) + 1 + FILENAME_LENGTH) // "/" + N * ("ADIRNAME/") + "filename.ext"
|
||||
|
||||
#include "SdFile.h"
|
||||
#include "disk_io_driver.h"
|
||||
|
||||
#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
|
||||
#include "usb_flashdrive/Sd2Card_FlashDrive.h"
|
||||
#endif
|
||||
|
||||
#if NEED_SD2CARD_SDIO
|
||||
#include "Sd2Card_sdio.h"
|
||||
#elif NEED_SD2CARD_SPI
|
||||
#include "Sd2Card.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(MULTI_VOLUME)
|
||||
#define SV_SD_ONBOARD 1
|
||||
#define SV_USB_FLASH_DRIVE 2
|
||||
#define _VOLUME_ID(N) _CAT(SV_, N)
|
||||
#define SHARED_VOLUME_IS(N) (DEFAULT_SHARED_VOLUME == _VOLUME_ID(N))
|
||||
#if !SHARED_VOLUME_IS(SD_ONBOARD) && !SHARED_VOLUME_IS(USB_FLASH_DRIVE)
|
||||
#error "DEFAULT_SHARED_VOLUME must be either SD_ONBOARD or USB_FLASH_DRIVE."
|
||||
#endif
|
||||
#else
|
||||
#define SHARED_VOLUME_IS(...) 0
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
bool saving:1,
|
||||
logging:1,
|
||||
sdprinting:1,
|
||||
sdprintdone:1,
|
||||
mounted:1,
|
||||
filenameIsDir:1,
|
||||
workDirIsRoot:1,
|
||||
abort_sd_printing:1
|
||||
#if ENABLED(BINARY_FILE_TRANSFER)
|
||||
, binary_mode:1
|
||||
#endif
|
||||
;
|
||||
} card_flags_t;
|
||||
|
||||
#if ENABLED(AUTO_REPORT_SD_STATUS)
|
||||
#include "../libs/autoreport.h"
|
||||
#endif
|
||||
|
||||
class CardReader {
|
||||
public:
|
||||
static card_flags_t flag; // Flags (above)
|
||||
static char filename[FILENAME_LENGTH], // DOS 8.3 filename of the selected item
|
||||
longFilename[LONG_FILENAME_LENGTH]; // Long name of the selected item
|
||||
|
||||
// Fast! binary file transfer
|
||||
#if ENABLED(BINARY_FILE_TRANSFER)
|
||||
#if HAS_MULTI_SERIAL
|
||||
static serial_index_t transfer_port_index;
|
||||
#else
|
||||
static constexpr serial_index_t transfer_port_index = 0;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// // // Methods // // //
|
||||
|
||||
CardReader();
|
||||
|
||||
static void changeMedia(DiskIODriver *_driver) { driver = _driver; }
|
||||
|
||||
static SdFile getroot() { return root; }
|
||||
|
||||
static void mount();
|
||||
static void release();
|
||||
static inline bool isMounted() { return flag.mounted; }
|
||||
|
||||
// Handle media insert/remove
|
||||
static void manage_media();
|
||||
|
||||
// SD Card Logging
|
||||
static void openLogFile(const char * const path);
|
||||
static void write_command(char * const buf);
|
||||
|
||||
#if DISABLED(NO_SD_AUTOSTART) // Auto-Start auto#.g file handling
|
||||
static uint8_t autofile_index; // Next auto#.g index to run, plus one. Ignored by autofile_check when zero.
|
||||
static void autofile_begin(); // Begin check. Called automatically after boot-up.
|
||||
static bool autofile_check(); // Check for the next auto-start file and run it.
|
||||
static inline void autofile_cancel() { autofile_index = 0; }
|
||||
#endif
|
||||
|
||||
// Basic file ops
|
||||
static void openFileRead(const char * const path, const uint8_t subcall=0);
|
||||
static void openFileWrite(const char * const path);
|
||||
static void closefile(const bool store_location=false);
|
||||
static bool fileExists(const char * const name);
|
||||
static void removeFile(const char * const name);
|
||||
|
||||
static inline char* longest_filename() { return longFilename[0] ? longFilename : filename; }
|
||||
#if ENABLED(LONG_FILENAME_HOST_SUPPORT)
|
||||
static void printLongPath(char * const path); // Used by M33
|
||||
#endif
|
||||
|
||||
// Working Directory for SD card menu
|
||||
static void cdroot();
|
||||
static void cd(const char *relpath);
|
||||
static int8_t cdup();
|
||||
static uint16_t countFilesInWorkDir();
|
||||
static uint16_t get_num_Files();
|
||||
|
||||
// Select a file
|
||||
static void selectFileByIndex(const uint16_t nr);
|
||||
static void selectFileByName(const char * const match); // (working directory only)
|
||||
|
||||
// Print job
|
||||
static void report_status();
|
||||
static void getAbsFilenameInCWD(char *dst);
|
||||
static void printSelectedFilename();
|
||||
static void openAndPrintFile(const char *name); // (working directory or full path)
|
||||
static void startOrResumeFilePrinting();
|
||||
static void endFilePrintNow(TERN_(SD_RESORT, const bool re_sort=false));
|
||||
static void abortFilePrintNow(TERN_(SD_RESORT, const bool re_sort=false));
|
||||
static void fileHasFinished();
|
||||
static inline void abortFilePrintSoon() { flag.abort_sd_printing = true; }
|
||||
static inline void pauseSDPrint() { flag.sdprinting = false; }
|
||||
static inline bool isPrinting() { return flag.sdprinting; }
|
||||
static inline bool isPaused() { return isFileOpen() && !isPrinting(); }
|
||||
#if HAS_PRINT_PROGRESS_PERMYRIAD
|
||||
static inline uint16_t permyriadDone() {
|
||||
if (flag.sdprintdone) return 10000;
|
||||
if (isFileOpen() && filesize) return sdpos / ((filesize + 9999) / 10000);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
static inline uint8_t percentDone() {
|
||||
if (flag.sdprintdone) return 100;
|
||||
if (isFileOpen() && filesize) return sdpos / ((filesize + 99) / 100);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dive down to a relative or absolute path.
|
||||
* Relative paths apply to the workDir.
|
||||
*
|
||||
* update_cwd: Pass 'true' to update the workDir on success.
|
||||
* inDirPtr: On exit your pointer points to the target SdFile.
|
||||
* A nullptr indicates failure.
|
||||
* path: Start with '/' for abs path. End with '/' to get a folder ref.
|
||||
* echo: Set 'true' to print the path throughout the loop.
|
||||
*/
|
||||
static const char* diveToFile(const bool update_cwd, SdFile* &inDirPtr, const char * const path, const bool echo=false);
|
||||
|
||||
#if ENABLED(SDCARD_SORT_ALPHA)
|
||||
static void presort();
|
||||
static void getfilename_sorted(const uint16_t nr);
|
||||
#if ENABLED(SDSORT_GCODE)
|
||||
FORCE_INLINE static void setSortOn(bool b) { sort_alpha = b; presort(); }
|
||||
FORCE_INLINE static void setSortFolders(int i) { sort_folders = i; presort(); }
|
||||
//FORCE_INLINE static void setSortReverse(bool b) { sort_reverse = b; }
|
||||
#endif
|
||||
#else
|
||||
FORCE_INLINE static void getfilename_sorted(const uint16_t nr) { selectFileByIndex(nr); }
|
||||
#endif
|
||||
|
||||
static void ls();
|
||||
|
||||
#if ENABLED(POWER_LOSS_RECOVERY)
|
||||
static bool jobRecoverFileExists();
|
||||
static void openJobRecoveryFile(const bool read);
|
||||
static void removeJobRecoveryFile();
|
||||
#endif
|
||||
|
||||
// Current Working Dir - Set by cd, cdup, cdroot, and diveToFile(true, ...)
|
||||
static inline char* getWorkDirName() { workDir.getDosName(filename); return filename; }
|
||||
static inline SdFile& getWorkDir() { return workDir.isOpen() ? workDir : root; }
|
||||
|
||||
// Print File stats
|
||||
static inline uint32_t getFileSize() { return filesize; }
|
||||
static inline uint32_t getIndex() { return sdpos; }
|
||||
static inline bool isFileOpen() { return isMounted() && file.isOpen(); }
|
||||
static inline bool eof() { return getIndex() >= getFileSize(); }
|
||||
|
||||
// File data operations
|
||||
static inline int16_t get() { int16_t out = (int16_t)file.read(); sdpos = file.curPosition(); return out; }
|
||||
static inline int16_t read(void *buf, uint16_t nbyte) { return file.isOpen() ? file.read(buf, nbyte) : -1; }
|
||||
static inline int16_t write(void *buf, uint16_t nbyte) { return file.isOpen() ? file.write(buf, nbyte) : -1; }
|
||||
static inline void setIndex(const uint32_t index) { file.seekSet((sdpos = index)); }
|
||||
|
||||
// TODO: rename to diskIODriver()
|
||||
static DiskIODriver* diskIODriver() { return driver; }
|
||||
|
||||
#if ENABLED(AUTO_REPORT_SD_STATUS)
|
||||
//
|
||||
// SD Auto Reporting
|
||||
//
|
||||
struct AutoReportSD { static void report() { report_status(); } };
|
||||
static AutoReporter<AutoReportSD> auto_reporter;
|
||||
#endif
|
||||
|
||||
#if SHARED_VOLUME_IS(USB_FLASH_DRIVE) || ENABLED(USB_FLASH_DRIVE_SUPPORT)
|
||||
#define HAS_USB_FLASH_DRIVE 1
|
||||
static DiskIODriver_USBFlash media_driver_usbFlash;
|
||||
#endif
|
||||
|
||||
#if NEED_SD2CARD_SDIO || NEED_SD2CARD_SPI
|
||||
typedef TERN(NEED_SD2CARD_SDIO, DiskIODriver_SDIO, DiskIODriver_SPI_SD) sdcard_driver_t;
|
||||
static sdcard_driver_t media_driver_sdcard;
|
||||
#endif
|
||||
|
||||
private:
|
||||
//
|
||||
// Working directory and parents
|
||||
//
|
||||
static SdFile root, workDir, workDirParents[MAX_DIR_DEPTH];
|
||||
static uint8_t workDirDepth;
|
||||
|
||||
//
|
||||
// Alphabetical file and folder sorting
|
||||
//
|
||||
#if ENABLED(SDCARD_SORT_ALPHA)
|
||||
static uint16_t sort_count; // Count of sorted items in the current directory
|
||||
#if ENABLED(SDSORT_GCODE)
|
||||
static bool sort_alpha; // Flag to enable / disable the feature
|
||||
static int sort_folders; // Folder sorting before/none/after
|
||||
//static bool sort_reverse; // Flag to enable / disable reverse sorting
|
||||
#endif
|
||||
|
||||
// By default the sort index is static
|
||||
#if ENABLED(SDSORT_DYNAMIC_RAM)
|
||||
static uint8_t *sort_order;
|
||||
#else
|
||||
static uint8_t sort_order[SDSORT_LIMIT];
|
||||
#endif
|
||||
|
||||
#if BOTH(SDSORT_USES_RAM, SDSORT_CACHE_NAMES) && DISABLED(SDSORT_DYNAMIC_RAM)
|
||||
#define SORTED_LONGNAME_MAXLEN (SDSORT_CACHE_VFATS) * (FILENAME_LENGTH)
|
||||
#define SORTED_LONGNAME_STORAGE (SORTED_LONGNAME_MAXLEN + 1)
|
||||
#else
|
||||
#define SORTED_LONGNAME_MAXLEN LONG_FILENAME_LENGTH
|
||||
#define SORTED_LONGNAME_STORAGE SORTED_LONGNAME_MAXLEN
|
||||
#endif
|
||||
|
||||
// Cache filenames to speed up SD menus.
|
||||
#if ENABLED(SDSORT_USES_RAM)
|
||||
|
||||
// If using dynamic ram for names, allocate on the heap.
|
||||
#if ENABLED(SDSORT_CACHE_NAMES)
|
||||
static uint16_t nrFiles; // Cache the total count
|
||||
#if ENABLED(SDSORT_DYNAMIC_RAM)
|
||||
static char **sortshort, **sortnames;
|
||||
#else
|
||||
static char sortshort[SDSORT_LIMIT][FILENAME_LENGTH];
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (ENABLED(SDSORT_CACHE_NAMES) && DISABLED(SDSORT_DYNAMIC_RAM)) || NONE(SDSORT_CACHE_NAMES, SDSORT_USES_STACK)
|
||||
static char sortnames[SDSORT_LIMIT][SORTED_LONGNAME_STORAGE];
|
||||
#endif
|
||||
|
||||
// Folder sorting uses an isDir array when caching items.
|
||||
#if HAS_FOLDER_SORTING
|
||||
#if ENABLED(SDSORT_DYNAMIC_RAM)
|
||||
static uint8_t *isDir;
|
||||
#elif ENABLED(SDSORT_CACHE_NAMES) || DISABLED(SDSORT_USES_STACK)
|
||||
static uint8_t isDir[(SDSORT_LIMIT + 7) >> 3];
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // SDSORT_USES_RAM
|
||||
|
||||
#endif // SDCARD_SORT_ALPHA
|
||||
|
||||
static DiskIODriver *driver;
|
||||
static SdVolume volume;
|
||||
static SdFile file;
|
||||
|
||||
static uint32_t filesize, // Total size of the current file, in bytes
|
||||
sdpos; // Index most recently read (one behind file.getPos)
|
||||
|
||||
//
|
||||
// Procedure calls to other files
|
||||
//
|
||||
#if HAS_MEDIA_SUBCALLS
|
||||
static uint8_t file_subcall_ctr;
|
||||
static uint32_t filespos[SD_PROCEDURE_DEPTH];
|
||||
static char proc_filenames[SD_PROCEDURE_DEPTH][MAXPATHNAMELENGTH];
|
||||
#endif
|
||||
|
||||
//
|
||||
// Directory items
|
||||
//
|
||||
static bool is_dir_or_gcode(const dir_t &p);
|
||||
static int countItems(SdFile dir);
|
||||
static void selectByIndex(SdFile dir, const uint8_t index);
|
||||
static void selectByName(SdFile dir, const char * const match);
|
||||
static void printListing(SdFile parent, const char * const prepend=nullptr);
|
||||
|
||||
#if ENABLED(SDCARD_SORT_ALPHA)
|
||||
static void flush_presort();
|
||||
#endif
|
||||
};
|
||||
|
||||
#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
|
||||
#define IS_SD_INSERTED() DiskIODriver_USBFlash::isInserted()
|
||||
#elif PIN_EXISTS(SD_DETECT)
|
||||
#define IS_SD_INSERTED() (READ(SD_DETECT_PIN) == SD_DETECT_STATE)
|
||||
#else
|
||||
// No card detect line? Assume the card is inserted.
|
||||
#define IS_SD_INSERTED() true
|
||||
#endif
|
||||
|
||||
#define IS_SD_PRINTING() (card.flag.sdprinting && !card.flag.abort_sd_printing)
|
||||
#define IS_SD_FETCHING() (!card.flag.sdprintdone && IS_SD_PRINTING())
|
||||
#define IS_SD_PAUSED() card.isPaused()
|
||||
#define IS_SD_FILE_OPEN() card.isFileOpen()
|
||||
|
||||
extern CardReader card;
|
||||
|
||||
#else // !SDSUPPORT
|
||||
|
||||
#define IS_SD_PRINTING() false
|
||||
#define IS_SD_FETCHING() false
|
||||
#define IS_SD_PAUSED() false
|
||||
#define IS_SD_FILE_OPEN() false
|
||||
|
||||
#define LONG_FILENAME_LENGTH 0
|
||||
|
||||
#endif // !SDSUPPORT
|
67
Marlin Firmware/Marlin/src/sd/disk_io_driver.h
Normal file
67
Marlin Firmware/Marlin/src/sd/disk_io_driver.h
Normal file
@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* DiskIO Interace
|
||||
*
|
||||
* Interface for low level disk io
|
||||
*/
|
||||
class DiskIODriver {
|
||||
public:
|
||||
/**
|
||||
* Initialize an SD flash memory card with default clock rate and chip
|
||||
* select pin. See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin).
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
virtual bool init(const uint8_t sckRateID, const pin_t chipSelectPin) = 0; //TODO: only for SPI
|
||||
|
||||
/**
|
||||
* Read a card's CSD register. The CSD contains Card-Specific Data that
|
||||
* provides information regarding access to the card's contents.
|
||||
*
|
||||
* \param[out] csd pointer to area for returned data.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
virtual bool readCSD(csd_t* csd) = 0;
|
||||
|
||||
virtual bool readStart(const uint32_t block) = 0;
|
||||
virtual bool readData(uint8_t* dst) = 0;
|
||||
virtual bool readStop() = 0;
|
||||
|
||||
virtual bool writeStart(const uint32_t block, const uint32_t) = 0;
|
||||
virtual bool writeData(const uint8_t* src) = 0;
|
||||
virtual bool writeStop() = 0;
|
||||
|
||||
virtual bool readBlock(uint32_t block, uint8_t* dst) = 0;
|
||||
virtual bool writeBlock(uint32_t blockNumber, const uint8_t* src) = 0;
|
||||
|
||||
virtual uint32_t cardSize() = 0;
|
||||
|
||||
virtual bool isReady() = 0;
|
||||
|
||||
virtual void idle() = 0;
|
||||
};
|
@ -0,0 +1,326 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../inc/MarlinConfigPre.h"
|
||||
|
||||
/**
|
||||
* Adjust USB_DEBUG to select debugging verbosity.
|
||||
* 0 - no debug messages
|
||||
* 1 - basic insertion/removal messages
|
||||
* 2 - show USB state transitions
|
||||
* 3 - perform block range checking
|
||||
* 4 - print each block access
|
||||
*/
|
||||
#define USB_DEBUG 1
|
||||
#define USB_STARTUP_DELAY 0
|
||||
|
||||
// uncomment to get 'printf' console debugging. NOT FOR UNO!
|
||||
//#define HOST_DEBUG(...) {char s[255]; sprintf(s,__VA_ARGS__); SERIAL_ECHOLNPAIR("UHS:",s);}
|
||||
//#define BS_HOST_DEBUG(...) {char s[255]; sprintf(s,__VA_ARGS__); SERIAL_ECHOLNPAIR("UHS:",s);}
|
||||
//#define MAX_HOST_DEBUG(...) {char s[255]; sprintf(s,__VA_ARGS__); SERIAL_ECHOLNPAIR("UHS:",s);}
|
||||
|
||||
#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
|
||||
|
||||
#include "../../MarlinCore.h"
|
||||
#include "../../core/serial.h"
|
||||
#include "../../module/temperature.h"
|
||||
|
||||
#if DISABLED(USE_OTG_USB_HOST) && !PINS_EXIST(USB_CS, USB_INTR)
|
||||
#error "USB_FLASH_DRIVE_SUPPORT requires USB_CS_PIN and USB_INTR_PIN to be defined."
|
||||
#endif
|
||||
|
||||
#if ENABLED(USE_UHS3_USB)
|
||||
#define NO_AUTO_SPEED
|
||||
#define UHS_MAX3421E_SPD 8000000 >> SD_SPI_SPEED
|
||||
#define UHS_DEVICE_WINDOWS_USB_SPEC_VIOLATION_DESCRIPTOR_DEVICE 1
|
||||
#define UHS_HOST_MAX_INTERFACE_DRIVERS 2
|
||||
#define MASS_MAX_SUPPORTED_LUN 1
|
||||
#define USB_HOST_SERIAL MYSERIAL1
|
||||
|
||||
// Workaround for certain issues with UHS3
|
||||
#define SKIP_PAGE3F // Required for IOGEAR media adapter
|
||||
#define USB_NO_TEST_UNIT_READY // Required for removable media adapter
|
||||
#define USB_HOST_MANUAL_POLL // Optimization to shut off IRQ automatically
|
||||
|
||||
// Workarounds for keeping Marlin's watchdog timer from barking...
|
||||
void marlin_yield() {
|
||||
thermalManager.manage_heater();
|
||||
}
|
||||
#define SYSTEM_OR_SPECIAL_YIELD(...) marlin_yield();
|
||||
#define delay(x) safe_delay(x)
|
||||
|
||||
#define LOAD_USB_HOST_SYSTEM
|
||||
#define LOAD_USB_HOST_SHIELD
|
||||
#define LOAD_UHS_BULK_STORAGE
|
||||
|
||||
#define MARLIN_UHS_WRITE_SS(v) WRITE(USB_CS_PIN, v)
|
||||
#define MARLIN_UHS_READ_IRQ() READ(USB_INTR_PIN)
|
||||
|
||||
#include "lib-uhs3/UHS_host/UHS_host.h"
|
||||
|
||||
MAX3421E_HOST usb(USB_CS_PIN, USB_INTR_PIN);
|
||||
UHS_Bulk_Storage bulk(&usb);
|
||||
|
||||
#define UHS_START (usb.Init() == 0)
|
||||
#define UHS_STATE(state) UHS_USB_HOST_STATE_##state
|
||||
#elif ENABLED(USE_OTG_USB_HOST)
|
||||
|
||||
#if HAS_SD_HOST_DRIVE
|
||||
#include HAL_PATH(../../HAL, msc_sd.h)
|
||||
#endif
|
||||
|
||||
#include HAL_PATH(../../HAL, usb_host.h)
|
||||
|
||||
#define UHS_START usb.start()
|
||||
#define rREVISION 0
|
||||
#define UHS_STATE(state) USB_STATE_##state
|
||||
#else
|
||||
#include "lib-uhs2/Usb.h"
|
||||
#include "lib-uhs2/masstorage.h"
|
||||
|
||||
USB usb;
|
||||
BulkOnly bulk(&usb);
|
||||
|
||||
#define UHS_START usb.start()
|
||||
#define UHS_STATE(state) USB_STATE_##state
|
||||
#endif
|
||||
|
||||
#include "Sd2Card_FlashDrive.h"
|
||||
|
||||
#include "../../lcd/marlinui.h"
|
||||
|
||||
static enum {
|
||||
UNINITIALIZED,
|
||||
DO_STARTUP,
|
||||
WAIT_FOR_DEVICE,
|
||||
WAIT_FOR_LUN,
|
||||
MEDIA_READY,
|
||||
MEDIA_ERROR
|
||||
} state;
|
||||
|
||||
#if USB_DEBUG >= 3
|
||||
uint32_t lun0_capacity;
|
||||
#endif
|
||||
|
||||
bool DiskIODriver_USBFlash::usbStartup() {
|
||||
if (state <= DO_STARTUP) {
|
||||
SERIAL_ECHOPGM("Starting USB host...");
|
||||
if (!UHS_START) {
|
||||
SERIAL_ECHOLNPGM(" failed.");
|
||||
LCD_MESSAGEPGM(MSG_MEDIA_USB_FAILED);
|
||||
return false;
|
||||
}
|
||||
|
||||
// SPI quick test - check revision register
|
||||
switch (usb.regRd(rREVISION)) {
|
||||
case 0x01: SERIAL_ECHOLNPGM("rev.01 started"); break;
|
||||
case 0x12: SERIAL_ECHOLNPGM("rev.02 started"); break;
|
||||
case 0x13: SERIAL_ECHOLNPGM("rev.03 started"); break;
|
||||
default: SERIAL_ECHOLNPGM("started. rev unknown."); break;
|
||||
}
|
||||
state = WAIT_FOR_DEVICE;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// The USB library needs to be called periodically to detect USB thumbdrive
|
||||
// insertion and removals. Call this idle() function periodically to allow
|
||||
// the USB library to monitor for such events. This function also takes care
|
||||
// of initializing the USB library for the first time.
|
||||
|
||||
void DiskIODriver_USBFlash::idle() {
|
||||
usb.Task();
|
||||
|
||||
const uint8_t task_state = usb.getUsbTaskState();
|
||||
|
||||
#if USB_DEBUG >= 2
|
||||
if (state > DO_STARTUP) {
|
||||
static uint8_t laststate = 232;
|
||||
if (task_state != laststate) {
|
||||
laststate = task_state;
|
||||
#define UHS_USB_DEBUG(x) case UHS_STATE(x): SERIAL_ECHOLNPGM(#x); break
|
||||
switch (task_state) {
|
||||
UHS_USB_DEBUG(IDLE);
|
||||
UHS_USB_DEBUG(RESET_DEVICE);
|
||||
UHS_USB_DEBUG(RESET_NOT_COMPLETE);
|
||||
UHS_USB_DEBUG(DEBOUNCE);
|
||||
UHS_USB_DEBUG(DEBOUNCE_NOT_COMPLETE);
|
||||
UHS_USB_DEBUG(WAIT_SOF);
|
||||
UHS_USB_DEBUG(ERROR);
|
||||
UHS_USB_DEBUG(CONFIGURING);
|
||||
UHS_USB_DEBUG(CONFIGURING_DONE);
|
||||
UHS_USB_DEBUG(RUNNING);
|
||||
default:
|
||||
SERIAL_ECHOLNPAIR("UHS_USB_HOST_STATE: ", task_state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static millis_t next_state_ms = millis();
|
||||
|
||||
#define GOTO_STATE_AFTER_DELAY(STATE, DELAY) do{ state = STATE; next_state_ms = millis() + DELAY; }while(0)
|
||||
|
||||
if (ELAPSED(millis(), next_state_ms)) {
|
||||
GOTO_STATE_AFTER_DELAY(state, 250); // Default delay
|
||||
|
||||
switch (state) {
|
||||
|
||||
case UNINITIALIZED:
|
||||
#ifndef MANUAL_USB_STARTUP
|
||||
GOTO_STATE_AFTER_DELAY( DO_STARTUP, USB_STARTUP_DELAY );
|
||||
#endif
|
||||
break;
|
||||
|
||||
case DO_STARTUP: usbStartup(); break;
|
||||
|
||||
case WAIT_FOR_DEVICE:
|
||||
if (task_state == UHS_STATE(RUNNING)) {
|
||||
#if USB_DEBUG >= 1
|
||||
SERIAL_ECHOLNPGM("USB device inserted");
|
||||
#endif
|
||||
GOTO_STATE_AFTER_DELAY( WAIT_FOR_LUN, 250 );
|
||||
}
|
||||
break;
|
||||
|
||||
case WAIT_FOR_LUN:
|
||||
/* USB device is inserted, but if it is an SD card,
|
||||
* adapter it may not have an SD card in it yet. */
|
||||
if (bulk.LUNIsGood(0)) {
|
||||
#if USB_DEBUG >= 1
|
||||
SERIAL_ECHOLNPGM("LUN is good");
|
||||
#endif
|
||||
GOTO_STATE_AFTER_DELAY( MEDIA_READY, 100 );
|
||||
}
|
||||
else {
|
||||
#ifdef USB_HOST_MANUAL_POLL
|
||||
// Make sure we catch disconnect events
|
||||
usb.busprobe();
|
||||
usb.VBUS_changed();
|
||||
#endif
|
||||
#if USB_DEBUG >= 1
|
||||
SERIAL_ECHOLNPGM("Waiting for media");
|
||||
#endif
|
||||
LCD_MESSAGEPGM(MSG_MEDIA_WAITING);
|
||||
GOTO_STATE_AFTER_DELAY(state, 2000);
|
||||
}
|
||||
break;
|
||||
|
||||
case MEDIA_READY: break;
|
||||
case MEDIA_ERROR: break;
|
||||
}
|
||||
|
||||
if (state > WAIT_FOR_DEVICE && task_state != UHS_STATE(RUNNING)) {
|
||||
// Handle device removal events
|
||||
#if USB_DEBUG >= 1
|
||||
SERIAL_ECHOLNPGM("USB device removed");
|
||||
#endif
|
||||
if (state != MEDIA_READY)
|
||||
LCD_MESSAGEPGM(MSG_MEDIA_USB_REMOVED);
|
||||
GOTO_STATE_AFTER_DELAY(WAIT_FOR_DEVICE, 0);
|
||||
}
|
||||
|
||||
else if (state > WAIT_FOR_LUN && !bulk.LUNIsGood(0)) {
|
||||
// Handle media removal events
|
||||
#if USB_DEBUG >= 1
|
||||
SERIAL_ECHOLNPGM("Media removed");
|
||||
#endif
|
||||
LCD_MESSAGEPGM(MSG_MEDIA_REMOVED);
|
||||
GOTO_STATE_AFTER_DELAY(WAIT_FOR_DEVICE, 0);
|
||||
}
|
||||
|
||||
else if (task_state == UHS_STATE(ERROR)) {
|
||||
LCD_MESSAGEPGM(MSG_MEDIA_READ_ERROR);
|
||||
GOTO_STATE_AFTER_DELAY(MEDIA_ERROR, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Marlin calls this function to check whether an USB drive is inserted.
|
||||
// This is equivalent to polling the SD_DETECT when using SD cards.
|
||||
bool DiskIODriver_USBFlash::isInserted() {
|
||||
return state == MEDIA_READY;
|
||||
}
|
||||
|
||||
bool DiskIODriver_USBFlash::isReady() {
|
||||
return state > DO_STARTUP && usb.getUsbTaskState() == UHS_STATE(RUNNING);
|
||||
}
|
||||
|
||||
// Marlin calls this to initialize an SD card once it is inserted.
|
||||
bool DiskIODriver_USBFlash::init(const uint8_t, const pin_t) {
|
||||
if (!isInserted()) return false;
|
||||
|
||||
#if USB_DEBUG >= 1
|
||||
const uint32_t sectorSize = bulk.GetSectorSize(0);
|
||||
if (sectorSize != 512) {
|
||||
SERIAL_ECHOLNPAIR("Expecting sector size of 512. Got: ", sectorSize);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if USB_DEBUG >= 3
|
||||
lun0_capacity = bulk.GetCapacity(0);
|
||||
SERIAL_ECHOLNPAIR("LUN Capacity (in blocks): ", lun0_capacity);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns the capacity of the card in blocks.
|
||||
uint32_t DiskIODriver_USBFlash::cardSize() {
|
||||
if (!isInserted()) return false;
|
||||
#if USB_DEBUG < 3
|
||||
const uint32_t
|
||||
#endif
|
||||
lun0_capacity = bulk.GetCapacity(0);
|
||||
return lun0_capacity;
|
||||
}
|
||||
|
||||
bool DiskIODriver_USBFlash::readBlock(uint32_t block, uint8_t *dst) {
|
||||
if (!isInserted()) return false;
|
||||
#if USB_DEBUG >= 3
|
||||
if (block >= lun0_capacity) {
|
||||
SERIAL_ECHOLNPAIR("Attempt to read past end of LUN: ", block);
|
||||
return false;
|
||||
}
|
||||
#if USB_DEBUG >= 4
|
||||
SERIAL_ECHOLNPAIR("Read block ", block);
|
||||
#endif
|
||||
#endif
|
||||
return bulk.Read(0, block, 512, 1, dst) == 0;
|
||||
}
|
||||
|
||||
bool DiskIODriver_USBFlash::writeBlock(uint32_t block, const uint8_t *src) {
|
||||
if (!isInserted()) return false;
|
||||
#if USB_DEBUG >= 3
|
||||
if (block >= lun0_capacity) {
|
||||
SERIAL_ECHOLNPAIR("Attempt to write past end of LUN: ", block);
|
||||
return false;
|
||||
}
|
||||
#if USB_DEBUG >= 4
|
||||
SERIAL_ECHOLNPAIR("Write block ", block);
|
||||
#endif
|
||||
#endif
|
||||
return bulk.Write(0, block, 512, 1, src) == 0;
|
||||
}
|
||||
|
||||
#endif // USB_FLASH_DRIVE_SUPPORT
|
@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief Sd2Card class for USB Flash Drive
|
||||
*/
|
||||
#include "../SdFatConfig.h"
|
||||
#include "../SdInfo.h"
|
||||
#include "../disk_io_driver.h"
|
||||
|
||||
#if DISABLED(USE_OTG_USB_HOST)
|
||||
/**
|
||||
* Define SOFTWARE_SPI to use bit-bang SPI
|
||||
*/
|
||||
#if EITHER(MEGA_SOFT_SPI, USE_SOFTWARE_SPI)
|
||||
#define SOFTWARE_SPI
|
||||
#endif
|
||||
|
||||
// SPI pin definitions - do not edit here - change in SdFatConfig.h
|
||||
#if ENABLED(SOFTWARE_SPI)
|
||||
#warning "Auto-assigning '10' as the SD_CHIP_SELECT_PIN."
|
||||
#define SD_CHIP_SELECT_PIN 10 // Software SPI chip select pin for the SD
|
||||
#else
|
||||
// hardware pin defs
|
||||
#define SD_CHIP_SELECT_PIN SD_SS_PIN // The default chip select pin for the SD card is SS.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class DiskIODriver_USBFlash : public DiskIODriver {
|
||||
private:
|
||||
uint32_t pos;
|
||||
|
||||
static void usbStateDebug();
|
||||
|
||||
public:
|
||||
static bool usbStartup();
|
||||
static bool isInserted();
|
||||
|
||||
bool init(const uint8_t sckRateID=0, const pin_t chipSelectPin=TERN(USE_OTG_USB_HOST, 0, SD_CHIP_SELECT_PIN)) override;
|
||||
|
||||
inline bool readCSD(csd_t*) override { return true; }
|
||||
|
||||
inline bool readStart(const uint32_t block) override { pos = block; return isReady(); }
|
||||
inline bool readData(uint8_t *dst) override { return readBlock(pos++, dst); }
|
||||
inline bool readStop() override { return true; }
|
||||
|
||||
inline bool writeStart(const uint32_t block, const uint32_t) override { pos = block; return isReady(); }
|
||||
inline bool writeData(const uint8_t *src) override { return writeBlock(pos++, src); }
|
||||
inline bool writeStop() override { return true; }
|
||||
|
||||
bool readBlock(uint32_t block, uint8_t *dst) override;
|
||||
bool writeBlock(uint32_t blockNumber, const uint8_t *src) override;
|
||||
|
||||
uint32_t cardSize() override;
|
||||
|
||||
bool isReady() override;
|
||||
|
||||
void idle() override;
|
||||
};
|
@ -0,0 +1,46 @@
|
||||
|
||||
==== USB HOST SHIELD 2.0 LIBRARY ====
|
||||
|
||||
The lib/ folder contains a subset of the files from the USB Host Shield 2.0
|
||||
library:
|
||||
|
||||
https://github.com/felis/USB_Host_Shield_2.0
|
||||
|
||||
While the original library was released under the GPLv2 and could not be
|
||||
commingled with Marlin, the developers have graciously re-licenced the
|
||||
files needed for Marlin as "GPLv2 or later", as documented in this thread.
|
||||
|
||||
https://github.com/felis/USB_Host_Shield_2.0/issues/364
|
||||
|
||||
Small modifications have been made to the source. Please search for
|
||||
USB_FLASH_DRIVE_SUPPORT or look at the patch file to see what was changed.
|
||||
|
||||
==== LICENSE SUMMARY ====
|
||||
|
||||
Source Path: Repository: License:
|
||||
------------ ----------- --------
|
||||
lib-uhs3/ github.com/felis/USB_Host_Shield_2.0 GPLv2 or later
|
||||
lib-uhs3/lib/masstorage.cpp github.com/greiman/UsbFat [1] MIT
|
||||
lib-uhs3/lib/settings.h github.com/greiman/UsbFat [1] MIT
|
||||
|
||||
[1] Changes related to SKIP_WRITE_PROTECT and DELAY only
|
||||
|
||||
==== PERFORMANCE ENHANCEMENTS FOR USB DRIVES ====
|
||||
|
||||
There are also some small performance enhancements from Bill Greiman, regarding
|
||||
SKIP_WRITE_PROTECT and DELAY. These changes came from the following repo:
|
||||
|
||||
https://github.com/greiman/UsbFat
|
||||
|
||||
While the original library was released under the GPLv2 and could not be
|
||||
commingled with Marlin, the developer has graciously re-licenced his changes
|
||||
under the "MIT" license, as documented here:
|
||||
|
||||
https://github.com/greiman/UsbFat/issues/8
|
||||
|
||||
==== MARLIN INTEGRATION WORK ====
|
||||
|
||||
All additional work done to integrate USB into Marlin was performed by AlephObjects, Inc.
|
||||
and is licensed under the GPLv3.
|
||||
|
||||
-- marcio@alephobjects.com
|
795
Marlin Firmware/Marlin/src/sd/usb_flashdrive/lib-uhs2/Usb.cpp
Normal file
795
Marlin Firmware/Marlin/src/sd/usb_flashdrive/lib-uhs2/Usb.cpp
Normal file
@ -0,0 +1,795 @@
|
||||
/**
|
||||
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
*
|
||||
* This program 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information
|
||||
* -------------------
|
||||
*
|
||||
* Circuits At Home, LTD
|
||||
* Web : https://www.circuitsathome.com
|
||||
* e-mail : support@circuitsathome.com
|
||||
*/
|
||||
|
||||
//
|
||||
// USB functions supporting Flash Drive
|
||||
//
|
||||
|
||||
#include "../../../inc/MarlinConfigPre.h"
|
||||
|
||||
#if ENABLED(USB_FLASH_DRIVE_SUPPORT) && DISABLED(USE_UHS3_USB)
|
||||
|
||||
#include "Usb.h"
|
||||
|
||||
static uint8_t usb_error = 0;
|
||||
static uint8_t usb_task_state;
|
||||
|
||||
/* constructor */
|
||||
USB::USB() : bmHubPre(0) {
|
||||
usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; // Set up state machine
|
||||
init();
|
||||
}
|
||||
|
||||
/* Initialize data structures */
|
||||
void USB::init() {
|
||||
//devConfigIndex = 0;
|
||||
bmHubPre = 0;
|
||||
}
|
||||
|
||||
uint8_t USB::getUsbTaskState() { return usb_task_state; }
|
||||
void USB::setUsbTaskState(uint8_t state) { usb_task_state = state; }
|
||||
|
||||
EpInfo* USB::getEpInfoEntry(uint8_t addr, uint8_t ep) {
|
||||
UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
|
||||
|
||||
if (!p || !p->epinfo)
|
||||
return nullptr;
|
||||
|
||||
EpInfo *pep = p->epinfo;
|
||||
|
||||
for (uint8_t i = 0; i < p->epcount; i++) {
|
||||
if ((pep)->epAddr == ep)
|
||||
return pep;
|
||||
|
||||
pep++;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set device table entry
|
||||
* Each device is different and has different number of endpoints.
|
||||
* This function plugs endpoint record structure, defined in application, to devtable
|
||||
*/
|
||||
uint8_t USB::setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr) {
|
||||
if (!eprecord_ptr)
|
||||
return USB_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
|
||||
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
|
||||
p->address.devAddress = addr;
|
||||
p->epinfo = eprecord_ptr;
|
||||
p->epcount = epcount;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t USB::SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t *nak_limit) {
|
||||
UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
|
||||
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
|
||||
if (!p->epinfo)
|
||||
return USB_ERROR_EPINFO_IS_NULL;
|
||||
|
||||
*ppep = getEpInfoEntry(addr, ep);
|
||||
|
||||
if (!*ppep)
|
||||
return USB_ERROR_EP_NOT_FOUND_IN_TBL;
|
||||
|
||||
*nak_limit = (0x0001UL << (((*ppep)->bmNakPower > USB_NAK_MAX_POWER) ? USB_NAK_MAX_POWER : (*ppep)->bmNakPower));
|
||||
(*nak_limit)--;
|
||||
/*
|
||||
USBTRACE2("\r\nAddress: ", addr);
|
||||
USBTRACE2(" EP: ", ep);
|
||||
USBTRACE2(" NAK Power: ",(*ppep)->bmNakPower);
|
||||
USBTRACE2(" NAK Limit: ", nak_limit);
|
||||
USBTRACE("\r\n");
|
||||
*/
|
||||
regWr(rPERADDR, addr); // Set peripheral address
|
||||
|
||||
uint8_t mode = regRd(rMODE);
|
||||
|
||||
//Serial.print("\r\nMode: ");
|
||||
//Serial.println( mode, HEX);
|
||||
//Serial.print("\r\nLS: ");
|
||||
//Serial.println(p->lowspeed, HEX);
|
||||
|
||||
// Set bmLOWSPEED and bmHUBPRE in case of low-speed device, reset them otherwise
|
||||
regWr(rMODE, (p->lowspeed) ? mode | bmLOWSPEED | bmHubPre : mode & ~(bmHUBPRE | bmLOWSPEED));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Control transfer. Sets address, endpoint, fills control packet with necessary data, dispatches control packet, and initiates bulk IN transfer, */
|
||||
/* depending on request. Actual requests are defined as inlines */
|
||||
/* return codes: */
|
||||
/* 00 = success */
|
||||
/* 01-0f = non-zero HRSLT */
|
||||
uint8_t USB::ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi,
|
||||
uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t *dataptr, USBReadParser *p) {
|
||||
bool direction = false; // Request direction, IN or OUT
|
||||
uint8_t rcode;
|
||||
SETUP_PKT setup_pkt;
|
||||
|
||||
EpInfo *pep = nullptr;
|
||||
uint16_t nak_limit = 0;
|
||||
|
||||
rcode = SetAddress(addr, ep, &pep, &nak_limit);
|
||||
if (rcode) return rcode;
|
||||
|
||||
direction = ((bmReqType & 0x80) > 0);
|
||||
|
||||
/* fill in setup packet */
|
||||
setup_pkt.ReqType_u.bmRequestType = bmReqType;
|
||||
setup_pkt.bRequest = bRequest;
|
||||
setup_pkt.wVal_u.wValueLo = wValLo;
|
||||
setup_pkt.wVal_u.wValueHi = wValHi;
|
||||
setup_pkt.wIndex = wInd;
|
||||
setup_pkt.wLength = total;
|
||||
|
||||
bytesWr(rSUDFIFO, 8, (uint8_t*) & setup_pkt); // Transfer to setup packet FIFO
|
||||
|
||||
rcode = dispatchPkt(tokSETUP, ep, nak_limit); // Dispatch packet
|
||||
if (rcode) return rcode; // Return HRSLT if not zero
|
||||
|
||||
if (dataptr) { // Data stage, if present
|
||||
if (direction) { // IN transfer
|
||||
uint16_t left = total;
|
||||
pep->bmRcvToggle = 1; // BmRCVTOG1;
|
||||
|
||||
while (left) {
|
||||
// Bytes read into buffer
|
||||
uint16_t read = nbytes;
|
||||
//uint16_t read = (left<nbytes) ? left : nbytes;
|
||||
|
||||
rcode = InTransfer(pep, nak_limit, &read, dataptr);
|
||||
if (rcode == hrTOGERR) {
|
||||
// Yes, we flip it wrong here so that next time it is actually correct!
|
||||
pep->bmRcvToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rcode) return rcode;
|
||||
|
||||
// Invoke callback function if inTransfer completed successfully and callback function pointer is specified
|
||||
if (!rcode && p) ((USBReadParser*)p)->Parse(read, dataptr, total - left);
|
||||
|
||||
left -= read;
|
||||
|
||||
if (read < nbytes) break;
|
||||
}
|
||||
}
|
||||
else { // OUT transfer
|
||||
pep->bmSndToggle = 1; // BmSNDTOG1;
|
||||
rcode = OutTransfer(pep, nak_limit, nbytes, dataptr);
|
||||
}
|
||||
if (rcode) return rcode; // Return error
|
||||
}
|
||||
// Status stage
|
||||
return dispatchPkt((direction) ? tokOUTHS : tokINHS, ep, nak_limit); // GET if direction
|
||||
}
|
||||
|
||||
/**
|
||||
* IN transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes.
|
||||
* Keep sending INs and writes data to memory area pointed by 'data'
|
||||
* rcode 0 if no errors. rcode 01-0f is relayed from dispatchPkt(). Rcode f0 means RCVDAVIRQ error, fe = USB xfer timeout
|
||||
*/
|
||||
uint8_t USB::inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t *data, uint8_t bInterval /*= 0*/) {
|
||||
EpInfo *pep = nullptr;
|
||||
uint16_t nak_limit = 0;
|
||||
|
||||
uint8_t rcode = SetAddress(addr, ep, &pep, &nak_limit);
|
||||
if (rcode) {
|
||||
USBTRACE3("(USB::InTransfer) SetAddress Failed ", rcode, 0x81);
|
||||
USBTRACE3("(USB::InTransfer) addr requested ", addr, 0x81);
|
||||
USBTRACE3("(USB::InTransfer) ep requested ", ep, 0x81);
|
||||
return rcode;
|
||||
}
|
||||
return InTransfer(pep, nak_limit, nbytesptr, data, bInterval);
|
||||
}
|
||||
|
||||
uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t *data, uint8_t bInterval /*= 0*/) {
|
||||
uint8_t rcode = 0;
|
||||
uint8_t pktsize;
|
||||
|
||||
uint16_t nbytes = *nbytesptr;
|
||||
//printf("Requesting %i bytes ", nbytes);
|
||||
uint8_t maxpktsize = pep->maxPktSize;
|
||||
|
||||
*nbytesptr = 0;
|
||||
regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); // Set toggle value
|
||||
|
||||
// Use a 'break' to exit this loop
|
||||
for (;;) {
|
||||
rcode = dispatchPkt(tokIN, pep->epAddr, nak_limit); // IN packet to EP-'endpoint'. Function takes care of NAKS.
|
||||
if (rcode == hrTOGERR) {
|
||||
// Yes, we flip it wrong here so that next time it is actually correct!
|
||||
pep->bmRcvToggle = (regRd(rHRSL) & bmRCVTOGRD) ? 0 : 1;
|
||||
regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); // Set toggle value
|
||||
continue;
|
||||
}
|
||||
if (rcode) {
|
||||
//printf(">>>>>>>> Problem! dispatchPkt %2.2x\r\n", rcode);
|
||||
break; // Should be 0, indicating ACK. Else return error code.
|
||||
}
|
||||
/* check for RCVDAVIRQ and generate error if not present */
|
||||
/* the only case when absence of RCVDAVIRQ makes sense is when toggle error occurred. Need to add handling for that */
|
||||
if ((regRd(rHIRQ) & bmRCVDAVIRQ) == 0) {
|
||||
//printf(">>>>>>>> Problem! NO RCVDAVIRQ!\r\n");
|
||||
rcode = 0xF0; // Receive error
|
||||
break;
|
||||
}
|
||||
pktsize = regRd(rRCVBC); // Number of received bytes
|
||||
//printf("Got %i bytes \r\n", pktsize);
|
||||
// This would be OK, but...
|
||||
//assert(pktsize <= nbytes);
|
||||
if (pktsize > nbytes) {
|
||||
// This can happen. Use of assert on Arduino locks up the Arduino.
|
||||
// So I will trim the value, and hope for the best.
|
||||
//printf(">>>>>>>> Problem! Wanted %i bytes but got %i.\r\n", nbytes, pktsize);
|
||||
pktsize = nbytes;
|
||||
}
|
||||
|
||||
int16_t mem_left = (int16_t)nbytes - *((int16_t*)nbytesptr);
|
||||
if (mem_left < 0) mem_left = 0;
|
||||
|
||||
data = bytesRd(rRCVFIFO, ((pktsize > mem_left) ? mem_left : pktsize), data);
|
||||
|
||||
regWr(rHIRQ, bmRCVDAVIRQ); // Clear the IRQ & free the buffer
|
||||
*nbytesptr += pktsize; // Add this packet's byte count to total transfer length
|
||||
|
||||
/* The transfer is complete under two conditions: */
|
||||
/* 1. The device sent a short packet (L.T. maxPacketSize) */
|
||||
/* 2. 'nbytes' have been transferred. */
|
||||
if (pktsize < maxpktsize || *nbytesptr >= nbytes) { // Transferred 'nbytes' bytes?
|
||||
// Save toggle value
|
||||
pep->bmRcvToggle = ((regRd(rHRSL) & bmRCVTOGRD)) ? 1 : 0;
|
||||
//printf("\r\n");
|
||||
rcode = 0;
|
||||
break;
|
||||
}
|
||||
else if (bInterval > 0)
|
||||
delay(bInterval); // Delay according to polling interval
|
||||
}
|
||||
return rcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* OUT transfer to arbitrary endpoint. Handles multiple packets if necessary. Transfers 'nbytes' bytes.
|
||||
* Handles NAK bug per Maxim Application Note 4000 for single buffer transfer
|
||||
* rcode 0 if no errors. rcode 01-0f is relayed from HRSL
|
||||
*/
|
||||
uint8_t USB::outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *data) {
|
||||
EpInfo *pep = nullptr;
|
||||
uint16_t nak_limit = 0;
|
||||
|
||||
uint8_t rcode = SetAddress(addr, ep, &pep, &nak_limit);
|
||||
if (rcode) return rcode;
|
||||
|
||||
return OutTransfer(pep, nak_limit, nbytes, data);
|
||||
}
|
||||
|
||||
uint8_t USB::OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data) {
|
||||
uint8_t rcode = hrSUCCESS, retry_count;
|
||||
uint8_t *data_p = data; // Local copy of the data pointer
|
||||
uint16_t bytes_tosend, nak_count;
|
||||
uint16_t bytes_left = nbytes;
|
||||
|
||||
uint8_t maxpktsize = pep->maxPktSize;
|
||||
|
||||
if (maxpktsize < 1 || maxpktsize > 64)
|
||||
return USB_ERROR_INVALID_MAX_PKT_SIZE;
|
||||
|
||||
uint32_t timeout = (uint32_t)millis() + USB_XFER_TIMEOUT;
|
||||
|
||||
regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); // Set toggle value
|
||||
|
||||
while (bytes_left) {
|
||||
retry_count = 0;
|
||||
nak_count = 0;
|
||||
bytes_tosend = (bytes_left >= maxpktsize) ? maxpktsize : bytes_left;
|
||||
bytesWr(rSNDFIFO, bytes_tosend, data_p); // Filling output FIFO
|
||||
regWr(rSNDBC, bytes_tosend); // Set number of bytes
|
||||
regWr(rHXFR, (tokOUT | pep->epAddr)); // Dispatch packet
|
||||
while (!(regRd(rHIRQ) & bmHXFRDNIRQ)); // Wait for the completion IRQ
|
||||
regWr(rHIRQ, bmHXFRDNIRQ); // Clear IRQ
|
||||
rcode = (regRd(rHRSL) & 0x0F);
|
||||
|
||||
while (rcode && ((int32_t)((uint32_t)millis() - timeout) < 0L)) {
|
||||
switch (rcode) {
|
||||
case hrNAK:
|
||||
nak_count++;
|
||||
if (nak_limit && (nak_count == nak_limit))
|
||||
goto breakout;
|
||||
//return rcode;
|
||||
break;
|
||||
case hrTIMEOUT:
|
||||
retry_count++;
|
||||
if (retry_count == USB_RETRY_LIMIT)
|
||||
goto breakout;
|
||||
//return rcode;
|
||||
break;
|
||||
case hrTOGERR:
|
||||
// Yes, we flip it wrong here so that next time it is actually correct!
|
||||
pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1;
|
||||
regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); // Set toggle value
|
||||
break;
|
||||
default:
|
||||
goto breakout;
|
||||
}
|
||||
|
||||
/* process NAK according to Host out NAK bug */
|
||||
regWr(rSNDBC, 0);
|
||||
regWr(rSNDFIFO, *data_p);
|
||||
regWr(rSNDBC, bytes_tosend);
|
||||
regWr(rHXFR, (tokOUT | pep->epAddr)); // Dispatch packet
|
||||
while (!(regRd(rHIRQ) & bmHXFRDNIRQ)); // Wait for the completion IRQ
|
||||
regWr(rHIRQ, bmHXFRDNIRQ); // Clear IRQ
|
||||
rcode = (regRd(rHRSL) & 0x0F);
|
||||
} // While rcode && ....
|
||||
bytes_left -= bytes_tosend;
|
||||
data_p += bytes_tosend;
|
||||
} // While bytes_left...
|
||||
breakout:
|
||||
|
||||
pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 1 : 0; // BmSNDTOG1 : bmSNDTOG0; // Update toggle
|
||||
return ( rcode); // Should be 0 in all cases
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch USB packet. Assumes peripheral address is set and relevant buffer is loaded/empty
|
||||
* If NAK, tries to re-send up to nak_limit times
|
||||
* If nak_limit == 0, do not count NAKs, exit after timeout
|
||||
* If bus timeout, re-sends up to USB_RETRY_LIMIT times
|
||||
* return codes 0x00-0x0F are HRSLT( 0x00 being success ), 0xFF means timeout
|
||||
*/
|
||||
uint8_t USB::dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit) {
|
||||
uint32_t timeout = (uint32_t)millis() + USB_XFER_TIMEOUT;
|
||||
uint8_t tmpdata;
|
||||
uint8_t rcode = hrSUCCESS;
|
||||
uint8_t retry_count = 0;
|
||||
uint16_t nak_count = 0;
|
||||
|
||||
while ((int32_t)((uint32_t)millis() - timeout) < 0L) {
|
||||
#if defined(ESP8266) || defined(ESP32)
|
||||
yield(); // Needed in order to reset the watchdog timer on the ESP8266
|
||||
#endif
|
||||
regWr(rHXFR, (token | ep)); // Launch the transfer
|
||||
rcode = USB_ERROR_TRANSFER_TIMEOUT;
|
||||
|
||||
while ((int32_t)((uint32_t)millis() - timeout) < 0L) { // Wait for transfer completion
|
||||
#if defined(ESP8266) || defined(ESP32)
|
||||
yield(); // Needed to reset the watchdog timer on the ESP8266
|
||||
#endif
|
||||
tmpdata = regRd(rHIRQ);
|
||||
|
||||
if (tmpdata & bmHXFRDNIRQ) {
|
||||
regWr(rHIRQ, bmHXFRDNIRQ); // Clear the interrupt
|
||||
rcode = 0x00;
|
||||
break;
|
||||
}
|
||||
|
||||
} // While millis() < timeout
|
||||
|
||||
//if (rcode != 0x00) return rcode; // Exit if timeout
|
||||
|
||||
rcode = (regRd(rHRSL) & 0x0F); // Analyze transfer result
|
||||
|
||||
switch (rcode) {
|
||||
case hrNAK:
|
||||
nak_count++;
|
||||
if (nak_limit && (nak_count == nak_limit))
|
||||
return (rcode);
|
||||
break;
|
||||
case hrTIMEOUT:
|
||||
retry_count++;
|
||||
if (retry_count == USB_RETRY_LIMIT)
|
||||
return (rcode);
|
||||
break;
|
||||
default:
|
||||
return (rcode);
|
||||
}
|
||||
|
||||
} // While timeout > millis()
|
||||
return rcode;
|
||||
}
|
||||
|
||||
// USB main task. Performs enumeration/cleanup
|
||||
void USB::Task() { // USB state machine
|
||||
uint8_t rcode;
|
||||
uint8_t tmpdata;
|
||||
static uint32_t delay = 0;
|
||||
//USB_FD_DEVICE_DESCRIPTOR buf;
|
||||
bool lowspeed = false;
|
||||
|
||||
MAX3421E::Task();
|
||||
|
||||
tmpdata = getVbusState();
|
||||
|
||||
/* modify USB task state if Vbus changed */
|
||||
switch (tmpdata) {
|
||||
case SE1: // Illegal state
|
||||
usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL;
|
||||
lowspeed = false;
|
||||
break;
|
||||
case SE0: // Disconnected
|
||||
if ((usb_task_state & USB_STATE_MASK) != USB_STATE_DETACHED)
|
||||
usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
|
||||
lowspeed = false;
|
||||
break;
|
||||
case LSHOST:
|
||||
lowspeed = true;
|
||||
// Intentional fallthrough
|
||||
case FSHOST: // Attached
|
||||
if ((usb_task_state & USB_STATE_MASK) == USB_STATE_DETACHED) {
|
||||
delay = (uint32_t)millis() + USB_SETTLE_DELAY;
|
||||
usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < USB_NUMDEVICES; i++)
|
||||
if (devConfig[i]) rcode = devConfig[i]->Poll();
|
||||
|
||||
switch (usb_task_state) {
|
||||
case USB_DETACHED_SUBSTATE_INITIALIZE:
|
||||
init();
|
||||
|
||||
for (uint8_t i = 0; i < USB_NUMDEVICES; i++)
|
||||
if (devConfig[i])
|
||||
rcode = devConfig[i]->Release();
|
||||
|
||||
usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE;
|
||||
break;
|
||||
case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE: // Just sit here
|
||||
break;
|
||||
case USB_DETACHED_SUBSTATE_ILLEGAL: // Just sit here
|
||||
break;
|
||||
case USB_ATTACHED_SUBSTATE_SETTLE: // Settle time for just attached device
|
||||
if ((int32_t)((uint32_t)millis() - delay) >= 0L)
|
||||
usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE;
|
||||
else break; // Don't fall through
|
||||
case USB_ATTACHED_SUBSTATE_RESET_DEVICE:
|
||||
regWr(rHCTL, bmBUSRST); // Issue bus reset
|
||||
usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE;
|
||||
break;
|
||||
case USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE:
|
||||
if ((regRd(rHCTL) & bmBUSRST) == 0) {
|
||||
tmpdata = regRd(rMODE) | bmSOFKAENAB; // Start SOF generation
|
||||
regWr(rMODE, tmpdata);
|
||||
usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF;
|
||||
//delay = (uint32_t)millis() + 20; // 20ms wait after reset per USB spec
|
||||
}
|
||||
break;
|
||||
case USB_ATTACHED_SUBSTATE_WAIT_SOF: // Todo: change check order
|
||||
if (regRd(rHIRQ) & bmFRAMEIRQ) {
|
||||
// When first SOF received _and_ 20ms has passed we can continue
|
||||
/*
|
||||
if (delay < (uint32_t)millis()) // 20ms passed
|
||||
usb_task_state = USB_STATE_CONFIGURING;
|
||||
*/
|
||||
usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET;
|
||||
delay = (uint32_t)millis() + 20;
|
||||
}
|
||||
break;
|
||||
case USB_ATTACHED_SUBSTATE_WAIT_RESET:
|
||||
if ((int32_t)((uint32_t)millis() - delay) >= 0L) usb_task_state = USB_STATE_CONFIGURING;
|
||||
else break; // Don't fall through
|
||||
case USB_STATE_CONFIGURING:
|
||||
|
||||
//Serial.print("\r\nConf.LS: ");
|
||||
//Serial.println(lowspeed, HEX);
|
||||
|
||||
rcode = Configuring(0, 0, lowspeed);
|
||||
|
||||
if (!rcode)
|
||||
usb_task_state = USB_STATE_RUNNING;
|
||||
else if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE) {
|
||||
usb_error = rcode;
|
||||
usb_task_state = USB_STATE_ERROR;
|
||||
}
|
||||
break;
|
||||
case USB_STATE_RUNNING:
|
||||
break;
|
||||
case USB_STATE_ERROR:
|
||||
//MAX3421E::Init();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t USB::DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed) {
|
||||
//uint8_t buf[12];
|
||||
uint8_t rcode;
|
||||
UsbDevice *p0 = nullptr, *p = nullptr;
|
||||
|
||||
// Get pointer to pseudo device with address 0 assigned
|
||||
p0 = addrPool.GetUsbDevicePtr(0);
|
||||
if (!p0) return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
if (!p0->epinfo) return USB_ERROR_EPINFO_IS_NULL;
|
||||
|
||||
p0->lowspeed = lowspeed;
|
||||
|
||||
// Allocate new address according to device class
|
||||
uint8_t bAddress = addrPool.AllocAddress(parent, false, port);
|
||||
if (!bAddress) return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
||||
|
||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||
if (!p) return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
|
||||
p->lowspeed = lowspeed;
|
||||
|
||||
// Assign new address to the device
|
||||
rcode = setAddr(0, 0, bAddress);
|
||||
if (rcode) {
|
||||
addrPool.FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
}
|
||||
return rcode;
|
||||
}
|
||||
|
||||
uint8_t USB::AttemptConfig(uint8_t driver, uint8_t parent, uint8_t port, bool lowspeed) {
|
||||
//printf("AttemptConfig: parent = %i, port = %i\r\n", parent, port);
|
||||
uint8_t retries = 0;
|
||||
|
||||
again:
|
||||
uint8_t rcode = devConfig[driver]->ConfigureDevice(parent, port, lowspeed);
|
||||
if (rcode == USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET) {
|
||||
if (parent == 0) {
|
||||
// Send a bus reset on the root interface.
|
||||
regWr(rHCTL, bmBUSRST); // Issue bus reset
|
||||
delay(102); // Delay 102ms, compensate for clock inaccuracy.
|
||||
}
|
||||
else {
|
||||
// Reset parent port
|
||||
devConfig[parent]->ResetHubPort(port);
|
||||
}
|
||||
}
|
||||
else if (rcode == hrJERR && retries < 3) { // Some devices returns this when plugged in - trying to initialize the device again usually works
|
||||
delay(100);
|
||||
retries++;
|
||||
goto again;
|
||||
}
|
||||
else if (rcode)
|
||||
return rcode;
|
||||
|
||||
rcode = devConfig[driver]->Init(parent, port, lowspeed);
|
||||
if (rcode == hrJERR && retries < 3) { // Some devices returns this when plugged in - trying to initialize the device again usually works
|
||||
delay(100);
|
||||
retries++;
|
||||
goto again;
|
||||
}
|
||||
|
||||
if (rcode) {
|
||||
// Issue a bus reset, because the device may be in a limbo state
|
||||
if (parent == 0) {
|
||||
// Send a bus reset on the root interface.
|
||||
regWr(rHCTL, bmBUSRST); // Issue bus reset
|
||||
delay(102); // Delay 102ms, compensate for clock inaccuracy.
|
||||
}
|
||||
else {
|
||||
// Reset parent port
|
||||
devConfig[parent]->ResetHubPort(port);
|
||||
}
|
||||
}
|
||||
return rcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is broken. It needs to enumerate differently.
|
||||
* It causes major problems with several devices if detected in an unexpected order.
|
||||
*
|
||||
* Oleg - I wouldn't do anything before the newly connected device is considered sane.
|
||||
* i.e.(delays are not indicated for brevity):
|
||||
* 1. reset
|
||||
* 2. GetDevDescr();
|
||||
* 3a. If ACK, continue with allocating address, addressing, etc.
|
||||
* 3b. Else reset again, count resets, stop at some number (5?).
|
||||
* 4. When max.number of resets is reached, toggle power/fail
|
||||
* If desired, this could be modified by performing two resets with GetDevDescr() in the middle - however, from my experience, if a device answers to GDD()
|
||||
* it doesn't need to be reset again
|
||||
* New steps proposal:
|
||||
* 1: get address pool instance. exit on fail
|
||||
* 2: pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf). exit on fail.
|
||||
* 3: bus reset, 100ms delay
|
||||
* 4: set address
|
||||
* 5: pUsb->setEpInfoEntry(bAddress, 1, epInfo), exit on fail
|
||||
* 6: while (configurations) {
|
||||
* for (each configuration) {
|
||||
* for (each driver) {
|
||||
* 6a: Ask device if it likes configuration. Returns 0 on OK.
|
||||
* If successful, the driver configured device.
|
||||
* The driver now owns the endpoints, and takes over managing them.
|
||||
* The following will need codes:
|
||||
* Everything went well, instance consumed, exit with success.
|
||||
* Instance already in use, ignore it, try next driver.
|
||||
* Not a supported device, ignore it, try next driver.
|
||||
* Not a supported configuration for this device, ignore it, try next driver.
|
||||
* Could not configure device, fatal, exit with fail.
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* 7: for (each driver) {
|
||||
* 7a: Ask device if it knows this VID/PID. Acts exactly like 6a, but using VID/PID
|
||||
* 8: if we get here, no driver likes the device plugged in, so exit failure.
|
||||
*/
|
||||
uint8_t USB::Configuring(uint8_t parent, uint8_t port, bool lowspeed) {
|
||||
//uint8_t bAddress = 0;
|
||||
//printf("Configuring: parent = %i, port = %i\r\n", parent, port);
|
||||
uint8_t devConfigIndex;
|
||||
uint8_t rcode = 0;
|
||||
uint8_t buf[sizeof (USB_FD_DEVICE_DESCRIPTOR)];
|
||||
USB_FD_DEVICE_DESCRIPTOR *udd = reinterpret_cast<USB_FD_DEVICE_DESCRIPTOR *>(buf);
|
||||
UsbDevice *p = nullptr;
|
||||
EpInfo *oldep_ptr = nullptr;
|
||||
EpInfo epInfo;
|
||||
|
||||
epInfo.epAddr = 0;
|
||||
epInfo.maxPktSize = 8;
|
||||
epInfo.bmSndToggle = 0;
|
||||
epInfo.bmRcvToggle = 0;
|
||||
epInfo.bmNakPower = USB_NAK_MAX_POWER;
|
||||
|
||||
//delay(2000);
|
||||
AddressPool &addrPool = GetAddressPool();
|
||||
// Get pointer to pseudo device with address 0 assigned
|
||||
p = addrPool.GetUsbDevicePtr(0);
|
||||
if (!p) {
|
||||
//printf("Configuring error: USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL\r\n");
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
}
|
||||
|
||||
// Save old pointer to EP_RECORD of address 0
|
||||
oldep_ptr = p->epinfo;
|
||||
|
||||
// Temporary assign new pointer to epInfo to p->epinfo in order to
|
||||
// Avoid toggle inconsistence
|
||||
|
||||
p->epinfo = &epInfo;
|
||||
|
||||
p->lowspeed = lowspeed;
|
||||
// Get device descriptor
|
||||
rcode = getDevDescr(0, 0, sizeof (USB_FD_DEVICE_DESCRIPTOR), (uint8_t*)buf);
|
||||
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
|
||||
if (rcode) {
|
||||
//printf("Configuring error: Can't get USB_FD_DEVICE_DESCRIPTOR\r\n");
|
||||
return rcode;
|
||||
}
|
||||
|
||||
// To-do?
|
||||
// Allocate new address according to device class
|
||||
//bAddress = addrPool.AllocAddress(parent, false, port);
|
||||
|
||||
uint16_t vid = udd->idVendor, pid = udd->idProduct;
|
||||
uint8_t klass = udd->bDeviceClass, subklass = udd->bDeviceSubClass;
|
||||
|
||||
// Attempt to configure if VID/PID or device class matches with a driver
|
||||
// Qualify with subclass too.
|
||||
//
|
||||
// VID/PID & class tests default to false for drivers not yet ported
|
||||
// Subclass defaults to true, so you don't have to define it if you don't have to.
|
||||
//
|
||||
for (devConfigIndex = 0; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) {
|
||||
if (!devConfig[devConfigIndex]) continue; // No driver
|
||||
if (devConfig[devConfigIndex]->GetAddress()) continue; // Consumed
|
||||
if (devConfig[devConfigIndex]->DEVSUBCLASSOK(subklass) && (devConfig[devConfigIndex]->VIDPIDOK(vid, pid) || devConfig[devConfigIndex]->DEVCLASSOK(klass))) {
|
||||
rcode = AttemptConfig(devConfigIndex, parent, port, lowspeed);
|
||||
if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (devConfigIndex < USB_NUMDEVICES) return rcode;
|
||||
|
||||
// Blindly attempt to configure
|
||||
for (devConfigIndex = 0; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) {
|
||||
if (!devConfig[devConfigIndex]) continue;
|
||||
if (devConfig[devConfigIndex]->GetAddress()) continue; // Consumed
|
||||
if (devConfig[devConfigIndex]->DEVSUBCLASSOK(subklass) && (devConfig[devConfigIndex]->VIDPIDOK(vid, pid) || devConfig[devConfigIndex]->DEVCLASSOK(klass))) continue; // If this is true it means it must have returned USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED above
|
||||
rcode = AttemptConfig(devConfigIndex, parent, port, lowspeed);
|
||||
|
||||
//printf("ERROR ENUMERATING %2.2x\r\n", rcode);
|
||||
if (!(rcode == USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED || rcode == USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE)) {
|
||||
// In case of an error dev_index should be reset to 0
|
||||
// in order to start from the very beginning the
|
||||
// next time the program gets here
|
||||
//if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE)
|
||||
//devConfigIndex = 0;
|
||||
return rcode;
|
||||
}
|
||||
}
|
||||
// Arriving here means the device class is unsupported by registered classes
|
||||
return DefaultAddressing(parent, port, lowspeed);
|
||||
}
|
||||
|
||||
uint8_t USB::ReleaseDevice(uint8_t addr) {
|
||||
if (addr) {
|
||||
for (uint8_t i = 0; i < USB_NUMDEVICES; i++) {
|
||||
if (!devConfig[i]) continue;
|
||||
if (devConfig[i]->GetAddress() == addr)
|
||||
return devConfig[i]->Release();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get device descriptor
|
||||
uint8_t USB::getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *dataptr) {
|
||||
return ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, nbytes, dataptr, nullptr);
|
||||
}
|
||||
|
||||
// Get configuration descriptor
|
||||
uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t *dataptr) {
|
||||
return ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, nbytes, dataptr, nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests Configuration Descriptor. Sends two Get Conf Descr requests.
|
||||
* The first one gets the total length of all descriptors, then the second one requests this
|
||||
* total length. The length of the first request can be shorter (4 bytes), however, there are
|
||||
* devices which won't work unless this length is set to 9.
|
||||
*/
|
||||
uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser *p) {
|
||||
const uint8_t bufSize = 64;
|
||||
uint8_t buf[bufSize];
|
||||
USB_FD_CONFIGURATION_DESCRIPTOR *ucd = reinterpret_cast<USB_FD_CONFIGURATION_DESCRIPTOR *>(buf);
|
||||
|
||||
uint8_t ret = getConfDescr(addr, ep, 9, conf, buf);
|
||||
if (ret) return ret;
|
||||
|
||||
uint16_t total = ucd->wTotalLength;
|
||||
|
||||
//USBTRACE2("\r\ntotal conf.size:", total);
|
||||
|
||||
return ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, total, bufSize, buf, p);
|
||||
}
|
||||
|
||||
// Get string descriptor
|
||||
uint8_t USB::getStrDescr(uint8_t addr, uint8_t ep, uint16_t ns, uint8_t index, uint16_t langid, uint8_t *dataptr) {
|
||||
return ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, ns, ns, dataptr, nullptr);
|
||||
}
|
||||
|
||||
// Set address
|
||||
uint8_t USB::setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr) {
|
||||
uint8_t rcode = ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0x0000, nullptr, nullptr);
|
||||
//delay(2); // Per USB 2.0 sect.9.2.6.3
|
||||
delay(300); // Older spec says you should wait at least 200ms
|
||||
return rcode;
|
||||
//return ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0x0000, nullptr, nullptr);
|
||||
}
|
||||
|
||||
// Set configuration
|
||||
uint8_t USB::setConf(uint8_t addr, uint8_t ep, uint8_t conf_value) {
|
||||
return ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, 0x0000, nullptr, nullptr);
|
||||
}
|
||||
|
||||
#endif // USB_FLASH_DRIVE_SUPPORT
|
53
Marlin Firmware/Marlin/src/sd/usb_flashdrive/lib-uhs2/Usb.h
Normal file
53
Marlin Firmware/Marlin/src/sd/usb_flashdrive/lib-uhs2/Usb.h
Normal file
@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
*
|
||||
* This program 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information
|
||||
* -------------------
|
||||
*
|
||||
* Circuits At Home, LTD
|
||||
* Web : https://www.circuitsathome.com
|
||||
* e-mail : support@circuitsathome.com
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
/* USB functions */
|
||||
#define _usb_h_
|
||||
|
||||
#include "../../../inc/MarlinConfigPre.h"
|
||||
|
||||
// WARNING: Do not change the order of includes, or stuff will break!
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// None of these should ever be included by a driver, or a user's sketch.
|
||||
#include "settings.h"
|
||||
#include "printhex.h"
|
||||
#include "message.h"
|
||||
|
||||
#include "hexdump.h"
|
||||
//#include "sink_parser.h"
|
||||
#include "max3421e.h"
|
||||
#include "address.h"
|
||||
//#include "avrpins.h"
|
||||
#include "usb_ch9.h"
|
||||
#include "usbhost.h"
|
||||
#include "UsbCore.h"
|
||||
#include "parsetools.h"
|
||||
#include "confdescparser.h"
|
||||
|
||||
#undef _usb_h_
|
312
Marlin Firmware/Marlin/src/sd/usb_flashdrive/lib-uhs2/UsbCore.h
Normal file
312
Marlin Firmware/Marlin/src/sd/usb_flashdrive/lib-uhs2/UsbCore.h
Normal file
@ -0,0 +1,312 @@
|
||||
/**
|
||||
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
*
|
||||
* This program 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information
|
||||
* -------------------
|
||||
*
|
||||
* Circuits At Home, LTD
|
||||
* Web : https://www.circuitsathome.com
|
||||
* e-mail : support@circuitsathome.com
|
||||
*/
|
||||
|
||||
#ifndef _usb_h_
|
||||
#error "Never include UsbCore.h directly; include Usb.h instead"
|
||||
#endif
|
||||
|
||||
#pragma once
|
||||
|
||||
// Not used anymore? If anyone uses this, please let us know so that this may be
|
||||
// moved to the proper place, settings.h.
|
||||
//#define USB_METHODS_INLINE
|
||||
|
||||
/* shield pins. First parameter - SS pin, second parameter - INT pin */
|
||||
|
||||
#ifdef __MARLIN_FIRMWARE__
|
||||
typedef MAX3421e MAX3421E; // Marlin redefines this class in "../usb_host.h"
|
||||
#elif defined(BOARD_BLACK_WIDDOW)
|
||||
typedef MAX3421e<P6, P3> MAX3421E; // Black Widow
|
||||
#elif defined(CORE_TEENSY) && (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__))
|
||||
#if EXT_RAM
|
||||
typedef MAX3421e<P20, P7> MAX3421E; // Teensy++ 2.0 with XMEM2
|
||||
#else
|
||||
typedef MAX3421e<P9, P8> MAX3421E; // Teensy++ 1.0 and 2.0
|
||||
#endif
|
||||
#elif defined(BOARD_MEGA_ADK)
|
||||
typedef MAX3421e<P53, P54> MAX3421E; // Arduino Mega ADK
|
||||
#elif defined(ARDUINO_AVR_BALANDUINO)
|
||||
typedef MAX3421e<P20, P19> MAX3421E; // Balanduino
|
||||
#elif defined(__ARDUINO_X86__) && PLATFORM_ID == 0x06
|
||||
typedef MAX3421e<P3, P2> MAX3421E; // The Intel Galileo supports much faster read and write speed at pin 2 and 3
|
||||
#elif defined(ESP8266)
|
||||
typedef MAX3421e<P15, P5> MAX3421E; // ESP8266 boards
|
||||
#elif defined(ESP32)
|
||||
typedef MAX3421e<P5, P17> MAX3421E; // ESP32 boards
|
||||
#else
|
||||
typedef MAX3421e<P10, P9> MAX3421E; // Official Arduinos (UNO, Duemilanove, Mega, 2560, Leonardo, Due etc.), Intel Edison, Intel Galileo 2 or Teensy 2.0 and 3.x
|
||||
#endif
|
||||
|
||||
/* Common setup data constant combinations */
|
||||
#define bmREQ_GET_DESCR USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //get descriptor request type
|
||||
#define bmREQ_SET USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //set request type for all but 'set feature' and 'set interface'
|
||||
#define bmREQ_CL_GET_INTF USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE //get interface request type
|
||||
|
||||
// D7 data transfer direction (0 - host-to-device, 1 - device-to-host)
|
||||
// D6-5 Type (0- standard, 1 - class, 2 - vendor, 3 - reserved)
|
||||
// D4-0 Recipient (0 - device, 1 - interface, 2 - endpoint, 3 - other, 4..31 - reserved)
|
||||
|
||||
// USB Device Classes
|
||||
#define USB_CLASS_USE_CLASS_INFO 0x00 // Use Class Info in the Interface Descriptors
|
||||
#define USB_CLASS_AUDIO 0x01 // Audio
|
||||
#define USB_CLASS_COM_AND_CDC_CTRL 0x02 // Communications and CDC Control
|
||||
#define USB_CLASS_HID 0x03 // HID
|
||||
#define USB_CLASS_PHYSICAL 0x05 // Physical
|
||||
#define USB_CLASS_IMAGE 0x06 // Image
|
||||
#define USB_CLASS_PRINTER 0x07 // Printer
|
||||
#define USB_CLASS_MASS_STORAGE 0x08 // Mass Storage
|
||||
#define USB_CLASS_HUB 0x09 // Hub
|
||||
#define USB_CLASS_CDC_DATA 0x0A // CDC-Data
|
||||
#define USB_CLASS_SMART_CARD 0x0B // Smart-Card
|
||||
#define USB_CLASS_CONTENT_SECURITY 0x0D // Content Security
|
||||
#define USB_CLASS_VIDEO 0x0E // Video
|
||||
#define USB_CLASS_PERSONAL_HEALTH 0x0F // Personal Healthcare
|
||||
#define USB_CLASS_DIAGNOSTIC_DEVICE 0xDC // Diagnostic Device
|
||||
#define USB_CLASS_WIRELESS_CTRL 0xE0 // Wireless Controller
|
||||
#define USB_CLASS_MISC 0xEF // Miscellaneous
|
||||
#define USB_CLASS_APP_SPECIFIC 0xFE // Application Specific
|
||||
#define USB_CLASS_VENDOR_SPECIFIC 0xFF // Vendor Specific
|
||||
|
||||
// Additional Error Codes
|
||||
#define USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED 0xD1
|
||||
#define USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE 0xD2
|
||||
#define USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS 0xD3
|
||||
#define USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL 0xD4
|
||||
#define USB_ERROR_HUB_ADDRESS_OVERFLOW 0xD5
|
||||
#define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL 0xD6
|
||||
#define USB_ERROR_EPINFO_IS_NULL 0xD7
|
||||
#define USB_ERROR_INVALID_ARGUMENT 0xD8
|
||||
#define USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE 0xD9
|
||||
#define USB_ERROR_INVALID_MAX_PKT_SIZE 0xDA
|
||||
#define USB_ERROR_EP_NOT_FOUND_IN_TBL 0xDB
|
||||
#define USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET 0xE0
|
||||
#define USB_ERROR_FailGetDevDescr 0xE1
|
||||
#define USB_ERROR_FailSetDevTblEntry 0xE2
|
||||
#define USB_ERROR_FailGetConfDescr 0xE3
|
||||
#define USB_ERROR_TRANSFER_TIMEOUT 0xFF
|
||||
|
||||
#define USB_XFER_TIMEOUT 5000 // (5000) USB transfer timeout in milliseconds, per section 9.2.6.1 of USB 2.0 spec
|
||||
//#define USB_NAK_LIMIT 32000 // NAK limit for a transfer. 0 means NAKs are not counted
|
||||
#define USB_RETRY_LIMIT 3 // 3 retry limit for a transfer
|
||||
#define USB_SETTLE_DELAY 200 // settle delay in milliseconds
|
||||
|
||||
#define USB_NUMDEVICES 16 //number of USB devices
|
||||
//#define HUB_MAX_HUBS 7 // maximum number of hubs that can be attached to the host controller
|
||||
#define HUB_PORT_RESET_DELAY 20 // hub port reset delay 10 ms recomended, can be up to 20 ms
|
||||
|
||||
/* USB state machine states */
|
||||
#define USB_STATE_MASK 0xF0
|
||||
|
||||
#define USB_STATE_DETACHED 0x10
|
||||
#define USB_DETACHED_SUBSTATE_INITIALIZE 0x11
|
||||
#define USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE 0x12
|
||||
#define USB_DETACHED_SUBSTATE_ILLEGAL 0x13
|
||||
#define USB_ATTACHED_SUBSTATE_SETTLE 0x20
|
||||
#define USB_ATTACHED_SUBSTATE_RESET_DEVICE 0x30
|
||||
#define USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE 0x40
|
||||
#define USB_ATTACHED_SUBSTATE_WAIT_SOF 0x50
|
||||
#define USB_ATTACHED_SUBSTATE_WAIT_RESET 0x51
|
||||
#define USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE 0x60
|
||||
#define USB_STATE_ADDRESSING 0x70
|
||||
#define USB_STATE_CONFIGURING 0x80
|
||||
#define USB_STATE_RUNNING 0x90
|
||||
#define USB_STATE_ERROR 0xA0
|
||||
|
||||
class USBDeviceConfig {
|
||||
public:
|
||||
|
||||
virtual uint8_t Init(uint8_t parent __attribute__((unused)), uint8_t port __attribute__((unused)), bool lowspeed __attribute__((unused))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual uint8_t ConfigureDevice(uint8_t parent __attribute__((unused)), uint8_t port __attribute__((unused)), bool lowspeed __attribute__((unused))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual uint8_t Release() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual uint8_t Poll() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual uint8_t GetAddress() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual void ResetHubPort(uint8_t port __attribute__((unused))) {
|
||||
return;
|
||||
} // Note used for hubs only!
|
||||
|
||||
virtual bool VIDPIDOK(uint16_t vid __attribute__((unused)), uint16_t pid __attribute__((unused))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool DEVCLASSOK(uint8_t klass __attribute__((unused))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool DEVSUBCLASSOK(uint8_t subklass __attribute__((unused))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/* USB Setup Packet Structure */
|
||||
typedef struct {
|
||||
|
||||
union { // offset description
|
||||
uint8_t bmRequestType; // 0 Bit-map of request type
|
||||
|
||||
struct {
|
||||
uint8_t recipient : 5; // Recipient of the request
|
||||
uint8_t type : 2; // Type of request
|
||||
uint8_t direction : 1; // Direction of data X-fer
|
||||
} __attribute__((packed));
|
||||
} ReqType_u;
|
||||
uint8_t bRequest; // 1 Request
|
||||
|
||||
union {
|
||||
uint16_t wValue; // 2 Depends on bRequest
|
||||
|
||||
struct {
|
||||
uint8_t wValueLo;
|
||||
uint8_t wValueHi;
|
||||
} __attribute__((packed));
|
||||
} wVal_u;
|
||||
uint16_t wIndex; // 4 Depends on bRequest
|
||||
uint16_t wLength; // 6 Depends on bRequest
|
||||
} __attribute__((packed)) SETUP_PKT, *PSETUP_PKT;
|
||||
|
||||
|
||||
|
||||
// Base class for incoming data parser
|
||||
|
||||
class USBReadParser {
|
||||
public:
|
||||
virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) = 0;
|
||||
};
|
||||
|
||||
class USB : public MAX3421E {
|
||||
AddressPoolImpl<USB_NUMDEVICES> addrPool;
|
||||
USBDeviceConfig* devConfig[USB_NUMDEVICES];
|
||||
uint8_t bmHubPre;
|
||||
|
||||
public:
|
||||
USB();
|
||||
|
||||
void SetHubPreMask() {
|
||||
bmHubPre |= bmHUBPRE;
|
||||
};
|
||||
|
||||
void ResetHubPreMask() {
|
||||
bmHubPre &= (~bmHUBPRE);
|
||||
};
|
||||
|
||||
AddressPool& GetAddressPool() {
|
||||
return (AddressPool&)addrPool;
|
||||
};
|
||||
|
||||
uint8_t RegisterDeviceClass(USBDeviceConfig *pdev) {
|
||||
for (uint8_t i = 0; i < USB_NUMDEVICES; i++) {
|
||||
if (!devConfig[i]) {
|
||||
devConfig[i] = pdev;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS;
|
||||
};
|
||||
|
||||
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) {
|
||||
addrPool.ForEachUsbDevice(pfunc);
|
||||
};
|
||||
uint8_t getUsbTaskState();
|
||||
void setUsbTaskState(uint8_t state);
|
||||
|
||||
EpInfo* getEpInfoEntry(uint8_t addr, uint8_t ep);
|
||||
uint8_t setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr);
|
||||
|
||||
/* Control requests */
|
||||
uint8_t getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *dataptr);
|
||||
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t *dataptr);
|
||||
|
||||
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser *p);
|
||||
|
||||
uint8_t getStrDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t index, uint16_t langid, uint8_t *dataptr);
|
||||
uint8_t setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr);
|
||||
uint8_t setConf(uint8_t addr, uint8_t ep, uint8_t conf_value);
|
||||
/**/
|
||||
uint8_t ctrlData(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *dataptr, bool direction);
|
||||
uint8_t ctrlStatus(uint8_t ep, bool direction, uint16_t nak_limit);
|
||||
uint8_t inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t *data, uint8_t bInterval = 0);
|
||||
uint8_t outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *data);
|
||||
uint8_t dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit);
|
||||
|
||||
void Task();
|
||||
|
||||
uint8_t DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
uint8_t Configuring(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
uint8_t ReleaseDevice(uint8_t addr);
|
||||
|
||||
uint8_t ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi,
|
||||
uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t *dataptr, USBReadParser *p);
|
||||
|
||||
private:
|
||||
void init();
|
||||
uint8_t SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t *nak_limit);
|
||||
uint8_t OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data);
|
||||
uint8_t InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t *data, uint8_t bInterval = 0);
|
||||
uint8_t AttemptConfig(uint8_t driver, uint8_t parent, uint8_t port, bool lowspeed);
|
||||
};
|
||||
|
||||
#if 0 //defined(USB_METHODS_INLINE)
|
||||
//get device descriptor
|
||||
|
||||
inline uint8_t USB::getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *dataptr) {
|
||||
return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, dataptr));
|
||||
}
|
||||
//get configuration descriptor
|
||||
|
||||
inline uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t *dataptr) {
|
||||
return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, dataptr));
|
||||
}
|
||||
//get string descriptor
|
||||
|
||||
inline uint8_t USB::getStrDescr(uint8_t addr, uint8_t ep, uint16_t nuint8_ts, uint8_t index, uint16_t langid, uint8_t *dataptr) {
|
||||
return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, nuint8_ts, dataptr));
|
||||
}
|
||||
//set address
|
||||
|
||||
inline uint8_t USB::setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr) {
|
||||
return ( ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, nullptr));
|
||||
}
|
||||
//set configuration
|
||||
|
||||
inline uint8_t USB::setConf(uint8_t addr, uint8_t ep, uint8_t conf_value) {
|
||||
return ( ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, nullptr));
|
||||
}
|
||||
|
||||
#endif // defined(USB_METHODS_INLINE)
|
271
Marlin Firmware/Marlin/src/sd/usb_flashdrive/lib-uhs2/address.h
Normal file
271
Marlin Firmware/Marlin/src/sd/usb_flashdrive/lib-uhs2/address.h
Normal file
@ -0,0 +1,271 @@
|
||||
/**
|
||||
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
*
|
||||
* This program 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information
|
||||
* -------------------
|
||||
*
|
||||
* Circuits At Home, LTD
|
||||
* Web : https://www.circuitsathome.com
|
||||
* e-mail : support@circuitsathome.com
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifndef _usb_h_
|
||||
#error "Never include address.h directly; include Usb.h instead"
|
||||
#endif
|
||||
|
||||
/* NAK powers. To save space in endpoint data structure, amount of retries before giving up and returning 0x4 is stored in */
|
||||
/* bmNakPower as a power of 2. The actual nak_limit is then calculated as nak_limit = ( 2^bmNakPower - 1) */
|
||||
#define USB_NAK_MAX_POWER 15 //NAK binary order maximum value
|
||||
#define USB_NAK_DEFAULT 14 //default 32K-1 NAKs before giving up
|
||||
#define USB_NAK_NOWAIT 1 //Single NAK stops transfer
|
||||
#define USB_NAK_NONAK 0 //Do not count NAKs, stop retrying after USB Timeout
|
||||
|
||||
struct EpInfo {
|
||||
uint8_t epAddr; // Endpoint address
|
||||
uint8_t maxPktSize; // Maximum packet size
|
||||
|
||||
union {
|
||||
uint8_t epAttribs;
|
||||
|
||||
struct {
|
||||
uint8_t bmSndToggle : 1; // Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise
|
||||
uint8_t bmRcvToggle : 1; // Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise
|
||||
uint8_t bmNakPower : 6; // Binary order for NAK_LIMIT value
|
||||
} __attribute__((packed));
|
||||
};
|
||||
} __attribute__((packed));
|
||||
|
||||
// 7 6 5 4 3 2 1 0
|
||||
// ---------------------------------
|
||||
// | | H | P | P | P | A | A | A |
|
||||
// ---------------------------------
|
||||
//
|
||||
// H - if 1 the address is a hub address
|
||||
// P - parent hub address
|
||||
// A - device address / port number in case of hub
|
||||
//
|
||||
|
||||
struct UsbDeviceAddress {
|
||||
union {
|
||||
struct {
|
||||
uint8_t bmAddress : 3; // device address/port number
|
||||
uint8_t bmParent : 3; // parent hub address
|
||||
uint8_t bmHub : 1; // hub flag
|
||||
uint8_t bmReserved : 1; // reserved, must be zero
|
||||
} __attribute__((packed));
|
||||
uint8_t devAddress;
|
||||
};
|
||||
} __attribute__((packed));
|
||||
|
||||
#define bmUSB_DEV_ADDR_ADDRESS 0x07
|
||||
#define bmUSB_DEV_ADDR_PARENT 0x38
|
||||
#define bmUSB_DEV_ADDR_HUB 0x40
|
||||
|
||||
struct UsbDevice {
|
||||
EpInfo *epinfo; // endpoint info pointer
|
||||
UsbDeviceAddress address;
|
||||
uint8_t epcount; // number of endpoints
|
||||
bool lowspeed; // indicates if a device is the low speed one
|
||||
// uint8_t devclass; // device class
|
||||
} __attribute__((packed));
|
||||
|
||||
class AddressPool {
|
||||
public:
|
||||
virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) = 0;
|
||||
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) = 0;
|
||||
virtual void FreeAddress(uint8_t addr) = 0;
|
||||
};
|
||||
|
||||
typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev);
|
||||
|
||||
#define ADDR_ERROR_INVALID_INDEX 0xFF
|
||||
#define ADDR_ERROR_INVALID_ADDRESS 0xFF
|
||||
|
||||
template <const uint8_t MAX_DEVICES_ALLOWED>
|
||||
class AddressPoolImpl : public AddressPool {
|
||||
EpInfo dev0ep; //Endpoint data structure used during enumeration for uninitialized device
|
||||
|
||||
uint8_t hubCounter; // hub counter is kept
|
||||
// in order to avoid hub address duplication
|
||||
|
||||
UsbDevice thePool[MAX_DEVICES_ALLOWED];
|
||||
|
||||
// Initialize address pool entry
|
||||
|
||||
void InitEntry(uint8_t index) {
|
||||
thePool[index].address.devAddress = 0;
|
||||
thePool[index].epcount = 1;
|
||||
thePool[index].lowspeed = 0;
|
||||
thePool[index].epinfo = &dev0ep;
|
||||
}
|
||||
|
||||
// Return thePool index for a given address
|
||||
|
||||
uint8_t FindAddressIndex(uint8_t address = 0) {
|
||||
for (uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
|
||||
if (thePool[i].address.devAddress == address)
|
||||
return i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Return thePool child index for a given parent
|
||||
|
||||
uint8_t FindChildIndex(UsbDeviceAddress addr, uint8_t start = 1) {
|
||||
for (uint8_t i = (start < 1 || start >= MAX_DEVICES_ALLOWED) ? 1 : start; i < MAX_DEVICES_ALLOWED; i++) {
|
||||
if (thePool[i].address.bmParent == addr.bmAddress)
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Frees address entry specified by index parameter
|
||||
|
||||
void FreeAddressByIndex(uint8_t index) {
|
||||
// Zero field is reserved and should not be affected
|
||||
if (index == 0) return;
|
||||
|
||||
UsbDeviceAddress uda = thePool[index].address;
|
||||
// If a hub was switched off all port addresses should be freed
|
||||
if (uda.bmHub == 1) {
|
||||
for (uint8_t i = 1; (i = FindChildIndex(uda, i));)
|
||||
FreeAddressByIndex(i);
|
||||
|
||||
// If the hub had the last allocated address, hubCounter should be decremented
|
||||
if (hubCounter == uda.bmAddress) hubCounter--;
|
||||
}
|
||||
InitEntry(index);
|
||||
}
|
||||
|
||||
// Initialize the whole address pool at once
|
||||
|
||||
void InitAllAddresses() {
|
||||
for (uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
|
||||
InitEntry(i);
|
||||
|
||||
hubCounter = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
AddressPoolImpl() : hubCounter(0) {
|
||||
// Zero address is reserved
|
||||
InitEntry(0);
|
||||
|
||||
thePool[0].address.devAddress = 0;
|
||||
thePool[0].epinfo = &dev0ep;
|
||||
dev0ep.epAddr = 0;
|
||||
dev0ep.maxPktSize = 8;
|
||||
dev0ep.bmSndToggle = 0; // Set DATA0/1 toggles to 0
|
||||
dev0ep.bmRcvToggle = 0;
|
||||
dev0ep.bmNakPower = USB_NAK_MAX_POWER;
|
||||
|
||||
InitAllAddresses();
|
||||
}
|
||||
|
||||
// Return a pointer to a specified address entry
|
||||
|
||||
virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) {
|
||||
if (!addr) return thePool;
|
||||
uint8_t index = FindAddressIndex(addr);
|
||||
return index ? thePool + index : nullptr;
|
||||
}
|
||||
|
||||
// Perform an operation specified by pfunc for each addressed device
|
||||
|
||||
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) {
|
||||
if (pfunc) {
|
||||
for (uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
|
||||
if (thePool[i].address.devAddress)
|
||||
pfunc(thePool + i);
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate new address
|
||||
|
||||
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) {
|
||||
/* if (parent != 0 && port == 0)
|
||||
USB_HOST_SERIAL.println("PRT:0"); */
|
||||
UsbDeviceAddress _parent;
|
||||
_parent.devAddress = parent;
|
||||
if (_parent.bmReserved || port > 7)
|
||||
//if(parent > 127 || port > 7)
|
||||
return 0;
|
||||
|
||||
if (is_hub && hubCounter == 7) return 0;
|
||||
|
||||
// finds first empty address entry starting from one
|
||||
uint8_t index = FindAddressIndex(0);
|
||||
|
||||
if (!index) return 0; // if empty entry is not found
|
||||
|
||||
if (_parent.devAddress == 0) {
|
||||
if (is_hub) {
|
||||
thePool[index].address.devAddress = 0x41;
|
||||
hubCounter++;
|
||||
}
|
||||
else
|
||||
thePool[index].address.devAddress = 1;
|
||||
|
||||
return thePool[index].address.devAddress;
|
||||
}
|
||||
|
||||
UsbDeviceAddress addr;
|
||||
addr.devAddress = 0; // Ensure all bits are zero
|
||||
addr.bmParent = _parent.bmAddress;
|
||||
if (is_hub) {
|
||||
addr.bmHub = 1;
|
||||
addr.bmAddress = ++hubCounter;
|
||||
}
|
||||
else {
|
||||
addr.bmHub = 0;
|
||||
addr.bmAddress = port;
|
||||
}
|
||||
thePool[index].address = addr;
|
||||
/*
|
||||
USB_HOST_SERIAL.print("Addr:");
|
||||
USB_HOST_SERIAL.print(addr.bmHub, HEX);
|
||||
USB_HOST_SERIAL.print(".");
|
||||
USB_HOST_SERIAL.print(addr.bmParent, HEX);
|
||||
USB_HOST_SERIAL.print(".");
|
||||
USB_HOST_SERIAL.println(addr.bmAddress, HEX);
|
||||
*/
|
||||
return thePool[index].address.devAddress;
|
||||
}
|
||||
|
||||
// Empty the pool entry
|
||||
|
||||
virtual void FreeAddress(uint8_t addr) {
|
||||
// if the root hub is disconnected all the addresses should be initialized
|
||||
if (addr == 0x41) {
|
||||
InitAllAddresses();
|
||||
return;
|
||||
}
|
||||
FreeAddressByIndex(FindAddressIndex(addr));
|
||||
}
|
||||
|
||||
// Return number of hubs attached
|
||||
// It can be helpful to find out if hubs are attached when getting the exact number of hubs.
|
||||
//uint8_t GetNumHubs() { return hubCounter; }
|
||||
//uint8_t GetNumDevices() {
|
||||
// uint8_t counter = 0;
|
||||
// for (uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
|
||||
// if (thePool[i].address != 0); counter++;
|
||||
// return counter;
|
||||
//}
|
||||
};
|
@ -0,0 +1,201 @@
|
||||
/**
|
||||
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
*
|
||||
* This program 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information
|
||||
* -------------------
|
||||
*
|
||||
* Circuits At Home, LTD
|
||||
* Web : https://www.circuitsathome.com
|
||||
* e-mail : support@circuitsathome.com
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifndef _usb_h_
|
||||
#error "Never include confdescparser.h directly; include Usb.h instead"
|
||||
#endif
|
||||
|
||||
class UsbConfigXtracter {
|
||||
public:
|
||||
//virtual void ConfigXtract(const USB_FD_CONFIGURATION_DESCRIPTOR *conf) = 0;
|
||||
//virtual void InterfaceXtract(uint8_t conf, const USB_FD_INTERFACE_DESCRIPTOR *iface) = 0;
|
||||
|
||||
virtual void EndpointXtract(uint8_t conf __attribute__((unused)), uint8_t iface __attribute__((unused)), uint8_t alt __attribute__((unused)), uint8_t proto __attribute__((unused)), const USB_FD_ENDPOINT_DESCRIPTOR *ep __attribute__((unused))) {
|
||||
}
|
||||
};
|
||||
|
||||
#define CP_MASK_COMPARE_CLASS 1
|
||||
#define CP_MASK_COMPARE_SUBCLASS 2
|
||||
#define CP_MASK_COMPARE_PROTOCOL 4
|
||||
#define CP_MASK_COMPARE_ALL 7
|
||||
|
||||
// Configuration Descriptor Parser Class Template
|
||||
|
||||
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
||||
class ConfigDescParser : public USBReadParser {
|
||||
UsbConfigXtracter *theXtractor;
|
||||
MultiValueBuffer theBuffer;
|
||||
MultiByteValueParser valParser;
|
||||
ByteSkipper theSkipper;
|
||||
uint8_t varBuffer[16 /*sizeof(USB_FD_CONFIGURATION_DESCRIPTOR)*/];
|
||||
|
||||
uint8_t stateParseDescr; // ParseDescriptor state
|
||||
|
||||
uint8_t dscrLen; // Descriptor length
|
||||
uint8_t dscrType; // Descriptor type
|
||||
|
||||
bool isGoodInterface; // Apropriate interface flag
|
||||
uint8_t confValue; // Configuration value
|
||||
uint8_t protoValue; // Protocol value
|
||||
uint8_t ifaceNumber; // Interface number
|
||||
uint8_t ifaceAltSet; // Interface alternate settings
|
||||
|
||||
bool UseOr;
|
||||
bool ParseDescriptor(uint8_t **pp, uint16_t *pcntdn);
|
||||
void PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc);
|
||||
|
||||
public:
|
||||
|
||||
void SetOR() { UseOr = true; }
|
||||
ConfigDescParser(UsbConfigXtracter *xtractor);
|
||||
void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset);
|
||||
};
|
||||
|
||||
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
||||
ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ConfigDescParser(UsbConfigXtracter *xtractor) :
|
||||
theXtractor(xtractor),
|
||||
stateParseDescr(0),
|
||||
dscrLen(0),
|
||||
dscrType(0),
|
||||
UseOr(false) {
|
||||
theBuffer.pValue = varBuffer;
|
||||
valParser.Initialize(&theBuffer);
|
||||
theSkipper.Initialize(&theBuffer);
|
||||
};
|
||||
|
||||
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
||||
void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset __attribute__((unused))) {
|
||||
uint16_t cntdn = (uint16_t)len;
|
||||
uint8_t *p = (uint8_t*)pbuf;
|
||||
while (cntdn) if (!ParseDescriptor(&p, &cntdn)) return;
|
||||
}
|
||||
|
||||
/* Parser for the configuration descriptor. Takes values for class, subclass, protocol fields in interface descriptor and
|
||||
compare masks for them. When the match is found, calls EndpointXtract passing buffer containing endpoint descriptor */
|
||||
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
||||
bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor(uint8_t **pp, uint16_t *pcntdn) {
|
||||
USB_FD_CONFIGURATION_DESCRIPTOR* ucd = reinterpret_cast<USB_FD_CONFIGURATION_DESCRIPTOR*>(varBuffer);
|
||||
USB_FD_INTERFACE_DESCRIPTOR* uid = reinterpret_cast<USB_FD_INTERFACE_DESCRIPTOR*>(varBuffer);
|
||||
switch (stateParseDescr) {
|
||||
case 0:
|
||||
theBuffer.valueSize = 2;
|
||||
valParser.Initialize(&theBuffer);
|
||||
stateParseDescr = 1;
|
||||
case 1:
|
||||
if (!valParser.Parse(pp, pcntdn)) return false;
|
||||
dscrLen = *((uint8_t*)theBuffer.pValue);
|
||||
dscrType = *((uint8_t*)theBuffer.pValue + 1);
|
||||
stateParseDescr = 2;
|
||||
case 2:
|
||||
// This is a sort of hack. Assuming that two bytes are all ready in the buffer
|
||||
// the pointer is positioned two bytes ahead in order for the rest of descriptor
|
||||
// to be read right after the size and the type fields.
|
||||
// This should be used carefully. varBuffer should be used directly to handle data
|
||||
// in the buffer.
|
||||
theBuffer.pValue = varBuffer + 2;
|
||||
stateParseDescr = 3;
|
||||
case 3:
|
||||
switch (dscrType) {
|
||||
case USB_DESCRIPTOR_INTERFACE:
|
||||
isGoodInterface = false;
|
||||
break;
|
||||
case USB_DESCRIPTOR_CONFIGURATION:
|
||||
case USB_DESCRIPTOR_ENDPOINT:
|
||||
case HID_DESCRIPTOR_HID:
|
||||
break;
|
||||
}
|
||||
theBuffer.valueSize = dscrLen - 2;
|
||||
valParser.Initialize(&theBuffer);
|
||||
stateParseDescr = 4;
|
||||
case 4:
|
||||
switch (dscrType) {
|
||||
case USB_DESCRIPTOR_CONFIGURATION:
|
||||
if (!valParser.Parse(pp, pcntdn)) return false;
|
||||
confValue = ucd->bConfigurationValue;
|
||||
break;
|
||||
case USB_DESCRIPTOR_INTERFACE:
|
||||
if (!valParser.Parse(pp, pcntdn)) return false;
|
||||
if ((MASK & CP_MASK_COMPARE_CLASS) && uid->bInterfaceClass != CLASS_ID)
|
||||
break;
|
||||
if ((MASK & CP_MASK_COMPARE_SUBCLASS) && uid->bInterfaceSubClass != SUBCLASS_ID)
|
||||
break;
|
||||
if (UseOr) {
|
||||
if ((!((MASK & CP_MASK_COMPARE_PROTOCOL) && uid->bInterfaceProtocol))) break;
|
||||
}
|
||||
else if ((MASK & CP_MASK_COMPARE_PROTOCOL) && uid->bInterfaceProtocol != PROTOCOL_ID)
|
||||
break;
|
||||
isGoodInterface = true;
|
||||
ifaceNumber = uid->bInterfaceNumber;
|
||||
ifaceAltSet = uid->bAlternateSetting;
|
||||
protoValue = uid->bInterfaceProtocol;
|
||||
break;
|
||||
case USB_DESCRIPTOR_ENDPOINT:
|
||||
if (!valParser.Parse(pp, pcntdn)) return false;
|
||||
if (isGoodInterface && theXtractor)
|
||||
theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_FD_ENDPOINT_DESCRIPTOR*)varBuffer);
|
||||
break;
|
||||
//case HID_DESCRIPTOR_HID:
|
||||
// if (!valParser.Parse(pp, pcntdn)) return false;
|
||||
// PrintHidDescriptor((const USB_HID_DESCRIPTOR*)varBuffer);
|
||||
// break;
|
||||
default:
|
||||
if (!theSkipper.Skip(pp, pcntdn, dscrLen - 2)) return false;
|
||||
}
|
||||
theBuffer.pValue = varBuffer;
|
||||
stateParseDescr = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
||||
void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc) {
|
||||
Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"), 0x80);
|
||||
Notify(PSTR("bDescLength:\t\t"), 0x80);
|
||||
PrintHex<uint8_t > (pDesc->bLength, 0x80);
|
||||
|
||||
Notify(PSTR("\r\nbDescriptorType:\t"), 0x80);
|
||||
PrintHex<uint8_t > (pDesc->bDescriptorType, 0x80);
|
||||
|
||||
Notify(PSTR("\r\nbcdHID:\t\t\t"), 0x80);
|
||||
PrintHex<uint16_t > (pDesc->bcdHID, 0x80);
|
||||
|
||||
Notify(PSTR("\r\nbCountryCode:\t\t"), 0x80);
|
||||
PrintHex<uint8_t > (pDesc->bCountryCode, 0x80);
|
||||
|
||||
Notify(PSTR("\r\nbNumDescriptors:\t"), 0x80);
|
||||
PrintHex<uint8_t > (pDesc->bNumDescriptors, 0x80);
|
||||
|
||||
for (uint8_t i = 0; i < pDesc->bNumDescriptors; i++) {
|
||||
HID_CLASS_DESCRIPTOR_LEN_AND_TYPE *pLT = (HID_CLASS_DESCRIPTOR_LEN_AND_TYPE*)&(pDesc->bDescrType);
|
||||
|
||||
Notify(PSTR("\r\nbDescrType:\t\t"), 0x80);
|
||||
PrintHex<uint8_t > (pLT[i].bDescrType, 0x80);
|
||||
|
||||
Notify(PSTR("\r\nwDescriptorLength:\t"), 0x80);
|
||||
PrintHex<uint16_t > (pLT[i].wDescriptorLength, 0x80);
|
||||
}
|
||||
Notify(PSTR("\r\n"), 0x80);
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
*
|
||||
* This program 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information
|
||||
* -------------------
|
||||
*
|
||||
* Circuits At Home, LTD
|
||||
* Web : https://www.circuitsathome.com
|
||||
* e-mail : support@circuitsathome.com
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifndef _usb_h_
|
||||
#error "Never include hexdump.h directly; include Usb.h instead"
|
||||
#endif
|
||||
|
||||
extern int UsbDEBUGlvl;
|
||||
|
||||
template <class BASE_CLASS, class LEN_TYPE, class OFFSET_TYPE>
|
||||
class HexDumper : public BASE_CLASS {
|
||||
uint8_t byteCount;
|
||||
OFFSET_TYPE byteTotal;
|
||||
|
||||
public:
|
||||
|
||||
HexDumper() : byteCount(0), byteTotal(0) {
|
||||
};
|
||||
|
||||
void Initialize() {
|
||||
byteCount = 0;
|
||||
byteTotal = 0;
|
||||
};
|
||||
|
||||
void Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset);
|
||||
};
|
||||
|
||||
template <class BASE_CLASS, class LEN_TYPE, class OFFSET_TYPE>
|
||||
void HexDumper<BASE_CLASS, LEN_TYPE, OFFSET_TYPE>::Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset __attribute__((unused))) {
|
||||
if (UsbDEBUGlvl >= 0x80) { // Fully bypass this block of code if we do not debug.
|
||||
for (LEN_TYPE j = 0; j < len; j++, byteCount++, byteTotal++) {
|
||||
if (!byteCount) {
|
||||
PrintHex<OFFSET_TYPE > (byteTotal, 0x80);
|
||||
E_Notify(PSTR(": "), 0x80);
|
||||
}
|
||||
PrintHex<uint8_t > (pbuf[j], 0x80);
|
||||
E_Notify(PSTR(" "), 0x80);
|
||||
|
||||
if (byteCount == 15) {
|
||||
E_Notify(PSTR("\r\n"), 0x80);
|
||||
byteCount = 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
/**
|
||||
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
*
|
||||
* This program 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information
|
||||
* -------------------
|
||||
*
|
||||
* Circuits At Home, LTD
|
||||
* Web : https://www.circuitsathome.com
|
||||
* e-mail : support@circuitsathome.com
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifndef _usb_h_
|
||||
#error "Never include macros.h directly; include Usb.h instead"
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// HANDY MACROS
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define VALUE_BETWEEN(v,l,h) (((v)>(l)) && ((v)<(h)))
|
||||
#define VALUE_WITHIN(v,l,h) (((v)>=(l)) && ((v)<=(h)))
|
||||
#define output_pgm_message(wa,fp,mp,el) wa = &mp, fp((char *)pgm_read_pointer(wa), el)
|
||||
#define output_if_between(v,l,h,wa,fp,mp,el) if (VALUE_BETWEEN(v,l,h)) output_pgm_message(wa,fp,mp[v-(l+1)],el);
|
||||
|
||||
#define SWAP(a, b) (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b)))
|
||||
#ifndef __BYTE_GRABBING_DEFINED__
|
||||
#define __BYTE_GRABBING_DEFINED__ 1
|
||||
#ifdef BROKEN_OPTIMIZER_LITTLE_ENDIAN
|
||||
// Note: Use this if your compiler generates horrible assembler!
|
||||
#define BGRAB0(__usi__) (((uint8_t *)&(__usi__))[0])
|
||||
#define BGRAB1(__usi__) (((uint8_t *)&(__usi__))[1])
|
||||
#define BGRAB2(__usi__) (((uint8_t *)&(__usi__))[2])
|
||||
#define BGRAB3(__usi__) (((uint8_t *)&(__usi__))[3])
|
||||
#define BGRAB4(__usi__) (((uint8_t *)&(__usi__))[4])
|
||||
#define BGRAB5(__usi__) (((uint8_t *)&(__usi__))[5])
|
||||
#define BGRAB6(__usi__) (((uint8_t *)&(__usi__))[6])
|
||||
#define BGRAB7(__usi__) (((uint8_t *)&(__usi__))[7])
|
||||
#else
|
||||
// Note: The cast alone to uint8_t is actually enough.
|
||||
// GCC throws out the "& 0xFF", and the size is no different.
|
||||
// Some compilers need it.
|
||||
#define BGRAB0(__usi__) ((uint8_t)((__usi__) & 0xFF ))
|
||||
#define BGRAB1(__usi__) ((uint8_t)(((__usi__) >> 8) & 0xFF))
|
||||
#define BGRAB2(__usi__) ((uint8_t)(((__usi__) >> 16) & 0xFF))
|
||||
#define BGRAB3(__usi__) ((uint8_t)(((__usi__) >> 24) & 0xFF))
|
||||
#define BGRAB4(__usi__) ((uint8_t)(((__usi__) >> 32) & 0xFF))
|
||||
#define BGRAB5(__usi__) ((uint8_t)(((__usi__) >> 40) & 0xFF))
|
||||
#define BGRAB6(__usi__) ((uint8_t)(((__usi__) >> 48) & 0xFF))
|
||||
#define BGRAB7(__usi__) ((uint8_t)(((__usi__) >> 56) & 0xFF))
|
||||
#endif
|
||||
#define BOVER1(__usi__) ((uint16_t)(__usi__) << 8)
|
||||
#define BOVER2(__usi__) ((uint32_t)(__usi__) << 16)
|
||||
#define BOVER3(__usi__) ((uint32_t)(__usi__) << 24)
|
||||
#define BOVER4(__usi__) ((uint64_t)(__usi__) << 32)
|
||||
#define BOVER5(__usi__) ((uint64_t)(__usi__) << 40)
|
||||
#define BOVER6(__usi__) ((uint64_t)(__usi__) << 48)
|
||||
#define BOVER7(__usi__) ((uint64_t)(__usi__) << 56)
|
||||
|
||||
// These are the smallest and fastest ways I have found so far in pure C/C++.
|
||||
#define BMAKE16(__usc1__,__usc0__) ((uint16_t)((uint16_t)(__usc0__) | (uint16_t)BOVER1(__usc1__)))
|
||||
#define BMAKE32(__usc3__,__usc2__,__usc1__,__usc0__) ((uint32_t)((uint32_t)(__usc0__) | (uint32_t)BOVER1(__usc1__) | (uint32_t)BOVER2(__usc2__) | (uint32_t)BOVER3(__usc3__)))
|
||||
#define BMAKE64(__usc7__,__usc6__,__usc5__,__usc4__,__usc3__,__usc2__,__usc1__,__usc0__) ((uint64_t)((uint64_t)__usc0__ | (uint64_t)BOVER1(__usc1__) | (uint64_t)BOVER2(__usc2__) | (uint64_t)BOVER3(__usc3__) | (uint64_t)BOVER4(__usc4__) | (uint64_t)BOVER5(__usc5__) | (uint64_t)BOVER6(__usc6__) | (uint64_t)BOVER1(__usc7__)))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Debug macros: Strings are stored in progmem (flash) instead of RAM.
|
||||
*/
|
||||
#define USBTRACE(s) (Notify(PSTR(s), 0x80))
|
||||
#define USBTRACE1(s,l) (Notify(PSTR(s), l))
|
||||
#define USBTRACE2(s,r) (Notify(PSTR(s), 0x80), D_PrintHex((r), 0x80), Notify(PSTR("\r\n"), 0x80))
|
||||
#define USBTRACE3(s,r,l) (Notify(PSTR(s), l), D_PrintHex((r), l), Notify(PSTR("\r\n"), l))
|
1209
Marlin Firmware/Marlin/src/sd/usb_flashdrive/lib-uhs2/masstorage.cpp
Normal file
1209
Marlin Firmware/Marlin/src/sd/usb_flashdrive/lib-uhs2/masstorage.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,559 @@
|
||||
/**
|
||||
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
*
|
||||
* This program 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information
|
||||
* -------------------
|
||||
*
|
||||
* Circuits At Home, LTD
|
||||
* Web : https://www.circuitsathome.com
|
||||
* e-mail : support@circuitsathome.com
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Cruft removal, makes driver smaller, faster.
|
||||
#ifndef MS_WANT_PARSER
|
||||
#define MS_WANT_PARSER 0
|
||||
#endif
|
||||
|
||||
#include "Usb.h"
|
||||
|
||||
#define bmREQ_MASSOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
|
||||
#define bmREQ_MASSIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
|
||||
|
||||
// Mass Storage Subclass Constants
|
||||
#define MASS_SUBCLASS_SCSI_NOT_REPORTED 0x00 // De facto use
|
||||
#define MASS_SUBCLASS_RBC 0x01
|
||||
#define MASS_SUBCLASS_ATAPI 0x02 // MMC-5 (ATAPI)
|
||||
#define MASS_SUBCLASS_OBSOLETE1 0x03 // Was QIC-157
|
||||
#define MASS_SUBCLASS_UFI 0x04 // Specifies how to interface Floppy Disk Drives to USB
|
||||
#define MASS_SUBCLASS_OBSOLETE2 0x05 // Was SFF-8070i
|
||||
#define MASS_SUBCLASS_SCSI 0x06 // SCSI Transparent Command Set
|
||||
#define MASS_SUBCLASS_LSDFS 0x07 // Specifies how host has to negotiate access before trying SCSI
|
||||
#define MASS_SUBCLASS_IEEE1667 0x08
|
||||
|
||||
// Mass Storage Class Protocols
|
||||
#define MASS_PROTO_CBI 0x00 // CBI (with command completion interrupt)
|
||||
#define MASS_PROTO_CBI_NO_INT 0x01 // CBI (without command completion interrupt)
|
||||
#define MASS_PROTO_OBSOLETE 0x02
|
||||
#define MASS_PROTO_BBB 0x50 // Bulk Only Transport
|
||||
#define MASS_PROTO_UAS 0x62
|
||||
|
||||
// Request Codes
|
||||
#define MASS_REQ_ADSC 0x00
|
||||
#define MASS_REQ_GET 0xFC
|
||||
#define MASS_REQ_PUT 0xFD
|
||||
#define MASS_REQ_GET_MAX_LUN 0xFE
|
||||
#define MASS_REQ_BOMSR 0xFF // Bulk-Only Mass Storage Reset
|
||||
|
||||
#define MASS_CBW_SIGNATURE 0x43425355
|
||||
#define MASS_CSW_SIGNATURE 0x53425355
|
||||
|
||||
#define MASS_CMD_DIR_OUT 0 // (0 << 7)
|
||||
#define MASS_CMD_DIR_IN 0x80 //(1 << 7)
|
||||
|
||||
/*
|
||||
* Reference documents from T10 (https://www.t10.org)
|
||||
* SCSI Primary Commands - 3 (SPC-3)
|
||||
* SCSI Block Commands - 2 (SBC-2)
|
||||
* Multi-Media Commands - 5 (MMC-5)
|
||||
*/
|
||||
|
||||
/* Group 1 commands (CDB's here are should all be 6-bytes) */
|
||||
#define SCSI_CMD_TEST_UNIT_READY 0x00
|
||||
#define SCSI_CMD_REQUEST_SENSE 0x03
|
||||
#define SCSI_CMD_FORMAT_UNIT 0x04
|
||||
#define SCSI_CMD_READ_6 0x08
|
||||
#define SCSI_CMD_WRITE_6 0x0A
|
||||
#define SCSI_CMD_INQUIRY 0x12
|
||||
#define SCSI_CMD_MODE_SELECT_6 0x15
|
||||
#define SCSI_CMD_MODE_SENSE_6 0x1A
|
||||
#define SCSI_CMD_START_STOP_UNIT 0x1B
|
||||
#define SCSI_CMD_PREVENT_REMOVAL 0x1E
|
||||
/* Group 2 Commands (CDB's here are 10-bytes) */
|
||||
#define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23
|
||||
#define SCSI_CMD_READ_CAPACITY_10 0x25
|
||||
#define SCSI_CMD_READ_10 0x28
|
||||
#define SCSI_CMD_WRITE_10 0x2A
|
||||
#define SCSI_CMD_SEEK_10 0x2B
|
||||
#define SCSI_CMD_ERASE_10 0x2C
|
||||
#define SCSI_CMD_WRITE_AND_VERIFY_10 0x2E
|
||||
#define SCSI_CMD_VERIFY_10 0x2F
|
||||
#define SCSI_CMD_SYNCHRONIZE_CACHE 0x35
|
||||
#define SCSI_CMD_WRITE_BUFFER 0x3B
|
||||
#define SCSI_CMD_READ_BUFFER 0x3C
|
||||
#define SCSI_CMD_READ_SUBCHANNEL 0x42
|
||||
#define SCSI_CMD_READ_TOC 0x43
|
||||
#define SCSI_CMD_READ_HEADER 0x44
|
||||
#define SCSI_CMD_PLAY_AUDIO_10 0x45
|
||||
#define SCSI_CMD_GET_CONFIGURATION 0x46
|
||||
#define SCSI_CMD_PLAY_AUDIO_MSF 0x47
|
||||
#define SCSI_CMD_PLAY_AUDIO_TI 0x48
|
||||
#define SCSI_CMD_PLAY_TRACK_REL_10 0x49
|
||||
#define SCSI_CMD_GET_EVENT_STATUS 0x4A
|
||||
#define SCSI_CMD_PAUSE_RESUME 0x4B
|
||||
#define SCSI_CMD_READ_DISC_INFORMATION 0x51
|
||||
#define SCSI_CMD_READ_TRACK_INFORMATION 0x52
|
||||
#define SCSI_CMD_RESERVE_TRACK 0x53
|
||||
#define SCSI_CMD_SEND_OPC_INFORMATION 0x54
|
||||
#define SCSI_CMD_MODE_SELECT_10 0x55
|
||||
#define SCSI_CMD_REPAIR_TRACK 0x58
|
||||
#define SCSI_CMD_MODE_SENSE_10 0x5A
|
||||
#define SCSI_CMD_CLOSE_TRACK_SESSION 0x5B
|
||||
#define SCSI_CMD_READ_BUFFER_CAPACITY 0x5C
|
||||
#define SCSI_CMD_SEND_CUE_SHEET 0x5D
|
||||
/* Group 5 Commands (CDB's here are 12-bytes) */
|
||||
#define SCSI_CMD_REPORT_LUNS 0xA0
|
||||
#define SCSI_CMD_BLANK 0xA1
|
||||
#define SCSI_CMD_SECURITY_PROTOCOL_IN 0xA2
|
||||
#define SCSI_CMD_SEND_KEY 0xA3
|
||||
#define SCSI_CMD_REPORT_KEY 0xA4
|
||||
#define SCSI_CMD_PLAY_AUDIO_12 0xA5
|
||||
#define SCSI_CMD_LOAD_UNLOAD 0xA6
|
||||
#define SCSI_CMD_SET_READ_AHEAD 0xA7
|
||||
#define SCSI_CMD_READ_12 0xA8
|
||||
#define SCSI_CMD_PLAY_TRACK_REL_12 0xA9
|
||||
#define SCSI_CMD_WRITE_12 0xAA
|
||||
#define SCSI_CMD_READ_MEDIA_SERIAL_12 0xAB
|
||||
#define SCSI_CMD_GET_PERFORMANCE 0xAC
|
||||
#define SCSI_CMD_READ_DVD_STRUCTURE 0xAD
|
||||
#define SCSI_CMD_SECURITY_PROTOCOL_OUT 0xB5
|
||||
#define SCSI_CMD_SET_STREAMING 0xB6
|
||||
#define SCSI_CMD_READ_MSF 0xB9
|
||||
#define SCSI_CMD_SET_SPEED 0xBB
|
||||
#define SCSI_CMD_MECHANISM_STATUS 0xBD
|
||||
#define SCSI_CMD_READ_CD 0xBE
|
||||
#define SCSI_CMD_SEND_DISC_STRUCTURE 0xBF
|
||||
/* Vendor-unique Commands, included for completeness */
|
||||
#define SCSI_CMD_CD_PLAYBACK_STATUS 0xC4 /* SONY unique */
|
||||
#define SCSI_CMD_PLAYBACK_CONTROL 0xC9 /* SONY unique */
|
||||
#define SCSI_CMD_READ_CDDA 0xD8 /* Vendor unique */
|
||||
#define SCSI_CMD_READ_CDXA 0xDB /* Vendor unique */
|
||||
#define SCSI_CMD_READ_ALL_SUBCODES 0xDF /* Vendor unique */
|
||||
|
||||
/* SCSI error codes */
|
||||
#define SCSI_S_NOT_READY 0x02
|
||||
#define SCSI_S_MEDIUM_ERROR 0x03
|
||||
#define SCSI_S_ILLEGAL_REQUEST 0x05
|
||||
#define SCSI_S_UNIT_ATTENTION 0x06
|
||||
#define SCSI_ASC_LBA_OUT_OF_RANGE 0x21
|
||||
#define SCSI_ASC_MEDIA_CHANGED 0x28
|
||||
#define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3A
|
||||
|
||||
/* USB error codes */
|
||||
#define MASS_ERR_SUCCESS 0x00
|
||||
#define MASS_ERR_PHASE_ERROR 0x02
|
||||
#define MASS_ERR_UNIT_NOT_READY 0x03
|
||||
#define MASS_ERR_UNIT_BUSY 0x04
|
||||
#define MASS_ERR_STALL 0x05
|
||||
#define MASS_ERR_CMD_NOT_SUPPORTED 0x06
|
||||
#define MASS_ERR_INVALID_CSW 0x07
|
||||
#define MASS_ERR_NO_MEDIA 0x08
|
||||
#define MASS_ERR_BAD_LBA 0x09
|
||||
#define MASS_ERR_MEDIA_CHANGED 0x0A
|
||||
#define MASS_ERR_DEVICE_DISCONNECTED 0x11
|
||||
#define MASS_ERR_UNABLE_TO_RECOVER 0x12 // Reset recovery error
|
||||
#define MASS_ERR_INVALID_LUN 0x13
|
||||
#define MASS_ERR_WRITE_STALL 0x14
|
||||
#define MASS_ERR_READ_NAKS 0x15
|
||||
#define MASS_ERR_WRITE_NAKS 0x16
|
||||
#define MASS_ERR_WRITE_PROTECTED 0x17
|
||||
#define MASS_ERR_NOT_IMPLEMENTED 0xFD
|
||||
#define MASS_ERR_GENERAL_SCSI_ERROR 0xFE
|
||||
#define MASS_ERR_GENERAL_USB_ERROR 0xFF
|
||||
#define MASS_ERR_USER 0xA0 // For subclasses to define their own error codes
|
||||
|
||||
#define MASS_TRANS_FLG_CALLBACK 0x01 // Callback is involved
|
||||
#define MASS_TRANS_FLG_NO_STALL_CHECK 0x02 // STALL condition is not checked
|
||||
#define MASS_TRANS_FLG_NO_PHASE_CHECK 0x04 // PHASE_ERROR is not checked
|
||||
|
||||
#define MASS_MAX_ENDPOINTS 3
|
||||
|
||||
struct Capacity {
|
||||
uint8_t data[8];
|
||||
//uint32_t dwBlockAddress;
|
||||
//uint32_t dwBlockLength;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct BASICCDB {
|
||||
uint8_t Opcode;
|
||||
|
||||
unsigned unused : 5;
|
||||
unsigned LUN : 3;
|
||||
|
||||
uint8_t info[12];
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef BASICCDB BASICCDB_t;
|
||||
|
||||
struct CDB6 {
|
||||
uint8_t Opcode;
|
||||
|
||||
unsigned LBAMSB : 5;
|
||||
unsigned LUN : 3;
|
||||
|
||||
uint8_t LBAHB;
|
||||
uint8_t LBALB;
|
||||
uint8_t AllocationLength;
|
||||
uint8_t Control;
|
||||
|
||||
public:
|
||||
|
||||
CDB6(uint8_t _Opcode, uint8_t _LUN, uint32_t LBA, uint8_t _AllocationLength, uint8_t _Control) :
|
||||
Opcode(_Opcode), LBAMSB(BGRAB2(LBA) & 0x1F), LUN(_LUN), LBAHB(BGRAB1(LBA)), LBALB(BGRAB0(LBA)),
|
||||
AllocationLength(_AllocationLength), Control(_Control) {
|
||||
}
|
||||
|
||||
CDB6(uint8_t _Opcode, uint8_t _LUN, uint8_t _AllocationLength, uint8_t _Control) :
|
||||
Opcode(_Opcode), LBAMSB(0), LUN(_LUN), LBAHB(0), LBALB(0),
|
||||
AllocationLength(_AllocationLength), Control(_Control) {
|
||||
}
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef CDB6 CDB6_t;
|
||||
|
||||
struct CDB10 {
|
||||
uint8_t Opcode;
|
||||
|
||||
unsigned Service_Action : 5;
|
||||
unsigned LUN : 3;
|
||||
|
||||
uint8_t LBA_L_M_MB;
|
||||
uint8_t LBA_L_M_LB;
|
||||
uint8_t LBA_L_L_MB;
|
||||
uint8_t LBA_L_L_LB;
|
||||
|
||||
uint8_t Misc2;
|
||||
|
||||
uint8_t ALC_MB;
|
||||
uint8_t ALC_LB;
|
||||
|
||||
uint8_t Control;
|
||||
public:
|
||||
|
||||
CDB10(uint8_t _Opcode, uint8_t _LUN) :
|
||||
Opcode(_Opcode), Service_Action(0), LUN(_LUN),
|
||||
LBA_L_M_MB(0), LBA_L_M_LB(0), LBA_L_L_MB(0), LBA_L_L_LB(0),
|
||||
Misc2(0), ALC_MB(0), ALC_LB(0), Control(0) {
|
||||
}
|
||||
|
||||
CDB10(uint8_t _Opcode, uint8_t _LUN, uint16_t xflen, uint32_t _LBA) :
|
||||
Opcode(_Opcode), Service_Action(0), LUN(_LUN),
|
||||
LBA_L_M_MB(BGRAB3(_LBA)), LBA_L_M_LB(BGRAB2(_LBA)), LBA_L_L_MB(BGRAB1(_LBA)), LBA_L_L_LB(BGRAB0(_LBA)),
|
||||
Misc2(0), ALC_MB(BGRAB1(xflen)), ALC_LB(BGRAB0(xflen)), Control(0) {
|
||||
}
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef CDB10 CDB10_t;
|
||||
|
||||
struct CDB12 {
|
||||
uint8_t Opcode;
|
||||
|
||||
unsigned Service_Action : 5;
|
||||
unsigned Misc : 3;
|
||||
|
||||
uint8_t LBA_L_M_LB;
|
||||
uint8_t LBA_L_L_MB;
|
||||
uint8_t LBA_L_L_LB;
|
||||
|
||||
uint8_t ALC_M_LB;
|
||||
uint8_t ALC_L_MB;
|
||||
uint8_t ALC_L_LB;
|
||||
uint8_t Control;
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef CDB12 CDB12_t;
|
||||
|
||||
struct CDB_LBA32_16 {
|
||||
uint8_t Opcode;
|
||||
|
||||
unsigned Service_Action : 5;
|
||||
unsigned Misc : 3;
|
||||
|
||||
uint8_t LBA_L_M_MB;
|
||||
uint8_t LBA_L_M_LB;
|
||||
uint8_t LBA_L_L_MB;
|
||||
uint8_t LBA_L_L_LB;
|
||||
|
||||
uint8_t A_M_M_MB;
|
||||
uint8_t A_M_M_LB;
|
||||
uint8_t A_M_L_MB;
|
||||
uint8_t A_M_L_LB;
|
||||
|
||||
uint8_t ALC_M_MB;
|
||||
uint8_t ALC_M_LB;
|
||||
uint8_t ALC_L_MB;
|
||||
uint8_t ALC_L_LB;
|
||||
|
||||
uint8_t Misc2;
|
||||
uint8_t Control;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct CDB_LBA64_16 {
|
||||
uint8_t Opcode;
|
||||
uint8_t Misc;
|
||||
|
||||
uint8_t LBA_M_M_MB;
|
||||
uint8_t LBA_M_M_LB;
|
||||
uint8_t LBA_M_L_MB;
|
||||
uint8_t LBA_M_L_LB;
|
||||
|
||||
uint8_t LBA_L_M_MB;
|
||||
uint8_t LBA_L_M_LB;
|
||||
uint8_t LBA_L_L_MB;
|
||||
uint8_t LBA_L_L_LB;
|
||||
|
||||
uint8_t ALC_M_MB;
|
||||
uint8_t ALC_M_LB;
|
||||
uint8_t ALC_L_MB;
|
||||
uint8_t ALC_L_LB;
|
||||
|
||||
uint8_t Misc2;
|
||||
uint8_t Control;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct InquiryResponse {
|
||||
uint8_t DeviceType : 5;
|
||||
uint8_t PeripheralQualifier : 3;
|
||||
|
||||
unsigned Reserved : 7;
|
||||
unsigned Removable : 1;
|
||||
|
||||
uint8_t Version;
|
||||
|
||||
unsigned ResponseDataFormat : 4;
|
||||
unsigned HISUP : 1;
|
||||
unsigned NormACA : 1;
|
||||
unsigned TrmTsk : 1;
|
||||
unsigned AERC : 1;
|
||||
|
||||
uint8_t AdditionalLength;
|
||||
//uint8_t Reserved3[2];
|
||||
|
||||
unsigned PROTECT : 1;
|
||||
unsigned Res : 2;
|
||||
unsigned ThreePC : 1;
|
||||
unsigned TPGS : 2;
|
||||
unsigned ACC : 1;
|
||||
unsigned SCCS : 1;
|
||||
|
||||
unsigned ADDR16 : 1;
|
||||
unsigned R1 : 1;
|
||||
unsigned R2 : 1;
|
||||
unsigned MCHNGR : 1;
|
||||
unsigned MULTIP : 1;
|
||||
unsigned VS : 1;
|
||||
unsigned ENCSERV : 1;
|
||||
unsigned BQUE : 1;
|
||||
|
||||
unsigned SoftReset : 1;
|
||||
unsigned CmdQue : 1;
|
||||
unsigned Reserved4 : 1;
|
||||
unsigned Linked : 1;
|
||||
unsigned Sync : 1;
|
||||
unsigned WideBus16Bit : 1;
|
||||
unsigned WideBus32Bit : 1;
|
||||
unsigned RelAddr : 1;
|
||||
|
||||
uint8_t VendorID[8];
|
||||
uint8_t ProductID[16];
|
||||
uint8_t RevisionID[4];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct CommandBlockWrapperBase {
|
||||
uint32_t dCBWSignature;
|
||||
uint32_t dCBWTag;
|
||||
uint32_t dCBWDataTransferLength;
|
||||
uint8_t bmCBWFlags;
|
||||
public:
|
||||
|
||||
CommandBlockWrapperBase() {
|
||||
}
|
||||
|
||||
CommandBlockWrapperBase(uint32_t tag, uint32_t xflen, uint8_t flgs) :
|
||||
dCBWSignature(MASS_CBW_SIGNATURE), dCBWTag(tag), dCBWDataTransferLength(xflen), bmCBWFlags(flgs) {
|
||||
}
|
||||
} __attribute__((packed));
|
||||
|
||||
struct CommandBlockWrapper : public CommandBlockWrapperBase {
|
||||
|
||||
struct {
|
||||
uint8_t bmCBWLUN : 4;
|
||||
uint8_t bmReserved1 : 4;
|
||||
};
|
||||
|
||||
struct {
|
||||
uint8_t bmCBWCBLength : 4;
|
||||
uint8_t bmReserved2 : 4;
|
||||
};
|
||||
|
||||
uint8_t CBWCB[16];
|
||||
|
||||
public:
|
||||
// All zeroed.
|
||||
|
||||
CommandBlockWrapper() :
|
||||
CommandBlockWrapperBase(0, 0, 0), bmReserved1(0), bmReserved2(0) {
|
||||
for (int i = 0; i < 16; i++) CBWCB[i] = 0;
|
||||
}
|
||||
|
||||
// Generic Wrap, CDB zeroed.
|
||||
|
||||
CommandBlockWrapper(uint32_t tag, uint32_t xflen, uint8_t flgs, uint8_t lu, uint8_t cmdlen, uint8_t cmd) :
|
||||
CommandBlockWrapperBase(tag, xflen, flgs),
|
||||
bmCBWLUN(lu), bmReserved1(0), bmCBWCBLength(cmdlen), bmReserved2(0) {
|
||||
for (int i = 0; i < 16; i++) CBWCB[i] = 0;
|
||||
// Type punning can cause optimization problems and bugs.
|
||||
// Using reinterpret_cast to a dreinterpretifferent object is the proper way to do this.
|
||||
//(((BASICCDB_t *) CBWCB)->LUN) = cmd;
|
||||
BASICCDB_t *x = reinterpret_cast<BASICCDB_t *>(CBWCB);
|
||||
x->LUN = cmd;
|
||||
}
|
||||
|
||||
// Wrap for CDB of 6
|
||||
|
||||
CommandBlockWrapper(uint32_t tag, uint32_t xflen, CDB6_t *cdb, uint8_t dir) :
|
||||
CommandBlockWrapperBase(tag, xflen, dir),
|
||||
bmCBWLUN(cdb->LUN), bmReserved1(0), bmCBWCBLength(6), bmReserved2(0) {
|
||||
memcpy(&CBWCB, cdb, 6);
|
||||
}
|
||||
// Wrap for CDB of 10
|
||||
|
||||
CommandBlockWrapper(uint32_t tag, uint32_t xflen, CDB10_t *cdb, uint8_t dir) :
|
||||
CommandBlockWrapperBase(tag, xflen, dir),
|
||||
bmCBWLUN(cdb->LUN), bmReserved1(0), bmCBWCBLength(10), bmReserved2(0) {
|
||||
memcpy(&CBWCB, cdb, 10);
|
||||
}
|
||||
} __attribute__((packed));
|
||||
|
||||
struct CommandStatusWrapper {
|
||||
uint32_t dCSWSignature;
|
||||
uint32_t dCSWTag;
|
||||
uint32_t dCSWDataResidue;
|
||||
uint8_t bCSWStatus;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct RequestSenseResponce {
|
||||
uint8_t bResponseCode;
|
||||
uint8_t bSegmentNumber;
|
||||
|
||||
uint8_t bmSenseKey : 4;
|
||||
uint8_t bmReserved : 1;
|
||||
uint8_t bmILI : 1;
|
||||
uint8_t bmEOM : 1;
|
||||
uint8_t bmFileMark : 1;
|
||||
|
||||
uint8_t Information[4];
|
||||
uint8_t bAdditionalLength;
|
||||
uint8_t CmdSpecificInformation[4];
|
||||
uint8_t bAdditionalSenseCode;
|
||||
uint8_t bAdditionalSenseQualifier;
|
||||
uint8_t bFieldReplaceableUnitCode;
|
||||
uint8_t SenseKeySpecific[3];
|
||||
} __attribute__((packed));
|
||||
|
||||
class BulkOnly : public USBDeviceConfig, public UsbConfigXtracter {
|
||||
protected:
|
||||
static const uint8_t epDataInIndex; // DataIn endpoint index
|
||||
static const uint8_t epDataOutIndex; // DataOUT endpoint index
|
||||
static const uint8_t epInterruptInIndex; // InterruptIN endpoint index
|
||||
|
||||
USB *pUsb;
|
||||
uint8_t bAddress;
|
||||
uint8_t bConfNum; // configuration number
|
||||
uint8_t bIface; // interface value
|
||||
uint8_t bNumEP; // total number of EP in the configuration
|
||||
uint32_t qNextPollTime; // next poll time
|
||||
bool bPollEnable; // poll enable flag
|
||||
|
||||
EpInfo epInfo[MASS_MAX_ENDPOINTS];
|
||||
|
||||
uint32_t dCBWTag; // Tag
|
||||
//uint32_t dCBWDataTransferLength; // Data Transfer Length
|
||||
uint8_t bLastUsbError; // Last USB error
|
||||
uint8_t bMaxLUN; // Max LUN
|
||||
uint8_t bTheLUN; // Active LUN
|
||||
uint32_t CurrentCapacity[MASS_MAX_SUPPORTED_LUN]; // Total sectors
|
||||
uint16_t CurrentSectorSize[MASS_MAX_SUPPORTED_LUN]; // Sector size, clipped to 16 bits
|
||||
bool LUNOk[MASS_MAX_SUPPORTED_LUN]; // use this to check for media changes.
|
||||
bool WriteOk[MASS_MAX_SUPPORTED_LUN];
|
||||
void PrintEndpointDescriptor(const USB_FD_ENDPOINT_DESCRIPTOR* ep_ptr);
|
||||
|
||||
// Additional Initialization Method for Subclasses
|
||||
|
||||
virtual uint8_t OnInit() { return 0; }
|
||||
|
||||
public:
|
||||
BulkOnly(USB *p);
|
||||
|
||||
uint8_t GetLastUsbError() { return bLastUsbError; };
|
||||
|
||||
uint8_t GetbMaxLUN() { return bMaxLUN; } // Max LUN
|
||||
uint8_t GetbTheLUN() { return bTheLUN; } // Active LUN
|
||||
|
||||
bool WriteProtected(uint8_t lun);
|
||||
uint8_t MediaCTL(uint8_t lun, uint8_t ctl);
|
||||
uint8_t Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, uint8_t *buf);
|
||||
uint8_t Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, USBReadParser *prs);
|
||||
uint8_t Write(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, const uint8_t *buf);
|
||||
uint8_t LockMedia(uint8_t lun, uint8_t lock);
|
||||
|
||||
bool LUNIsGood(uint8_t lun);
|
||||
uint32_t GetCapacity(uint8_t lun);
|
||||
uint16_t GetSectorSize(uint8_t lun);
|
||||
|
||||
// USBDeviceConfig implementation
|
||||
uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
uint8_t ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
|
||||
uint8_t Release();
|
||||
uint8_t Poll();
|
||||
|
||||
virtual uint8_t GetAddress() { return bAddress; }
|
||||
|
||||
// UsbConfigXtracter implementation
|
||||
void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_FD_ENDPOINT_DESCRIPTOR *ep);
|
||||
|
||||
virtual bool DEVCLASSOK(uint8_t klass) { return klass == USB_CLASS_MASS_STORAGE; }
|
||||
|
||||
uint8_t SCSITransaction6(CDB6_t *cdb, uint16_t buf_size, void *buf, uint8_t dir);
|
||||
uint8_t SCSITransaction10(CDB10_t *cdb, uint16_t buf_size, void *buf, uint8_t dir);
|
||||
|
||||
private:
|
||||
uint8_t Inquiry(uint8_t lun, uint16_t size, uint8_t *buf);
|
||||
uint8_t TestUnitReady(uint8_t lun);
|
||||
uint8_t RequestSense(uint8_t lun, uint16_t size, uint8_t *buf);
|
||||
uint8_t ModeSense6(uint8_t lun, uint8_t pc, uint8_t page, uint8_t subpage, uint8_t len, uint8_t *buf);
|
||||
uint8_t GetMaxLUN(uint8_t *max_lun);
|
||||
uint8_t SetCurLUN(uint8_t lun);
|
||||
void Reset();
|
||||
uint8_t ResetRecovery();
|
||||
uint8_t ReadCapacity10(uint8_t lun, uint8_t *buf);
|
||||
void ClearAllEP();
|
||||
void CheckMedia();
|
||||
bool CheckLUN(uint8_t lun);
|
||||
uint8_t Page3F(uint8_t lun);
|
||||
bool IsValidCBW(uint8_t size, uint8_t *pcbw);
|
||||
bool IsMeaningfulCBW(uint8_t size, uint8_t *pcbw);
|
||||
|
||||
bool IsValidCSW(CommandStatusWrapper *pcsw, CommandBlockWrapperBase *pcbw);
|
||||
|
||||
uint8_t ClearEpHalt(uint8_t index);
|
||||
uint8_t Transaction(CommandBlockWrapper *cbw, uint16_t bsize, void *buf OPTARG(MS_WANT_PARSER, uint8_t flags=0));
|
||||
uint8_t HandleUsbError(uint8_t error, uint8_t index);
|
||||
uint8_t HandleSCSIError(uint8_t status);
|
||||
};
|
242
Marlin Firmware/Marlin/src/sd/usb_flashdrive/lib-uhs2/max3421e.h
Normal file
242
Marlin Firmware/Marlin/src/sd/usb_flashdrive/lib-uhs2/max3421e.h
Normal file
@ -0,0 +1,242 @@
|
||||
/**
|
||||
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
*
|
||||
* This program 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information
|
||||
* -------------------
|
||||
*
|
||||
* Circuits At Home, LTD
|
||||
* Web : https://www.circuitsathome.com
|
||||
* e-mail : support@circuitsathome.com
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifndef _usb_h_
|
||||
#error "Never include max3421e.h directly; include Usb.h instead"
|
||||
#endif
|
||||
|
||||
/* MAX3421E register/bit names and bitmasks */
|
||||
|
||||
/* Arduino pin definitions */
|
||||
/* pin numbers to port numbers */
|
||||
|
||||
#define SE0 0
|
||||
#define SE1 1
|
||||
#define FSHOST 2
|
||||
#define LSHOST 3
|
||||
|
||||
/* MAX3421E command byte format: rrrrr0wa where 'r' is register number */
|
||||
//
|
||||
// MAX3421E Registers in HOST mode.
|
||||
//
|
||||
#define rRCVFIFO 0x08 //1<<3
|
||||
#define rSNDFIFO 0x10 //2<<3
|
||||
#define rSUDFIFO 0x20 //4<<3
|
||||
#define rRCVBC 0x30 //6<<3
|
||||
#define rSNDBC 0x38 //7<<3
|
||||
|
||||
#define rUSBIRQ 0x68 //13<<3
|
||||
/* USBIRQ Bits */
|
||||
#define bmVBUSIRQ 0x40 //b6
|
||||
#define bmNOVBUSIRQ 0x20 //b5
|
||||
#define bmOSCOKIRQ 0x01 //b0
|
||||
|
||||
#define rUSBIEN 0x70 //14<<3
|
||||
/* USBIEN Bits */
|
||||
#define bmVBUSIE 0x40 //b6
|
||||
#define bmNOVBUSIE 0x20 //b5
|
||||
#define bmOSCOKIE 0x01 //b0
|
||||
|
||||
#define rUSBCTL 0x78 //15<<3
|
||||
/* USBCTL Bits */
|
||||
#define bmCHIPRES 0x20 //b5
|
||||
#define bmPWRDOWN 0x10 //b4
|
||||
|
||||
#define rCPUCTL 0x80 //16<<3
|
||||
/* CPUCTL Bits */
|
||||
#define bmPUSLEWID1 0x80 //b7
|
||||
#define bmPULSEWID0 0x40 //b6
|
||||
#define bmIE 0x01 //b0
|
||||
|
||||
#define rPINCTL 0x88 //17<<3
|
||||
/* PINCTL Bits */
|
||||
#define bmFDUPSPI 0x10 //b4
|
||||
#define bmINTLEVEL 0x08 //b3
|
||||
#define bmPOSINT 0x04 //b2
|
||||
#define bmGPXB 0x02 //b1
|
||||
#define bmGPXA 0x01 //b0
|
||||
// GPX pin selections
|
||||
#define GPX_OPERATE 0x00
|
||||
#define GPX_VBDET 0x01
|
||||
#define GPX_BUSACT 0x02
|
||||
#define GPX_SOF 0x03
|
||||
|
||||
#define rREVISION 0x90 //18<<3
|
||||
|
||||
#define rIOPINS1 0xA0 //20<<3
|
||||
|
||||
/* IOPINS1 Bits */
|
||||
#define bmGPOUT0 0x01
|
||||
#define bmGPOUT1 0x02
|
||||
#define bmGPOUT2 0x04
|
||||
#define bmGPOUT3 0x08
|
||||
#define bmGPIN0 0x10
|
||||
#define bmGPIN1 0x20
|
||||
#define bmGPIN2 0x40
|
||||
#define bmGPIN3 0x80
|
||||
|
||||
#define rIOPINS2 0xA8 //21<<3
|
||||
/* IOPINS2 Bits */
|
||||
#define bmGPOUT4 0x01
|
||||
#define bmGPOUT5 0x02
|
||||
#define bmGPOUT6 0x04
|
||||
#define bmGPOUT7 0x08
|
||||
#define bmGPIN4 0x10
|
||||
#define bmGPIN5 0x20
|
||||
#define bmGPIN6 0x40
|
||||
#define bmGPIN7 0x80
|
||||
|
||||
#define rGPINIRQ 0xB0 //22<<3
|
||||
/* GPINIRQ Bits */
|
||||
#define bmGPINIRQ0 0x01
|
||||
#define bmGPINIRQ1 0x02
|
||||
#define bmGPINIRQ2 0x04
|
||||
#define bmGPINIRQ3 0x08
|
||||
#define bmGPINIRQ4 0x10
|
||||
#define bmGPINIRQ5 0x20
|
||||
#define bmGPINIRQ6 0x40
|
||||
#define bmGPINIRQ7 0x80
|
||||
|
||||
#define rGPINIEN 0xB8 //23<<3
|
||||
/* GPINIEN Bits */
|
||||
#define bmGPINIEN0 0x01
|
||||
#define bmGPINIEN1 0x02
|
||||
#define bmGPINIEN2 0x04
|
||||
#define bmGPINIEN3 0x08
|
||||
#define bmGPINIEN4 0x10
|
||||
#define bmGPINIEN5 0x20
|
||||
#define bmGPINIEN6 0x40
|
||||
#define bmGPINIEN7 0x80
|
||||
|
||||
#define rGPINPOL 0xC0 //24<<3
|
||||
/* GPINPOL Bits */
|
||||
#define bmGPINPOL0 0x01
|
||||
#define bmGPINPOL1 0x02
|
||||
#define bmGPINPOL2 0x04
|
||||
#define bmGPINPOL3 0x08
|
||||
#define bmGPINPOL4 0x10
|
||||
#define bmGPINPOL5 0x20
|
||||
#define bmGPINPOL6 0x40
|
||||
#define bmGPINPOL7 0x80
|
||||
|
||||
#define rHIRQ 0xC8 //25<<3
|
||||
/* HIRQ Bits */
|
||||
#define bmBUSEVENTIRQ 0x01 // indicates BUS Reset Done or BUS Resume
|
||||
#define bmRWUIRQ 0x02
|
||||
#define bmRCVDAVIRQ 0x04
|
||||
#define bmSNDBAVIRQ 0x08
|
||||
#define bmSUSDNIRQ 0x10
|
||||
#define bmCONDETIRQ 0x20
|
||||
#define bmFRAMEIRQ 0x40
|
||||
#define bmHXFRDNIRQ 0x80
|
||||
|
||||
#define rHIEN 0xD0 //26<<3
|
||||
|
||||
/* HIEN Bits */
|
||||
#define bmBUSEVENTIE 0x01
|
||||
#define bmRWUIE 0x02
|
||||
#define bmRCVDAVIE 0x04
|
||||
#define bmSNDBAVIE 0x08
|
||||
#define bmSUSDNIE 0x10
|
||||
#define bmCONDETIE 0x20
|
||||
#define bmFRAMEIE 0x40
|
||||
#define bmHXFRDNIE 0x80
|
||||
|
||||
#define rMODE 0xD8 //27<<3
|
||||
|
||||
/* MODE Bits */
|
||||
#define bmHOST 0x01
|
||||
#define bmLOWSPEED 0x02
|
||||
#define bmHUBPRE 0x04
|
||||
#define bmSOFKAENAB 0x08
|
||||
#define bmSEPIRQ 0x10
|
||||
#define bmDELAYISO 0x20
|
||||
#define bmDMPULLDN 0x40
|
||||
#define bmDPPULLDN 0x80
|
||||
|
||||
#define rPERADDR 0xE0 //28<<3
|
||||
|
||||
#define rHCTL 0xE8 //29<<3
|
||||
/* HCTL Bits */
|
||||
#define bmBUSRST 0x01
|
||||
#define bmFRMRST 0x02
|
||||
#define bmSAMPLEBUS 0x04
|
||||
#define bmSIGRSM 0x08
|
||||
#define bmRCVTOG0 0x10
|
||||
#define bmRCVTOG1 0x20
|
||||
#define bmSNDTOG0 0x40
|
||||
#define bmSNDTOG1 0x80
|
||||
|
||||
#define rHXFR 0xF0 //30<<3
|
||||
|
||||
#undef tokSETUP
|
||||
#undef tokIN
|
||||
#undef tokOUT
|
||||
#undef tokINHS
|
||||
#undef tokOUTHS
|
||||
#undef tokISOIN
|
||||
#undef tokISOOUT
|
||||
|
||||
/* Host transfer token values for writing the HXFR register (R30) */
|
||||
/* OR this bit field with the endpoint number in bits 3:0 */
|
||||
#define tokSETUP 0x10 // HS=0, ISO=0, OUTNIN=0, SETUP=1
|
||||
#define tokIN 0x00 // HS=0, ISO=0, OUTNIN=0, SETUP=0
|
||||
#define tokOUT 0x20 // HS=0, ISO=0, OUTNIN=1, SETUP=0
|
||||
#define tokINHS 0x80 // HS=1, ISO=0, OUTNIN=0, SETUP=0
|
||||
#define tokOUTHS 0xA0 // HS=1, ISO=0, OUTNIN=1, SETUP=0
|
||||
#define tokISOIN 0x40 // HS=0, ISO=1, OUTNIN=0, SETUP=0
|
||||
#define tokISOOUT 0x60 // HS=0, ISO=1, OUTNIN=1, SETUP=0
|
||||
|
||||
#define rHRSL 0xF8 //31<<3
|
||||
|
||||
/* HRSL Bits */
|
||||
#define bmRCVTOGRD 0x10
|
||||
#define bmSNDTOGRD 0x20
|
||||
#define bmKSTATUS 0x40
|
||||
#define bmJSTATUS 0x80
|
||||
#define bmSE0 0x00 //SE0 - disconnect state
|
||||
#define bmSE1 0xC0 //SE1 - illegal state
|
||||
|
||||
/* Host error result codes, the 4 LSB's in the HRSL register */
|
||||
#define hrSUCCESS 0x00
|
||||
#define hrBUSY 0x01
|
||||
#define hrBADREQ 0x02
|
||||
#define hrUNDEF 0x03
|
||||
#define hrNAK 0x04
|
||||
#define hrSTALL 0x05
|
||||
#define hrTOGERR 0x06
|
||||
#define hrWRONGPID 0x07
|
||||
#define hrBADBC 0x08
|
||||
#define hrPIDERR 0x09
|
||||
#define hrPKTERR 0x0A
|
||||
#define hrCRCERR 0x0B
|
||||
#define hrKERR 0x0C
|
||||
#define hrJERR 0x0D
|
||||
#define hrTIMEOUT 0x0E
|
||||
#define hrBABBLE 0x0F
|
||||
|
||||
#define MODE_FS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmSOFKAENAB)
|
||||
#define MODE_LS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmLOWSPEED|bmSOFKAENAB)
|
@ -0,0 +1,128 @@
|
||||
/**
|
||||
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
*
|
||||
* This program 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information
|
||||
* -------------------
|
||||
*
|
||||
* Circuits At Home, LTD
|
||||
* Web : https://www.circuitsathome.com
|
||||
* e-mail : support@circuitsathome.com
|
||||
*/
|
||||
|
||||
#include "../../../inc/MarlinConfigPre.h"
|
||||
|
||||
#if ENABLED(USB_FLASH_DRIVE_SUPPORT) && DISABLED(USE_UHS3_USB)
|
||||
|
||||
#include "Usb.h"
|
||||
|
||||
// 0x80 is the default (i.e. trace) to turn off set this global to something lower.
|
||||
// this allows for 126 other debugging levels.
|
||||
// TO-DO: Allow assignment to a different serial port by software
|
||||
int UsbDEBUGlvl = 0x80;
|
||||
|
||||
void E_Notifyc(char c, int lvl) {
|
||||
if (UsbDEBUGlvl < lvl) return;
|
||||
USB_HOST_SERIAL.print(c
|
||||
#if !defined(ARDUINO) && !defined(ARDUINO_ARCH_LPC176X)
|
||||
, BYTE
|
||||
#endif
|
||||
);
|
||||
//USB_HOST_SERIAL.flush();
|
||||
}
|
||||
|
||||
void E_Notify(char const * msg, int lvl) {
|
||||
if (UsbDEBUGlvl < lvl) return;
|
||||
if (!msg) return;
|
||||
while (const char c = pgm_read_byte(msg++)) E_Notifyc(c, lvl);
|
||||
}
|
||||
|
||||
void E_NotifyStr(char const * msg, int lvl) {
|
||||
if (UsbDEBUGlvl < lvl) return;
|
||||
if (!msg) return;
|
||||
while (const char c = *msg++) E_Notifyc(c, lvl);
|
||||
}
|
||||
|
||||
void E_Notify(uint8_t b, int lvl) {
|
||||
if (UsbDEBUGlvl < lvl) return;
|
||||
USB_HOST_SERIAL.print(b
|
||||
#if !defined(ARDUINO) || ARDUINO < 100
|
||||
, DEC
|
||||
#endif
|
||||
);
|
||||
//USB_HOST_SERIAL.flush();
|
||||
}
|
||||
|
||||
void E_Notify(double d, int lvl) {
|
||||
if (UsbDEBUGlvl < lvl) return;
|
||||
USB_HOST_SERIAL.print(d);
|
||||
//USB_HOST_SERIAL.flush();
|
||||
}
|
||||
|
||||
#ifdef DEBUG_USB_HOST
|
||||
|
||||
void NotifyFailGetDevDescr() {
|
||||
Notify(PSTR("\r\ngetDevDescr "), 0x80);
|
||||
}
|
||||
|
||||
void NotifyFailSetDevTblEntry() {
|
||||
Notify(PSTR("\r\nsetDevTblEn "), 0x80);
|
||||
}
|
||||
|
||||
void NotifyFailGetConfDescr() {
|
||||
Notify(PSTR("\r\ngetConf "), 0x80);
|
||||
}
|
||||
|
||||
void NotifyFailSetConfDescr() {
|
||||
Notify(PSTR("\r\nsetConf "), 0x80);
|
||||
}
|
||||
|
||||
void NotifyFailGetDevDescr(uint8_t reason) {
|
||||
NotifyFailGetDevDescr();
|
||||
NotifyFail(reason);
|
||||
}
|
||||
|
||||
void NotifyFailSetDevTblEntry(uint8_t reason) {
|
||||
NotifyFailSetDevTblEntry();
|
||||
NotifyFail(reason);
|
||||
|
||||
}
|
||||
|
||||
void NotifyFailGetConfDescr(uint8_t reason) {
|
||||
NotifyFailGetConfDescr();
|
||||
NotifyFail(reason);
|
||||
}
|
||||
|
||||
void NotifyFailSetConfDescr(uint8_t reason) {
|
||||
NotifyFailSetConfDescr();
|
||||
NotifyFail(reason);
|
||||
}
|
||||
|
||||
void NotifyFailUnknownDevice(uint16_t VID, uint16_t PID) {
|
||||
Notify(PSTR("\r\nUnknown Device Connected - VID: "), 0x80);
|
||||
D_PrintHex<uint16_t > (VID, 0x80);
|
||||
Notify(PSTR(" PID: "), 0x80);
|
||||
D_PrintHex<uint16_t > (PID, 0x80);
|
||||
}
|
||||
|
||||
void NotifyFail(uint8_t rcode) {
|
||||
D_PrintHex<uint8_t > (rcode, 0x80);
|
||||
Notify(PSTR("\r\n"), 0x80);
|
||||
}
|
||||
|
||||
#endif // DEBUG_USB_HOST
|
||||
|
||||
#endif // USB_FLASH_DRIVE_SUPPORT
|
@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
*
|
||||
* This program 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information
|
||||
* -------------------
|
||||
*
|
||||
* Circuits At Home, LTD
|
||||
* Web : https://www.circuitsathome.com
|
||||
* e-mail : support@circuitsathome.com
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifndef _usb_h_
|
||||
#error "Never include message.h directly; include Usb.h instead"
|
||||
#endif
|
||||
|
||||
extern int UsbDEBUGlvl;
|
||||
|
||||
void E_Notify(char const * msg, int lvl);
|
||||
void E_Notify(uint8_t b, int lvl);
|
||||
void E_NotifyStr(char const * msg, int lvl);
|
||||
void E_Notifyc(char c, int lvl);
|
||||
|
||||
#ifdef DEBUG_USB_HOST
|
||||
#define Notify E_Notify
|
||||
#define NotifyStr E_NotifyStr
|
||||
#define Notifyc E_Notifyc
|
||||
void NotifyFailGetDevDescr(uint8_t reason);
|
||||
void NotifyFailSetDevTblEntry(uint8_t reason);
|
||||
void NotifyFailGetConfDescr(uint8_t reason);
|
||||
void NotifyFailSetConfDescr(uint8_t reason);
|
||||
void NotifyFailGetDevDescr();
|
||||
void NotifyFailSetDevTblEntry();
|
||||
void NotifyFailGetConfDescr();
|
||||
void NotifyFailSetConfDescr();
|
||||
void NotifyFailUnknownDevice(uint16_t VID, uint16_t PID);
|
||||
void NotifyFail(uint8_t rcode);
|
||||
#else
|
||||
#define Notify(...) ((void)0)
|
||||
#define NotifyStr(...) ((void)0)
|
||||
#define Notifyc(...) ((void)0)
|
||||
#define NotifyFailGetDevDescr(...) ((void)0)
|
||||
#define NotifyFailSetDevTblEntry(...) ((void)0)
|
||||
#define NotifyFailGetConfDescr(...) ((void)0)
|
||||
#define NotifyFailGetDevDescr(...) ((void)0)
|
||||
#define NotifyFailSetDevTblEntry(...) ((void)0)
|
||||
#define NotifyFailGetConfDescr(...) ((void)0)
|
||||
#define NotifyFailSetConfDescr(...) ((void)0)
|
||||
#define NotifyFailUnknownDevice(...) ((void)0)
|
||||
#define NotifyFail(...) ((void)0)
|
||||
#endif
|
||||
|
||||
template <class ERROR_TYPE>
|
||||
void ErrorMessage(uint8_t level, char const * msg, ERROR_TYPE rcode = 0) {
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(msg, level);
|
||||
Notify(PSTR(": "), level);
|
||||
D_PrintHex<ERROR_TYPE > (rcode, level);
|
||||
Notify(PSTR("\r\n"), level);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class ERROR_TYPE>
|
||||
void ErrorMessage(char const * msg __attribute__((unused)), ERROR_TYPE rcode __attribute__((unused)) = 0) {
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(msg, 0x80);
|
||||
Notify(PSTR(": "), 0x80);
|
||||
D_PrintHex<ERROR_TYPE > (rcode, 0x80);
|
||||
Notify(PSTR("\r\n"), 0x80);
|
||||
#endif
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
*
|
||||
* This program 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information
|
||||
* -------------------
|
||||
*
|
||||
* Circuits At Home, LTD
|
||||
* Web : https://www.circuitsathome.com
|
||||
* e-mail : support@circuitsathome.com
|
||||
*/
|
||||
|
||||
#include "../../../inc/MarlinConfigPre.h"
|
||||
|
||||
#if ENABLED(USB_FLASH_DRIVE_SUPPORT) && DISABLED(USE_UHS3_USB)
|
||||
|
||||
#include "Usb.h"
|
||||
|
||||
bool MultiByteValueParser::Parse(uint8_t **pp, uint16_t *pcntdn) {
|
||||
if (!pBuf) {
|
||||
Notify(PSTR("Buffer pointer is NULL!\r\n"), 0x80);
|
||||
return false;
|
||||
}
|
||||
for (; countDown && (*pcntdn); countDown--, (*pcntdn)--, (*pp)++)
|
||||
pBuf[valueSize - countDown] = (**pp);
|
||||
|
||||
if (countDown) return false;
|
||||
|
||||
countDown = valueSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PTPListParser::Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me) {
|
||||
switch (nStage) {
|
||||
case 0:
|
||||
pBuf->valueSize = lenSize;
|
||||
theParser.Initialize(pBuf);
|
||||
nStage = 1;
|
||||
|
||||
case 1:
|
||||
if (!theParser.Parse(pp, pcntdn)) return false;
|
||||
|
||||
arLen = 0;
|
||||
arLen = (pBuf->valueSize >= 4) ? *((uint32_t*)pBuf->pValue) : (uint32_t)(*((uint16_t*)pBuf->pValue));
|
||||
arLenCntdn = arLen;
|
||||
nStage = 2;
|
||||
|
||||
case 2:
|
||||
pBuf->valueSize = valSize;
|
||||
theParser.Initialize(pBuf);
|
||||
nStage = 3;
|
||||
|
||||
case 3:
|
||||
for (; arLenCntdn; arLenCntdn--) {
|
||||
if (!theParser.Parse(pp, pcntdn)) return false;
|
||||
if (pf) pf(pBuf, (arLen - arLenCntdn), me);
|
||||
}
|
||||
|
||||
nStage = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // USB_FLASH_DRIVE_SUPPORT
|
@ -0,0 +1,145 @@
|
||||
/**
|
||||
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
*
|
||||
* This program 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information
|
||||
* -------------------
|
||||
*
|
||||
* Circuits At Home, LTD
|
||||
* Web : https://www.circuitsathome.com
|
||||
* e-mail : support@circuitsathome.com
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifndef _usb_h_
|
||||
#error "Never include parsetools.h directly; include Usb.h instead"
|
||||
#endif
|
||||
|
||||
struct MultiValueBuffer {
|
||||
uint8_t valueSize;
|
||||
void *pValue;
|
||||
} __attribute__((packed));
|
||||
|
||||
class MultiByteValueParser {
|
||||
uint8_t * pBuf;
|
||||
uint8_t countDown;
|
||||
uint8_t valueSize;
|
||||
|
||||
public:
|
||||
|
||||
MultiByteValueParser() : pBuf(nullptr), countDown(0), valueSize(0) {
|
||||
};
|
||||
|
||||
const uint8_t* GetBuffer() { return pBuf; }
|
||||
|
||||
void Initialize(MultiValueBuffer * const pbuf) {
|
||||
pBuf = (uint8_t*)pbuf->pValue;
|
||||
countDown = valueSize = pbuf->valueSize;
|
||||
}
|
||||
|
||||
bool Parse(uint8_t **pp, uint16_t *pcntdn);
|
||||
};
|
||||
|
||||
class ByteSkipper {
|
||||
uint8_t *pBuf;
|
||||
uint8_t nStage;
|
||||
uint16_t countDown;
|
||||
|
||||
public:
|
||||
|
||||
ByteSkipper() : pBuf(nullptr), nStage(0), countDown(0) {
|
||||
}
|
||||
|
||||
void Initialize(MultiValueBuffer *pbuf) {
|
||||
pBuf = (uint8_t*)pbuf->pValue;
|
||||
countDown = 0;
|
||||
}
|
||||
|
||||
bool Skip(uint8_t **pp, uint16_t *pcntdn, uint16_t bytes_to_skip) {
|
||||
switch (nStage) {
|
||||
case 0:
|
||||
countDown = bytes_to_skip;
|
||||
nStage++;
|
||||
case 1:
|
||||
for (; countDown && (*pcntdn); countDown--, (*pp)++, (*pcntdn)--);
|
||||
|
||||
if (!countDown)
|
||||
nStage = 0;
|
||||
}
|
||||
return (!countDown);
|
||||
}
|
||||
};
|
||||
|
||||
// Pointer to a callback function triggered for each element of PTP array when used with PTPArrayParser
|
||||
typedef void (*PTP_ARRAY_EL_FUNC)(const MultiValueBuffer * const p, uint32_t count, const void *me);
|
||||
|
||||
class PTPListParser {
|
||||
public:
|
||||
|
||||
enum ParseMode {
|
||||
modeArray, modeRange/*, modeEnum*/
|
||||
};
|
||||
|
||||
private:
|
||||
uint8_t nStage;
|
||||
uint8_t enStage;
|
||||
|
||||
uint32_t arLen;
|
||||
uint32_t arLenCntdn;
|
||||
|
||||
uint8_t lenSize; // size of the array length field in bytes
|
||||
uint8_t valSize; // size of the array element in bytes
|
||||
|
||||
MultiValueBuffer *pBuf;
|
||||
|
||||
// The only parser for both size and array element parsing
|
||||
MultiByteValueParser theParser;
|
||||
|
||||
uint8_t /*ParseMode*/ prsMode;
|
||||
|
||||
public:
|
||||
|
||||
PTPListParser() :
|
||||
nStage(0),
|
||||
enStage(0),
|
||||
arLen(0),
|
||||
arLenCntdn(0),
|
||||
lenSize(0),
|
||||
valSize(0),
|
||||
pBuf(nullptr),
|
||||
prsMode(modeArray) {}
|
||||
;
|
||||
|
||||
void Initialize(const uint8_t len_size, const uint8_t val_size, MultiValueBuffer * const p, const uint8_t mode = modeArray) {
|
||||
pBuf = p;
|
||||
lenSize = len_size;
|
||||
valSize = val_size;
|
||||
prsMode = mode;
|
||||
|
||||
if (prsMode == modeRange) {
|
||||
arLenCntdn = arLen = 3;
|
||||
nStage = 2;
|
||||
}
|
||||
else {
|
||||
arLenCntdn = arLen = 0;
|
||||
nStage = 0;
|
||||
}
|
||||
enStage = 0;
|
||||
theParser.Initialize(p);
|
||||
}
|
||||
|
||||
bool Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me = nullptr);
|
||||
};
|
@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
*
|
||||
* This program 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information
|
||||
* -------------------
|
||||
*
|
||||
* Circuits At Home, LTD
|
||||
* Web : https://www.circuitsathome.com
|
||||
* e-mail : support@circuitsathome.com
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifndef _usb_h_
|
||||
#error "Never include printhex.h directly; include Usb.h instead"
|
||||
#endif
|
||||
|
||||
void E_Notifyc(char c, int lvl);
|
||||
|
||||
template <class T>
|
||||
void PrintHex(T val, int lvl) {
|
||||
int num_nybbles = sizeof (T) * 2;
|
||||
do {
|
||||
char v = 48 + (((val >> (num_nybbles - 1) * 4)) & 0x0F);
|
||||
if (v > 57) v += 7;
|
||||
E_Notifyc(v, lvl);
|
||||
} while (--num_nybbles);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void PrintBin(T val, int lvl) {
|
||||
for (T mask = (((T)1) << ((sizeof (T) << 3) - 1)); mask; mask >>= 1)
|
||||
E_Notifyc(val & mask ? '1' : '0', lvl);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void SerialPrintHex(T val) {
|
||||
int num_nybbles = sizeof (T) * 2;
|
||||
do {
|
||||
char v = 48 + (((val >> (num_nybbles - 1) * 4)) & 0x0F);
|
||||
if (v > 57) v += 7;
|
||||
USB_HOST_SERIAL.print(v);
|
||||
} while (--num_nybbles);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void PrintHex2(Print *prn, T val) {
|
||||
T mask = (((T)1) << (((sizeof (T) << 1) - 1) << 2));
|
||||
while (mask > 1) {
|
||||
if (val < mask) prn->print("0");
|
||||
mask >>= 4;
|
||||
}
|
||||
prn->print((T)val, HEX);
|
||||
}
|
||||
|
||||
template <class T> void D_PrintHex(T val __attribute__((unused)), int lvl __attribute__((unused))) {
|
||||
#ifdef DEBUG_USB_HOST
|
||||
PrintHex<T > (val, lvl);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void D_PrintBin(T val, int lvl) {
|
||||
#ifdef DEBUG_USB_HOST
|
||||
PrintBin<T > (val, lvl);
|
||||
#endif
|
||||
}
|
236
Marlin Firmware/Marlin/src/sd/usb_flashdrive/lib-uhs2/settings.h
Normal file
236
Marlin Firmware/Marlin/src/sd/usb_flashdrive/lib-uhs2/settings.h
Normal file
@ -0,0 +1,236 @@
|
||||
/**
|
||||
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
*
|
||||
* This program 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information
|
||||
* -------------------
|
||||
*
|
||||
* Circuits At Home, LTD
|
||||
* Web : https://www.circuitsathome.com
|
||||
* e-mail : support@circuitsathome.com
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../../inc/MarlinConfig.h"
|
||||
|
||||
#include "macros.h"
|
||||
|
||||
#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/* Added by Bill Greiman to speed up mass storage initialization with USB
|
||||
* flash drives and simple USB hard drives.
|
||||
* Disable this by defining DELAY(x) to be delay(x).
|
||||
*/
|
||||
#define delay(x) if ((x) < 200) safe_delay(x)
|
||||
/* Almost all USB flash drives and simple USB hard drives fail the write
|
||||
* protect test and add 20 - 30 seconds to USB init. Set SKIP_WRITE_PROTECT
|
||||
* to nonzero to skip the test and assume the drive is writable.
|
||||
*/
|
||||
#define SKIP_WRITE_PROTECT 1
|
||||
/* Since Marlin only cares about USB flash drives, we only need one LUN. */
|
||||
#define MASS_MAX_SUPPORTED_LUN 1
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// SPI Configuration
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef USB_SPI
|
||||
#define USB_SPI SPI
|
||||
//#define USB_SPI SPI1
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// DEBUGGING
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/* Set this to 1 to activate serial debugging */
|
||||
#define ENABLE_UHS_DEBUGGING 0
|
||||
|
||||
/* This can be used to select which serial port to use for debugging if
|
||||
* multiple serial ports are available.
|
||||
* For example Serial3.
|
||||
*/
|
||||
#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
|
||||
#define USB_HOST_SERIAL MYSERIAL1
|
||||
#endif
|
||||
|
||||
#ifndef USB_HOST_SERIAL
|
||||
#define USB_HOST_SERIAL Serial
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Manual board activation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/* Set this to 1 if you are using an Arduino Mega ADK board with MAX3421e built-in */
|
||||
#define USE_UHS_MEGA_ADK 0 // If you are using Arduino 1.5.5 or newer there is no need to do this manually
|
||||
|
||||
/* Set this to 1 if you are using a Black Widdow */
|
||||
#define USE_UHS_BLACK_WIDDOW 0
|
||||
|
||||
/* Set this to a one to use the xmem2 lock. This is needed for multitasking and threading */
|
||||
#define USE_XMEM_SPI_LOCK 0
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Wii IR camera
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/* Set this to 1 to activate code for the Wii IR camera */
|
||||
#define ENABLE_WII_IR_CAMERA 0
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// MASS STORAGE
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// ******* IMPORTANT *******
|
||||
// Set this to 1 to support single LUN devices, and save RAM. -- I.E. thumb drives.
|
||||
// Each LUN needs ~13 bytes to be able to track the state of each unit.
|
||||
#ifndef MASS_MAX_SUPPORTED_LUN
|
||||
#define MASS_MAX_SUPPORTED_LUN 8
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Set to 1 to use the faster spi4teensy3 driver.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef USE_SPI4TEENSY3
|
||||
#define USE_SPI4TEENSY3 1
|
||||
#endif
|
||||
|
||||
// Disabled on the Teensy LC, as it is incompatible for now
|
||||
#ifdef __MKL26Z64__
|
||||
#undef USE_SPI4TEENSY3
|
||||
#define USE_SPI4TEENSY3 0
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// AUTOMATIC Settings
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// No user serviceable parts below this line.
|
||||
// DO NOT change anything below here unless you are a developer!
|
||||
|
||||
//#include "version_helper.h"
|
||||
|
||||
#if defined(__GNUC__) && defined(__AVR__)
|
||||
#ifndef GCC_VERSION
|
||||
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
|
||||
#endif
|
||||
#if GCC_VERSION < 40602 // Test for GCC < 4.6.2
|
||||
#ifdef PROGMEM
|
||||
#undef PROGMEM
|
||||
#define PROGMEM __attribute__((section(".progmem.data"))) // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=34734#c4
|
||||
#ifdef PSTR
|
||||
#undef PSTR
|
||||
#define PSTR(s) (__extension__({static const char __c[] PROGMEM = (s); &__c[0];})) // Copied from pgmspace.h in avr-libc source
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(DEBUG_USB_HOST) && ENABLE_UHS_DEBUGGING
|
||||
#define DEBUG_USB_HOST
|
||||
#endif
|
||||
|
||||
#if !defined(WIICAMERA) && ENABLE_WII_IR_CAMERA
|
||||
#define WIICAMERA
|
||||
#endif
|
||||
|
||||
// To use some other locking (e.g. freertos),
|
||||
// define XMEM_ACQUIRE_SPI and XMEM_RELEASE_SPI to point to your lock and unlock.
|
||||
// NOTE: NO argument is passed. You have to do this within your routine for
|
||||
// whatever you are using to lock and unlock.
|
||||
#ifndef XMEM_ACQUIRE_SPI
|
||||
#if USE_XMEM_SPI_LOCK || defined(USE_MULTIPLE_APP_API)
|
||||
#include <xmem.h>
|
||||
#else
|
||||
#define XMEM_ACQUIRE_SPI() (void(0))
|
||||
#define XMEM_RELEASE_SPI() (void(0))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(EXT_RAM) && defined(EXT_RAM_STACK) || defined(EXT_RAM_HEAP)
|
||||
#include <xmem.h>
|
||||
#else
|
||||
#define EXT_RAM 0
|
||||
#endif
|
||||
|
||||
#if defined(CORE_TEENSY) && defined(KINETISK)
|
||||
#define USING_SPI4TEENSY3 USE_SPI4TEENSY3
|
||||
#else
|
||||
#define USING_SPI4TEENSY3 0
|
||||
#endif
|
||||
#if ((defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)) || defined(__ARDUINO_X86__) || ARDUINO >= 10600) && !USING_SPI4TEENSY3
|
||||
#include <SPI.h> // Use the Arduino SPI library for the Arduino Due, Intel Galileo 1 & 2, Intel Edison or if the SPI library with transaction is available
|
||||
#endif
|
||||
#ifdef RBL_NRF51822
|
||||
#include <nrf_gpio.h>
|
||||
#include <SPI_Master.h>
|
||||
#define SPI SPI_Master
|
||||
#define MFK_CASTUINT8T (uint8_t) // RBLs return type for sizeof needs casting to uint8_t
|
||||
#endif
|
||||
#if defined(__PIC32MX__) || defined(__PIC32MZ__)
|
||||
#include <../../../../hardware/pic32/libraries/SPI/SPI.h> // Hack to use the SPI library
|
||||
#endif
|
||||
|
||||
#if defined(ESP8266) || defined(ESP32)
|
||||
#define MFK_CASTUINT8T (uint8_t) // ESP return type for sizeof needs casting to uint8_t
|
||||
#endif
|
||||
|
||||
#ifdef STM32F4
|
||||
#include "stm32f4xx_hal.h"
|
||||
extern SPI_HandleTypeDef SPI_Handle; // Needed to be declared in your main.cpp
|
||||
#endif
|
||||
|
||||
// Fix defines on Arduino Due
|
||||
#ifdef ARDUINO_SAM_DUE
|
||||
#ifdef tokSETUP
|
||||
#undef tokSETUP
|
||||
#endif
|
||||
#ifdef tokIN
|
||||
#undef tokIN
|
||||
#endif
|
||||
#ifdef tokOUT
|
||||
#undef tokOUT
|
||||
#endif
|
||||
#ifdef tokINHS
|
||||
#undef tokINHS
|
||||
#endif
|
||||
#ifdef tokOUTHS
|
||||
#undef tokOUTHS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Set defaults
|
||||
#ifndef MFK_CASTUINT8T
|
||||
#define MFK_CASTUINT8T
|
||||
#endif
|
||||
|
||||
// Workaround issue: https://github.com/esp8266/Arduino/issues/2078
|
||||
#ifdef ESP8266
|
||||
#undef PROGMEM
|
||||
#define PROGMEM
|
||||
#undef PSTR
|
||||
#define PSTR(s) (s)
|
||||
#undef pgm_read_byte
|
||||
#define pgm_read_byte(addr) (*reinterpret_cast<const uint8_t*>(addr))
|
||||
#undef pgm_read_word
|
||||
#define pgm_read_word(addr) (*reinterpret_cast<const uint16_t*>(addr))
|
||||
#endif
|
||||
|
||||
#ifdef ARDUINO_ESP8266_WIFIO
|
||||
#error "This board is currently not supported"
|
||||
#endif
|
170
Marlin Firmware/Marlin/src/sd/usb_flashdrive/lib-uhs2/usb_ch9.h
Normal file
170
Marlin Firmware/Marlin/src/sd/usb_flashdrive/lib-uhs2/usb_ch9.h
Normal file
@ -0,0 +1,170 @@
|
||||
/**
|
||||
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
*
|
||||
* This program 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information
|
||||
* -------------------
|
||||
*
|
||||
* Circuits At Home, LTD
|
||||
* Web : https://www.circuitsathome.com
|
||||
* e-mail : support@circuitsathome.com
|
||||
*/
|
||||
|
||||
#ifndef _usb_h_
|
||||
#error "Never include usb_ch9.h directly; include Usb.h instead"
|
||||
#endif
|
||||
|
||||
/* USB chapter 9 structures */
|
||||
|
||||
/* Misc.USB constants */
|
||||
#define DEV_DESCR_LEN 18 //device descriptor length
|
||||
#define CONF_DESCR_LEN 9 //configuration descriptor length
|
||||
#define INTR_DESCR_LEN 9 //interface descriptor length
|
||||
#define EP_DESCR_LEN 7 //endpoint descriptor length
|
||||
|
||||
/* Standard Device Requests */
|
||||
|
||||
#define USB_REQUEST_GET_STATUS 0 // Standard Device Request - GET STATUS
|
||||
#define USB_REQUEST_CLEAR_FEATURE 1 // Standard Device Request - CLEAR FEATURE
|
||||
#define USB_REQUEST_SET_FEATURE 3 // Standard Device Request - SET FEATURE
|
||||
#define USB_REQUEST_SET_ADDRESS 5 // Standard Device Request - SET ADDRESS
|
||||
#define USB_REQUEST_GET_DESCRIPTOR 6 // Standard Device Request - GET DESCRIPTOR
|
||||
#define USB_REQUEST_SET_DESCRIPTOR 7 // Standard Device Request - SET DESCRIPTOR
|
||||
#define USB_REQUEST_GET_CONFIGURATION 8 // Standard Device Request - GET CONFIGURATION
|
||||
#define USB_REQUEST_SET_CONFIGURATION 9 // Standard Device Request - SET CONFIGURATION
|
||||
#define USB_REQUEST_GET_INTERFACE 10 // Standard Device Request - GET INTERFACE
|
||||
#define USB_REQUEST_SET_INTERFACE 11 // Standard Device Request - SET INTERFACE
|
||||
#define USB_REQUEST_SYNCH_FRAME 12 // Standard Device Request - SYNCH FRAME
|
||||
|
||||
#define USB_FEATURE_ENDPOINT_HALT 0 // CLEAR/SET FEATURE - Endpoint Halt
|
||||
#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // CLEAR/SET FEATURE - Device remote wake-up
|
||||
#define USB_FEATURE_TEST_MODE 2 // CLEAR/SET FEATURE - Test mode
|
||||
|
||||
/* Setup Data Constants */
|
||||
|
||||
#define USB_SETUP_HOST_TO_DEVICE 0x00 // Device Request bmRequestType transfer direction - host to device transfer
|
||||
#define USB_SETUP_DEVICE_TO_HOST 0x80 // Device Request bmRequestType transfer direction - device to host transfer
|
||||
#define USB_SETUP_TYPE_STANDARD 0x00 // Device Request bmRequestType type - standard
|
||||
#define USB_SETUP_TYPE_CLASS 0x20 // Device Request bmRequestType type - class
|
||||
#define USB_SETUP_TYPE_VENDOR 0x40 // Device Request bmRequestType type - vendor
|
||||
#define USB_SETUP_RECIPIENT_DEVICE 0x00 // Device Request bmRequestType recipient - device
|
||||
#define USB_SETUP_RECIPIENT_INTERFACE 0x01 // Device Request bmRequestType recipient - interface
|
||||
#define USB_SETUP_RECIPIENT_ENDPOINT 0x02 // Device Request bmRequestType recipient - endpoint
|
||||
#define USB_SETUP_RECIPIENT_OTHER 0x03 // Device Request bmRequestType recipient - other
|
||||
|
||||
/* USB descriptors */
|
||||
|
||||
#define USB_DESCRIPTOR_DEVICE 0x01 // bDescriptorType for a Device Descriptor.
|
||||
#define USB_DESCRIPTOR_CONFIGURATION 0x02 // bDescriptorType for a Configuration Descriptor.
|
||||
#define USB_DESCRIPTOR_STRING 0x03 // bDescriptorType for a String Descriptor.
|
||||
#define USB_DESCRIPTOR_INTERFACE 0x04 // bDescriptorType for an Interface Descriptor.
|
||||
#define USB_DESCRIPTOR_ENDPOINT 0x05 // bDescriptorType for an Endpoint Descriptor.
|
||||
#define USB_DESCRIPTOR_DEVICE_QUALIFIER 0x06 // bDescriptorType for a Device Qualifier.
|
||||
#define USB_DESCRIPTOR_OTHER_SPEED 0x07 // bDescriptorType for a Other Speed Configuration.
|
||||
#define USB_DESCRIPTOR_INTERFACE_POWER 0x08 // bDescriptorType for Interface Power.
|
||||
#define USB_DESCRIPTOR_OTG 0x09 // bDescriptorType for an OTG Descriptor.
|
||||
|
||||
#define HID_DESCRIPTOR_HID 0x21
|
||||
|
||||
|
||||
/* OTG SET FEATURE Constants */
|
||||
#define OTG_FEATURE_B_HNP_ENABLE 3 // SET FEATURE OTG - Enable B device to perform HNP
|
||||
#define OTG_FEATURE_A_HNP_SUPPORT 4 // SET FEATURE OTG - A device supports HNP
|
||||
#define OTG_FEATURE_A_ALT_HNP_SUPPORT 5 // SET FEATURE OTG - Another port on the A device supports HNP
|
||||
|
||||
/* USB Endpoint Transfer Types */
|
||||
#define USB_TRANSFER_TYPE_CONTROL 0x00 // Endpoint is a control endpoint.
|
||||
#define USB_TRANSFER_TYPE_ISOCHRONOUS 0x01 // Endpoint is an isochronous endpoint.
|
||||
#define USB_TRANSFER_TYPE_BULK 0x02 // Endpoint is a bulk endpoint.
|
||||
#define USB_TRANSFER_TYPE_INTERRUPT 0x03 // Endpoint is an interrupt endpoint.
|
||||
#define bmUSB_TRANSFER_TYPE 0x03 // bit mask to separate transfer type from ISO attributes
|
||||
|
||||
|
||||
/* Standard Feature Selectors for CLEAR_FEATURE Requests */
|
||||
#define USB_FEATURE_ENDPOINT_STALL 0 // Endpoint recipient
|
||||
#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // Device recipient
|
||||
#define USB_FEATURE_TEST_MODE 2 // Device recipient
|
||||
|
||||
/* descriptor data structures */
|
||||
|
||||
/* Device descriptor structure */
|
||||
typedef struct {
|
||||
uint8_t bLength; // Length of this descriptor.
|
||||
uint8_t bDescriptorType; // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE).
|
||||
uint16_t bcdUSB; // USB Spec Release Number (BCD).
|
||||
uint8_t bDeviceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific.
|
||||
uint8_t bDeviceSubClass; // Subclass code (assigned by the USB-IF).
|
||||
uint8_t bDeviceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific.
|
||||
uint8_t bMaxPacketSize0; // Maximum packet size for endpoint 0.
|
||||
uint16_t idVendor; // Vendor ID (assigned by the USB-IF).
|
||||
uint16_t idProduct; // Product ID (assigned by the manufacturer).
|
||||
uint16_t bcdDevice; // Device release number (BCD).
|
||||
uint8_t iManufacturer; // Index of String Descriptor describing the manufacturer.
|
||||
uint8_t iProduct; // Index of String Descriptor describing the product.
|
||||
uint8_t iSerialNumber; // Index of String Descriptor with the device's serial number.
|
||||
uint8_t bNumConfigurations; // Number of possible configurations.
|
||||
} __attribute__((packed)) USB_FD_DEVICE_DESCRIPTOR;
|
||||
|
||||
/* Configuration descriptor structure */
|
||||
typedef struct {
|
||||
uint8_t bLength; // Length of this descriptor.
|
||||
uint8_t bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION).
|
||||
uint16_t wTotalLength; // Total length of all descriptors for this configuration.
|
||||
uint8_t bNumInterfaces; // Number of interfaces in this configuration.
|
||||
uint8_t bConfigurationValue; // Value of this configuration (1 based).
|
||||
uint8_t iConfiguration; // Index of String Descriptor describing the configuration.
|
||||
uint8_t bmAttributes; // Configuration characteristics.
|
||||
uint8_t bMaxPower; // Maximum power consumed by this configuration.
|
||||
} __attribute__((packed)) USB_FD_CONFIGURATION_DESCRIPTOR;
|
||||
|
||||
/* Interface descriptor structure */
|
||||
typedef struct {
|
||||
uint8_t bLength; // Length of this descriptor.
|
||||
uint8_t bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE).
|
||||
uint8_t bInterfaceNumber; // Number of this interface (0 based).
|
||||
uint8_t bAlternateSetting; // Value of this alternate interface setting.
|
||||
uint8_t bNumEndpoints; // Number of endpoints in this interface.
|
||||
uint8_t bInterfaceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific.
|
||||
uint8_t bInterfaceSubClass; // Subclass code (assigned by the USB-IF).
|
||||
uint8_t bInterfaceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific.
|
||||
uint8_t iInterface; // Index of String Descriptor describing the interface.
|
||||
} __attribute__((packed)) USB_FD_INTERFACE_DESCRIPTOR;
|
||||
|
||||
/* Endpoint descriptor structure */
|
||||
typedef struct {
|
||||
uint8_t bLength; // Length of this descriptor.
|
||||
uint8_t bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT).
|
||||
uint8_t bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN).
|
||||
uint8_t bmAttributes; // Endpoint transfer type.
|
||||
uint16_t wMaxPacketSize; // Maximum packet size.
|
||||
uint8_t bInterval; // Polling interval in frames.
|
||||
} __attribute__((packed)) USB_FD_ENDPOINT_DESCRIPTOR;
|
||||
|
||||
/* HID descriptor */
|
||||
typedef struct {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint16_t bcdHID; // HID class specification release
|
||||
uint8_t bCountryCode;
|
||||
uint8_t bNumDescriptors; // Number of additional class specific descriptors
|
||||
uint8_t bDescrType; // Type of class descriptor
|
||||
uint16_t wDescriptorLength; // Total size of the Report descriptor
|
||||
} __attribute__((packed)) USB_HID_DESCRIPTOR;
|
||||
|
||||
typedef struct {
|
||||
uint8_t bDescrType; // Type of class descriptor
|
||||
uint16_t wDescriptorLength; // Total size of the Report descriptor
|
||||
} __attribute__((packed)) HID_CLASS_DESCRIPTOR_LEN_AND_TYPE;
|
@ -0,0 +1,207 @@
|
||||
/****************
|
||||
* usb_host.cpp *
|
||||
****************/
|
||||
|
||||
/****************************************************************************
|
||||
* Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
|
||||
* *
|
||||
* This program 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. *
|
||||
* *
|
||||
* This program 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. *
|
||||
* *
|
||||
* To view a copy of the GNU General Public License, go to the following *
|
||||
* location: <https://www.gnu.org/licenses/>. *
|
||||
****************************************************************************/
|
||||
|
||||
/* What follows is a modified version of the MAX3421e originally defined in
|
||||
* lib/usbhost.c". This has been rewritten to use SPI routines from the
|
||||
* Marlin HAL */
|
||||
|
||||
#include "../../../inc/MarlinConfigPre.h"
|
||||
|
||||
#if ENABLED(USB_FLASH_DRIVE_SUPPORT) && DISABLED(USE_UHS3_USB)
|
||||
|
||||
#include "Usb.h"
|
||||
#include "usbhost.h"
|
||||
|
||||
uint8_t MAX3421e::vbusState = 0;
|
||||
|
||||
// constructor
|
||||
void MAX3421e::cs() {
|
||||
WRITE(USB_CS_PIN,0);
|
||||
}
|
||||
|
||||
void MAX3421e::ncs() {
|
||||
WRITE(USB_CS_PIN,1);
|
||||
}
|
||||
|
||||
// write single byte into MAX3421 register
|
||||
void MAX3421e::regWr(uint8_t reg, uint8_t data) {
|
||||
cs();
|
||||
spiSend(reg | 0x02);
|
||||
spiSend(data);
|
||||
ncs();
|
||||
};
|
||||
|
||||
// multiple-byte write
|
||||
// return a pointer to memory position after last written
|
||||
uint8_t* MAX3421e::bytesWr(uint8_t reg, uint8_t nbytes, uint8_t *data_p) {
|
||||
cs();
|
||||
spiSend(reg | 0x02);
|
||||
while (nbytes--) spiSend(*data_p++);
|
||||
ncs();
|
||||
return data_p;
|
||||
}
|
||||
|
||||
// GPIO write
|
||||
// GPIO byte is split between 2 registers, so two writes are needed to write one byte
|
||||
|
||||
// GPOUT bits are in the low nybble. 0-3 in IOPINS1, 4-7 in IOPINS2
|
||||
void MAX3421e::gpioWr(uint8_t data) {
|
||||
regWr(rIOPINS1, data);
|
||||
regWr(rIOPINS2, data >> 4);
|
||||
}
|
||||
|
||||
// single host register read
|
||||
uint8_t MAX3421e::regRd(uint8_t reg) {
|
||||
cs();
|
||||
spiSend(reg);
|
||||
uint8_t rv = spiRec();
|
||||
ncs();
|
||||
return rv;
|
||||
}
|
||||
// multiple-byte register read
|
||||
|
||||
// return a pointer to a memory position after last read
|
||||
uint8_t* MAX3421e::bytesRd(uint8_t reg, uint8_t nbytes, uint8_t *data_p) {
|
||||
cs();
|
||||
spiSend(reg);
|
||||
while (nbytes--) *data_p++ = spiRec();
|
||||
ncs();
|
||||
return data_p;
|
||||
}
|
||||
// GPIO read. See gpioWr for explanation
|
||||
|
||||
// GPIN pins are in high nybbles of IOPINS1, IOPINS2
|
||||
uint8_t MAX3421e::gpioRd() {
|
||||
return (regRd(rIOPINS2) & 0xF0) | // pins 4-7, clean lower nybble
|
||||
(regRd(rIOPINS1) >> 4); // shift low bits and OR with upper from previous operation.
|
||||
}
|
||||
|
||||
// reset MAX3421e. Returns false if PLL failed to stabilize 1 second after reset
|
||||
bool MAX3421e::reset() {
|
||||
regWr(rUSBCTL, bmCHIPRES);
|
||||
regWr(rUSBCTL, 0x00);
|
||||
for (uint8_t i = 100; i--;) {
|
||||
if (regRd(rUSBIRQ) & bmOSCOKIRQ) return true;
|
||||
delay(10);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// initialize MAX3421e. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not
|
||||
bool MAX3421e::start() {
|
||||
// Initialize pins and SPI bus
|
||||
|
||||
SET_OUTPUT(USB_CS_PIN);
|
||||
SET_INPUT_PULLUP(USB_INTR_PIN);
|
||||
ncs();
|
||||
spiBegin();
|
||||
|
||||
spiInit(SD_SPI_SPEED);
|
||||
|
||||
// MAX3421e - full-duplex, level interrupt, vbus off.
|
||||
regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL | GPX_VBDET));
|
||||
|
||||
const uint8_t revision = regRd(rREVISION);
|
||||
if (revision == 0x00 || revision == 0xFF) {
|
||||
SERIAL_ECHOLNPAIR("Revision register appears incorrect on MAX3421e initialization. Got ", revision);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!reset()) {
|
||||
SERIAL_ECHOLNPGM("OSCOKIRQ hasn't asserted in time");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Delay a minimum of 1 second to ensure any capacitors are drained.
|
||||
// 1 second is required to make sure we do not smoke a Microdrive!
|
||||
|
||||
delay(1000);
|
||||
|
||||
regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host
|
||||
regWr(rHIEN, bmCONDETIE | bmFRAMEIE); // connection detection
|
||||
|
||||
// check if device is connected
|
||||
regWr(rHCTL, bmSAMPLEBUS); // sample USB bus
|
||||
while (!(regRd(rHCTL) & bmSAMPLEBUS)) delay(10); // wait for sample operation to finish
|
||||
|
||||
busprobe(); // check if anything is connected
|
||||
|
||||
regWr(rHIRQ, bmCONDETIRQ); // clear connection detect interrupt
|
||||
regWr(rCPUCTL, 0x01); // enable interrupt pin
|
||||
|
||||
// GPX pin on. This is done here so that busprobe will fail if we have a switch connected.
|
||||
regWr(rPINCTL, bmFDUPSPI | bmINTLEVEL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Probe bus to determine device presence and speed. Switch host to this speed.
|
||||
void MAX3421e::busprobe() {
|
||||
// Switch on just the J & K bits
|
||||
switch (regRd(rHRSL) & (bmJSTATUS | bmKSTATUS)) {
|
||||
case bmJSTATUS:
|
||||
if ((regRd(rMODE) & bmLOWSPEED) == 0) {
|
||||
regWr(rMODE, MODE_FS_HOST); // start full-speed host
|
||||
vbusState = FSHOST;
|
||||
}
|
||||
else {
|
||||
regWr(rMODE, MODE_LS_HOST); // start low-speed host
|
||||
vbusState = LSHOST;
|
||||
}
|
||||
break;
|
||||
case bmKSTATUS:
|
||||
if ((regRd(rMODE) & bmLOWSPEED) == 0) {
|
||||
regWr(rMODE, MODE_LS_HOST); // start low-speed host
|
||||
vbusState = LSHOST;
|
||||
}
|
||||
else {
|
||||
regWr(rMODE, MODE_FS_HOST); // start full-speed host
|
||||
vbusState = FSHOST;
|
||||
}
|
||||
break;
|
||||
case bmSE1: // illegal state
|
||||
vbusState = SE1;
|
||||
break;
|
||||
case bmSE0: // disconnected state
|
||||
regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST | bmSEPIRQ);
|
||||
vbusState = SE0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// MAX3421 state change task and interrupt handler
|
||||
uint8_t MAX3421e::Task() {
|
||||
return READ(USB_INTR_PIN) ? 0 : IntHandler();
|
||||
}
|
||||
|
||||
uint8_t MAX3421e::IntHandler() {
|
||||
uint8_t HIRQ = regRd(rHIRQ), // determine interrupt source
|
||||
HIRQ_sendback = 0x00;
|
||||
if (HIRQ & bmCONDETIRQ) {
|
||||
busprobe();
|
||||
HIRQ_sendback |= bmCONDETIRQ;
|
||||
}
|
||||
// End HIRQ interrupts handling, clear serviced IRQs
|
||||
regWr(rHIRQ, HIRQ_sendback);
|
||||
return HIRQ_sendback;
|
||||
}
|
||||
|
||||
#endif // USB_FLASH_DRIVE_SUPPORT
|
@ -0,0 +1,58 @@
|
||||
/**************
|
||||
* usb_host.h *
|
||||
**************/
|
||||
|
||||
/****************************************************************************
|
||||
* Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
|
||||
* *
|
||||
* This program 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. *
|
||||
* *
|
||||
* This program 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. *
|
||||
* *
|
||||
* To view a copy of the GNU General Public License, go to the following *
|
||||
* location: <https://www.gnu.org/licenses/>. *
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
/* This the following comes from "lib/usbhost.h", but has been rewritten
|
||||
* to use the SPI functions from Marlin's HAL */
|
||||
|
||||
class MAX3421e {
|
||||
private:
|
||||
static uint8_t vbusState;
|
||||
void cs();
|
||||
void ncs();
|
||||
|
||||
uint8_t GpxHandler();
|
||||
uint8_t IntHandler();
|
||||
|
||||
public:
|
||||
bool start();
|
||||
|
||||
void regWr(uint8_t reg, uint8_t data);
|
||||
uint8_t* bytesWr(uint8_t reg, uint8_t nbytes, uint8_t *data_p);
|
||||
void gpioWr(uint8_t data);
|
||||
uint8_t regRd(uint8_t reg);
|
||||
uint8_t* bytesRd(uint8_t reg, uint8_t nbytes, uint8_t *data_p);
|
||||
uint8_t gpioRd();
|
||||
bool reset();
|
||||
|
||||
uint8_t getVbusState() {return vbusState;};
|
||||
|
||||
void busprobe();
|
||||
|
||||
uint8_t Task();
|
||||
};
|
||||
|
||||
#define USE_MARLIN_MAX3421E
|
||||
|
||||
#if defined(__SAM3X8E__) && !defined(ARDUINO_SAM_DUE)
|
||||
#define ARDUINO_SAM_DUE // Spoof the USB library that this is a DUE
|
||||
#endif
|
@ -0,0 +1,31 @@
|
||||
==== USB HOST SHIELD 3.0 LIBRARY ====
|
||||
|
||||
The lib-uhs3/ folder contains a subset of the files from the USB Host Shield
|
||||
3.0 library:
|
||||
|
||||
https://github.com/felis/UHS30
|
||||
|
||||
|
||||
==== LICENSE SUMMARY ====
|
||||
|
||||
Source Path: Repository: License:
|
||||
------------ ----------- --------
|
||||
usb_flashdrive/lib github.com/felis/UHS30 GPLv2 or later
|
||||
|
||||
|
||||
==== MARLIN INTEGRATION WORK ====
|
||||
|
||||
All additional work done to integrate USB into Marlin was performed by
|
||||
AlephObjects, Inc. and is licensed under the GPLv3.
|
||||
|
||||
This version of UHS3 has been modified for better compatibility with Marlin.
|
||||
The upstream version of UHS 3.0 runs a frame timer interrupt every 1 ms to
|
||||
handle device polling. This timer interrupt interferes with Marlin's stepper
|
||||
IRQ, so the flag USB_HOST_MANUAL_POLL has been added to move the polling to
|
||||
the idle task. Additional logic was added to disable and enable the frame
|
||||
IRQ.
|
||||
|
||||
SKIP_PAGE3F and USB_NO_TEST_UNIT_READY were added to work around bugs with
|
||||
certain devices.
|
||||
|
||||
-- marcio@alephobjects.com
|
@ -0,0 +1,249 @@
|
||||
/* Copyright (C) 2015-2016 Andrew J. Kroll
|
||||
and
|
||||
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Contact information
|
||||
-------------------
|
||||
|
||||
Circuits At Home, LTD
|
||||
Web : https://www.circuitsathome.com
|
||||
e-mail : support@circuitsathome.com
|
||||
*/
|
||||
|
||||
#ifndef __UHS_BULK_STORAGE_H__
|
||||
#define __UHS_BULK_STORAGE_H__
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Define any of these options at the top of your sketch to override
|
||||
// the defaults contained herewith. Do NOT do modifications here.
|
||||
// Macro | Settings and notes | Default
|
||||
// -----------------------------------------+-----------------------+-----------
|
||||
// | 1 to 8 |
|
||||
// | Each LUN needs |
|
||||
// MASS_MAX_SUPPORTED_LUN | ~13 bytes to be able | 8
|
||||
// | to track the state of |
|
||||
// | each unit. |
|
||||
// -----------------------------------------+-----------------------+-----------
|
||||
// | Just define to use. |
|
||||
// DEBUG_PRINTF_EXTRA_HUGE_UHS_BULK_STORAGE | works only if extra |
|
||||
// | huge debug is on too. |
|
||||
// -----------------------------------------^-----------------------^-----------
|
||||
|
||||
#ifndef MASS_MAX_SUPPORTED_LUN
|
||||
#define MASS_MAX_SUPPORTED_LUN 8
|
||||
#endif
|
||||
|
||||
#include "UHS_SCSI.h"
|
||||
|
||||
#define UHS_BULK_bmREQ_OUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
|
||||
#define UHS_BULK_bmREQ_IN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
|
||||
|
||||
// Request Codes
|
||||
#define UHS_BULK_REQ_ADSC 0x00U
|
||||
#define UHS_BULK_REQ_GET 0xFCU
|
||||
#define UHS_BULK_REQ_PUT 0xFDU
|
||||
#define UHS_BULK_REQ_GET_MAX_LUN 0xFEU
|
||||
#define UHS_BULK_REQ_BOMSR 0xFFU // Mass Storage Reset
|
||||
|
||||
#define UHS_BULK_CBW_SIGNATURE 0x43425355LU
|
||||
#define UHS_BULK_CSW_SIGNATURE 0x53425355LU
|
||||
|
||||
#define UHS_BULK_CMD_DIR_OUT 0x00U
|
||||
#define UHS_BULK_CMD_DIR_IN 0x80U
|
||||
|
||||
/* Bulk error codes */
|
||||
#define UHS_BULK_ERR_SUCCESS UHS_HOST_ERROR_NONE
|
||||
#define UHS_BULK_ERR_PHASE_ERROR 0x22U
|
||||
#define UHS_BULK_ERR_UNIT_NOT_READY 0x23U
|
||||
#define UHS_BULK_ERR_UNIT_BUSY 0x24U
|
||||
#define UHS_BULK_ERR_STALL 0x25U
|
||||
#define UHS_BULK_ERR_CMD_NOT_SUPPORTED 0x26U
|
||||
#define UHS_BULK_ERR_INVALID_CSW 0x27U
|
||||
#define UHS_BULK_ERR_NO_MEDIA 0x28U
|
||||
#define UHS_BULK_ERR_BAD_LBA 0x29U
|
||||
#define UHS_BULK_ERR_MEDIA_CHANGED 0x2AU
|
||||
#define UHS_BULK_ERR_DEVICE_DISCONNECTED UHS_HOST_ERROR_UNPLUGGED
|
||||
#define UHS_BULK_ERR_UNABLE_TO_RECOVER 0x32U // Reset recovery error
|
||||
#define UHS_BULK_ERR_INVALID_LUN 0x33U
|
||||
#define UHS_BULK_ERR_WRITE_STALL 0x34U
|
||||
#define UHS_BULK_ERR_READ_NAKS 0x35U
|
||||
#define UHS_BULK_ERR_WRITE_NAKS 0x36U
|
||||
#define UHS_BULK_ERR_WRITE_PROTECTED 0x37U
|
||||
#define UHS_BULK_ERR_NOT_IMPLEMENTED 0xFDU
|
||||
#define UHS_BULK_ERR_GENERAL_SCSI_ERROR 0xF0U
|
||||
#define UHS_BULK_ERR_GENERAL_USB_ERROR 0xFFU
|
||||
#define UHS_BULK_ERR_USER 0xA0U // For subclasses to define their own error codes
|
||||
|
||||
#define MASS_MAX_ENDPOINTS 3
|
||||
|
||||
struct UHS_BULK_CommandBlockWrapperBase {
|
||||
volatile uint32_t dCBWSignature;
|
||||
volatile uint32_t dCBWTag;
|
||||
volatile uint32_t dCBWDataTransferLength;
|
||||
volatile uint8_t bmCBWFlags;
|
||||
public:
|
||||
|
||||
UHS_BULK_CommandBlockWrapperBase() {
|
||||
}
|
||||
|
||||
UHS_BULK_CommandBlockWrapperBase(uint32_t tag, uint32_t xflen, uint8_t flgs) :
|
||||
dCBWSignature(UHS_BULK_CBW_SIGNATURE), dCBWTag(tag), dCBWDataTransferLength(xflen), bmCBWFlags(flgs) {
|
||||
}
|
||||
} __attribute__((packed));
|
||||
|
||||
struct UHS_BULK_CommandBlockWrapper : public UHS_BULK_CommandBlockWrapperBase {
|
||||
|
||||
struct {
|
||||
uint8_t bmCBWLUN : 4;
|
||||
uint8_t bmReserved1 : 4;
|
||||
};
|
||||
|
||||
struct {
|
||||
uint8_t bmCBWCBLength : 4;
|
||||
uint8_t bmReserved2 : 4;
|
||||
};
|
||||
|
||||
uint8_t CBWCB[16];
|
||||
|
||||
public:
|
||||
// All zeroed.
|
||||
|
||||
UHS_BULK_CommandBlockWrapper() :
|
||||
UHS_BULK_CommandBlockWrapperBase(0, 0, 0), bmReserved1(0), bmReserved2(0) {
|
||||
for(int i = 0; i < 16; i++) CBWCB[i] = 0;
|
||||
}
|
||||
|
||||
// Generic Wrap, CDB zeroed.
|
||||
|
||||
UHS_BULK_CommandBlockWrapper(uint32_t tag, uint32_t xflen, uint8_t flgs, uint8_t lu, uint8_t cmdlen, uint8_t cmd) :
|
||||
UHS_BULK_CommandBlockWrapperBase(tag, xflen, flgs),
|
||||
bmCBWLUN(lu), bmReserved1(0), bmCBWCBLength(cmdlen), bmReserved2(0) {
|
||||
for(int i = 0; i < 16; i++) CBWCB[i] = 0;
|
||||
SCSI_CDB_BASE_t *x = reinterpret_cast<SCSI_CDB_BASE_t *>(CBWCB);
|
||||
x->LUN = cmd;
|
||||
}
|
||||
|
||||
// Wrap for CDB of 6
|
||||
|
||||
UHS_BULK_CommandBlockWrapper(uint32_t tag, uint32_t xflen, SCSI_CDB6_t *cdb, uint8_t dir) :
|
||||
UHS_BULK_CommandBlockWrapperBase(tag, xflen, dir),
|
||||
bmCBWLUN(cdb->LUN), bmReserved1(0), bmCBWCBLength(6), bmReserved2(0) {
|
||||
memcpy(&CBWCB, cdb, 6);
|
||||
}
|
||||
// Wrap for CDB of 10
|
||||
|
||||
UHS_BULK_CommandBlockWrapper(uint32_t tag, uint32_t xflen, SCSI_CDB10_t *cdb, uint8_t dir) :
|
||||
UHS_BULK_CommandBlockWrapperBase(tag, xflen, dir),
|
||||
bmCBWLUN(cdb->LUN), bmReserved1(0), bmCBWCBLength(10), bmReserved2(0) {
|
||||
memcpy(&CBWCB, cdb, 10);
|
||||
}
|
||||
} __attribute__((packed));
|
||||
|
||||
struct UHS_BULK_CommandStatusWrapper {
|
||||
uint32_t dCSWSignature;
|
||||
uint32_t dCSWTag;
|
||||
uint32_t dCSWDataResidue;
|
||||
uint8_t bCSWStatus;
|
||||
} __attribute__((packed));
|
||||
|
||||
class UHS_Bulk_Storage : public UHS_USBInterface {
|
||||
protected:
|
||||
static const uint8_t epDataInIndex = 1; // DataIn endpoint index
|
||||
static const uint8_t epDataOutIndex = 2; // DataOUT endpoint index
|
||||
static const uint8_t epInterruptInIndex = 3; // InterruptIN endpoint index
|
||||
|
||||
uint8_t bMaxLUN; // Max LUN
|
||||
volatile uint32_t dCBWTag; // Tag
|
||||
volatile uint8_t bTheLUN; // Active LUN
|
||||
volatile uint32_t CurrentCapacity[MASS_MAX_SUPPORTED_LUN]; // Total sectors
|
||||
volatile uint16_t CurrentSectorSize[MASS_MAX_SUPPORTED_LUN]; // Sector size, clipped to 16 bits
|
||||
volatile bool LUNOk[MASS_MAX_SUPPORTED_LUN]; // use this to check for media changes.
|
||||
volatile bool WriteOk[MASS_MAX_SUPPORTED_LUN];
|
||||
void PrintEndpointDescriptor(const USB_FD_ENDPOINT_DESCRIPTOR* ep_ptr);
|
||||
|
||||
public:
|
||||
UHS_Bulk_Storage(UHS_USB_HOST_BASE *p);
|
||||
|
||||
volatile UHS_EpInfo epInfo[MASS_MAX_ENDPOINTS];
|
||||
|
||||
uint8_t GetbMaxLUN() {
|
||||
return bMaxLUN; // Max LUN
|
||||
}
|
||||
|
||||
uint8_t GetbTheLUN() {
|
||||
return bTheLUN; // Active LUN
|
||||
}
|
||||
|
||||
bool WriteProtected(uint8_t lun);
|
||||
uint8_t MediaCTL(uint8_t lun, uint8_t ctl);
|
||||
uint8_t Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, uint8_t *buf);
|
||||
uint8_t Write(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, const uint8_t *buf);
|
||||
uint8_t LockMedia(uint8_t lun, uint8_t lock);
|
||||
|
||||
bool LUNIsGood(uint8_t lun);
|
||||
uint32_t GetCapacity(uint8_t lun);
|
||||
uint16_t GetSectorSize(uint8_t lun);
|
||||
uint8_t SCSITransaction6(SCSI_CDB6_t *cdb, uint16_t buf_size, void *buf, uint8_t dir);
|
||||
uint8_t SCSITransaction10(SCSI_CDB10_t *cdb, uint16_t buf_size, void *buf, uint8_t dir);
|
||||
|
||||
|
||||
// Configure and internal methods, these should never be called by a user's sketch.
|
||||
uint8_t Start();
|
||||
bool OKtoEnumerate(ENUMERATION_INFO *ei);
|
||||
uint8_t SetInterface(ENUMERATION_INFO *ei);
|
||||
|
||||
uint8_t GetAddress() {
|
||||
return bAddress;
|
||||
};
|
||||
|
||||
|
||||
void Poll();
|
||||
|
||||
void DriverDefaults();
|
||||
|
||||
|
||||
private:
|
||||
void Reset();
|
||||
void CheckMedia();
|
||||
|
||||
bool IsValidCBW(uint8_t size, uint8_t *pcbw);
|
||||
bool IsMeaningfulCBW(uint8_t size, uint8_t *pcbw);
|
||||
bool IsValidCSW(UHS_BULK_CommandStatusWrapper *pcsw, UHS_BULK_CommandBlockWrapperBase *pcbw);
|
||||
|
||||
bool CheckLUN(uint8_t lun);
|
||||
|
||||
uint8_t Inquiry(uint8_t lun, uint16_t size, uint8_t *buf);
|
||||
uint8_t TestUnitReady(uint8_t lun);
|
||||
uint8_t RequestSense(uint8_t lun, uint16_t size, uint8_t *buf);
|
||||
uint8_t ModeSense6(uint8_t lun, uint8_t pc, uint8_t page, uint8_t subpage, uint8_t len, uint8_t *buf);
|
||||
uint8_t GetMaxLUN(uint8_t *max_lun);
|
||||
uint8_t SetCurLUN(uint8_t lun);
|
||||
uint8_t ResetRecovery();
|
||||
uint8_t ReadCapacity10(uint8_t lun, uint8_t *buf);
|
||||
uint8_t Page3F(uint8_t lun);
|
||||
uint8_t ClearEpHalt(uint8_t index);
|
||||
uint8_t Transaction(UHS_BULK_CommandBlockWrapper *cbw, uint16_t bsize, void *buf);
|
||||
uint8_t HandleUsbError(uint8_t error, uint8_t index);
|
||||
uint8_t HandleSCSIError(uint8_t status);
|
||||
|
||||
};
|
||||
|
||||
#if defined(LOAD_UHS_BULK_STORAGE) && !defined(UHS_BULK_STORAGE_LOADED)
|
||||
#include "UHS_BULK_STORAGE_INLINE.h"
|
||||
#endif
|
||||
#endif // __MASSTORAGE_H__
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,327 @@
|
||||
/* Copyright (C) 2015-2016 Andrew J. Kroll
|
||||
and
|
||||
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Contact information
|
||||
-------------------
|
||||
|
||||
Circuits At Home, LTD
|
||||
Web : https://www.circuitsathome.com
|
||||
e-mail : support@circuitsathome.com
|
||||
*/
|
||||
|
||||
#ifndef UHS_SCSI_H
|
||||
#define UHS_SCSI_H
|
||||
|
||||
/*
|
||||
* Reference documents from T10 (https://www.t10.org)
|
||||
* SCSI Primary Commands - 3 (SPC-3)
|
||||
* SCSI Block Commands - 2 (SBC-2)
|
||||
* Multi-Media Commands - 5 (MMC-5)
|
||||
*/
|
||||
|
||||
/* Group 1 commands (CDB's here are should all be 6-bytes) */
|
||||
#define SCSI_CMD_TEST_UNIT_READY 0x00U
|
||||
#define SCSI_CMD_REQUEST_SENSE 0x03U
|
||||
#define SCSI_CMD_FORMAT_UNIT 0x04U
|
||||
#define SCSI_CMD_READ_6 0x08U
|
||||
#define SCSI_CMD_WRITE_6 0x0AU
|
||||
#define SCSI_CMD_INQUIRY 0x12U
|
||||
#define SCSI_CMD_MODE_SELECT_6 0x15U
|
||||
#define SCSI_CMD_MODE_SENSE_6 0x1AU
|
||||
#define SCSI_CMD_START_STOP_UNIT 0x1BU
|
||||
#define SCSI_CMD_PREVENT_REMOVAL 0x1EU
|
||||
/* Group 2 Commands (CDB's here are 10-bytes) */
|
||||
#define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23U
|
||||
#define SCSI_CMD_READ_CAPACITY_10 0x25U
|
||||
#define SCSI_CMD_READ_10 0x28U
|
||||
#define SCSI_CMD_WRITE_10 0x2AU
|
||||
#define SCSI_CMD_SEEK_10 0x2BU
|
||||
#define SCSI_CMD_ERASE_10 0x2CU
|
||||
#define SCSI_CMD_WRITE_AND_VERIFY_10 0x2EU
|
||||
#define SCSI_CMD_VERIFY_10 0x2FU
|
||||
#define SCSI_CMD_SYNCHRONIZE_CACHE 0x35U
|
||||
#define SCSI_CMD_WRITE_BUFFER 0x3BU
|
||||
#define SCSI_CMD_READ_BUFFER 0x3CU
|
||||
#define SCSI_CMD_READ_SUBCHANNEL 0x42U
|
||||
#define SCSI_CMD_READ_TOC 0x43U
|
||||
#define SCSI_CMD_READ_HEADER 0x44U
|
||||
#define SCSI_CMD_PLAY_AUDIO_10 0x45U
|
||||
#define SCSI_CMD_GET_CONFIGURATION 0x46U
|
||||
#define SCSI_CMD_PLAY_AUDIO_MSF 0x47U
|
||||
#define SCSI_CMD_PLAY_AUDIO_TI 0x48U
|
||||
#define SCSI_CMD_PLAY_TRACK_REL_10 0x49U
|
||||
#define SCSI_CMD_GET_EVENT_STATUS 0x4AU
|
||||
#define SCSI_CMD_PAUSE_RESUME 0x4BU
|
||||
#define SCSI_CMD_READ_DISC_INFORMATION 0x51U
|
||||
#define SCSI_CMD_READ_TRACK_INFORMATION 0x52U
|
||||
#define SCSI_CMD_RESERVE_TRACK 0x53U
|
||||
#define SCSI_CMD_SEND_OPC_INFORMATION 0x54U
|
||||
#define SCSI_CMD_MODE_SELECT_10 0x55U
|
||||
#define SCSI_CMD_REPAIR_TRACK 0x58U
|
||||
#define SCSI_CMD_MODE_SENSE_10 0x5AU
|
||||
#define SCSI_CMD_CLOSE_TRACK_SESSION 0x5BU
|
||||
#define SCSI_CMD_READ_BUFFER_CAPACITY 0x5CU
|
||||
#define SCSI_CMD_SEND_CUE_SHEET 0x5DU
|
||||
/* Group 5 Commands (CDB's here are 12-bytes) */
|
||||
#define SCSI_CMD_REPORT_LUNS 0xA0U
|
||||
#define SCSI_CMD_BLANK 0xA1U
|
||||
#define SCSI_CMD_SECURITY_PROTOCOL_IN 0xA2U
|
||||
#define SCSI_CMD_SEND_KEY 0xA3U
|
||||
#define SCSI_CMD_REPORT_KEY 0xA4U
|
||||
#define SCSI_CMD_PLAY_AUDIO_12 0xA5U
|
||||
#define SCSI_CMD_LOAD_UNLOAD 0xA6U
|
||||
#define SCSI_CMD_SET_READ_AHEAD 0xA7U
|
||||
#define SCSI_CMD_READ_12 0xA8U
|
||||
#define SCSI_CMD_PLAY_TRACK_REL_12 0xA9U
|
||||
#define SCSI_CMD_WRITE_12 0xAAU
|
||||
#define SCSI_CMD_READ_MEDIA_SERIAL_12 0xABU
|
||||
#define SCSI_CMD_GET_PERFORMANCE 0xACU
|
||||
#define SCSI_CMD_READ_DVD_STRUCTURE 0xADU
|
||||
#define SCSI_CMD_SECURITY_PROTOCOL_OUT 0xB5U
|
||||
#define SCSI_CMD_SET_STREAMING 0xB6U
|
||||
#define SCSI_CMD_READ_MSF 0xB9U
|
||||
#define SCSI_CMD_SET_SPEED 0xBBU
|
||||
#define SCSI_CMD_MECHANISM_STATUS 0xBDU
|
||||
#define SCSI_CMD_READ_CD 0xBEU
|
||||
#define SCSI_CMD_SEND_DISC_STRUCTURE 0xBFU
|
||||
/* Vendor-unique Commands, included for completeness */
|
||||
#define SCSI_CMD_CD_PLAYBACK_STATUS 0xC4U /* SONY unique */
|
||||
#define SCSI_CMD_PLAYBACK_CONTROL 0xC9U /* SONY unique */
|
||||
#define SCSI_CMD_READ_CDDA 0xD8U /* Vendor unique */
|
||||
#define SCSI_CMD_READ_CDXA 0xDBU /* Vendor unique */
|
||||
#define SCSI_CMD_READ_ALL_SUBCODES 0xDFU /* Vendor unique */
|
||||
|
||||
/* SCSI error codes */
|
||||
#define SCSI_S_NOT_READY 0x02U
|
||||
#define SCSI_S_MEDIUM_ERROR 0x03U
|
||||
#define SCSI_S_ILLEGAL_REQUEST 0x05U
|
||||
#define SCSI_S_UNIT_ATTENTION 0x06U
|
||||
#define SCSI_ASC_LBA_OUT_OF_RANGE 0x21U
|
||||
#define SCSI_ASC_MEDIA_CHANGED 0x28U
|
||||
#define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3AU
|
||||
|
||||
struct SCSI_Capacity {
|
||||
uint8_t data[8];
|
||||
//uint32_t dwBlockAddress;
|
||||
//uint32_t dwBlockLength;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct SCSI_CDB_BASE {
|
||||
uint8_t Opcode;
|
||||
|
||||
unsigned unused : 5;
|
||||
unsigned LUN : 3;
|
||||
|
||||
uint8_t info[12];
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef SCSI_CDB_BASE SCSI_CDB_BASE_t;
|
||||
|
||||
struct SCSI_CDB6 {
|
||||
uint8_t Opcode;
|
||||
|
||||
unsigned LBAMSB : 5;
|
||||
unsigned LUN : 3;
|
||||
|
||||
uint8_t LBAHB;
|
||||
uint8_t LBALB;
|
||||
uint8_t AllocationLength;
|
||||
uint8_t Control;
|
||||
|
||||
public:
|
||||
|
||||
SCSI_CDB6(uint8_t _Opcode, uint8_t _LUN, uint32_t LBA, uint8_t _AllocationLength, uint8_t _Control) :
|
||||
Opcode(_Opcode), LBAMSB(UHS_UINT8_BYTE2(LBA) & 0x1F), LUN(_LUN), LBAHB(UHS_UINT8_BYTE1(LBA)), LBALB(UHS_UINT8_BYTE0(LBA)),
|
||||
AllocationLength(_AllocationLength), Control(_Control) {
|
||||
}
|
||||
|
||||
SCSI_CDB6(uint8_t _Opcode, uint8_t _LUN, uint8_t _AllocationLength, uint8_t _Control) :
|
||||
Opcode(_Opcode), LBAMSB(0), LUN(_LUN), LBAHB(0), LBALB(0),
|
||||
AllocationLength(_AllocationLength), Control(_Control) {
|
||||
}
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef SCSI_CDB6 SCSI_CDB6_t;
|
||||
|
||||
struct SCSI_CDB10 {
|
||||
uint8_t Opcode;
|
||||
|
||||
unsigned Service_Action : 5;
|
||||
unsigned LUN : 3;
|
||||
|
||||
uint8_t LBA_L_M_MB;
|
||||
uint8_t LBA_L_M_LB;
|
||||
uint8_t LBA_L_L_MB;
|
||||
uint8_t LBA_L_L_LB;
|
||||
|
||||
uint8_t Misc2;
|
||||
|
||||
uint8_t ALC_MB;
|
||||
uint8_t ALC_LB;
|
||||
|
||||
uint8_t Control;
|
||||
public:
|
||||
|
||||
SCSI_CDB10(uint8_t _Opcode, uint8_t _LUN) :
|
||||
Opcode(_Opcode), Service_Action(0), LUN(_LUN),
|
||||
LBA_L_M_MB(0), LBA_L_M_LB(0), LBA_L_L_MB(0), LBA_L_L_LB(0),
|
||||
Misc2(0), ALC_MB(0), ALC_LB(0), Control(0) {
|
||||
}
|
||||
|
||||
SCSI_CDB10(uint8_t _Opcode, uint8_t _LUN, uint16_t xflen, uint32_t _LBA) :
|
||||
Opcode(_Opcode), Service_Action(0), LUN(_LUN),
|
||||
LBA_L_M_MB(UHS_UINT8_BYTE3(_LBA)), LBA_L_M_LB(UHS_UINT8_BYTE2(_LBA)), LBA_L_L_MB(UHS_UINT8_BYTE1(_LBA)), LBA_L_L_LB(UHS_UINT8_BYTE0(_LBA)),
|
||||
Misc2(0), ALC_MB(UHS_UINT8_BYTE1(xflen)), ALC_LB(UHS_UINT8_BYTE0(xflen)), Control(0) {
|
||||
}
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef SCSI_CDB10 SCSI_CDB10_t;
|
||||
|
||||
struct SCSI_CDB12 {
|
||||
uint8_t Opcode;
|
||||
|
||||
unsigned Service_Action : 5;
|
||||
unsigned Misc : 3;
|
||||
|
||||
uint8_t LBA_L_M_LB;
|
||||
uint8_t LBA_L_L_MB;
|
||||
uint8_t LBA_L_L_LB;
|
||||
|
||||
uint8_t ALC_M_LB;
|
||||
uint8_t ALC_L_MB;
|
||||
uint8_t ALC_L_LB;
|
||||
uint8_t Control;
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef SCSI_CDB12 SCSI_CDB12_t;
|
||||
|
||||
struct SCSI_CDB_LBA32_16 {
|
||||
uint8_t Opcode;
|
||||
|
||||
unsigned Service_Action : 5;
|
||||
unsigned Misc : 3;
|
||||
|
||||
uint8_t LBA_L_M_MB;
|
||||
uint8_t LBA_L_M_LB;
|
||||
uint8_t LBA_L_L_MB;
|
||||
uint8_t LBA_L_L_LB;
|
||||
|
||||
uint8_t A_M_M_MB;
|
||||
uint8_t A_M_M_LB;
|
||||
uint8_t A_M_L_MB;
|
||||
uint8_t A_M_L_LB;
|
||||
|
||||
uint8_t ALC_M_MB;
|
||||
uint8_t ALC_M_LB;
|
||||
uint8_t ALC_L_MB;
|
||||
uint8_t ALC_L_LB;
|
||||
|
||||
uint8_t Misc2;
|
||||
uint8_t Control;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct SCSI_CDB_LBA64_16 {
|
||||
uint8_t Opcode;
|
||||
uint8_t Misc;
|
||||
|
||||
uint8_t LBA_M_M_MB;
|
||||
uint8_t LBA_M_M_LB;
|
||||
uint8_t LBA_M_L_MB;
|
||||
uint8_t LBA_M_L_LB;
|
||||
|
||||
uint8_t LBA_L_M_MB;
|
||||
uint8_t LBA_L_M_LB;
|
||||
uint8_t LBA_L_L_MB;
|
||||
uint8_t LBA_L_L_LB;
|
||||
|
||||
uint8_t ALC_M_MB;
|
||||
uint8_t ALC_M_LB;
|
||||
uint8_t ALC_L_MB;
|
||||
uint8_t ALC_L_LB;
|
||||
|
||||
uint8_t Misc2;
|
||||
uint8_t Control;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct SCSI_Inquiry_Response {
|
||||
uint8_t DeviceType : 5;
|
||||
uint8_t PeripheralQualifier : 3;
|
||||
|
||||
unsigned Reserved : 7;
|
||||
unsigned Removable : 1;
|
||||
|
||||
uint8_t Version;
|
||||
|
||||
unsigned ResponseDataFormat : 4;
|
||||
unsigned HISUP : 1;
|
||||
unsigned NormACA : 1;
|
||||
unsigned TrmTsk : 1;
|
||||
unsigned AERC : 1;
|
||||
|
||||
uint8_t AdditionalLength;
|
||||
|
||||
unsigned PROTECT : 1;
|
||||
unsigned Res : 2;
|
||||
unsigned ThreePC : 1;
|
||||
unsigned TPGS : 2;
|
||||
unsigned ACC : 1;
|
||||
unsigned SCCS : 1;
|
||||
|
||||
unsigned ADDR16 : 1;
|
||||
unsigned R1 : 1;
|
||||
unsigned R2 : 1;
|
||||
unsigned MCHNGR : 1;
|
||||
unsigned MULTIP : 1;
|
||||
unsigned VS : 1;
|
||||
unsigned ENCSERV : 1;
|
||||
unsigned BQUE : 1;
|
||||
|
||||
unsigned SoftReset : 1;
|
||||
unsigned CmdQue : 1;
|
||||
unsigned Reserved4 : 1;
|
||||
unsigned Linked : 1;
|
||||
unsigned Sync : 1;
|
||||
unsigned WideBus16Bit : 1;
|
||||
unsigned WideBus32Bit : 1;
|
||||
unsigned RelAddr : 1;
|
||||
|
||||
uint8_t VendorID[8];
|
||||
uint8_t ProductID[16];
|
||||
uint8_t RevisionID[4];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct SCSI_Request_Sense_Response {
|
||||
uint8_t bResponseCode;
|
||||
uint8_t bSegmentNumber;
|
||||
|
||||
uint8_t bmSenseKey : 4;
|
||||
uint8_t bmReserved : 1;
|
||||
uint8_t bmILI : 1;
|
||||
uint8_t bmEOM : 1;
|
||||
uint8_t bmFileMark : 1;
|
||||
|
||||
uint8_t Information[4];
|
||||
uint8_t bAdditionalLength;
|
||||
uint8_t CmdSpecificInformation[4];
|
||||
uint8_t bAdditionalSenseCode;
|
||||
uint8_t bAdditionalSenseQualifier;
|
||||
uint8_t bFieldReplaceableUnitCode;
|
||||
uint8_t SenseKeySpecific[3];
|
||||
} __attribute__((packed));
|
||||
|
||||
#endif /* UHS_SCSI_H */
|
@ -0,0 +1,33 @@
|
||||
/* Copyright (C) 2015-2016 Andrew J. Kroll
|
||||
and
|
||||
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Contact information
|
||||
-------------------
|
||||
|
||||
Circuits At Home, LTD
|
||||
Web : https://www.circuitsathome.com
|
||||
e-mail : support@circuitsathome.com
|
||||
*/
|
||||
#ifndef _UHS_UNOFFICIAL_IDs_h
|
||||
#define _UHS_UNOFFICIAL_IDs_h
|
||||
|
||||
// Bogus unofficial and unregistered VIDs from cloners to be listed here.
|
||||
|
||||
#define UHS_VID_UNOFFICIAL_JOYTECH 0x162EU // For unofficial Joytech controllers
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,336 @@
|
||||
/* Copyright (C) 2015-2016 Andrew J. Kroll
|
||||
and
|
||||
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Contact information
|
||||
-------------------
|
||||
|
||||
Circuits At Home, LTD
|
||||
Web : https://www.circuitsathome.com
|
||||
e-mail : support@circuitsathome.com
|
||||
*/
|
||||
|
||||
#if !defined(_UHS_host_h_) || defined(USBCORE_H)
|
||||
#error "Never include UHS_UsbCore.h directly; include UHS_Host.h instead"
|
||||
#else
|
||||
#define USBCORE_H
|
||||
|
||||
#ifndef UHS_HOST_MAX_INTERFACE_DRIVERS
|
||||
#define UHS_HOST_MAX_INTERFACE_DRIVERS 0x10U // Default maximum number of USB interface drivers
|
||||
#endif
|
||||
|
||||
#ifndef SYSTEM_OR_SPECIAL_YIELD
|
||||
#define SYSTEM_OR_SPECIAL_YIELD(...) VOID0
|
||||
#endif
|
||||
|
||||
#ifndef SYSTEM_OR_SPECIAL_YIELD_FROM_ISR
|
||||
#define SYSTEM_OR_SPECIAL_YIELD_FROM_ISR(...) SYSTEM_OR_SPECIAL_YIELD
|
||||
#endif
|
||||
|
||||
// As we make extensions to a target interface add to UHS_HOST_MAX_INTERFACE_DRIVERS
|
||||
// This offset gets calculated for supporting wide subclasses, such as HID, BT, etc.
|
||||
#define UHS_HID_INDEX (UHS_HOST_MAX_INTERFACE_DRIVERS + 1)
|
||||
|
||||
/* Common setup data constant combinations */
|
||||
//get descriptor request type
|
||||
#define UHS_bmREQ_GET_DESCR (USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE)
|
||||
|
||||
//set request type for all but 'set feature' and 'set interface'
|
||||
#define UHS_bmREQ_SET (USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE)
|
||||
|
||||
//get interface request type
|
||||
#define UHS_bmREQ_CL_GET_INTF (USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE)
|
||||
|
||||
// D7 data transfer direction (0 - host-to-device, 1 - device-to-host)
|
||||
// D6-5 Type (0- standard, 1 - class, 2 - vendor, 3 - reserved)
|
||||
// D4-0 Recipient (0 - device, 1 - interface, 2 - endpoint, 3 - other, 4..31 - reserved)
|
||||
|
||||
|
||||
// TO-DO: Use the python script to generate these.
|
||||
// TO-DO: Add _all_ subclasses here.
|
||||
// USB Device Classes, Subclasses and Protocols
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Use Class Info in the Interface Descriptors
|
||||
#define UHS_USB_CLASS_USE_CLASS_INFO 0x00U
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Audio
|
||||
#define UHS_USB_CLASS_AUDIO 0x01U
|
||||
// Subclasses
|
||||
#define UHS_USB_SUBCLASS_AUDIOCONTROL 0x01U
|
||||
#define UHS_USB_SUBCLASS_AUDIOSTREAMING 0x02U
|
||||
#define UHS_USB_SUBCLASS_MIDISTREAMING 0x03U
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Communications and CDC Control
|
||||
#define UHS_USB_CLASS_COM_AND_CDC_CTRL 0x02U
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// HID
|
||||
#define UHS_USB_CLASS_HID 0x03U
|
||||
// Subclasses
|
||||
#define UHS_HID_BOOT_SUBCLASS 0x01U
|
||||
// Protocols
|
||||
#define UHS_HID_PROTOCOL_HIDBOOT_KEYBOARD 0x01U
|
||||
#define UHS_HID_PROTOCOL_HIDBOOT_MOUSE 0x02U
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Physical
|
||||
#define UHS_USB_CLASS_PHYSICAL 0x05U
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Image
|
||||
#define UHS_USB_CLASS_IMAGE 0x06U
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Printer
|
||||
#define UHS_USB_CLASS_PRINTER 0x07U
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Mass Storage
|
||||
#define UHS_USB_CLASS_MASS_STORAGE 0x08
|
||||
// Subclasses
|
||||
#define UHS_BULK_SUBCLASS_SCSI_NOT_REPORTED 0x00U // De facto use
|
||||
#define UHS_BULK_SUBCLASS_RBC 0x01U
|
||||
#define UHS_BULK_SUBCLASS_ATAPI 0x02U // MMC-5 (ATAPI)
|
||||
#define UHS_BULK_SUBCLASS_OBSOLETE1 0x03U // Was QIC-157
|
||||
#define UHS_BULK_SUBCLASS_UFI 0x04U // Specifies how to interface Floppy Disk Drives to USB
|
||||
#define UHS_BULK_SUBCLASS_OBSOLETE2 0x05U // Was SFF-8070i
|
||||
#define UHS_BULK_SUBCLASS_SCSI 0x06U // SCSI Transparent Command Set
|
||||
#define UHS_BULK_SUBCLASS_LSDFS 0x07U // Specifies how host has to negotiate access before trying SCSI
|
||||
#define UHS_BULK_SUBCLASS_IEEE1667 0x08U
|
||||
// Protocols
|
||||
#define UHS_STOR_PROTO_CBI 0x00U // CBI (with command completion interrupt)
|
||||
#define UHS_STOR_PROTO_CBI_NO_INT 0x01U // CBI (without command completion interrupt)
|
||||
#define UHS_STOR_PROTO_OBSOLETE 0x02U
|
||||
#define UHS_STOR_PROTO_BBB 0x50U // Bulk Only Transport
|
||||
#define UHS_STOR_PROTO_UAS 0x62U
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Hub
|
||||
#define UHS_USB_CLASS_HUB 0x09U
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// CDC-Data
|
||||
#define UHS_USB_CLASS_CDC_DATA 0x0AU
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Smart-Card
|
||||
#define UHS_USB_CLASS_SMART_CARD 0x0BU
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Content Security
|
||||
#define UHS_USB_CLASS_CONTENT_SECURITY 0x0DU
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Video
|
||||
#define UHS_USB_CLASS_VIDEO 0x0EU
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Personal Healthcare
|
||||
#define UHS_USB_CLASS_PERSONAL_HEALTH 0x0FU
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Diagnostic Device
|
||||
#define UHS_USB_CLASS_DIAGNOSTIC_DEVICE 0xDCU
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Wireless Controller
|
||||
#define UHS_USB_CLASS_WIRELESS_CTRL 0xE0U
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Miscellaneous
|
||||
#define UHS_USB_CLASS_MISC 0xEFU
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Application Specific
|
||||
#define UHS_USB_CLASS_APP_SPECIFIC 0xFEU
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Vendor Specific
|
||||
#define UHS_USB_CLASS_VENDOR_SPECIFIC 0xFFU
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/* USB state machine states */
|
||||
#define UHS_USB_HOST_STATE_MASK 0xF0U
|
||||
|
||||
// Configure states, MSN == 0 --------------------------V
|
||||
#define UHS_USB_HOST_STATE_DETACHED 0x00U
|
||||
#define UHS_USB_HOST_STATE_DEBOUNCE 0x01U
|
||||
#define UHS_USB_HOST_STATE_DEBOUNCE_NOT_COMPLETE 0x02U
|
||||
#define UHS_USB_HOST_STATE_RESET_NOT_COMPLETE 0x03U
|
||||
#define UHS_USB_HOST_STATE_WAIT_SOF 0x04U
|
||||
#define UHS_USB_HOST_STATE_WAIT_BUS_READY 0x05U
|
||||
#define UHS_USB_HOST_STATE_RESET_DEVICE 0x0AU
|
||||
#define UHS_USB_HOST_STATE_CONFIGURING 0x0CU // Looks like "CO"nfig (backwards)
|
||||
#define UHS_USB_HOST_STATE_CONFIGURING_DONE 0x0DU // Looks like "DO"one (backwards)
|
||||
#define UHS_USB_HOST_STATE_CHECK 0x0EU
|
||||
#define UHS_USB_HOST_STATE_ILLEGAL 0x0FU // Foo
|
||||
|
||||
// Run states, MSN != 0 --------------------------------V
|
||||
#define UHS_USB_HOST_STATE_RUNNING 0x60U // Looks like "GO"
|
||||
#define UHS_USB_HOST_STATE_IDLE 0x1DU // Looks like "ID"le
|
||||
#define UHS_USB_HOST_STATE_ERROR 0xF0U // Looks like "FO"o
|
||||
#define UHS_USB_HOST_STATE_INITIALIZE 0x10U // Looks like "I"nit
|
||||
|
||||
// Host SE result codes.
|
||||
// Common SE results are stored in the low nybble, all interface drivers understand these plus 0x1F.
|
||||
// Extended SE results are 0x10-0x1E. SE code only understands these internal to the hardware.
|
||||
// Values > 0x1F are driver or other internal error conditions.
|
||||
// Return these result codes from your host controller driver to match the error condition
|
||||
// ALL Non-zero values are errors.
|
||||
// Values not listed in this table are not handled in the base class, or any host driver.
|
||||
|
||||
#define UHS_HOST_ERROR_NONE 0x00U // No error
|
||||
#define UHS_HOST_ERROR_BUSY 0x01U // transfer pending
|
||||
#define UHS_HOST_ERROR_BADREQ 0x02U // Transfer Launch Request was bad
|
||||
#define UHS_HOST_ERROR_DMA 0x03U // DMA was too short, or too long
|
||||
#define UHS_HOST_ERROR_NAK 0x04U // Peripheral returned NAK
|
||||
#define UHS_HOST_ERROR_STALL 0x05U // Peripheral returned STALL
|
||||
#define UHS_HOST_ERROR_TOGERR 0x06U // Toggle error/ISO over-underrun
|
||||
#define UHS_HOST_ERROR_WRONGPID 0x07U // Received wrong Packet ID
|
||||
#define UHS_HOST_ERROR_BADBC 0x08U // Byte count is bad
|
||||
#define UHS_HOST_ERROR_PIDERR 0x09U // Received Packet ID is corrupted
|
||||
#define UHS_HOST_ERROR_BADRQ 0x0AU // Packet error. Increase max packet.
|
||||
#define UHS_HOST_ERROR_CRC 0x0BU // USB CRC was incorrect
|
||||
#define UHS_HOST_ERROR_KERR 0x0CU // K-state instead of response, usually indicates wrong speed
|
||||
#define UHS_HOST_ERROR_JERR 0x0DU // J-state instead of response, usually indicates wrong speed
|
||||
#define UHS_HOST_ERROR_TIMEOUT 0x0EU // Device did not respond in time
|
||||
#define UHS_HOST_ERROR_BABBLE 0x0FU // Line noise/unexpected data
|
||||
#define UHS_HOST_ERROR_MEM_LAT 0x10U // Error caused by memory latency.
|
||||
#define UHS_HOST_ERROR_NYET 0x11U // OUT transfer accepted with NYET
|
||||
|
||||
// Addressing error codes
|
||||
#define ADDR_ERROR_INVALID_INDEX 0xA0U
|
||||
#define ADDR_ERROR_INVALID_ADDRESS 0xA1U
|
||||
|
||||
// Common Interface Driver error codes
|
||||
#define UHS_HOST_ERROR_DEVICE_NOT_SUPPORTED 0xD1U // Driver doesn't support the device or interfaces
|
||||
#define UHS_HOST_ERROR_DEVICE_INIT_INCOMPLETE 0xD2U // Init partially finished, but died.
|
||||
#define UHS_HOST_ERROR_CANT_REGISTER_DEVICE_CLASS 0xD3U // There was no driver for the interface requested.
|
||||
#define UHS_HOST_ERROR_ADDRESS_POOL_FULL 0xD4U // No addresses left in the address pool.
|
||||
#define UHS_HOST_ERROR_HUB_ADDRESS_OVERFLOW 0xD5U // No hub addresses left. The maximum is 7.
|
||||
#define UHS_HOST_ERROR_NO_ADDRESS_IN_POOL 0xD6U // Address was not allocated in the pool, thus not found.
|
||||
#define UHS_HOST_ERROR_NULL_EPINFO 0xD7U // The supplied endpoint was NULL, indicates a bug or other problem.
|
||||
#define UHS_HOST_ERROR_BAD_ARGUMENT 0xD8U // Indicates a range violation bug.
|
||||
#define UHS_HOST_ERROR_DEVICE_DRIVER_BUSY 0xD9U // The interface driver is busy or out buffer is full, try again later.
|
||||
#define UHS_HOST_ERROR_BAD_MAX_PACKET_SIZE 0xDAU // The maximum packet size was exceeded. Try again with smaller size.
|
||||
#define UHS_HOST_ERROR_NO_ENDPOINT_IN_TABLE 0xDBU // The endpoint could not be found in the endpoint table.
|
||||
#define UHS_HOST_ERROR_UNPLUGGED 0xDEU // Someone removed the USB device, or Vbus was turned off.
|
||||
#define UHS_HOST_ERROR_NOMEM 0xDFU // Out Of Memory.
|
||||
|
||||
// Control request stream errors
|
||||
#define UHS_HOST_ERROR_FailGetDevDescr 0xE1U
|
||||
#define UHS_HOST_ERROR_FailSetDevTblEntry 0xE2U
|
||||
#define UHS_HOST_ERROR_FailGetConfDescr 0xE3U
|
||||
#define UHS_HOST_ERROR_END_OF_STREAM 0xEFU
|
||||
|
||||
// Host base class specific Error codes
|
||||
#define UHS_HOST_ERROR_NOT_IMPLEMENTED 0xFEU
|
||||
#define UHS_HOST_ERROR_TRANSFER_TIMEOUT 0xFFU
|
||||
|
||||
// SEI interaction defaults
|
||||
#define UHS_HOST_TRANSFER_MAX_MS 10000 // USB transfer timeout in ms, per section 9.2.6.1 of USB 2.0 spec
|
||||
#define UHS_HOST_TRANSFER_RETRY_MAXIMUM 3 // 3 retry limit for a transfer
|
||||
#define UHS_HOST_DEBOUNCE_DELAY_MS 500 // settle delay in milliseconds
|
||||
#define UHS_HUB_RESET_DELAY_MS 20 // hub port reset delay, 10ms recomended, but can be up to 20ms
|
||||
|
||||
//
|
||||
// We only provide the minimum needed information for enumeration.
|
||||
// Interface drivers should be able to set up what is needed with nothing more.
|
||||
// A driver needs to know the following information:
|
||||
// 1: address on the USB network, parent and port (aka UsbDeviceAddress)
|
||||
// 2: endpoints
|
||||
// 3: vid:pid, class, subclass, protocol
|
||||
//
|
||||
|
||||
struct ENDPOINT_INFO {
|
||||
uint8_t bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN).
|
||||
uint8_t bmAttributes; // Endpoint transfer type.
|
||||
uint16_t wMaxPacketSize; // Maximum packet size.
|
||||
uint8_t bInterval; // Polling interval in frames.
|
||||
} __attribute__((packed));
|
||||
|
||||
struct INTERFACE_INFO {
|
||||
uint8_t bInterfaceNumber;
|
||||
uint8_t bAlternateSetting;
|
||||
uint8_t numep;
|
||||
uint8_t klass;
|
||||
uint8_t subklass;
|
||||
uint8_t protocol;
|
||||
ENDPOINT_INFO epInfo[16];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ENUMERATION_INFO {
|
||||
uint16_t vid;
|
||||
uint16_t pid;
|
||||
uint16_t bcdDevice;
|
||||
uint8_t klass;
|
||||
uint8_t subklass;
|
||||
uint8_t protocol;
|
||||
uint8_t bMaxPacketSize0;
|
||||
uint8_t currentconfig;
|
||||
uint8_t parent;
|
||||
uint8_t port;
|
||||
uint8_t address;
|
||||
INTERFACE_INFO interface;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* USB Setup Packet Structure */
|
||||
typedef struct {
|
||||
// offset description
|
||||
// 0 Bit-map of request type
|
||||
union {
|
||||
uint8_t bmRequestType;
|
||||
|
||||
struct {
|
||||
uint8_t recipient : 5; // Recipient of the request
|
||||
uint8_t type : 2; // Type of request
|
||||
uint8_t direction : 1; // Direction of data transfer
|
||||
} __attribute__((packed));
|
||||
} ReqType_u;
|
||||
|
||||
// 1 Request
|
||||
uint8_t bRequest;
|
||||
|
||||
// 2 Depends on bRequest
|
||||
union {
|
||||
uint16_t wValue;
|
||||
|
||||
struct {
|
||||
uint8_t wValueLo;
|
||||
uint8_t wValueHi;
|
||||
} __attribute__((packed));
|
||||
} wVal_u;
|
||||
// 4 Depends on bRequest
|
||||
uint16_t wIndex;
|
||||
// 6 Depends on bRequest
|
||||
uint16_t wLength;
|
||||
// 8 bytes total
|
||||
} __attribute__((packed)) SETUP_PKT, *PSETUP_PKT;
|
||||
|
||||
|
||||
// little endian :-) 8 8 8 8 16 16
|
||||
#define mkSETUP_PKT8(bmReqType, bRequest, wValLo, wValHi, wInd, total) ((uint64_t)(((uint64_t)(bmReqType)))|(((uint64_t)(bRequest))<<8)|(((uint64_t)(wValLo))<<16)|(((uint64_t)(wValHi))<<24)|(((uint64_t)(wInd))<<32)|(((uint64_t)(total)<<48)))
|
||||
#define mkSETUP_PKT16(bmReqType, bRequest, wVal, wInd, total) ((uint64_t)(((uint64_t)(bmReqType)))|(((uint64_t)(bRequest))<<8)|(((uint64_t)(wVal ))<<16) |(((uint64_t)(wInd))<<32)|(((uint64_t)(total)<<48)))
|
||||
|
||||
// Big endian -- but we aren't able to use this :-/
|
||||
//#define mkSETUP_PKT8(bmReqType, bRequest, wValLo, wValHi, wInd, total) ((uint64_t)(((uint64_t)(bmReqType))<<56)|(((uint64_t)(bRequest))<<48)|(((uint64_t)(wValLo))<<40)|(((uint64_t)(wValHi))<<32)|(((uint64_t)(wInd))<<16)|((uint64_t)(total)))
|
||||
//#define mkSETUP_PKT16(bmReqType, bRequest, wVal, wInd, total) ((uint64_t)(((uint64_t)(bmReqType))<<56)|(((uint64_t)(bRequest))<<48) |(((uint64_t)(wVal))<<32) |(((uint64_t)(wInd))<<16)|((uint64_t)(total)))
|
||||
|
||||
#endif /* USBCORE_H */
|
@ -0,0 +1,248 @@
|
||||
/* Copyright (C) 2015-2016 Andrew J. Kroll
|
||||
and
|
||||
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Contact information
|
||||
-------------------
|
||||
|
||||
Circuits At Home, LTD
|
||||
Web : https://www.circuitsathome.com
|
||||
e-mail : support@circuitsathome.com
|
||||
*/
|
||||
|
||||
#if !defined(_UHS_host_h_) || defined(__ADDRESS_H__)
|
||||
#error "Never include UHS_address.h directly; include UHS_Usb.h instead"
|
||||
#else
|
||||
#define __ADDRESS_H__
|
||||
|
||||
|
||||
|
||||
/* NAK powers. To save space in endpoint data structure, amount of retries before giving up and returning 0x4 is stored in */
|
||||
/* bmNakPower as a power of 2. The actual nak_limit is then calculated as nak_limit = ( 2^bmNakPower - 1) */
|
||||
#define UHS_USB_NAK_MAX_POWER 14 // NAK binary order maximum value
|
||||
#define UHS_USB_NAK_DEFAULT 13 // default 16K-1 NAKs before giving up
|
||||
#define UHS_USB_NAK_NOWAIT 1 // Single NAK stops transfer
|
||||
#define UHS_USB_NAK_NONAK 0 // Do not count NAKs, stop retrying after USB Timeout. Try not to use this.
|
||||
|
||||
#define bmUSB_DEV_ADDR_PORT 0x07
|
||||
#define bmUSB_DEV_ADDR_PARENT 0x78
|
||||
#define bmUSB_DEV_ADDR_HUB 0x40
|
||||
|
||||
// TODO: embed parent?
|
||||
struct UHS_EpInfo {
|
||||
uint8_t epAddr; // Endpoint address
|
||||
uint8_t bIface;
|
||||
uint16_t maxPktSize; // Maximum packet size
|
||||
|
||||
union {
|
||||
uint8_t epAttribs;
|
||||
|
||||
struct {
|
||||
uint8_t bmSndToggle : 1; // Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise
|
||||
uint8_t bmRcvToggle : 1; // Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise
|
||||
uint8_t bmNeedPing : 1; // 1 == ping protocol needed for next out packet
|
||||
uint8_t bmNakPower : 5; // Binary order for NAK_LIMIT value
|
||||
} __attribute__((packed));
|
||||
};
|
||||
} __attribute__((packed));
|
||||
|
||||
// TODO: embed parent address and port into epinfo struct,
|
||||
// and nuke this address stupidity.
|
||||
// This is a compact scheme. Should also support full spec.
|
||||
// This produces a 7 hub limit, 49 devices + 7 hubs, 56 total.
|
||||
//
|
||||
// 7 6 5 4 3 2 1 0
|
||||
// ---------------------------------
|
||||
// | | H | P | P | P | A | A | A |
|
||||
// ---------------------------------
|
||||
//
|
||||
// H - if 1 the address is a hub address
|
||||
// P - parent hub number
|
||||
// A - port number of parent
|
||||
//
|
||||
|
||||
struct UHS_DeviceAddress {
|
||||
|
||||
union {
|
||||
|
||||
struct {
|
||||
uint8_t bmAddress : 3; // port number
|
||||
uint8_t bmParent : 3; // parent hub address
|
||||
uint8_t bmHub : 1; // hub flag
|
||||
uint8_t bmReserved : 1; // reserved, must be zero
|
||||
} __attribute__((packed));
|
||||
uint8_t devAddress;
|
||||
};
|
||||
} __attribute__((packed));
|
||||
|
||||
struct UHS_Device {
|
||||
volatile UHS_EpInfo *epinfo[UHS_HOST_MAX_INTERFACE_DRIVERS]; // endpoint info pointer
|
||||
UHS_DeviceAddress address;
|
||||
uint8_t epcount; // number of endpoints
|
||||
uint8_t speed; // indicates device speed
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef void (*UsbDeviceHandleFunc)(UHS_Device *pdev);
|
||||
|
||||
class AddressPool {
|
||||
UHS_EpInfo dev0ep; //Endpoint data structure used during enumeration for uninitialized device
|
||||
|
||||
// In order to avoid hub address duplication, this should use bits
|
||||
uint8_t hubCounter; // hub counter
|
||||
|
||||
UHS_Device thePool[UHS_HOST_MAX_INTERFACE_DRIVERS];
|
||||
|
||||
// Initializes address pool entry
|
||||
|
||||
void UHS_NI InitEntry(uint8_t index) {
|
||||
thePool[index].address.devAddress = 0;
|
||||
thePool[index].epcount = 1;
|
||||
thePool[index].speed = 0;
|
||||
for(uint8_t i = 0; i < UHS_HOST_MAX_INTERFACE_DRIVERS; i++) {
|
||||
thePool[index].epinfo[i] = &dev0ep;
|
||||
}
|
||||
};
|
||||
|
||||
// Returns thePool index for a given address
|
||||
|
||||
uint8_t UHS_NI FindAddressIndex(uint8_t address = 0) {
|
||||
for(uint8_t i = 1; i < UHS_HOST_MAX_INTERFACE_DRIVERS; i++) {
|
||||
if(thePool[i].address.devAddress == address)
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Returns thePool child index for a given parent
|
||||
|
||||
uint8_t UHS_NI FindChildIndex(UHS_DeviceAddress addr, uint8_t start = 1) {
|
||||
for(uint8_t i = (start < 1 || start >= UHS_HOST_MAX_INTERFACE_DRIVERS) ? 1 : start; i < UHS_HOST_MAX_INTERFACE_DRIVERS; i++) {
|
||||
if(thePool[i].address.bmParent == addr.bmAddress)
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Frees address entry specified by index parameter
|
||||
|
||||
void UHS_NI FreeAddressByIndex(uint8_t index) {
|
||||
// Zero field is reserved and should not be affected
|
||||
if(index == 0)
|
||||
return;
|
||||
|
||||
UHS_DeviceAddress uda = thePool[index].address;
|
||||
// If a hub was switched off all port addresses should be freed
|
||||
if(uda.bmHub == 1) {
|
||||
for(uint8_t i = 1; (i = FindChildIndex(uda, i));)
|
||||
FreeAddressByIndex(i);
|
||||
|
||||
// FIXME: use BIT MASKS
|
||||
// If the hub had the last allocated address, hubCounter should be decremented
|
||||
if(hubCounter == uda.bmAddress)
|
||||
hubCounter--;
|
||||
}
|
||||
InitEntry(index);
|
||||
}
|
||||
|
||||
void InitAllAddresses() {
|
||||
for(uint8_t i = 1; i < UHS_HOST_MAX_INTERFACE_DRIVERS; i++) InitEntry(i);
|
||||
hubCounter = 0;
|
||||
};
|
||||
public:
|
||||
|
||||
AddressPool() {
|
||||
hubCounter = 0;
|
||||
// Zero address is reserved
|
||||
InitEntry(0);
|
||||
|
||||
thePool[0].epinfo[0] = &dev0ep;
|
||||
dev0ep.epAddr = 0;
|
||||
#if UHS_DEVICE_WINDOWS_USB_SPEC_VIOLATION_DESCRIPTOR_DEVICE
|
||||
dev0ep.maxPktSize = 0x40; //starting at 0x40 and work down
|
||||
#else
|
||||
dev0ep.maxPktSize = 0x08;
|
||||
#endif
|
||||
dev0ep.epAttribs = 0; //set DATA0/1 toggles to 0
|
||||
dev0ep.bmNakPower = UHS_USB_NAK_MAX_POWER;
|
||||
InitAllAddresses();
|
||||
};
|
||||
|
||||
// Returns a pointer to a specified address entry
|
||||
|
||||
UHS_Device* UHS_NI GetUsbDevicePtr(uint8_t addr) {
|
||||
if(!addr)
|
||||
return thePool;
|
||||
|
||||
uint8_t index = FindAddressIndex(addr);
|
||||
|
||||
return (!index) ? NULL : &thePool[index];
|
||||
};
|
||||
|
||||
|
||||
// Allocates new address
|
||||
|
||||
uint8_t UHS_NI AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 1) {
|
||||
/* if (parent != 0 && port == 0)
|
||||
USB_HOST_SERIAL.println("PRT:0"); */
|
||||
UHS_DeviceAddress _parent;
|
||||
_parent.devAddress = parent;
|
||||
if(_parent.bmReserved || port > 7)
|
||||
//if(parent > 127 || port > 7)
|
||||
return 0;
|
||||
|
||||
// FIXME: use BIT MASKS
|
||||
if(is_hub && hubCounter == 7)
|
||||
return 0;
|
||||
|
||||
// finds first empty address entry starting from one
|
||||
uint8_t index = FindAddressIndex(0);
|
||||
|
||||
if(!index) // if empty entry is not found
|
||||
return 0;
|
||||
|
||||
UHS_DeviceAddress addr;
|
||||
addr.devAddress = port;
|
||||
addr.bmParent = _parent.bmAddress;
|
||||
|
||||
// FIXME: use BIT MASKS
|
||||
if(is_hub) {
|
||||
hubCounter++;
|
||||
addr.bmHub = 1;
|
||||
addr.bmAddress = hubCounter;
|
||||
}
|
||||
thePool[index].address = addr;
|
||||
#if DEBUG_PRINTF_EXTRA_HUGE
|
||||
#ifdef UHS_DEBUG_USB_ADDRESS
|
||||
printf("Address: %x (%x.%x.%x)\r\n", addr.devAddress, addr.bmHub, addr.bmParent, addr.bmAddress);
|
||||
#endif
|
||||
#endif
|
||||
return thePool[index].address.devAddress;
|
||||
};
|
||||
|
||||
void UHS_NI FreeAddress(uint8_t addr) {
|
||||
// if the root hub is disconnected all the addresses should be initialized
|
||||
if(addr == 0x41) {
|
||||
InitAllAddresses();
|
||||
return;
|
||||
}
|
||||
uint8_t index = FindAddressIndex(addr);
|
||||
FreeAddressByIndex(index);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif // __ADDRESS_H__
|
@ -0,0 +1,70 @@
|
||||
/* Copyright (C) 2015-2016 Andrew J. Kroll
|
||||
and
|
||||
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Contact information
|
||||
-------------------
|
||||
|
||||
Circuits At Home, LTD
|
||||
Web : https://www.circuitsathome.com
|
||||
e-mail : support@circuitsathome.com
|
||||
*/
|
||||
#if !defined(_usb_h_) || defined(__HEXDUMP_H__)
|
||||
#error "Never include UHS_hexdump.h directly; include UHS_Usb.h instead"
|
||||
#else
|
||||
#define __HEXDUMP_H__
|
||||
|
||||
extern int UsbDEBUGlvl;
|
||||
|
||||
template <class BASE_CLASS, class LEN_TYPE, class OFFSET_TYPE>
|
||||
class HexDumper : public BASE_CLASS {
|
||||
uint8_t byteCount;
|
||||
OFFSET_TYPE byteTotal;
|
||||
|
||||
public:
|
||||
|
||||
HexDumper() : byteCount(0), byteTotal(0) {
|
||||
};
|
||||
|
||||
void Initialize() {
|
||||
byteCount = 0;
|
||||
byteTotal = 0;
|
||||
};
|
||||
|
||||
virtual void Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset);
|
||||
};
|
||||
|
||||
template <class BASE_CLASS, class LEN_TYPE, class OFFSET_TYPE>
|
||||
void HexDumper<BASE_CLASS, LEN_TYPE, OFFSET_TYPE>::Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset) {
|
||||
if(UsbDEBUGlvl >= 0x80) { // Fully bypass this block of code if we do not debug.
|
||||
for(LEN_TYPE j = 0; j < len; j++, byteCount++, byteTotal++) {
|
||||
if(!byteCount) {
|
||||
PrintHex<OFFSET_TYPE > (byteTotal, 0x80);
|
||||
E_Notify(PSTR(": "), 0x80);
|
||||
}
|
||||
PrintHex<uint8_t > (pbuf[j], 0x80);
|
||||
E_Notify(PSTR(" "), 0x80);
|
||||
|
||||
if(byteCount == 15) {
|
||||
E_Notify(PSTR("\r\n"), 0x80);
|
||||
byteCount = 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __HEXDUMP_H__
|
@ -0,0 +1,111 @@
|
||||
/* Copyright (C) 2015-2016 Andrew J. Kroll
|
||||
and
|
||||
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Contact information
|
||||
-------------------
|
||||
|
||||
Circuits At Home, LTD
|
||||
Web : https://www.circuitsathome.com
|
||||
e-mail : support@circuitsathome.com
|
||||
*/
|
||||
/* USB functions */
|
||||
#ifndef _UHS_host_h_
|
||||
#define _UHS_host_h_
|
||||
|
||||
// WARNING: Do not change the order of includes, or stuff will break!
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if DISABLED(USE_UHS3_USB)
|
||||
#include <ISR_safe_memory.h>
|
||||
#include <Wire.h>
|
||||
#include <SPI.h>
|
||||
#include <UHS_ByteBuffer.h>
|
||||
#endif
|
||||
#include "UHS_macros.h"
|
||||
|
||||
// None of these should ever be directly included by a driver, or a user's sketch.
|
||||
#include "../dyn_SWI/dyn_SWI.h"
|
||||
#include "UHS_USB_IDs.h"
|
||||
#include "UHS_settings.h"
|
||||
#include "UHS_usb_ch9.h"
|
||||
#include "UHS_UsbCore.h"
|
||||
#include "UHS_address.h"
|
||||
#include "UHS_usbhost.h"
|
||||
#include "UHS_printhex.h"
|
||||
#include "UHS_message.h"
|
||||
|
||||
// Load system components as required
|
||||
#if defined(LOAD_USB_HOST_SYSTEM) && !defined(USB_HOST_SYSTEM_LOADED)
|
||||
#include "UHS_util_INLINE.h"
|
||||
#include "UHS_host_INLINE.h"
|
||||
#include "UHS_printf_HELPER.h"
|
||||
|
||||
#ifdef LOAD_USB_HOST_SHIELD
|
||||
#include "USB_HOST_SHIELD/USB_HOST_SHIELD.h"
|
||||
#endif
|
||||
|
||||
#if defined(LOAD_UHS_KINETIS_FS_HOST) && !defined(UHS_KINETIS_FS_HOST_LOADED)
|
||||
#include "UHS_KINETIS_FS_HOST/UHS_KINETIS_FS_HOST.h"
|
||||
#endif
|
||||
|
||||
#if defined(LOAD_UHS_KINETIS_EHCI) && !defined(UHS_KINETIS_EHCI_LOADED)
|
||||
#include "UHS_KINETIS_EHCI/UHS_KINETIS_EHCI.h"
|
||||
#endif
|
||||
|
||||
// Load USB drivers and multiplexers
|
||||
|
||||
#ifdef LOAD_UHS_HUB
|
||||
#include "UHS_HUB/UHS_HUB.h"
|
||||
#endif // HUB loaded
|
||||
|
||||
#ifdef LOAD_UHS_BULK_STORAGE
|
||||
#include "UHS_BULK_STORAGE/UHS_BULK_STORAGE.h"
|
||||
#endif
|
||||
|
||||
#ifdef LOAD_GENERIC_STORAGE
|
||||
#include "../UHS_FS/UHS_FS.h"
|
||||
#endif
|
||||
// Add BT and optionally HID if directed to do so
|
||||
#ifdef LOAD_UHS_BT
|
||||
#include "UHS_BT/UHS_BT.h"
|
||||
#endif // BT and optionally HID loaded
|
||||
|
||||
// Add HID
|
||||
#ifdef LOAD_UHS_HID
|
||||
#include "UHS_HID/UHS_HID.h"
|
||||
#endif // HID loaded
|
||||
|
||||
// Add CDC multiplexers (currently only ACM)
|
||||
#if defined(LOAD_UHS_CDC_ACM) || defined(LOAD_UHS_CDC_ACM_FTDI) || defined(LOAD_UHS_CDC_ACM_PROLIFIC) || defined(LOAD_UHS_CDC_ACM_XR21B1411)
|
||||
#include "UHS_CDC/UHS_CDC.h"
|
||||
#endif // CDC loaded
|
||||
|
||||
#ifdef LOAD_UHS_ADK
|
||||
#include "UHS_ADK/UHS_ADK.h"
|
||||
#endif
|
||||
|
||||
#ifdef LOAD_UHS_MIDI
|
||||
#include "UHS_MIDI/UHS_MIDI.h"
|
||||
#endif
|
||||
|
||||
#endif // System code loaded
|
||||
|
||||
#endif // _UHS_host_h_
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,230 @@
|
||||
/* Copyright (C) 2015-2016 Andrew J. Kroll
|
||||
and
|
||||
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Contact information
|
||||
-------------------
|
||||
|
||||
Circuits At Home, LTD
|
||||
Web : https://www.circuitsathome.com
|
||||
e-mail : support@circuitsathome.com
|
||||
*/
|
||||
|
||||
#ifndef MACROS_H
|
||||
#define MACROS_H
|
||||
#include "macro_logic.h"
|
||||
/*
|
||||
* Universal Arduino(tm) "IDE" fixups.
|
||||
*/
|
||||
|
||||
|
||||
// Just in case...
|
||||
#ifndef SERIAL_PORT_MONITOR
|
||||
#define SERIAL_PORT_MONITOR Serial
|
||||
#endif
|
||||
|
||||
#ifndef INT16_MIN
|
||||
#define INT16_MIN -32768
|
||||
#endif
|
||||
// require 10607+
|
||||
#if defined(ARDUINO) && ARDUINO >=10607
|
||||
// nop :-)
|
||||
#else
|
||||
#error "Arduino version too old, and must be at least 1.6.7"
|
||||
#endif
|
||||
|
||||
// Nuke screwed up macro junk from the IDE.
|
||||
#ifdef __cplusplus
|
||||
#ifdef true
|
||||
#undef true
|
||||
#endif
|
||||
#ifdef false
|
||||
#undef false
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef UHS_DEVICE_WINDOWS_USB_SPEC_VIOLATION_DESCRIPTOR_DEVICE
|
||||
|
||||
#ifndef UHS_BIG_FLASH
|
||||
|
||||
#if defined(FLASHEND) && defined(FLASHSTART)
|
||||
#if (FLASHEND - FLASHSTART) > 0x0FFFFU
|
||||
#define UHS_BIG_FLASH 1
|
||||
#else
|
||||
#define UHS_BIG_FLASH 0
|
||||
#endif
|
||||
|
||||
#elif defined(__PIC32_FLASH_SIZE)
|
||||
#if __PIC32_FLASH_SIZE > 511
|
||||
#define UHS_BIG_FLASH 1
|
||||
#else
|
||||
#define UHS_BIG_FLASH 0
|
||||
#endif
|
||||
|
||||
#elif defined(FLASHEND) && !defined(FLASHSTART)
|
||||
// Assumes flash starts at 0x00000, is this a safe assumption?
|
||||
// 192K + should be OK
|
||||
#if FLASHEND > 0x02FFFFU
|
||||
#define UHS_BIG_FLASH 1
|
||||
#else
|
||||
#define UHS_BIG_FLASH 0
|
||||
#endif
|
||||
|
||||
#elif defined(IFLASH_SIZE)
|
||||
#if IFLASH_SIZE > 0x0FFFFU
|
||||
#define UHS_BIG_FLASH 1
|
||||
#else
|
||||
#define UHS_BIG_FLASH 0
|
||||
#endif
|
||||
|
||||
#elif defined(ESP8266)
|
||||
#define UHS_BIG_FLASH 1
|
||||
#define SYSTEM_OR_SPECIAL_YIELD(...) yield()
|
||||
|
||||
#elif defined(__arm__) && defined(CORE_TEENSY)
|
||||
#define UHS_BIG_FLASH 1
|
||||
|
||||
#elif defined(ARDUINO_spresense_ast)
|
||||
#define UHS_BIG_FLASH 1
|
||||
#else
|
||||
// safe default
|
||||
#warning Small flash?
|
||||
#define UHS_BIG_FLASH 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if UHS_BIG_FLASH
|
||||
#define UHS_DEVICE_WINDOWS_USB_SPEC_VIOLATION_DESCRIPTOR_DEVICE 1
|
||||
#else
|
||||
#define UHS_DEVICE_WINDOWS_USB_SPEC_VIOLATION_DESCRIPTOR_DEVICE 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__arm__) && defined(CORE_TEENSY)
|
||||
#define UHS_PIN_WRITE(p, v) digitalWriteFast(p, v)
|
||||
#define UHS_PIN_READ(p) digitalReadFast(p)
|
||||
#endif
|
||||
// TODO: Fast inline code for AVR and SAM based microcontrollers
|
||||
// This can be done pretty easily.
|
||||
// For now, this will just work out-of-the-box.
|
||||
#ifndef UHS_PIN_WRITE
|
||||
#define UHS_PIN_WRITE(p, v) digitalWrite(p, v)
|
||||
#endif
|
||||
#ifndef UHS_PIN_READ
|
||||
#define UHS_PIN_READ(p) digitalRead(p)
|
||||
#endif
|
||||
|
||||
#if defined( __PIC32MX__ ) && !defined(interrupts) // compiling with Microchip XC32 compiler
|
||||
#define interrupts() __builtin_enable_interrupts()
|
||||
#edfine noInterrupts() __builtin_disable_interrupts()
|
||||
#endif
|
||||
|
||||
#ifndef ARDUINO_SAMD_ZERO
|
||||
#ifdef ARDUINO_AVR_ADK
|
||||
#define UHS_GET_DPI(x) (x == 54 ? 6 : digitalPinToInterrupt(x))
|
||||
#else
|
||||
#define UHS_GET_DPI(x) digitalPinToInterrupt(x)
|
||||
#endif
|
||||
#else
|
||||
#define UHS_GET_DPI(x) (x)
|
||||
#endif
|
||||
|
||||
#include "../../../../HAL/shared/progmem.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// HANDY MACROS
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Atmoically set/clear single bits using bitbands.
|
||||
// Believe it or not, this boils down to a constant,
|
||||
// and is less code than using |= &= operators.
|
||||
// Bonus, it makes code easier to read too.
|
||||
// Bitbanding is a wonderful thing.
|
||||
#define BITNR(i) (i&0x1?0:i&0x2?1:i&0x4?2:i&0x8?3:i&0x10?4:i&0x20?5:i&0x40?6:i&0x80?7:i&0x100?8:i&0x200?9:i&0x400?10:i&0x800?11:i&0x1000?12:i&0x2000?13:i&0x4000?14:i&0x8000?15:i&0x10000?16:i&0x20000?17:i&0x40000?18:i&0x80000?19:i&0x100000?20:i&0x200000?21:i&0x400000?22:i&0x800000?23:i&0x1000000?24:i&0x2000000?25:i&0x4000000?26:i&0x8000000?27:i&0x10000000?28:i&0x20000000?29:i&0x40000000?30:i&0x80000000?31:32)
|
||||
#define UHS_KIO_BITBAND_ADDR(r, i) (((uint32_t)&(r) - 0x40000000) * 32 + (i) * 4 + 0x42000000)
|
||||
#define UHS_KIO_SETBIT_ATOMIC(r, m) (*(uint32_t *)UHS_KIO_BITBAND_ADDR((r), BITNR((m)))) = 1
|
||||
#define UHS_KIO_CLRBIT_ATOMIC(r, m) (*(uint32_t *)UHS_KIO_BITBAND_ADDR((r), BITNR((m)))) = 0
|
||||
|
||||
|
||||
#define VALUE_BETWEEN(v,l,h) (((v)>(l)) && ((v)<(h)))
|
||||
#define VALUE_WITHIN(v,l,h) (((v)>=(l)) && ((v)<=(h)))
|
||||
#define output_pgm_message(wa,fp,mp,el) wa = &mp, fp((char *)pgm_read_pointer(wa), el)
|
||||
#define output_if_between(v,l,h,wa,fp,mp,el) if(VALUE_BETWEEN(v,l,h)) output_pgm_message(wa,fp,mp[v-(l+1)],el);
|
||||
|
||||
#define UHS_SWAP_VALUES(a, b) (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b)))
|
||||
#ifndef __BYTE_GRABBING_DEFINED__
|
||||
#define __BYTE_GRABBING_DEFINED__ 1
|
||||
#ifdef BROKEN_OPTIMIZER_LITTLE_ENDIAN
|
||||
// Note: Use this if your compiler generates horrible assembler!
|
||||
#define UHS_UINT8_BYTE0(__usi__) (((uint8_t *)&(__usi__))[0])
|
||||
#define UHS_UINT8_BYTE1(__usi__) (((uint8_t *)&(__usi__))[1])
|
||||
#define UHS_UINT8_BYTE2(__usi__) (((uint8_t *)&(__usi__))[2])
|
||||
#define UHS_UINT8_BYTE3(__usi__) (((uint8_t *)&(__usi__))[3])
|
||||
#define UHS_UINT8_BYTE4(__usi__) (((uint8_t *)&(__usi__))[4])
|
||||
#define UHS_UINT8_BYTE5(__usi__) (((uint8_t *)&(__usi__))[5])
|
||||
#define UHS_UINT8_BYTE6(__usi__) (((uint8_t *)&(__usi__))[6])
|
||||
#define UHS_UINT8_BYTE7(__usi__) (((uint8_t *)&(__usi__))[7])
|
||||
#else
|
||||
// Note: The cast alone to uint8_t is actually enough.
|
||||
// GCC throws out the "& 0xFF", and the size is no different.
|
||||
// Some compilers need it.
|
||||
#define UHS_UINT8_BYTE0(__usi__) ((uint8_t)((__usi__) & 0xFF ))
|
||||
#define UHS_UINT8_BYTE1(__usi__) ((uint8_t)(((__usi__) >> 8) & 0xFF))
|
||||
#define UHS_UINT8_BYTE2(__usi__) ((uint8_t)(((__usi__) >> 16) & 0xFF))
|
||||
#define UHS_UINT8_BYTE3(__usi__) ((uint8_t)(((__usi__) >> 24) & 0xFF))
|
||||
#define UHS_UINT8_BYTE4(__usi__) ((uint8_t)(((__usi__) >> 32) & 0xFF))
|
||||
#define UHS_UINT8_BYTE5(__usi__) ((uint8_t)(((__usi__) >> 40) & 0xFF))
|
||||
#define UHS_UINT8_BYTE6(__usi__) ((uint8_t)(((__usi__) >> 48) & 0xFF))
|
||||
#define UHS_UINT8_BYTE7(__usi__) ((uint8_t)(((__usi__) >> 56) & 0xFF))
|
||||
#endif
|
||||
#define UHS_UINT16_SET_BYTE1(__usi__) ((uint16_t)(__usi__) << 8)
|
||||
#define UHS_UINT32_SET_BYTE1(__usi__) ((uint32_t)(__usi__) << 8)
|
||||
#define UHS_UINT64_SET_BYTE1(__usi__) ((uint64_t)(__usi__) << 8)
|
||||
#define UHS_UINT32_SET_BYTE2(__usi__) ((uint32_t)(__usi__) << 16)
|
||||
#define UHS_UINT64_SET_BYTE2(__usi__) ((uint64_t)(__usi__) << 16)
|
||||
#define UHS_UINT32_SET_BYTE3(__usi__) ((uint32_t)(__usi__) << 24)
|
||||
#define UHS_UINT64_SET_BYTE3(__usi__) ((uint64_t)(__usi__) << 24)
|
||||
#define UHS_UINT64_SET_BYTE4(__usi__) ((uint64_t)(__usi__) << 32)
|
||||
#define UHS_UINT64_SET_BYTE5(__usi__) ((uint64_t)(__usi__) << 40)
|
||||
#define UHS_UINT64_SET_BYTE6(__usi__) ((uint64_t)(__usi__) << 48)
|
||||
#define UHS_UINT64_SET_BYTE7(__usi__) ((uint64_t)(__usi__) << 56)
|
||||
|
||||
// These are the smallest and fastest ways I have found so far in pure C/C++.
|
||||
#define UHS_BYTES_TO_UINT16(__usc1__,__usc0__) ((uint16_t)((uint16_t)(__usc0__) | (uint16_t)UHS_UINT16_SET_BYTE1(__usc1__)))
|
||||
#define UHS_BYTES_TO_UINT32(__usc3__,__usc2__,__usc1__,__usc0__) ((uint32_t)((uint32_t)(__usc0__) | UHS_UINT32_SET_BYTE1(__usc1__) | UHS_UINT32_SET_BYTE2(__usc2__) | UHS_UINT32_SET_BYTE3(__usc3__)))
|
||||
#define UHS_BYTES_TO_UINT64(__usc7__,__usc6__,__usc5__,__usc4__,__usc3__,__usc2__,__usc1__,__usc0__) ((uint64_t)((uint64_t)__usc0__ | UHS_UINT64_SET_BYTE1(__usc1__) | UHS_UINT64_SET_BYTE2(__usc2__) | UHS_UINT64_SET_BYTE3(__usc3__) | UHS_UINT64_SET_BYTE4(__usc4__) | UHS_UINT64_SET_BYTE5(__usc5__) | UHS_UINT64_SET_BYTE6(__usc6__) | UHS_UINT64_SET_BYTE7(__usc7__)))
|
||||
#endif
|
||||
/*
|
||||
* Debug macros.
|
||||
* Useful when porting from UHS2.
|
||||
* Do not use these for any new code.
|
||||
* Change to better debugging after port is completed.
|
||||
* Strings are stored in progmem (flash) instead of RAM.
|
||||
*/
|
||||
#define USBTRACE1(s,l) (Notify(PSTR(s), l))
|
||||
#define USBTRACE(s) (USBTRACE1((s), 0x80)); USB_HOST_SERIAL.flush()
|
||||
#define USBTRACE3(s,r,l) (Notify(PSTR(s), l), D_PrintHex((r), l), Notify(PSTR("\r\n"), l))
|
||||
#define USBTRACE3X(s,r,l) (Notify(PSTR(s), l), D_PrintHex((r), l))
|
||||
#define USBTRACE2(s,r) (USBTRACE3((s),(r),0x80)); USB_HOST_SERIAL.flush()
|
||||
#define USBTRACE2X(s,r) (USBTRACE3X((s),(r),0x80)); USB_HOST_SERIAL.flush()
|
||||
|
||||
#define VOID0 ((void)0)
|
||||
#ifndef NOTUSED
|
||||
#define NOTUSED(...) __VA_ARGS__ __attribute__((unused))
|
||||
#endif
|
||||
#endif /* MACROS_H */
|
@ -0,0 +1,91 @@
|
||||
/* Copyright (C) 2015-2016 Andrew J. Kroll
|
||||
and
|
||||
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Contact information
|
||||
-------------------
|
||||
|
||||
Circuits At Home, LTD
|
||||
Web : https://www.circuitsathome.com
|
||||
e-mail : support@circuitsathome.com
|
||||
*/
|
||||
#if !defined(_UHS_host_h_) || defined(__MESSAGE_H__)
|
||||
#error "Never include UHS_message.h directly; include UHS_Usb.h instead"
|
||||
#else
|
||||
#define __MESSAGE_H__
|
||||
|
||||
extern int UsbDEBUGlvl;
|
||||
|
||||
void E_Notify(char const * msg, int lvl);
|
||||
void E_Notify(uint8_t b, int lvl);
|
||||
void E_NotifyStr(char const * msg, int lvl);
|
||||
void E_Notifyc(char c, int lvl);
|
||||
|
||||
#ifdef DEBUG_USB_HOST
|
||||
#define Notify E_Notify
|
||||
#define NotifyStr E_NotifyStr
|
||||
#define Notifyc E_Notifyc
|
||||
void NotifyFailGetDevDescr(uint8_t reason);
|
||||
void NotifyFailSetDevTblEntry(uint8_t reason);
|
||||
void NotifyFailGetConfDescr(uint8_t reason);
|
||||
void NotifyFailSetConfDescr(uint8_t reason);
|
||||
void NotifyFailGetDevDescr();
|
||||
void NotifyFailSetDevTblEntry();
|
||||
void NotifyFailGetConfDescr();
|
||||
void NotifyFailSetConfDescr();
|
||||
void NotifyFailUnknownDevice(uint16_t VID, uint16_t PID);
|
||||
void NotifyFail(uint8_t rcode);
|
||||
#else
|
||||
#define Notify(...) VOID0
|
||||
#define NotifyStr(...) VOID0
|
||||
#define Notifyc(...) VOID0
|
||||
#define NotifyFailGetDevDescr(...) VOID0
|
||||
#define NotifyFailSetDevTblEntry(...) VOID0
|
||||
#define NotifyFailGetConfDescr(...) VOID0
|
||||
#define NotifyFailGetDevDescr(...) VOID0
|
||||
#define NotifyFailSetDevTblEntry(...) VOID0
|
||||
#define NotifyFailGetConfDescr(...) VOID0
|
||||
#define NotifyFailSetConfDescr(...) VOID0
|
||||
#define NotifyFailUnknownDevice(...) VOID0
|
||||
#define NotifyFail(...) VOID0
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_USB_HOST
|
||||
template <class ERROR_TYPE> void ErrorMessage(uint8_t level, char const * msg, ERROR_TYPE rcode = 0) {
|
||||
Notify(msg, level);
|
||||
Notify(PSTR(": "), level);
|
||||
D_PrintHex<ERROR_TYPE > (rcode, level);
|
||||
Notify(PSTR("\r\n"), level);
|
||||
#else
|
||||
template <class ERROR_TYPE> void ErrorMessage(NOTUSED(uint8_t level), NOTUSED(char const * msg), ERROR_TYPE rcode = 0) {
|
||||
(void)rcode;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DEBUG_USB_HOST
|
||||
template <class ERROR_TYPE> void ErrorMessage(char const * msg, ERROR_TYPE rcode = 0) {
|
||||
Notify(msg, 0x80);
|
||||
Notify(PSTR(": "), 0x80);
|
||||
D_PrintHex<ERROR_TYPE > (rcode, 0x80);
|
||||
Notify(PSTR("\r\n"), 0x80);
|
||||
#else
|
||||
template <class ERROR_TYPE> void ErrorMessage(NOTUSED(char const * msg), ERROR_TYPE rcode = 0) {
|
||||
(void)rcode;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // __MESSAGE_H__
|
@ -0,0 +1,200 @@
|
||||
/* Copyright (C) 2015-2016 Andrew J. Kroll
|
||||
and
|
||||
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Contact information
|
||||
-------------------
|
||||
|
||||
Circuits At Home, LTD
|
||||
Web : https://www.circuitsathome.com
|
||||
e-mail : support@circuitsathome.com
|
||||
*/
|
||||
|
||||
#ifndef UHS_PRINTF_HELPER_H
|
||||
#define UHS_PRINTF_HELPER_H
|
||||
|
||||
#ifdef LOAD_UHS_PRINTF_HELPER
|
||||
#include <Arduino.h>
|
||||
#ifdef true
|
||||
#undef true
|
||||
#endif
|
||||
#ifdef false
|
||||
#undef false
|
||||
#endif
|
||||
|
||||
#ifndef STDIO_IS_OK_TO_USE_AS_IS
|
||||
#if defined(ARDUINO_SAMD_ZERO) || defined(ARDUINO_SAM_DUE) || defined(ARDUINO_spresense_ast)
|
||||
// STDIO patching not required.
|
||||
#define STDIO_IS_OK_TO_USE_AS_IS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef STDIO_IS_OK_TO_USE_AS_IS
|
||||
// We need to patch STDIO so it can be used.
|
||||
|
||||
#ifndef SERIAL_PORT_MONITOR
|
||||
// Some don't define this.
|
||||
#define SERIAL_PORT_MONITOR Serial
|
||||
#endif
|
||||
|
||||
#ifndef SERIAL_PORT_HARDWARE
|
||||
// Some don't define this.
|
||||
#define SERIAL_PORT_HARDWARE SERIAL_PORT_MONITOR
|
||||
#endif
|
||||
|
||||
#ifndef USB_HOST_SERIAL
|
||||
#if defined(SERIAL_PORT_USBVIRTUAL) && defined(LOAD_UHS_KINETIS_FS_HOST)
|
||||
#define USB_HOST_SERIAL SERIAL_PORT_HARDWARE
|
||||
#else
|
||||
#define USB_HOST_SERIAL SERIAL_PORT_MONITOR
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NOTUSED
|
||||
#define NOTUSED(...) __VA_ARGS__ __attribute__((unused))
|
||||
#endif
|
||||
|
||||
#ifndef __AVR__
|
||||
#ifndef printf_P
|
||||
#define printf_P(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ARDUINO_ARCH_PIC32
|
||||
/*
|
||||
* For printf() output with pic32 Arduino
|
||||
*/
|
||||
extern "C" {
|
||||
|
||||
void _mon_putc(char s) {
|
||||
USB_HOST_SERIAL.write(s);
|
||||
}
|
||||
|
||||
int _mon_getc() {
|
||||
while(!USB_HOST_SERIAL.available());
|
||||
return USB_HOST_SERIAL.read();
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(__AVR__)
|
||||
extern "C" {
|
||||
|
||||
static FILE tty_stdio;
|
||||
static FILE tty_stderr;
|
||||
|
||||
static int NOTUSED(tty_stderr_putc(char c, NOTUSED(FILE *t)));
|
||||
static int NOTUSED(tty_stderr_flush(NOTUSED(FILE *t)));
|
||||
static int NOTUSED(tty_std_putc(char c, NOTUSED(FILE *t)));
|
||||
static int NOTUSED(tty_std_getc(NOTUSED(FILE *t)));
|
||||
static int NOTUSED(tty_std_flush(NOTUSED(FILE *t)));
|
||||
|
||||
static int tty_stderr_putc(char c, NOTUSED(FILE *t)) {
|
||||
USB_HOST_SERIAL.write(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tty_stderr_flush(NOTUSED(FILE *t)) {
|
||||
USB_HOST_SERIAL.flush();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tty_std_putc(char c, NOTUSED(FILE *t)) {
|
||||
USB_HOST_SERIAL.write(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tty_std_getc(NOTUSED(FILE *t)) {
|
||||
while(!USB_HOST_SERIAL.available());
|
||||
return USB_HOST_SERIAL.read();
|
||||
}
|
||||
|
||||
static int tty_std_flush(NOTUSED(FILE *t)) {
|
||||
USB_HOST_SERIAL.flush();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#elif defined(CORE_TEENSY)
|
||||
extern "C" {
|
||||
|
||||
int _write(int fd, const char *ptr, int len) {
|
||||
int j;
|
||||
for(j = 0; j < len; j++) {
|
||||
if(fd == 1)
|
||||
USB_HOST_SERIAL.write(*ptr++);
|
||||
else if(fd == 2)
|
||||
USB_HOST_SERIAL.write(*ptr++);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int _read(int fd, char *ptr, int len) {
|
||||
if(len > 0 && fd == 0) {
|
||||
while(!USB_HOST_SERIAL.available());
|
||||
*ptr = USB_HOST_SERIAL.read();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
int _fstat(int fd, struct stat *st) {
|
||||
memset(st, 0, sizeof (*st));
|
||||
st->st_mode = S_IFCHR;
|
||||
st->st_blksize = 1024;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _isatty(int fd) {
|
||||
return (fd < 3) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#error no STDIO
|
||||
#endif // defined(ARDUINO_ARCH_PIC32)
|
||||
|
||||
|
||||
|
||||
#ifdef __AVR__
|
||||
// The only wierdo in the bunch...
|
||||
void UHS_AVR_printf_HELPER_init() {
|
||||
// Set up stdio/stderr
|
||||
tty_stdio.put = tty_std_putc;
|
||||
tty_stdio.get = tty_std_getc;
|
||||
tty_stdio.flags = _FDEV_SETUP_RW;
|
||||
tty_stdio.udata = 0;
|
||||
|
||||
tty_stderr.put = tty_stderr_putc;
|
||||
tty_stderr.get = NULL;
|
||||
tty_stderr.flags = _FDEV_SETUP_WRITE;
|
||||
tty_stderr.udata = 0;
|
||||
|
||||
stdout = &tty_stdio;
|
||||
stdin = &tty_stdio;
|
||||
stderr = &tty_stderr;
|
||||
|
||||
}
|
||||
#define UHS_printf_HELPER_init() UHS_AVR_printf_HELPER_init()
|
||||
#endif
|
||||
|
||||
#endif /* STDIO_IS_OK_TO_USE_AS_IS */
|
||||
#endif /* load.... */
|
||||
|
||||
#ifndef UHS_printf_HELPER_init
|
||||
#define UHS_printf_HELPER_init() (void(0))
|
||||
#endif
|
||||
#endif /* UHS_PRINTF_HELPER_H */
|
@ -0,0 +1,96 @@
|
||||
/* Copyright (C) 2015-2016 Andrew J. Kroll
|
||||
and
|
||||
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Contact information
|
||||
-------------------
|
||||
|
||||
Circuits At Home, LTD
|
||||
Web : https://www.circuitsathome.com
|
||||
e-mail : support@circuitsathome.com
|
||||
*/
|
||||
|
||||
#if !defined(_UHS_host_h_) || defined(__PRINTHEX_H__)
|
||||
#error "Never include UHS_printhex.h directly; include UHS_Usb.h instead"
|
||||
#else
|
||||
#define __PRINTHEX_H__
|
||||
|
||||
void E_Notifyc(char c, int lvl);
|
||||
|
||||
template <class T>
|
||||
void PrintHex(T val, int lvl) {
|
||||
int num_nybbles = sizeof (T) * 2;
|
||||
|
||||
do {
|
||||
char v = 48 + (((val >> (num_nybbles - 1) * 4)) & 0x0F);
|
||||
if(v > 57) v += 7;
|
||||
E_Notifyc(v, lvl);
|
||||
} while(--num_nybbles);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void PrintBin(T val, int lvl) {
|
||||
for(T mask = (((T)1) << ((sizeof (T) << 3) - 1)); mask; mask >>= 1)
|
||||
if(val & mask)
|
||||
E_Notifyc('1', lvl);
|
||||
else
|
||||
E_Notifyc('0', lvl);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void SerialPrintHex(T val) {
|
||||
int num_nybbles = sizeof (T) * 2;
|
||||
|
||||
do {
|
||||
char v = 48 + (((val >> (num_nybbles - 1) * 4)) & 0x0F);
|
||||
if(v > 57) v += 7;
|
||||
USB_HOST_SERIAL.print(v);
|
||||
} while(--num_nybbles);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void PrintHex2(Print *prn, T val) {
|
||||
T mask = (((T)1) << (((sizeof (T) << 1) - 1) << 2));
|
||||
|
||||
while(mask > 1) {
|
||||
if(val < mask)
|
||||
prn->print("0");
|
||||
|
||||
mask >>= 4;
|
||||
}
|
||||
prn->print((T)val, HEX);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_USB_HOST
|
||||
template <class T> void D_PrintHex(T val, int lvl) {
|
||||
PrintHex<T > (val, lvl);
|
||||
#else
|
||||
template <class T> void D_PrintHex(NOTUSED(T val), NOTUSED(int lvl)) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DEBUG_USB_HOST
|
||||
template <class T> void D_PrintBin(T val, int lvl) {
|
||||
PrintBin<T > (val, lvl);
|
||||
#else
|
||||
template <class T> void D_PrintBin(NOTUSED(T val), NOTUSED(int lvl)) {
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif // __PRINTHEX_H__
|
@ -0,0 +1,141 @@
|
||||
/* Copyright (C) 2015-2016 Andrew J. Kroll
|
||||
and
|
||||
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Contact information
|
||||
-------------------
|
||||
|
||||
Circuits At Home, LTD
|
||||
Web : https://www.circuitsathome.com
|
||||
e-mail : support@circuitsathome.com
|
||||
*/
|
||||
|
||||
#ifndef UHS_SETTINGS_H
|
||||
#define UHS_SETTINGS_H
|
||||
|
||||
// TO-DO: Move specific settings to modules which use them.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Define any of these options at the top of your sketch to override
|
||||
// the defaults contained herewith. Do NOT do modifications here.
|
||||
// Individual Components have their own settings.
|
||||
//
|
||||
// Macro | Settings and notes | Default
|
||||
// -----------------------------+-----------------------+-----------------------
|
||||
// | Any class that does |
|
||||
// USB_HOST_SERIAL | text streaming | SERIAL_PORT_MONITOR
|
||||
// | e.g. Serial2 |
|
||||
// -----------------------------+-----------------------+-----------------------
|
||||
// ENABLE_UHS_DEBUGGING | 0 = off, 1 = on | 0
|
||||
// -----------------------------+-----------------------+-----------------------
|
||||
// | 0 = off, 1 = on |
|
||||
// | Caution! Can make |
|
||||
// DEBUG_PRINTF_EXTRA_HUGE | program too large! | 0
|
||||
// | Other modules depend |
|
||||
// | on this setting. |
|
||||
// -----------------------------+-----------------------+-----------------------
|
||||
// USE_UHS_BLACK_WIDDOW | 0 = no, 1 = yes | 0
|
||||
// -----------------------------+-----------------------+-----------------------
|
||||
// ENABLE_WII_IR_CAMERA | 0 = no, 1 = yes | 0
|
||||
// -----------------------------^-----------------------^-----------------------
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// DEBUGGING
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef USB_HOST_SERIAL
|
||||
#if defined(SERIAL_PORT_USBVIRTUAL) && defined(LOAD_UHS_KINETIS_FS_HOST)
|
||||
#define USB_HOST_SERIAL SERIAL_PORT_HARDWARE
|
||||
#else
|
||||
#define USB_HOST_SERIAL SERIAL_PORT_MONITOR
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef ENABLE_UHS_DEBUGGING
|
||||
#define ENABLE_UHS_DEBUGGING 0
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG_PRINTF_EXTRA_HUGE
|
||||
#define DEBUG_PRINTF_EXTRA_HUGE 0
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Manual board activation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/* Set this to 1 if you are using a Black Widdow */
|
||||
#ifndef USE_UHS_BLACK_WIDDOW
|
||||
#define USE_UHS_BLACK_WIDDOW 0
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Wii IR camera
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/* Set this to 1 to activate code for the Wii IR camera */
|
||||
#ifndef ENABLE_WII_IR_CAMERA
|
||||
#define ENABLE_WII_IR_CAMERA 0
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Set to 1 to use the faster spi4teensy3 driver. (not used yet))
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef USE_SPI4TEENSY3
|
||||
#define USE_SPI4TEENSY3 0
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// AUTOMATIC Settings
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// No user serviceable parts below this line.
|
||||
// DO NOT change anything below here unless you are a developer!
|
||||
|
||||
#if defined(__GNUC__) && defined(__AVR__)
|
||||
#ifndef GCC_VERSION
|
||||
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
|
||||
#endif
|
||||
#if GCC_VERSION < 40602 // Test for GCC < 4.6.2
|
||||
#ifdef PROGMEM
|
||||
#undef PROGMEM
|
||||
#define PROGMEM __attribute__((section(".progmem.data"))) // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=34734#c4
|
||||
#ifdef PSTR
|
||||
#undef PSTR
|
||||
#define PSTR(s) (__extension__({static const char __c[] PROGMEM = (s); &__c[0];})) // Copied from pgmspace.h in avr-libc source
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(DEBUG_USB_HOST) && ENABLE_UHS_DEBUGGING
|
||||
#define DEBUG_USB_HOST
|
||||
#endif
|
||||
|
||||
#if !defined(WIICAMERA) && ENABLE_WII_IR_CAMERA
|
||||
#define WIICAMERA
|
||||
#endif
|
||||
|
||||
#define UHS_SLEEP_MS(v) pUsb->sof_delay(v)
|
||||
|
||||
#ifndef UHS_NI
|
||||
#define UHS_NI __attribute__((noinline))
|
||||
#endif
|
||||
|
||||
#endif /* SETTINGS_H */
|
@ -0,0 +1,222 @@
|
||||
/* Copyright (C) 2015-2016 Andrew J. Kroll
|
||||
and
|
||||
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Contact information
|
||||
-------------------
|
||||
|
||||
Circuits At Home, LTD
|
||||
Web : https://www.circuitsathome.com
|
||||
e-mail : support@circuitsathome.com
|
||||
*/
|
||||
|
||||
#if !defined(_UHS_host_h_) || defined(_UHS_ch9_h_)
|
||||
#error "Never include UHS_usb_ch9.h directly; include UHS_Usb.h instead"
|
||||
#else
|
||||
|
||||
/* USB chapter 9 structures */
|
||||
#define _UHS_ch9_h_
|
||||
|
||||
/* Misc.USB constants */
|
||||
#define DEV_DESCR_LEN 18 //device descriptor length
|
||||
#define CONF_DESCR_LEN 9 //configuration descriptor length
|
||||
#define INTR_DESCR_LEN 9 //interface descriptor length
|
||||
#define EP_DESCR_LEN 7 //endpoint descriptor length
|
||||
|
||||
/* Standard Device Requests */
|
||||
#define USB_REQUEST_GET_STATUS 0 // Standard Device Request - GET STATUS
|
||||
#define USB_REQUEST_CLEAR_FEATURE 1 // Standard Device Request - CLEAR FEATURE
|
||||
#define USB_REQUEST_SET_FEATURE 3 // Standard Device Request - SET FEATURE
|
||||
#define USB_REQUEST_SET_ADDRESS 5 // Standard Device Request - SET ADDRESS
|
||||
#define USB_REQUEST_GET_DESCRIPTOR 6 // Standard Device Request - GET DESCRIPTOR
|
||||
#define USB_REQUEST_SET_DESCRIPTOR 7 // Standard Device Request - SET DESCRIPTOR
|
||||
#define USB_REQUEST_GET_CONFIGURATION 8 // Standard Device Request - GET CONFIGURATION
|
||||
#define USB_REQUEST_SET_CONFIGURATION 9 // Standard Device Request - SET CONFIGURATION
|
||||
#define USB_REQUEST_GET_INTERFACE 10 // Standard Device Request - GET INTERFACE
|
||||
#define USB_REQUEST_SET_INTERFACE 11 // Standard Device Request - SET INTERFACE
|
||||
#define USB_REQUEST_SYNCH_FRAME 12 // Standard Device Request - SYNCH FRAME
|
||||
|
||||
/* Wireless USB Device Requests */
|
||||
#define USB_REQ_SET_ENCRYPTION 0x0D
|
||||
#define USB_REQ_GET_ENCRYPTION 0x0E
|
||||
#define USB_REQ_RPIPE_ABORT 0x0E
|
||||
#define USB_REQ_SET_HANDSHAKE 0x0F
|
||||
#define USB_REQ_RPIPE_RESET 0x0F
|
||||
#define USB_REQ_GET_HANDSHAKE 0x10
|
||||
#define USB_REQ_SET_CONNECTION 0x11
|
||||
#define USB_REQ_SET_SECURITY_DATA 0x12
|
||||
#define USB_REQ_GET_SECURITY_DATA 0x13
|
||||
#define USB_REQ_SET_WUSB_DATA 0x14
|
||||
#define USB_REQ_LOOPBACK_DATA_WRITE 0x15
|
||||
#define USB_REQ_LOOPBACK_DATA_READ 0x16
|
||||
#define USB_REQ_SET_INTERFACE_DS 0x17
|
||||
|
||||
/* USB feature flags */
|
||||
#define USB_DEVICE_SELF_POWERED 0 /* (read only) */
|
||||
#define USB_DEVICE_REMOTE_WAKEUP 1 /* dev may initiate wakeup */
|
||||
#define USB_DEVICE_TEST_MODE 2 /* (wired high speed only) */
|
||||
#define USB_DEVICE_BATTERY 2 /* (wireless) */
|
||||
#define USB_DEVICE_B_HNP_ENABLE 3 /* (otg) dev may initiate HNP */
|
||||
#define USB_DEVICE_WUSB_DEVICE 3 /* (wireless)*/
|
||||
#define USB_DEVICE_A_HNP_SUPPORT 4 /* (otg) RH port supports HNP */
|
||||
#define USB_DEVICE_A_ALT_HNP_SUPPORT 5 /* (otg) other RH port does */
|
||||
#define USB_DEVICE_DEBUG_MODE 6 /* (special devices only) */
|
||||
|
||||
#define USB_FEATURE_ENDPOINT_HALT 0 // CLEAR/SET FEATURE - Endpoint Halt
|
||||
#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // CLEAR/SET FEATURE - Device remote wake-up
|
||||
#define USB_FEATURE_TEST_MODE 2 // CLEAR/SET FEATURE - Test mode
|
||||
/* OTG SET FEATURE Constants */
|
||||
#define OTG_FEATURE_B_HNP_ENABLE 3 // SET FEATURE OTG - Enable B device to perform HNP
|
||||
#define OTG_FEATURE_A_HNP_SUPPORT 4 // SET FEATURE OTG - A device supports HNP
|
||||
#define OTG_FEATURE_A_ALT_HNP_SUPPORT 5 // SET FEATURE OTG - Another port on the A device supports HNP
|
||||
|
||||
/* Setup Data Constants */
|
||||
#define USB_SETUP_HOST_TO_DEVICE 0x00 // Device Request bmRequestType transfer direction - host to device transfer
|
||||
#define USB_SETUP_DEVICE_TO_HOST 0x80 // Device Request bmRequestType transfer direction - device to host transfer
|
||||
#define USB_SETUP_TYPE_STANDARD 0x00 // Device Request bmRequestType type - standard
|
||||
#define USB_SETUP_TYPE_CLASS 0x20 // Device Request bmRequestType type - class
|
||||
#define USB_SETUP_TYPE_VENDOR 0x40 // Device Request bmRequestType type - vendor
|
||||
#define USB_SETUP_RECIPIENT_DEVICE 0x00 // Device Request bmRequestType recipient - device
|
||||
#define USB_SETUP_RECIPIENT_INTERFACE 0x01 // Device Request bmRequestType recipient - interface
|
||||
#define USB_SETUP_RECIPIENT_ENDPOINT 0x02 // Device Request bmRequestType recipient - endpoint
|
||||
#define USB_SETUP_RECIPIENT_OTHER 0x03 // Device Request bmRequestType recipient - other
|
||||
#define USB_SETUP_RECIPIENT_PORT 0x04 // Wireless USB 1.0
|
||||
#define USB_SETUP_RECIPIENT_RPIPE 0x05 // Wireless USB 1.0
|
||||
|
||||
|
||||
/* USB descriptors */
|
||||
#define USB_DESCRIPTOR_DEVICE 0x01 // bDescriptorType for a Device Descriptor.
|
||||
#define USB_DESCRIPTOR_CONFIGURATION 0x02 // bDescriptorType for a Configuration Descriptor.
|
||||
#define USB_DESCRIPTOR_STRING 0x03 // bDescriptorType for a String Descriptor.
|
||||
#define USB_DESCRIPTOR_INTERFACE 0x04 // bDescriptorType for an Interface Descriptor.
|
||||
#define USB_DESCRIPTOR_ENDPOINT 0x05 // bDescriptorType for an Endpoint Descriptor.
|
||||
#define USB_DESCRIPTOR_DEVICE_QUALIFIER 0x06 // bDescriptorType for a Device Qualifier.
|
||||
#define USB_DESCRIPTOR_OTHER_SPEED 0x07 // bDescriptorType for a Other Speed Configuration.
|
||||
#define USB_DESCRIPTOR_INTERFACE_POWER 0x08 // bDescriptorType for Interface Power.
|
||||
#define USB_DESCRIPTOR_OTG 0x09 // bDescriptorType for an OTG Descriptor.
|
||||
#define USB_DESCRIPTOR_DEBUG 0x0A
|
||||
#define USB_DESCRIPTOR_INTERFACE_ASSOCIATION 0x0B
|
||||
#define USB_DESCRIPTOR_SECURITY 0x0C
|
||||
#define USB_DESCRIPTOR_KEY 0x0D
|
||||
#define USB_DESCRIPTOR_ENCRYPTION_TYPE 0x0E
|
||||
#define USB_DESCRIPTOR_BOS 0x0F
|
||||
#define USB_DESCRIPTOR_DEVICE_CAPABILITY 0x10
|
||||
#define USB_DESCRIPTOR_WIRELESS_ENDPOINT_COMP 0x11
|
||||
#define USB_DESCRIPTOR_WIRE_ADAPTER 0x21
|
||||
#define USB_DESCRIPTOR_RPIPE 0x22
|
||||
#define USB_DESCRIPTOR_CS_RADIO_CONTROL 0x23
|
||||
#define USB_DESCRIPTOR_SS_ENDPOINT_COMP 0x30
|
||||
|
||||
#define USB_HID_DESCRIPTOR 0x21
|
||||
|
||||
|
||||
// Conventional codes for class-specific descriptors. "Common Class" Spec (3.11)
|
||||
#define USB_DESCRIPTOR_CS_DEVICE 0x21
|
||||
#define USB_DESCRIPTOR_CS_CONFIG 0x22
|
||||
#define USB_DESCRIPTOR_CS_STRING 0x23
|
||||
#define USB_DESCRIPTOR_CS_INTERFACE 0x24
|
||||
#define USB_DESCRIPTOR_CS_ENDPOINT 0x25
|
||||
|
||||
|
||||
|
||||
/* USB Endpoint Transfer Types */
|
||||
#define USB_TRANSFER_TYPE_CONTROL 0x00 // Endpoint is a control endpoint.
|
||||
#define USB_TRANSFER_TYPE_ISOCHRONOUS 0x01 // Endpoint is an isochronous endpoint.
|
||||
#define USB_TRANSFER_TYPE_BULK 0x02 // Endpoint is a bulk endpoint.
|
||||
#define USB_TRANSFER_TYPE_INTERRUPT 0x03 // Endpoint is an interrupt endpoint.
|
||||
#define bmUSB_TRANSFER_TYPE 0x03 // bit mask to separate transfer type from ISO attributes
|
||||
#define USB_TRANSFER_DIRECTION_IN 0x80 // Indicate direction is IN
|
||||
|
||||
/* Standard Feature Selectors for CLEAR_FEATURE Requests */
|
||||
#define USB_FEATURE_ENDPOINT_STALL 0 // Endpoint recipient
|
||||
#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // Device recipient
|
||||
#define USB_FEATURE_TEST_MODE 2 // Device recipient
|
||||
|
||||
/* descriptor data structures */
|
||||
|
||||
/* Device descriptor structure */
|
||||
typedef struct {
|
||||
uint8_t bLength; // Length of this descriptor.
|
||||
uint8_t bDescriptorType; // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE).
|
||||
uint16_t bcdUSB; // USB Spec Release Number (BCD).
|
||||
uint8_t bDeviceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific.
|
||||
uint8_t bDeviceSubClass; // Subclass code (assigned by the USB-IF).
|
||||
uint8_t bDeviceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific.
|
||||
uint8_t bMaxPacketSize0; // Maximum packet size for endpoint 0.
|
||||
uint16_t idVendor; // Vendor ID (assigned by the USB-IF).
|
||||
uint16_t idProduct; // Product ID (assigned by the manufacturer).
|
||||
uint16_t bcdDevice; // Device release number (BCD).
|
||||
uint8_t iManufacturer; // Index of String Descriptor describing the manufacturer.
|
||||
uint8_t iProduct; // Index of String Descriptor describing the product.
|
||||
uint8_t iSerialNumber; // Index of String Descriptor with the device's serial number.
|
||||
uint8_t bNumConfigurations; // Number of possible configurations.
|
||||
} __attribute__((packed)) USB_FD_DEVICE_DESCRIPTOR;
|
||||
|
||||
/* Configuration descriptor structure */
|
||||
typedef struct {
|
||||
uint8_t bLength; // Length of this descriptor.
|
||||
uint8_t bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION).
|
||||
uint16_t wTotalLength; // Total length of all descriptors for this configuration.
|
||||
uint8_t bNumInterfaces; // Number of interfaces in this configuration.
|
||||
uint8_t bConfigurationValue; // Value of this configuration (1 based).
|
||||
uint8_t iConfiguration; // Index of String Descriptor describing the configuration.
|
||||
uint8_t bmAttributes; // Configuration characteristics.
|
||||
uint8_t bMaxPower; // Maximum power consumed by this configuration.
|
||||
} __attribute__((packed)) USB_FD_CONFIGURATION_DESCRIPTOR;
|
||||
|
||||
/* Interface descriptor structure */
|
||||
typedef struct {
|
||||
uint8_t bLength; // Length of this descriptor.
|
||||
uint8_t bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE).
|
||||
uint8_t bInterfaceNumber; // Number of this interface (0 based).
|
||||
uint8_t bAlternateSetting; // Value of this alternate interface setting.
|
||||
uint8_t bNumEndpoints; // Number of endpoints in this interface.
|
||||
uint8_t bInterfaceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific.
|
||||
uint8_t bInterfaceSubClass; // Subclass code (assigned by the USB-IF).
|
||||
uint8_t bInterfaceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific.
|
||||
uint8_t iInterface; // Index of String Descriptor describing the interface.
|
||||
} __attribute__((packed)) USB_FD_INTERFACE_DESCRIPTOR;
|
||||
|
||||
/* Endpoint descriptor structure */
|
||||
typedef struct {
|
||||
uint8_t bLength; // Length of this descriptor.
|
||||
uint8_t bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT).
|
||||
uint8_t bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN).
|
||||
uint8_t bmAttributes; // Endpoint transfer type.
|
||||
uint16_t wMaxPacketSize; // Maximum packet size.
|
||||
uint8_t bInterval; // Polling interval in frames.
|
||||
} __attribute__((packed)) USB_FD_ENDPOINT_DESCRIPTOR;
|
||||
|
||||
/* HID descriptor */
|
||||
/*
|
||||
typedef struct {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint16_t bcdHID; // HID class specification release
|
||||
uint8_t bCountryCode;
|
||||
uint8_t bNumDescriptors; // Number of additional class specific descriptors
|
||||
uint8_t bDescrType; // Type of class descriptor
|
||||
uint16_t wDescriptorLength; // Total size of the Report descriptor
|
||||
} __attribute__((packed)) USB_HID_DESCRIPTOR;
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
uint8_t bDescrType; // Type of class descriptor
|
||||
uint16_t wDescriptorLength; // Total size of the Report descriptor
|
||||
} __attribute__((packed)) HID_CLASS_DESCRIPTOR_LEN_AND_TYPE;
|
||||
|
||||
#endif // _ch9_h_
|
@ -0,0 +1,449 @@
|
||||
/* Copyright (C) 2015-2016 Andrew J. Kroll
|
||||
and
|
||||
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Contact information
|
||||
-------------------
|
||||
|
||||
Circuits At Home, LTD
|
||||
Web : https://www.circuitsathome.com
|
||||
e-mail : support@circuitsathome.com
|
||||
*/
|
||||
|
||||
#ifndef _UHS_host_h_
|
||||
#error "Never include UHS_usbhost.h directly; include UHS_host.h instead"
|
||||
#else
|
||||
#ifndef _USBHOST_H_
|
||||
#define _USBHOST_H_
|
||||
|
||||
// Very early prototypes
|
||||
#ifdef UHS_LOAD_BT
|
||||
void UHS_BT_SetUSBInterface(UHS_USB_HOST_BASE *host, ENUMERATION_INFO *ei);
|
||||
void UHS_BT_ScanUninitialized(UHS_USB_HOST_BASE *host);
|
||||
void UHS_BT_Poll(UHS_USB_HOST_BASE *host);
|
||||
#endif
|
||||
#ifdef UHS_LOAD_HID
|
||||
void UHS_HID_SetUSBInterface(UHS_USB_HOST_BASE *host, ENUMERATION_INFO *ei);
|
||||
void UHS_HID_ScanUninitialized(UHS_USB_HOST_BASE *host);
|
||||
void UHS_HID_Poll(UHS_USB_HOST_BASE *host);
|
||||
#endif
|
||||
|
||||
//#if defined(LOAD_UHS_CDC_ACM) || defined(LOAD_UHS_CDC_ACM_FTDI) || defined(LOAD_UHS_CDC_ACM_PROLIFIC) || defined(LOAD_UHS_CDC_ACM_XR21B1411)
|
||||
//void UHS_CDC_ACM_SetUSBInterface(UHS_USB_HOST_BASE *host, ENUMERATION_INFO *ei);
|
||||
//void UHS_CDC_ACM_ScanUninitialized(UHS_USB_HOST_BASE *host);
|
||||
//void UHS_CDC_ACM_Poll(UHS_USB_HOST_BASE *host);
|
||||
//#endif
|
||||
|
||||
class UHS_USBInterface; // forward class declaration
|
||||
|
||||
// enumerator to turn the VBUS on/off
|
||||
|
||||
typedef enum {
|
||||
vbus_on = 0,
|
||||
vbus_off = 1
|
||||
} VBUS_t;
|
||||
|
||||
// All host SEI use this base class
|
||||
|
||||
class UHS_USB_HOST_BASE {
|
||||
public:
|
||||
AddressPool addrPool;
|
||||
UHS_USBInterface* devConfig[UHS_HOST_MAX_INTERFACE_DRIVERS];
|
||||
volatile uint8_t usb_error;
|
||||
volatile uint8_t usb_task_state;
|
||||
volatile uint8_t usb_task_polling_disabled;
|
||||
volatile uint8_t usb_host_speed;
|
||||
volatile uint8_t hub_present;
|
||||
|
||||
UHS_USB_HOST_BASE() {
|
||||
for(uint16_t i = 0; i < UHS_HOST_MAX_INTERFACE_DRIVERS; i++) {
|
||||
devConfig[i] = NULL;
|
||||
}
|
||||
usb_task_polling_disabled = 0;
|
||||
usb_task_state = UHS_USB_HOST_STATE_INITIALIZE; //set up state machine
|
||||
usb_host_speed = 0;
|
||||
usb_error = 0;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////
|
||||
//
|
||||
// Virtual methods that interface to the SIE
|
||||
// Overriding each is mandatory.
|
||||
//
|
||||
/////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Delay for x milliseconds
|
||||
* Override if your controller provides an SOF IRQ, which may involve
|
||||
* some sort of reentrant ISR or workaround with interrupts enabled.
|
||||
*
|
||||
* @param x how many milliseconds to delay
|
||||
* @return true if delay completed without a state change, false if delay aborted
|
||||
*/
|
||||
virtual bool UHS_NI sof_delay(uint16_t x) {
|
||||
if(!(usb_task_state & UHS_USB_HOST_STATE_MASK)) return false;
|
||||
uint8_t current_state = usb_task_state;
|
||||
while(current_state == usb_task_state && x--) {
|
||||
delay(1);
|
||||
}
|
||||
return (current_state == usb_task_state);
|
||||
};
|
||||
|
||||
virtual UHS_EpInfo * UHS_NI ctrlReqOpen(NOTUSED(uint8_t addr), NOTUSED(uint64_t Request), NOTUSED(uint8_t *dataptr)) {
|
||||
return NULL;
|
||||
};
|
||||
|
||||
virtual void UHS_NI vbusPower(NOTUSED(VBUS_t state)) {
|
||||
};
|
||||
|
||||
virtual void UHS_NI Task() {
|
||||
};
|
||||
|
||||
virtual uint8_t UHS_NI SetAddress(NOTUSED(uint8_t addr), NOTUSED(uint8_t ep), NOTUSED(UHS_EpInfo **ppep), NOTUSED(uint16_t &nak_limit)) {
|
||||
return UHS_HOST_ERROR_NOT_IMPLEMENTED;
|
||||
};
|
||||
|
||||
virtual uint8_t UHS_NI OutTransfer(NOTUSED(UHS_EpInfo *pep), NOTUSED(uint16_t nak_limit), NOTUSED(uint16_t nbytes), NOTUSED(uint8_t *data)) {
|
||||
return UHS_HOST_ERROR_NOT_IMPLEMENTED;
|
||||
};
|
||||
|
||||
virtual uint8_t UHS_NI InTransfer(NOTUSED(UHS_EpInfo *pep), NOTUSED(uint16_t nak_limit), NOTUSED(uint16_t *nbytesptr), NOTUSED(uint8_t *data)) {
|
||||
return UHS_HOST_ERROR_NOT_IMPLEMENTED;
|
||||
};
|
||||
|
||||
virtual uint8_t UHS_NI ctrlReqClose(NOTUSED(UHS_EpInfo *pep), NOTUSED(uint8_t bmReqType), NOTUSED(uint16_t left), NOTUSED(uint16_t nbytes), NOTUSED(uint8_t *dataptr)) {
|
||||
return UHS_HOST_ERROR_NOT_IMPLEMENTED;
|
||||
};
|
||||
|
||||
virtual uint8_t UHS_NI ctrlReqRead(NOTUSED(UHS_EpInfo *pep), NOTUSED(uint16_t *left), NOTUSED(uint16_t *read), NOTUSED(uint16_t nbytes), NOTUSED(uint8_t *dataptr)) {
|
||||
return UHS_HOST_ERROR_NOT_IMPLEMENTED;
|
||||
};
|
||||
|
||||
virtual uint8_t UHS_NI dispatchPkt(NOTUSED(uint8_t token), NOTUSED(uint8_t ep), NOTUSED(uint16_t nak_limit)) {
|
||||
return UHS_HOST_ERROR_NOT_IMPLEMENTED;
|
||||
};
|
||||
|
||||
virtual uint8_t UHS_NI init() {
|
||||
return 0;
|
||||
};
|
||||
|
||||
virtual void UHS_NI doHostReset() {
|
||||
};
|
||||
|
||||
virtual int16_t UHS_NI Init(NOTUSED(int16_t mseconds)) {
|
||||
return -1;
|
||||
};
|
||||
|
||||
virtual int16_t UHS_NI Init() {
|
||||
return Init(INT16_MIN);
|
||||
};
|
||||
|
||||
virtual uint8_t hwlPowerUp() {
|
||||
/* This is for machine specific support to enable/power up the USB HW to operate*/
|
||||
return UHS_HOST_ERROR_NOT_IMPLEMENTED;
|
||||
};
|
||||
|
||||
virtual uint8_t hwPowerDown() {
|
||||
/* This is for machine specific support to disable/powerdown the USB Hw */
|
||||
return UHS_HOST_ERROR_NOT_IMPLEMENTED;
|
||||
};
|
||||
|
||||
virtual bool IsHub(uint8_t klass) {
|
||||
return (klass == UHS_USB_CLASS_HUB);
|
||||
};
|
||||
|
||||
virtual void UHS_NI suspend_host() {
|
||||
// Used on MCU that lack control of IRQ priority (AVR).
|
||||
// Suspends ISRs, for critical code. IRQ will be serviced after it is resumed.
|
||||
// NOTE: you must track the state yourself!
|
||||
};
|
||||
|
||||
virtual void UHS_NI resume_host() {
|
||||
// Used on MCU that lack control of IRQ priority (AVR).
|
||||
// Resumes ISRs.
|
||||
// NOTE: you must track the state yourself!
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////
|
||||
//
|
||||
// Built-ins, No need to override
|
||||
//
|
||||
/////////////////////////////////////////////
|
||||
// these two probably will go away, and won't be used, TBD
|
||||
inline void Poll_Others() {
|
||||
#ifdef UHS_LOAD_BT
|
||||
UHS_BT_Poll(this);
|
||||
#endif
|
||||
#ifdef UHS_LOAD_HID
|
||||
UHS_HID_Poll(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void DisablePoll() {
|
||||
noInterrupts();
|
||||
usb_task_polling_disabled++;
|
||||
DDSB();
|
||||
interrupts();
|
||||
}
|
||||
|
||||
inline void EnablePoll() {
|
||||
noInterrupts();
|
||||
usb_task_polling_disabled--;
|
||||
DDSB();
|
||||
interrupts();
|
||||
}
|
||||
|
||||
uint8_t UHS_NI seekInterface(ENUMERATION_INFO *ei, uint16_t inf, USB_FD_CONFIGURATION_DESCRIPTOR *ucd);
|
||||
|
||||
uint8_t UHS_NI setEpInfoEntry(uint8_t addr, uint8_t iface, uint8_t epcount, volatile UHS_EpInfo* eprecord_ptr);
|
||||
|
||||
uint8_t UHS_NI EPClearHalt(uint8_t addr, uint8_t ep);
|
||||
|
||||
uint8_t UHS_NI ctrlReq(uint8_t addr, uint64_t Request, uint16_t nbytes, uint8_t *dataptr);
|
||||
|
||||
uint8_t UHS_NI getDevDescr(uint8_t addr, uint16_t nbytes, uint8_t *dataptr);
|
||||
|
||||
uint8_t UHS_NI getConfDescr(uint8_t addr, uint16_t nbytes, uint8_t conf, uint8_t *dataptr);
|
||||
|
||||
uint8_t UHS_NI setAddr(uint8_t oldaddr, uint8_t newaddr);
|
||||
|
||||
uint8_t UHS_NI setConf(uint8_t addr, uint8_t conf_value);
|
||||
|
||||
uint8_t UHS_NI getStrDescr(uint8_t addr, uint16_t nbytes, uint8_t index, uint16_t langid, uint8_t *dataptr);
|
||||
|
||||
void UHS_NI ReleaseDevice(uint8_t addr);
|
||||
|
||||
uint8_t UHS_NI Configuring(uint8_t parent, uint8_t port, uint8_t speed);
|
||||
|
||||
void UHS_NI DeviceDefaults(uint8_t maxep, UHS_USBInterface *device);
|
||||
|
||||
UHS_EpInfo* UHS_NI getEpInfoEntry(uint8_t addr, uint8_t ep);
|
||||
|
||||
inline uint8_t getUsbTaskState() {
|
||||
return ( usb_task_state);
|
||||
};
|
||||
|
||||
inline AddressPool* GetAddressPool() {
|
||||
return &addrPool;
|
||||
};
|
||||
|
||||
int UHS_NI RegisterDeviceClass(UHS_USBInterface *pdev) {
|
||||
for(uint8_t i = 0; i < UHS_HOST_MAX_INTERFACE_DRIVERS; i++) {
|
||||
if(!devConfig[i]) {
|
||||
devConfig[i] = pdev;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
//return UHS_HOST_ERROR_CANT_REGISTER_DEVICE_CLASS;
|
||||
return -1;
|
||||
};
|
||||
#if 0
|
||||
|
||||
inline void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) {
|
||||
addrPool.ForEachUsbDevice(pfunc);
|
||||
};
|
||||
#endif
|
||||
|
||||
uint8_t TestInterface(ENUMERATION_INFO *ei);
|
||||
uint8_t enumerateInterface(ENUMERATION_INFO *ei);
|
||||
uint8_t getNextInterface(ENUMERATION_INFO *ei, UHS_EpInfo *pep, uint8_t data[], uint16_t *left, uint16_t *read, uint8_t *offset);
|
||||
uint8_t initDescrStream(ENUMERATION_INFO *ei, USB_FD_CONFIGURATION_DESCRIPTOR *ucd, UHS_EpInfo *pep, uint8_t *data, uint16_t *left, uint16_t *read, uint8_t *offset);
|
||||
uint8_t outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *data);
|
||||
uint8_t inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t *data);
|
||||
uint8_t doSoftReset(uint8_t parent, uint8_t port, uint8_t address);
|
||||
uint8_t getone(UHS_EpInfo *pep, uint16_t *left, uint16_t *read, uint8_t *dataptr, uint8_t *offset);
|
||||
uint8_t eat(UHS_EpInfo *pep, uint16_t *left, uint16_t *read, uint8_t *dataptr, uint8_t *offset, uint16_t *yum);
|
||||
|
||||
};
|
||||
|
||||
// All device interface drivers use this subclass
|
||||
|
||||
class UHS_USBInterface {
|
||||
public:
|
||||
|
||||
UHS_USB_HOST_BASE *pUsb; // Parent USB host
|
||||
volatile uint8_t bNumEP; // total number of EP in this interface
|
||||
volatile UHS_EpInfo epInfo[16]; // This is a stub, override in the driver.
|
||||
|
||||
volatile uint8_t bAddress; // address of the device
|
||||
volatile uint8_t bConfNum; // configuration number
|
||||
volatile uint8_t bIface; // interface value
|
||||
volatile bool bPollEnable; // poll enable flag, operating status
|
||||
volatile uint32_t qNextPollTime; // next poll time
|
||||
|
||||
/**
|
||||
* Resets interface driver to unused state. You should override this in
|
||||
* your driver if it requires extra class variable cleanup.
|
||||
*/
|
||||
virtual void DriverDefaults() {
|
||||
printf("Default driver defaults.\r\n");
|
||||
pUsb->DeviceDefaults(bNumEP, this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if this interface is supported.
|
||||
* Executed called when new devices are connected.
|
||||
*
|
||||
* @param ei
|
||||
* @return true if the interface is supported
|
||||
*/
|
||||
virtual bool OKtoEnumerate(NOTUSED(ENUMERATION_INFO *ei)) {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Configures any needed endpoint information for an interface.
|
||||
* You must provide this in your driver.
|
||||
* Executed when new devices are connected and OKtoEnumerate()
|
||||
* returned true.
|
||||
*
|
||||
* @param ei
|
||||
* @return zero on success
|
||||
*/
|
||||
virtual uint8_t SetInterface(NOTUSED(ENUMERATION_INFO *ei)) {
|
||||
return UHS_HOST_ERROR_NOT_IMPLEMENTED;
|
||||
};
|
||||
|
||||
/**
|
||||
* Interface specific additional setup and enumeration that
|
||||
* can't occur when the descriptor stream is open.
|
||||
* Also used for collection of unclaimed interfaces, to link to the master.
|
||||
*
|
||||
* @return zero on success
|
||||
*/
|
||||
virtual uint8_t Finalize() {
|
||||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Executed after interface is finalized but, before polling has started.
|
||||
*
|
||||
* @return 0 on success
|
||||
*/
|
||||
virtual uint8_t OnStart() {
|
||||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Start interface polling
|
||||
* @return
|
||||
*/
|
||||
virtual uint8_t Start() {
|
||||
uint8_t rcode = OnStart();
|
||||
if(!rcode) bPollEnable = true;
|
||||
return rcode;
|
||||
};
|
||||
|
||||
/**
|
||||
* Executed before anything else in Release().
|
||||
*/
|
||||
virtual void OnRelease() {
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Release resources when device is disconnected.
|
||||
* Normally this does not need to be overridden.
|
||||
*/
|
||||
virtual void Release() {
|
||||
OnRelease();
|
||||
DriverDefaults();
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Executed After driver polls.
|
||||
* Can be used when there is an important change detected during polling
|
||||
* and you want to handle it elsewhere.
|
||||
* Examples:
|
||||
* Media status change for bulk, e.g. ready, not-ready, media changed, door opened.
|
||||
* Button state/joystick position/etc changes on a HID device.
|
||||
* Flow control status change on a communication device, e.g. CTS on serial
|
||||
*/
|
||||
virtual void OnPoll() {
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Poll interface driver. You should override this in your driver if you
|
||||
* require polling faster or slower than every 100 milliseconds, or your
|
||||
* driver requires special housekeeping.
|
||||
*/
|
||||
virtual void Poll() {
|
||||
OnPoll();
|
||||
qNextPollTime = millis() + 100;
|
||||
};
|
||||
|
||||
virtual bool UHS_NI Polling() {
|
||||
return bPollEnable;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is only for a hub.
|
||||
* @param port
|
||||
*/
|
||||
virtual void ResetHubPort(NOTUSED(uint8_t port)) {
|
||||
return;
|
||||
};
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* @return true if this interface is Vendor Specific.
|
||||
*/
|
||||
virtual bool IsVSI() {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* Vendor Specific interface class.
|
||||
* This is used by a partner interface.
|
||||
* It can also be used to force-enumerate an interface that
|
||||
* can use this interface directly.
|
||||
* You can also add an instance of this class within the interface constructor
|
||||
* if you expect the interface.
|
||||
*
|
||||
* If this is not needed, it may be removed. Nothing I have written needs this.
|
||||
* Let me know if it is not required, then IsVSI method can also be shit-canned.
|
||||
* -- AJK
|
||||
*/
|
||||
|
||||
class UHS_VSI : public UHS_USBInterface {
|
||||
public:
|
||||
volatile UHS_EpInfo epInfo[1];
|
||||
volatile ENUMERATION_INFO eInfo;
|
||||
UHS_VSI(UHS_USB_HOST_BASE *p);
|
||||
bool OKtoEnumerate(ENUMERATION_INFO *ei);
|
||||
uint8_t SetInterface(ENUMERATION_INFO *ei);
|
||||
virtual void DriverDefaults();
|
||||
virtual void Release();
|
||||
|
||||
uint8_t GetAddress() {
|
||||
return bAddress;
|
||||
};
|
||||
|
||||
virtual bool IsVSI() {
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif //_USBHOST_H_
|
||||
#endif
|
@ -0,0 +1,129 @@
|
||||
/* Copyright (C) 2015-2016 Andrew J. Kroll
|
||||
and
|
||||
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Contact information
|
||||
-------------------
|
||||
|
||||
Circuits At Home, LTD
|
||||
Web : https://www.circuitsathome.com
|
||||
e-mail : support@circuitsathome.com
|
||||
*/
|
||||
|
||||
#if defined(LOAD_USB_HOST_SYSTEM) && !defined(USB_HOST_SYSTEM_UTIL_LOADED)
|
||||
#define USB_HOST_SYSTEM_UTIL_LOADED
|
||||
|
||||
// 0x80 is the default (i.e. trace) to turn off set this global to something lower.
|
||||
// this allows for 126 other debugging levels.
|
||||
// TO-DO: Allow assignment to a different serial port by software
|
||||
int UsbDEBUGlvl = 0x80;
|
||||
|
||||
void E_Notifyc(char c, int lvl) {
|
||||
if(UsbDEBUGlvl < lvl) return;
|
||||
#if defined(ARDUINO) && ARDUINO >=100
|
||||
USB_HOST_SERIAL.print(c);
|
||||
#else
|
||||
USB_HOST_SERIAL.print(c, BYTE);
|
||||
#endif
|
||||
//USB_HOST_SERIAL.flush();
|
||||
}
|
||||
|
||||
void E_Notify(char const * msg, int lvl) {
|
||||
if(UsbDEBUGlvl < lvl) return;
|
||||
if(!msg) return;
|
||||
char c;
|
||||
|
||||
while((c = pgm_read_byte(msg++))) E_Notifyc(c, lvl);
|
||||
}
|
||||
|
||||
void E_NotifyStr(char const * msg, int lvl) {
|
||||
if(UsbDEBUGlvl < lvl) return;
|
||||
if(!msg) return;
|
||||
char c;
|
||||
|
||||
while((c = *msg++)) E_Notifyc(c, lvl);
|
||||
}
|
||||
|
||||
void E_Notify(uint8_t b, int lvl) {
|
||||
if(UsbDEBUGlvl < lvl) return;
|
||||
#if defined(ARDUINO) && ARDUINO >=100
|
||||
USB_HOST_SERIAL.print(b);
|
||||
#else
|
||||
USB_HOST_SERIAL.print(b, DEC);
|
||||
#endif
|
||||
}
|
||||
|
||||
void E_Notify(double d, int lvl) {
|
||||
if(UsbDEBUGlvl < lvl) return;
|
||||
USB_HOST_SERIAL.print(d);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_USB_HOST
|
||||
|
||||
void NotifyFailGetDevDescr() {
|
||||
Notify(PSTR("\r\ngetDevDescr "), 0x80);
|
||||
}
|
||||
|
||||
void NotifyFailSetDevTblEntry() {
|
||||
Notify(PSTR("\r\nsetDevTblEn "), 0x80);
|
||||
}
|
||||
|
||||
void NotifyFailGetConfDescr() {
|
||||
Notify(PSTR("\r\ngetConf "), 0x80);
|
||||
}
|
||||
|
||||
void NotifyFailSetConfDescr() {
|
||||
Notify(PSTR("\r\nsetConf "), 0x80);
|
||||
}
|
||||
|
||||
void NotifyFailGetDevDescr(uint8_t reason) {
|
||||
NotifyFailGetDevDescr();
|
||||
NotifyFail(reason);
|
||||
}
|
||||
|
||||
void NotifyFailSetDevTblEntry(uint8_t reason) {
|
||||
NotifyFailSetDevTblEntry();
|
||||
NotifyFail(reason);
|
||||
|
||||
}
|
||||
|
||||
void NotifyFailGetConfDescr(uint8_t reason) {
|
||||
NotifyFailGetConfDescr();
|
||||
NotifyFail(reason);
|
||||
}
|
||||
|
||||
void NotifyFailSetConfDescr(uint8_t reason) {
|
||||
NotifyFailSetConfDescr();
|
||||
NotifyFail(reason);
|
||||
}
|
||||
|
||||
void NotifyFailUnknownDevice(uint16_t VID, uint16_t PID) {
|
||||
Notify(PSTR("\r\nUnknown Device Connected - VID: "), 0x80);
|
||||
D_PrintHex<uint16_t > (VID, 0x80);
|
||||
Notify(PSTR(" PID: "), 0x80);
|
||||
D_PrintHex<uint16_t > (PID, 0x80);
|
||||
}
|
||||
|
||||
void NotifyFail(uint8_t rcode) {
|
||||
D_PrintHex<uint8_t > (rcode, 0x80);
|
||||
Notify(PSTR("\r\n"), 0x80);
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
#error "Never include UHS_util_INLINE.h, include UHS_host.h instead"
|
||||
#endif
|
@ -0,0 +1,226 @@
|
||||
/* Copyright (C) 2015-2016 Andrew J. Kroll
|
||||
and
|
||||
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
|
||||
This software may be distributed and modified under the terms of the GNU
|
||||
General Public License version 2 (GPL2) as published by the Free Software
|
||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||
on this software must also be made publicly available under the terms of
|
||||
the GPL2 ("Copyleft").
|
||||
|
||||
Contact information
|
||||
-------------------
|
||||
|
||||
Circuits At Home, LTD
|
||||
Web : https://www.circuitsathome.com
|
||||
e-mail : support@circuitsathome.com
|
||||
*/
|
||||
#if !defined(USB_HOST_SHIELD_H) || defined(_max3421e_h_)
|
||||
#error "Never include UHS_max3421e.h directly; include USB_HOST_SHIELD.h instead"
|
||||
#else
|
||||
|
||||
#define _max3421e_h_
|
||||
|
||||
/* MAX3421E register/bit names and bitmasks */
|
||||
|
||||
#define SE0 0
|
||||
#define SE1 1
|
||||
#define FSHOST 2
|
||||
#define LSHOST 3
|
||||
|
||||
/* MAX3421E command byte format: rrrrr0wa where 'r' is register number */
|
||||
|
||||
//
|
||||
// MAX3421E Registers in HOST mode.
|
||||
//
|
||||
#define rRCVFIFO 0x08 // Receive FIFO Register
|
||||
#define rSNDFIFO 0x10 // Send FIFO Register
|
||||
#define rSUDFIFO 0x20 // Set Up Data FIFO Register
|
||||
#define rRCVBC 0x30 // Receive FIFO Byte Count Register
|
||||
#define rSNDBC 0x38 // Send FIFO Byte Count Register
|
||||
|
||||
// USB Interrupt Request Status (USBIRQ)
|
||||
#define rUSBIRQ 0x68 // USB Interrupt Request Register
|
||||
#define bmVBUSIRQ 0x40 // Vbus Present Interrupt Request
|
||||
#define bmNOVBUSIRQ 0x20 // Vbus Absent Interrupt Request
|
||||
#define bmOSCOKIRQ 0x01 // Oscillator OK Interrupt Request
|
||||
|
||||
// USB Interrupt Request Control (USBIEN)
|
||||
#define rUSBIEN 0x70 // USB Interrupt Request Enable Register
|
||||
#define bmVBUSIE bmVBUSIRQ // Vbus Present Interrupt Request Enable
|
||||
#define bmNOVBUSIE bmNOVBUSIRQ // Vbus Absent Interrupt Request Enable
|
||||
#define bmOSCOKIE bmOSCOKIRQ // Oscillator OK Interrupt Request Enable
|
||||
|
||||
// (USBCTL)
|
||||
#define rUSBCTL 0x78 //15<<3
|
||||
#define bmCHIPRES 0x20 //b5
|
||||
#define bmPWRDOWN 0x10 //b4
|
||||
|
||||
// (CPUCTL)
|
||||
#define rCPUCTL 0x80 //16<<3
|
||||
#define bmPUSLEWID1 0x80 //b7
|
||||
#define bmPULSEWID0 0x40 //b6
|
||||
#define bmIE 0x01 //b0
|
||||
|
||||
// bmPUSLEWID1 bmPULSEWID0 Pulse width
|
||||
// 0 0 10.6uS
|
||||
// 0 1 5.3uS
|
||||
// 1 0 2.6uS
|
||||
// 1 1 1.3uS
|
||||
#define PUSLEWIDTH10_6 (0)
|
||||
#define PUSLEWIDTH5_3 (bmPULSEWID0)
|
||||
#define PUSLEWIDTH2_6 (bmPUSLEWID1)
|
||||
#define PUSLEWIDTH1_3 (bmPULSEWID0 | bmPUSLEWID1)
|
||||
|
||||
// (PINCTL)
|
||||
#define rPINCTL 0x88 //17<<3
|
||||
#define bmFDUPSPI 0x10 //b4
|
||||
#define bmINTLEVEL 0x08 //b3
|
||||
#define bmPOSINT 0x04 //b2
|
||||
#define bmGPXB 0x02 //b1
|
||||
#define bmGPXA 0x01 //b0
|
||||
|
||||
// GPX pin selections
|
||||
#define GPX_OPERATE 0x00 //
|
||||
#define GPX_VBDET 0x01 //
|
||||
#define GPX_BUSACT 0x02 //
|
||||
#define GPX_SOF 0x03 //
|
||||
|
||||
#define rREVISION 0x90 //18<<3
|
||||
|
||||
// (IOPINS1)
|
||||
#define rIOPINS1 0xA0 //20<<3
|
||||
#define bmGPOUT0 0x01 //
|
||||
#define bmGPOUT1 0x02 //
|
||||
#define bmGPOUT2 0x04 //
|
||||
#define bmGPOUT3 0x08 //
|
||||
#define bmGPIN0 0x10 //
|
||||
#define bmGPIN1 0x20 //
|
||||
#define bmGPIN2 0x40 //
|
||||
#define bmGPIN3 0x80 //
|
||||
|
||||
// (IOPINS2)
|
||||
#define rIOPINS2 0xA8 //21<<3
|
||||
#define bmGPOUT4 0x01 //
|
||||
#define bmGPOUT5 0x02 //
|
||||
#define bmGPOUT6 0x04 //
|
||||
#define bmGPOUT7 0x08 //
|
||||
#define bmGPIN4 0x10 //
|
||||
#define bmGPIN5 0x20 //
|
||||
#define bmGPIN6 0x40 //
|
||||
#define bmGPIN7 0x80 //
|
||||
|
||||
// (GPINIRQ)
|
||||
#define rGPINIRQ 0xB0 //22<<3
|
||||
#define bmGPINIRQ0 0x01 //
|
||||
#define bmGPINIRQ1 0x02 //
|
||||
#define bmGPINIRQ2 0x04 //
|
||||
#define bmGPINIRQ3 0x08 //
|
||||
#define bmGPINIRQ4 0x10 //
|
||||
#define bmGPINIRQ5 0x20 //
|
||||
#define bmGPINIRQ6 0x40 //
|
||||
#define bmGPINIRQ7 0x80 //
|
||||
|
||||
// (GPINIEN)
|
||||
#define rGPINIEN 0xB8 //23<<3
|
||||
#define bmGPINIEN0 0x01 //
|
||||
#define bmGPINIEN1 0x02 //
|
||||
#define bmGPINIEN2 0x04 //
|
||||
#define bmGPINIEN3 0x08 //
|
||||
#define bmGPINIEN4 0x10 //
|
||||
#define bmGPINIEN5 0x20 //
|
||||
#define bmGPINIEN6 0x40 //
|
||||
#define bmGPINIEN7 0x80 //
|
||||
|
||||
// (GPINPOL)
|
||||
#define rGPINPOL 0xC0 //24<<3
|
||||
#define bmGPINPOL0 0x01 //
|
||||
#define bmGPINPOL1 0x02 //
|
||||
#define bmGPINPOL2 0x04 //
|
||||
#define bmGPINPOL3 0x08 //
|
||||
#define bmGPINPOL4 0x10 //
|
||||
#define bmGPINPOL5 0x20 //
|
||||
#define bmGPINPOL6 0x40 //
|
||||
#define bmGPINPOL7 0x80 //
|
||||
|
||||
//
|
||||
// If any data transfer errors occur, the HXFRDNIRQ asserts, while the RCVDAVIRQ does not.
|
||||
//
|
||||
// The CPU clears the SNDBAVIRQ by writing the SNDBC register.
|
||||
// The CPU should never directly clear the SNDBAVIRQ bit.
|
||||
|
||||
// Host Interrupt Request Status (HIRQ)
|
||||
#define rHIRQ 0xC8 // Host Interrupt Request Register
|
||||
#define bmBUSEVENTIRQ 0x01 // BUS Reset Done or BUS Resume Interrupt Request
|
||||
#define bmRWUIRQ 0x02 // Remote Wakeup Interrupt Request
|
||||
#define bmRCVDAVIRQ 0x04 // Receive FIFO Data Available Interrupt Request
|
||||
#define bmSNDBAVIRQ 0x08 // Send Buffer Available Interrupt Request
|
||||
#define bmSUSDNIRQ 0x10 // Suspend operation Done Interrupt Request
|
||||
#define bmCONDETIRQ 0x20 // Peripheral Connect/Disconnect Interrupt Request
|
||||
#define bmFRAMEIRQ 0x40 // Frame Generator Interrupt Request
|
||||
#define bmHXFRDNIRQ 0x80 // Host Transfer Done Interrupt Request
|
||||
|
||||
// IRQs that are OK for the CPU to clear
|
||||
#define ICLRALLBITS (bmBUSEVENTIRQ | bmRWUIRQ | bmRCVDAVIRQ | bmSUSDNIRQ | bmCONDETIRQ | bmFRAMEIRQ | bmHXFRDNIRQ)
|
||||
|
||||
// Host Interrupt Request Control (HIEN)
|
||||
#define rHIEN 0xD0 //
|
||||
#define bmBUSEVENTIE bmBUSEVENTIRQ // BUS Reset Done or BUS Resume Interrupt Request Enable
|
||||
#define bmRWUIE bmRWUIRQ // Remote Wakeup Interrupt Request Enable
|
||||
#define bmRCVDAVIE bmRCVDAVIRQ // Receive FIFO Data Available Interrupt Request Enable
|
||||
#define bmSNDBAVIE bmSNDBAVIRQ // Send Buffer Available Interrupt Request Enable
|
||||
#define bmSUSDNIE bmSUSDNIRQ // Suspend operation Done Interrupt Request Enable
|
||||
#define bmCONDETIE bmCONDETIRQ // Peripheral Connect/Disconnect Interrupt Request Enable
|
||||
#define bmFRAMEIE bmFRAMEIRQ // Frame Generator Interrupt Request Enable
|
||||
#define bmHXFRDNIE bmHXFRDNIRQ // Host Transfer Done Interrupt Request Enable
|
||||
|
||||
// (MODE))
|
||||
#define rMODE 0xD8 //27<<3
|
||||
#define bmHOST 0x01 //
|
||||
#define bmLOWSPEED 0x02 //
|
||||
#define bmHUBPRE 0x04 //
|
||||
#define bmSOFKAENAB 0x08 //
|
||||
#define bmSEPIRQ 0x10 //
|
||||
#define bmDELAYISO 0x20 //
|
||||
#define bmDMPULLDN 0x40 //
|
||||
#define bmDPPULLDN 0x80 //
|
||||
|
||||
#define rPERADDR 0xE0 //28<<3
|
||||
|
||||
// (HCTL)
|
||||
#define rHCTL 0xE8 //29<<3
|
||||
#define bmBUSRST 0x01 //
|
||||
#define bmFRMRST 0x02 //
|
||||
#define bmSAMPLEBUS 0x04 //
|
||||
#define bmSIGRSM 0x08 //
|
||||
#define bmRCVTOG0 0x10 //
|
||||
#define bmRCVTOG1 0x20 //
|
||||
#define bmSNDTOG0 0x40 //
|
||||
#define bmSNDTOG1 0x80 //
|
||||
|
||||
// Host transfer (HXFR)
|
||||
#define rHXFR 0xF0 //30<<3
|
||||
/* Host transfer token values for writing the HXFR register (R30) */
|
||||
/* OR this bit field with the endpoint number in bits 3:0 */
|
||||
#define MAX3421E_tokSETUP 0x10 // HS=0, ISO=0, OUTNIN=0, SETUP=1
|
||||
#define MAX3421E_tokIN 0x00 // HS=0, ISO=0, OUTNIN=0, SETUP=0
|
||||
#define MAX3421E_tokOUT 0x20 // HS=0, ISO=0, OUTNIN=1, SETUP=0
|
||||
#define MAX3421E_tokINHS 0x80 // HS=1, ISO=0, OUTNIN=0, SETUP=0
|
||||
#define MAX3421E_tokOUTHS 0xA0 // HS=1, ISO=0, OUTNIN=1, SETUP=0
|
||||
#define MAX3421E_tokISOIN 0x40 // HS=0, ISO=1, OUTNIN=0, SETUP=0
|
||||
#define MAX3421E_tokISOOUT 0x60 // HS=0, ISO=1, OUTNIN=1, SETUP=0
|
||||
|
||||
// (HRSL)
|
||||
#define rHRSL 0xF8 //31<<3
|
||||
#define bmRCVTOGRD 0x10 //
|
||||
#define bmSNDTOGRD 0x20 //
|
||||
#define bmKSTATUS 0x40 //
|
||||
#define bmJSTATUS 0x80 //
|
||||
#define bmSE0 0x00 //SE0 - disconnect state
|
||||
#define bmSE1 0xC0 //SE1 - illegal state
|
||||
|
||||
#define MODE_FS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmSOFKAENAB)
|
||||
#define MODE_LS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmLOWSPEED|bmSOFKAENAB)
|
||||
|
||||
#endif //_max3421e_h_
|
@ -0,0 +1,519 @@
|
||||
/* Copyright (C) 2015-2016 Andrew J. Kroll
|
||||
and
|
||||
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
|
||||
This software may be distributed and modified under the terms of the GNU
|
||||
General Public License version 2 (GPL2) as published by the Free Software
|
||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||
on this software must also be made publicly available under the terms of
|
||||
the GPL2 ("Copyleft").
|
||||
|
||||
Contact information
|
||||
-------------------
|
||||
|
||||
Circuits At Home, LTD
|
||||
Web : https://www.circuitsathome.com
|
||||
e-mail : support@circuitsathome.com
|
||||
*/
|
||||
|
||||
#ifndef USB_HOST_SHIELD_H
|
||||
#define USB_HOST_SHIELD_H
|
||||
|
||||
// uncomment to get 'printf' console debugging. NOT FOR UNO!
|
||||
//#define DEBUG_PRINTF_EXTRA_HUGE_USB_HOST_SHIELD
|
||||
|
||||
#ifdef LOAD_USB_HOST_SHIELD
|
||||
#include "UHS_max3421e.h"
|
||||
#include <SPI.h>
|
||||
|
||||
|
||||
#ifndef SPI_HAS_TRANSACTION
|
||||
#error "Your SPI library installation is too old."
|
||||
#else
|
||||
#ifndef SPI_ATOMIC_VERSION
|
||||
#warning "Your SPI library installation lacks 'SPI_ATOMIC_VERSION'. Please complain to the maintainer."
|
||||
#elif SPI_ATOMIC_VERSION < 1
|
||||
#error "Your SPI library installation is too old."
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#if DEBUG_PRINTF_EXTRA_HUGE
|
||||
#ifdef DEBUG_PRINTF_EXTRA_HUGE_USB_HOST_SHIELD
|
||||
#define MAX_HOST_DEBUG(...) printf_P(__VA_ARGS__)
|
||||
#else
|
||||
#define MAX_HOST_DEBUG(...) VOID0
|
||||
#endif
|
||||
#else
|
||||
#define MAX_HOST_DEBUG(...) VOID0
|
||||
#endif
|
||||
|
||||
#ifndef USB_HOST_SHIELD_USE_ISR
|
||||
#ifdef USE_MULTIPLE_APP_API
|
||||
#define USB_HOST_SHIELD_USE_ISR 0
|
||||
#else
|
||||
#define USB_HOST_SHIELD_USE_ISR 1
|
||||
#endif
|
||||
#else
|
||||
#define USB_HOST_SHIELD_USE_ISR 1
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if !USB_HOST_SHIELD_USE_ISR
|
||||
#error NOISR Polled mode _NOT SUPPORTED YET_
|
||||
|
||||
//
|
||||
// Polled defaults
|
||||
//
|
||||
#ifdef BOARD_BLACK_WIDDOW
|
||||
#define UHS_MAX3421E_SS_ 6
|
||||
#define UHS_MAX3421E_INT_ 3
|
||||
#elif defined(CORE_TEENSY) && (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__))
|
||||
#if EXT_RAM
|
||||
// Teensy++ 2.0 with XMEM2
|
||||
#define UHS_MAX3421E_SS_ 20
|
||||
#define UHS_MAX3421E_INT_ 7
|
||||
#else
|
||||
#define UHS_MAX3421E_SS_ 9
|
||||
#define UHS_MAX3421E_INT_ 8
|
||||
#endif
|
||||
#define UHS_MAX3421E_SPD
|
||||
#elif defined(ARDUINO_AVR_ADK)
|
||||
#define UHS_MAX3421E_SS_ 53
|
||||
#define UHS_MAX3421E_INT_ 54
|
||||
#elif defined(ARDUINO_AVR_BALANDUINO)
|
||||
#define UHS_MAX3421E_SS_ 20
|
||||
#define UHS_MAX3421E_INT_ 19
|
||||
#else
|
||||
#define UHS_MAX3421E_SS_ 10
|
||||
#define UHS_MAX3421E_INT_ 9
|
||||
#endif
|
||||
|
||||
#else
|
||||
#ifdef ARDUINO_ARCH_PIC32
|
||||
// PIC32 only allows edge interrupts, isn't that lovely? We'll emulate it...
|
||||
#if CHANGE < 2
|
||||
#error core too old.
|
||||
#endif
|
||||
|
||||
#define IRQ_IS_EDGE 0
|
||||
#ifndef digitalPinToInterrupt
|
||||
// great, this isn't implemented.
|
||||
#warning digitalPinToInterrupt is not defined, complain here https://github.com/chipKIT32/chipKIT-core/issues/114
|
||||
#if defined(_BOARD_UNO_) || defined(_BOARD_UC32_)
|
||||
#define digitalPinToInterrupt(p) ((p) == 2 ? 1 : ((p) == 7 ? 2 : ((p) == 8 ? 3 : ((p) == 35 ? 4 : ((p) == 38 ? 0 : NOT_AN_INTERRUPT)))))
|
||||
#warning digitalPinToInterrupt is now defined until this is taken care of.
|
||||
#else
|
||||
#error digitalPinToInterrupt not defined for your board, complain here https://github.com/chipKIT32/chipKIT-core/issues/114
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#define IRQ_IS_EDGE 0
|
||||
#endif
|
||||
|
||||
// More stupidity from our friends @ Sony...
|
||||
#ifdef ARDUINO_spresense_ast
|
||||
#ifndef NOT_AN_INTERRUPT
|
||||
#define NOT_AN_INTERRUPT -1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// SAMD uses an enum for this instead of a define. Isn't that just dandy?
|
||||
#if !defined(NOT_AN_INTERRUPT) && !defined(ARDUINO_ARCH_SAMD)
|
||||
#warning NOT_AN_INTERRUPT not defined, possible problems ahead.
|
||||
#warning If NOT_AN_INTERRUPT is an enum or something else, complain to UHS30 developers on github.
|
||||
#warning Otherwise complain to your board core developer/maintainer.
|
||||
#define NOT_AN_INTERRUPT -1
|
||||
#endif
|
||||
|
||||
//
|
||||
// Interrupt defaults. Int0 or Int1
|
||||
//
|
||||
#ifdef BOARD_BLACK_WIDDOW
|
||||
#error "HELP! Please send us an email, I don't know the values for Int0 and Int1 on the Black Widow board!"
|
||||
#elif defined(ARDUINO_AVR_ADK)
|
||||
#define UHS_MAX3421E_SS_ 53
|
||||
#define UHS_MAX3421E_INT_ 54
|
||||
#elif defined(ARDUINO_spresense_ast)
|
||||
#define UHS_MAX3421E_SS_ 21
|
||||
#define UHS_MAX3421E_INT_ 20
|
||||
#define SPIclass SPI5
|
||||
//#define UHS_MAX3421E_SPD 100000
|
||||
#elif defined(CORE_TEENSY) && (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__))
|
||||
|
||||
// TO-DO!
|
||||
|
||||
#if EXT_RAM
|
||||
// Teensy++ 2.0 with XMEM2
|
||||
#define UHS_MAX3421E_SS_ 20
|
||||
#define UHS_MAX3421E_INT_ 7
|
||||
#else
|
||||
#define UHS_MAX3421E_SS_ 9
|
||||
#define UHS_MAX3421E_INT_ 8
|
||||
#endif
|
||||
|
||||
#elif defined(ARDUINO_AVR_BALANDUINO)
|
||||
#error "ISR mode is currently not supported on the Balanduino. Please set USB_HOST_SHIELD_USE_ISR to 0."
|
||||
#else
|
||||
#define UHS_MAX3421E_SS_ 10
|
||||
#ifdef __AVR__
|
||||
#ifdef __AVR_ATmega32U4__
|
||||
#define INT_FOR_PIN2 1
|
||||
#define INT_FOR_PIN3 0
|
||||
#else
|
||||
// Everybody else???
|
||||
#define INT_FOR_PIN2 0
|
||||
#define INT_FOR_PIN3 1
|
||||
#endif
|
||||
#define UHS_MAX3421E_INT_ 3
|
||||
#else
|
||||
// Non-avr
|
||||
#ifdef ARDUINO_ARCH_PIC32
|
||||
// UNO32 External Interrupts:
|
||||
// Pin 38 (INT0), Pin 2 (INT1), Pin 7 (INT2), Pin 8 (INT3), Pin 35 (INT4)
|
||||
#define UHS_MAX3421E_INT_ 7
|
||||
#else
|
||||
#define UHS_MAX3421E_INT_ 9
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef NO_AUTO_SPEED
|
||||
// Ugly details section...
|
||||
// MAX3421E characteristics
|
||||
// SPI Serial - Clock Input. An external SPI master supplies SCLK with frequencies up to 26MHz. The
|
||||
// logic level is referenced to the voltage on VL. Data is clocked into the SPI slave inter face on the
|
||||
// rising edge of SCLK. Data is clocked out of the SPI slave interface on the falling edge of SCLK.
|
||||
// Serial Clock (SCLK) Period 38.4ns minimum. 17ns minimum pulse width. VL >2.5V
|
||||
// SCLK Fall to MISO Propagation Delay 14.2ns
|
||||
// SCLK Fall to MOSI Propagation Delay 14.2ns
|
||||
// SCLK Fall to MOSI Drive 3.5ns
|
||||
// Theoretical deadline for reply 17.7ns
|
||||
// 26MHz 38.4615ns period <-- MAX3421E theoretical maximum
|
||||
|
||||
#ifndef UHS_MAX3421E_SPD
|
||||
#ifdef ARDUINO_SAMD_ZERO
|
||||
// Zero violates spec early, needs a long setup time, or doesn't like high latency.
|
||||
#define UHS_MAX3421E_SPD 10000000
|
||||
#elif defined(ARDUINO_ARCH_PIC32)
|
||||
// PIC MX 5/6/7 characteristics
|
||||
// 25MHZ 40ns period <-- PIC MX 5/6/7 theoretical maximum
|
||||
// pulse width minimum Tsclk/2ns
|
||||
// Trise/fall 10ns maximum. 5ns is typical but not guaranteed.
|
||||
// Tsetup minimum for MISO 10ns.
|
||||
// We are in violation by 7.7ns @ 25MHz due to latency alone.
|
||||
// Even reading at end of data cycle, we only have a 2.3ns window.
|
||||
// This is too narrow to to compensate for capacitance, trace lengths, and noise.
|
||||
|
||||
// 17.7ns + 10ns = 27.7ns
|
||||
// 18MHz fits and has enough slack time to compensate for capacitance, trace lengths, and noise.
|
||||
// For high speeds the SMP bit is recommended too, which samples at the end instead of the middle.
|
||||
// 20Mhz seems to work.
|
||||
|
||||
#define UHS_MAX3421E_SPD 20000000
|
||||
#else
|
||||
#define UHS_MAX3421E_SPD 25000000
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
// We start at 25MHz, and back down until hardware can take it.
|
||||
// Of course, SPI library can adjust this for us too.
|
||||
// Why not 26MHz? Because I have not found any MCU board that
|
||||
// can actually go that fast without problems.
|
||||
// Could be a shield limitation too.
|
||||
#ifndef UHS_MAX3421E_SPD
|
||||
#define UHS_MAX3421E_SPD 25000000
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef UHS_MAX3421E_INT
|
||||
#define UHS_MAX3421E_INT UHS_MAX3421E_INT_
|
||||
#endif
|
||||
|
||||
#ifndef UHS_MAX3421E_SS
|
||||
#define UHS_MAX3421E_SS UHS_MAX3421E_SS_
|
||||
#endif
|
||||
|
||||
// NOTE: On the max3421e the irq enable and irq bits are in the same position.
|
||||
|
||||
// IRQs used if CPU polls
|
||||
#define ENIBITSPOLLED (bmCONDETIE | bmBUSEVENTIE | bmFRAMEIE)
|
||||
// IRQs used if CPU is interrupted
|
||||
#define ENIBITSISR (bmCONDETIE | bmBUSEVENTIE | bmFRAMEIE /* | bmRCVDAVIRQ | bmSNDBAVIRQ | bmHXFRDNIRQ */ )
|
||||
|
||||
#if !USB_HOST_SHIELD_USE_ISR
|
||||
#define IRQ_CHECK_MASK (ENIBITSPOLLED & ICLRALLBITS)
|
||||
#define IRQ_IS_EDGE 0
|
||||
#else
|
||||
#define IRQ_CHECK_MASK (ENIBITSISR & ICLRALLBITS)
|
||||
#endif
|
||||
|
||||
#if IRQ_IS_EDGE
|
||||
// Note: UNO32 Interrupts can only be RISING, or FALLING.
|
||||
// This poses an interesting problem, since we want to use a LOW level.
|
||||
// The MAX3421E provides for pulse width control for an IRQ.
|
||||
// We do need to watch the timing on this, as a second IRQ could cause
|
||||
// a missed IRQ, since we read the level of the line to check if the IRQ
|
||||
// is actually for this chip. The only other alternative is to add a capacitor
|
||||
// and an NPN transistor, and use two lines. We can try this first, though.
|
||||
// Worse case, we can ignore reading the pin for verification on UNO32.
|
||||
// Too bad there is no minimum low width setting.
|
||||
//
|
||||
// Single Clear First Second Clear first Clear last
|
||||
// IRQ Single IRQ IRQ Second active pending IRQ
|
||||
// | | | | | |
|
||||
// V V V V V V
|
||||
// _____ _________ _ _ _______
|
||||
// |______| |______| |______| |______________|
|
||||
//
|
||||
#define IRQ_SENSE FALLING
|
||||
#ifdef ARDUINO_ARCH_PIC32
|
||||
//#define bmPULSEWIDTH PUSLEWIDTH10_6
|
||||
#define bmPULSEWIDTH 0
|
||||
#define bmIRQ_SENSE 0
|
||||
#else
|
||||
#define bmPULSEWIDTH PUSLEWIDTH1_3
|
||||
#define bmIRQ_SENSE 0
|
||||
#endif
|
||||
#else
|
||||
#ifndef IRQ_SENSE
|
||||
#define IRQ_SENSE LOW
|
||||
#endif
|
||||
#ifndef bmPULSEWIDTH
|
||||
#define bmPULSEWIDTH 0
|
||||
#endif
|
||||
#ifndef bmIRQ_SENSE
|
||||
#define bmIRQ_SENSE bmINTLEVEL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class MAX3421E_HOST :
|
||||
public UHS_USB_HOST_BASE
|
||||
#ifdef SWI_IRQ_NUM
|
||||
, public dyn_SWI
|
||||
#endif
|
||||
{
|
||||
// TO-DO: move these into the parent class.
|
||||
volatile uint8_t vbusState;
|
||||
volatile uint16_t sof_countdown;
|
||||
|
||||
// TO-DO: pack into a struct/union and use one byte
|
||||
volatile bool busevent;
|
||||
volatile bool sofevent;
|
||||
volatile bool counted;
|
||||
volatile bool condet;
|
||||
volatile bool doingreset;
|
||||
|
||||
#ifdef USB_HOST_MANUAL_POLL
|
||||
volatile bool frame_irq_enabled = false;
|
||||
|
||||
bool enable_frame_irq(bool enable) {
|
||||
const bool prev_state = frame_irq_enabled;
|
||||
if(prev_state != enable) {
|
||||
if(enable)
|
||||
regWr(rHIEN, regRd(rHIEN) | bmFRAMEIE);
|
||||
else
|
||||
regWr(rHIEN, regRd(rHIEN) & ~bmFRAMEIE);
|
||||
frame_irq_enabled = enable;
|
||||
}
|
||||
return prev_state;
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
SPISettings MAX3421E_SPI_Settings;
|
||||
uint8_t ss_pin;
|
||||
uint8_t irq_pin;
|
||||
// Will use the defaults UHS_MAX3421E_SS, UHS_MAX3421E_INT and speed
|
||||
|
||||
UHS_NI MAX3421E_HOST() {
|
||||
sof_countdown = 0;
|
||||
busevent = false;
|
||||
doingreset = false;
|
||||
sofevent = false;
|
||||
condet = false;
|
||||
ss_pin = UHS_MAX3421E_SS;
|
||||
irq_pin = UHS_MAX3421E_INT;
|
||||
MAX3421E_SPI_Settings = SPISettings(UHS_MAX3421E_SPD, MSBFIRST, SPI_MODE0);
|
||||
hub_present = 0;
|
||||
};
|
||||
|
||||
// Will use user supplied pins, and UHS_MAX3421E_SPD
|
||||
|
||||
UHS_NI MAX3421E_HOST(uint8_t pss, uint8_t pirq) {
|
||||
sof_countdown = 0;
|
||||
busevent = false;
|
||||
doingreset = false;
|
||||
sofevent = false;
|
||||
condet = false;
|
||||
ss_pin = pss;
|
||||
irq_pin = pirq;
|
||||
MAX3421E_SPI_Settings = SPISettings(UHS_MAX3421E_SPD, MSBFIRST, SPI_MODE0);
|
||||
hub_present = 0;
|
||||
};
|
||||
|
||||
// Will use user supplied pins, and speed
|
||||
|
||||
UHS_NI MAX3421E_HOST(uint8_t pss, uint8_t pirq, uint32_t pspd) {
|
||||
sof_countdown = 0;
|
||||
doingreset = false;
|
||||
busevent = false;
|
||||
sofevent = false;
|
||||
condet = false;
|
||||
ss_pin = pss;
|
||||
irq_pin = pirq;
|
||||
MAX3421E_SPI_Settings = SPISettings(pspd, MSBFIRST, SPI_MODE0);
|
||||
hub_present = 0;
|
||||
};
|
||||
|
||||
virtual bool UHS_NI sof_delay(uint16_t x) {
|
||||
#ifdef USB_HOST_MANUAL_POLL
|
||||
const bool saved_irq_state = enable_frame_irq(true);
|
||||
#endif
|
||||
sof_countdown = x;
|
||||
while((sof_countdown != 0) && !condet) {
|
||||
SYSTEM_OR_SPECIAL_YIELD();
|
||||
#if !USB_HOST_SHIELD_USE_ISR
|
||||
Task();
|
||||
#endif
|
||||
}
|
||||
#ifdef USB_HOST_MANUAL_POLL
|
||||
enable_frame_irq(saved_irq_state);
|
||||
#endif
|
||||
// Serial.println("...Wake");
|
||||
return (!condet);
|
||||
};
|
||||
|
||||
virtual UHS_EpInfo *ctrlReqOpen(uint8_t addr, uint64_t Request, uint8_t *dataptr);
|
||||
|
||||
virtual void UHS_NI vbusPower(VBUS_t state) {
|
||||
regWr(rPINCTL, (bmFDUPSPI | bmIRQ_SENSE) | (uint8_t)(state));
|
||||
};
|
||||
|
||||
void UHS_NI Task();
|
||||
|
||||
virtual uint8_t SetAddress(uint8_t addr, uint8_t ep, UHS_EpInfo **ppep, uint16_t &nak_limit);
|
||||
virtual uint8_t OutTransfer(UHS_EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data);
|
||||
virtual uint8_t InTransfer(UHS_EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t *data);
|
||||
virtual uint8_t ctrlReqClose(UHS_EpInfo *pep, uint8_t bmReqType, uint16_t left, uint16_t nbytes, uint8_t *dataptr);
|
||||
virtual uint8_t ctrlReqRead(UHS_EpInfo *pep, uint16_t *left, uint16_t *read, uint16_t nbytes, uint8_t *dataptr);
|
||||
virtual uint8_t dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit);
|
||||
|
||||
void UHS_NI ReleaseChildren() {
|
||||
for(uint8_t i = 0; i < UHS_HOST_MAX_INTERFACE_DRIVERS; i++)
|
||||
if(devConfig[i])
|
||||
devConfig[i]->Release();
|
||||
hub_present = 0;
|
||||
};
|
||||
|
||||
virtual bool IsHub(uint8_t klass) {
|
||||
if(klass == UHS_USB_CLASS_HUB) {
|
||||
hub_present = bmHUBPRE;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
virtual void VBUS_changed();
|
||||
|
||||
virtual void UHS_NI doHostReset() {
|
||||
#if USB_HOST_SHIELD_USE_ISR
|
||||
// Enable interrupts
|
||||
noInterrupts();
|
||||
#endif
|
||||
doingreset = true;
|
||||
busevent = true;
|
||||
regWr(rHIRQ, bmBUSEVENTIRQ); // see data sheet.
|
||||
regWr(rHCTL, bmBUSRST); //issue bus reset
|
||||
#if USB_HOST_SHIELD_USE_ISR
|
||||
DDSB();
|
||||
// Enable interrupts
|
||||
interrupts();
|
||||
#endif
|
||||
while(busevent) {
|
||||
DDSB();
|
||||
SYSTEM_OR_SPECIAL_YIELD();
|
||||
}
|
||||
#endif
|
||||
#if USB_HOST_SHIELD_USE_ISR
|
||||
// Enable interrupts
|
||||
noInterrupts();
|
||||
#endif
|
||||
#ifdef USB_HOST_MANUAL_POLL
|
||||
enable_frame_irq(true);
|
||||
#endif
|
||||
sofevent = true;
|
||||
#if USB_HOST_SHIELD_USE_ISR
|
||||
DDSB();
|
||||
// Enable interrupts
|
||||
interrupts();
|
||||
#endif
|
||||
// Wait for SOF
|
||||
while(sofevent) {
|
||||
}
|
||||
#if USB_HOST_SHIELD_USE_ISR
|
||||
// Enable interrupts
|
||||
noInterrupts();
|
||||
#endif
|
||||
doingreset = false;
|
||||
#if USB_HOST_SHIELD_USE_ISR
|
||||
DDSB();
|
||||
// Enable interrupts
|
||||
interrupts();
|
||||
};
|
||||
|
||||
|
||||
int16_t UHS_NI Init(int16_t mseconds);
|
||||
|
||||
int16_t UHS_NI Init() {
|
||||
return Init(INT16_MIN);
|
||||
};
|
||||
|
||||
void ISRTask();
|
||||
void ISRbottom();
|
||||
void busprobe();
|
||||
uint16_t reset();
|
||||
|
||||
// MAX3421e specific
|
||||
void regWr(uint8_t reg, uint8_t data);
|
||||
void gpioWr(uint8_t data);
|
||||
uint8_t regRd(uint8_t reg);
|
||||
uint8_t gpioRd();
|
||||
uint8_t* bytesWr(uint8_t reg, uint8_t nbytes, uint8_t *data_p);
|
||||
uint8_t* bytesRd(uint8_t reg, uint8_t nbytes, uint8_t *data_p);
|
||||
|
||||
// ARM/NVIC specific, used to emulate reentrant ISR.
|
||||
#ifdef SWI_IRQ_NUM
|
||||
|
||||
void dyn_SWISR() {
|
||||
ISRbottom();
|
||||
};
|
||||
#endif
|
||||
|
||||
virtual void UHS_NI suspend_host() {
|
||||
// Used on MCU that lack control of IRQ priority (AVR).
|
||||
// Suspends ISRs, for critical code. IRQ will be serviced after it is resumed.
|
||||
// NOTE: you must track the state yourself!
|
||||
#ifdef __AVR__
|
||||
noInterrupts();
|
||||
detachInterrupt(UHS_GET_DPI(irq_pin));
|
||||
interrupts();
|
||||
#endif
|
||||
};
|
||||
|
||||
virtual void UHS_NI resume_host();
|
||||
};
|
||||
#ifndef SPIclass
|
||||
#define SPIclass SPI
|
||||
#endif
|
||||
#ifndef USB_HOST_SHIELD_LOADED
|
||||
#include "USB_HOST_SHIELD_INLINE.h"
|
||||
#endif
|
||||
#else
|
||||
#error "define LOAD_USB_HOST_SHIELD in your sketch, never include USB_HOST_SHIELD.h in a driver."
|
||||
#endif
|
||||
#endif /* USB_HOST_SHIELD_H */
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* File: macro_logic.h
|
||||
* Author: root
|
||||
*
|
||||
* Created on December 22, 2018, 4:49 AM
|
||||
*
|
||||
* To test:
|
||||
* gcc -DAJK_TEST_MACRO_LOGIC -E macro_logic.h
|
||||
*/
|
||||
|
||||
#ifndef MACRO_LOGIC_H
|
||||
#define MACRO_LOGIC_H
|
||||
|
||||
#define AJK_CAT(a, ...) AJK_PRIMITIVE_CAT(a, __VA_ARGS__)
|
||||
#define AJK_PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__
|
||||
|
||||
#define AJK_COMPL(b) AJK_PRIMITIVE_CAT(AJK_COMPL_, b)
|
||||
#define AJK_COMPL_0 1
|
||||
#define AJK_COMPL_1 0
|
||||
|
||||
#define AJK_BITAND(x) AJK_PRIMITIVE_CAT(AJK_BITAND_, x)
|
||||
#define AJK_BITAND_0(y) 0
|
||||
#define AJK_BITAND_1(y) y
|
||||
|
||||
#define AJK_INC(x) AJK_PRIMITIVE_CAT(AJK_INC_, x)
|
||||
#define AJK_INC_0 1
|
||||
#define AJK_INC_1 2
|
||||
#define AJK_INC_2 3
|
||||
#define AJK_INC_3 4
|
||||
#define AJK_INC_4 5
|
||||
#define AJK_INC_5 6
|
||||
#define AJK_INC_6 7
|
||||
#define AJK_INC_7 8
|
||||
#define AJK_INC_8 9
|
||||
#define AJK_INC_9 10
|
||||
#define AJK_INC_10 10
|
||||
|
||||
#define AJK_DEC(x) AJK_PRIMITIVE_CAT(AJK_DEC_, x)
|
||||
#define AJK_DEC_0 0
|
||||
#define AJK_DEC_1 0
|
||||
#define AJK_DEC_2 1
|
||||
#define AJK_DEC_3 2
|
||||
#define AJK_DEC_4 3
|
||||
#define AJK_DEC_5 4
|
||||
#define AJK_DEC_6 5
|
||||
#define AJK_DEC_7 6
|
||||
#define AJK_DEC_8 7
|
||||
#define AJK_DEC_9 8
|
||||
#define AJK_DEC_10 9
|
||||
|
||||
#define AJK_CHECK_N(x, n, ...) n
|
||||
#define AJK_CHECK(...) AJK_CHECK_N(__VA_ARGS__, 0,)
|
||||
#define AJK_PROBE(x) x, 1,
|
||||
|
||||
#define AJK_IS_PAREN(x) AJK_CHECK(AJK_IS_PAREN_PROBE x)
|
||||
#define AJK_IS_PAREN_PROBE(...) AJK_PROBE(~)
|
||||
|
||||
#define AJK_NOT(x) AJK_CHECK(AJK_PRIMITIVE_CAT(AJK_NOT_, x))
|
||||
#define AJK_NOT_0 AJK_PROBE(~)
|
||||
|
||||
#define AJK_COMPL(b) AJK_PRIMITIVE_CAT(AJK_COMPL_, b)
|
||||
#define AJK_COMPL_0 1
|
||||
#define AJK_COMPL_1 0
|
||||
|
||||
#define AJK_BOOL(x) AJK_COMPL(AJK_NOT(x))
|
||||
|
||||
#define AJK_IIF(c) AJK_PRIMITIVE_CAT(AJK_IIF_, c)
|
||||
#define AJK_IIF_0(t, ...) __VA_ARGS__
|
||||
#define AJK_IIF_1(t, ...) t
|
||||
|
||||
#define AJK_IF(c) AJK_IIF(AJK_BOOL(c))
|
||||
|
||||
#define AJK_EAT(...)
|
||||
#define AJK_EXPAND(...) __VA_ARGS__
|
||||
#define AJK_WHEN(c) AJK_IF(c)(AJK_EXPAND, AJK_EAT)
|
||||
|
||||
#define AJK_EMPTY()
|
||||
#define AJK_DEFER(id) id AJK_EMPTY()
|
||||
#define AJK_OBSTRUCT(id) id AJK_DEFER(AJK_EMPTY)()
|
||||
|
||||
#define AJK_EVAL(...) AJK_EVAL1(AJK_EVAL1(AJK_EVAL1(__VA_ARGS__)))
|
||||
#define AJK_EVAL1(...) AJK_EVAL2(AJK_EVAL2(AJK_EVAL2(__VA_ARGS__)))
|
||||
#define AJK_EVAL2(...) AJK_EVAL3(AJK_EVAL3(AJK_EVAL3(__VA_ARGS__)))
|
||||
#define AJK_EVAL3(...) AJK_EVAL4(AJK_EVAL4(AJK_EVAL4(__VA_ARGS__)))
|
||||
#define AJK_EVAL4(...) AJK_EVAL5(AJK_EVAL5(AJK_EVAL5(__VA_ARGS__)))
|
||||
#define AJK_EVAL5(...) __VA_ARGS__
|
||||
|
||||
#define AJK_REPEAT(AJK_count, AJK_macro, ...) \
|
||||
AJK_WHEN(AJK_count) \
|
||||
( \
|
||||
AJK_OBSTRUCT(AJK_REPEAT_INDIRECT) () \
|
||||
( \
|
||||
AJK_DEC(AJK_count), AJK_macro, __VA_ARGS__ \
|
||||
) \
|
||||
AJK_OBSTRUCT(AJK_macro) \
|
||||
( \
|
||||
AJK_DEC(AJK_count), __VA_ARGS__ \
|
||||
) \
|
||||
)
|
||||
#define AJK_REPEAT_INDIRECT() AJK_REPEAT
|
||||
|
||||
#define AJK_WHILE(AJK_pred, AJK_op, ...) \
|
||||
IF(AJK_pred(__VA_ARGS__)) \
|
||||
( \
|
||||
AJK_OBSTRUCT(AJK_WHILE_INDIRECT) () \
|
||||
( \
|
||||
AJK_pred, AJK_op, AJK_op(__VA_ARGS__) \
|
||||
), \
|
||||
__VA_ARGS__ \
|
||||
)
|
||||
#define AJK_WHILE_INDIRECT() AJK_WHILE
|
||||
|
||||
#define AJK_PRIMITIVE_COMPARE(x, y) AJK_IS_PAREN \
|
||||
( \
|
||||
AJK_COMPARE_ ## x ( AJK_COMPARE_ ## y) (()) \
|
||||
)
|
||||
|
||||
#define AJK_IS_COMPARABLE(x) AJK_IS_PAREN( AJK_CAT(AJK_COMPARE_, x) (()) )
|
||||
|
||||
#define AJK_NOT_EQUAL(x, y) \
|
||||
AJK_IIF(AJK_BITAND(AJK_IS_COMPARABLE(x))(AJK_IS_COMPARABLE(y)) ) \
|
||||
( \
|
||||
AJK_PRIMITIVE_COMPARE, \
|
||||
1 AJK_EAT \
|
||||
)(x, y)
|
||||
|
||||
#define AJK_EQUAL(x, y) AJK_COMPL(AJK_NOT_EQUAL(x, y))
|
||||
|
||||
|
||||
#define AJK_COMMA() ,
|
||||
|
||||
#define AJK_COMMA_IF(n) AJK_IF(n)(AJK_COMMA, AJK_EAT)()
|
||||
|
||||
|
||||
#define AJK_COMMA_VAR(AJK_count, AJK_v) AJK_COMMA_IF(AJK_count) AJK_v ## AJK_count
|
||||
|
||||
#define AJK_MAKE_LIST(AJK_v, AJK_count) AJK_EVAL(AJK_REPEAT(AJK_count, AJK_COMMA_VAR, AJK_v))
|
||||
|
||||
#define AJK_FUN(AJK_count, AJK_v, AJK_args, AJK_body) AJK_v ## AJK_count (AJK_args) { AJK_body(AJK_count) }
|
||||
#define AJK_MAKE_FUNS(AJK_v, AJK_args, AJK_count, AJK_body) AJK_EVAL(AJK_REPEAT(AJK_count, AJK_FUN, AJK_v, AJK_args, AJK_body))
|
||||
#ifdef AJK_TEST_MACRO_LOGIC
|
||||
|
||||
#define BODY(AJKindex) some(C, statement); contaning(a, test[AJKindex]);
|
||||
#define ZERO_TIMES_TEST 0
|
||||
#define THREE_TIMES_TEST 3
|
||||
blank > AJK_MAKE_LIST(VARIABLE_, ZERO_TIMES_TEST) < because zero repeats
|
||||
Make 3 comma separated indexed variables : AJK_MAKE_LIST(VARIABLE_, THREE_TIMES_TEST)
|
||||
Make 3 bogus function bodies
|
||||
AJK_MAKE_FUNS(unsigned Cfunc,(arg1, arg2),3,BODY)
|
||||
#endif
|
||||
|
||||
#endif /* MACRO_LOGIC_H */
|
@ -0,0 +1,244 @@
|
||||
/*
|
||||
* File: SWI_INLINE.h
|
||||
* Author: xxxajk@gmail.com
|
||||
*
|
||||
* Created on December 5, 2014, 9:40 AM
|
||||
*
|
||||
* This is the actual library.
|
||||
* There are no 'c' or 'cpp' files.
|
||||
*
|
||||
* This program 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifdef DYN_SWI_H
|
||||
#ifndef SWI_INLINE_H
|
||||
#define SWI_INLINE_H
|
||||
|
||||
#ifndef SWI_MAXIMUM_ALLOWED
|
||||
#define SWI_MAXIMUM_ALLOWED 4
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if defined(__arm__) || defined(ARDUINO_ARCH_PIC32)
|
||||
static char dyn_SWI_initied = 0;
|
||||
static dyn_SWI* dyn_SWI_LIST[SWI_MAXIMUM_ALLOWED];
|
||||
static dyn_SWI* dyn_SWI_EXEC[SWI_MAXIMUM_ALLOWED];
|
||||
#ifdef __arm__
|
||||
#ifdef __USE_CMSIS_VECTORS__
|
||||
extern "C" {
|
||||
void (*_VectorsRam[VECTORTABLE_SIZE])(void)__attribute__((aligned(VECTORTABLE_ALIGNMENT)));
|
||||
}
|
||||
#else
|
||||
|
||||
__attribute__((always_inline)) static inline void __DSB() {
|
||||
__asm__ volatile ("dsb");
|
||||
}
|
||||
#endif // defined(__USE_CMSIS_VECTORS__)
|
||||
#else // defined(__arm__)
|
||||
__attribute__((always_inline)) static inline void __DSB() {
|
||||
__asm__ volatile ("sync" : : : "memory");
|
||||
}
|
||||
#endif // defined(__arm__)
|
||||
|
||||
/**
|
||||
* Execute queued class ISR routines.
|
||||
*/
|
||||
#ifdef ARDUINO_ARCH_PIC32
|
||||
static p32_regset *ifs = ((p32_regset *) & IFS0) + (SWI_IRQ_NUM / 32); //interrupt flag register set
|
||||
static p32_regset *iec = ((p32_regset *) & IEC0) + (SWI_IRQ_NUM / 32); //interrupt enable control reg set
|
||||
static uint32_t swibit = 1 << (SWI_IRQ_NUM % 32);
|
||||
|
||||
void
|
||||
#ifdef __PIC32MZXX__
|
||||
__attribute__((nomips16,at_vector(SWI_VECTOR),interrupt(SWI_IPL)))
|
||||
#else
|
||||
__attribute__((interrupt(),nomips16))
|
||||
#endif
|
||||
softISR() {
|
||||
#else
|
||||
#ifdef ARDUINO_spresense_ast
|
||||
unsigned int softISR() {
|
||||
#else
|
||||
void softISR() {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//
|
||||
// TO-DO: Perhaps limit to 8, and inline this?
|
||||
//
|
||||
|
||||
|
||||
// Make a working copy, while clearing the queue.
|
||||
noInterrupts();
|
||||
#ifdef ARDUINO_ARCH_PIC32
|
||||
//ifs->clr = swibit;
|
||||
#endif
|
||||
for(int i = 0; i < SWI_MAXIMUM_ALLOWED; i++) {
|
||||
dyn_SWI_EXEC[i] = dyn_SWI_LIST[i];
|
||||
dyn_SWI_LIST[i] = NULL;
|
||||
}
|
||||
__DSB();
|
||||
interrupts();
|
||||
|
||||
// Execute each class SWI
|
||||
for(int i = 0; i < SWI_MAXIMUM_ALLOWED; i++) {
|
||||
if(dyn_SWI_EXEC[i]) {
|
||||
#ifdef __DYN_SWI_DEBUG_LED__
|
||||
digitalWrite(__DYN_SWI_DEBUG_LED__, HIGH);
|
||||
#endif
|
||||
dyn_SWI_EXEC[i]->dyn_SWISR();
|
||||
#ifdef __DYN_SWI_DEBUG_LED__
|
||||
digitalWrite(__DYN_SWI_DEBUG_LED__, LOW);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef ARDUINO_ARCH_PIC32
|
||||
noInterrupts();
|
||||
if(!dyn_SWI_EXEC[0]) ifs->clr = swibit;
|
||||
interrupts();
|
||||
#endif
|
||||
#ifdef ARDUINO_spresense_ast
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define DDSB() __DSB()
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __arm__
|
||||
#ifndef interruptsStatus
|
||||
#define interruptsStatus() __interruptsStatus()
|
||||
static inline unsigned char __interruptsStatus() __attribute__((always_inline, unused));
|
||||
|
||||
static inline unsigned char __interruptsStatus() {
|
||||
unsigned int primask;
|
||||
asm volatile ("mrs %0, primask" : "=r" (primask));
|
||||
if(primask) return 0;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initialize the Dynamic (class) Software Interrupt
|
||||
*/
|
||||
static void Init_dyn_SWI() {
|
||||
if(!dyn_SWI_initied) {
|
||||
#ifdef __USE_CMSIS_VECTORS__
|
||||
uint32_t *X_Vectors = (uint32_t*)SCB->VTOR;
|
||||
for(int i = 0; i < VECTORTABLE_SIZE; i++) {
|
||||
_VectorsRam[i] = reinterpret_cast<void (*)()>(X_Vectors[i]); /* copy vector table to RAM */
|
||||
}
|
||||
/* relocate vector table */
|
||||
noInterrupts();
|
||||
SCB->VTOR = reinterpret_cast<uint32_t>(&_VectorsRam);
|
||||
DDSB();
|
||||
interrupts();
|
||||
#endif
|
||||
#ifndef ARDUINO_spresense_ast
|
||||
for(int i = 0; i < SWI_MAXIMUM_ALLOWED; i++) dyn_SWI_LIST[i] = NULL;
|
||||
noInterrupts();
|
||||
_VectorsRam[SWI_IRQ_NUM + 16] = reinterpret_cast<void (*)()>(softISR);
|
||||
DDSB();
|
||||
interrupts();
|
||||
NVIC_SET_PRIORITY(SWI_IRQ_NUM, 255);
|
||||
NVIC_ENABLE_IRQ(SWI_IRQ_NUM);
|
||||
#endif
|
||||
#ifdef __DYN_SWI_DEBUG_LED__
|
||||
pinMode(__DYN_SWI_DEBUG_LED__, OUTPUT);
|
||||
digitalWrite(__DYN_SWI_DEBUG_LED__, LOW);
|
||||
#endif
|
||||
dyn_SWI_initied = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param klass class that extends dyn_SWI
|
||||
* @return 0 on queue full, else returns queue position (ones based)
|
||||
*/
|
||||
int exec_SWI(const dyn_SWI* klass) {
|
||||
int rc = 0;
|
||||
|
||||
uint8_t irestore = interruptsStatus();
|
||||
// Allow use from inside a critical section...
|
||||
// ... and prevent races if also used inside an ISR
|
||||
noInterrupts();
|
||||
for(int i = 0; i < SWI_MAXIMUM_ALLOWED; i++) {
|
||||
if(!dyn_SWI_LIST[i]) {
|
||||
rc = 1 + i; // Success!
|
||||
dyn_SWI_LIST[i] = (dyn_SWI*)klass;
|
||||
#ifndef ARDUINO_spresense_ast
|
||||
if(!NVIC_GET_PENDING(SWI_IRQ_NUM)) NVIC_SET_PENDING(SWI_IRQ_NUM);
|
||||
#else
|
||||
// Launch 1-shot timer as an emulated SWI
|
||||
// Hopefully the value of Zero is legal.
|
||||
// 1 microsecond latency would suck!
|
||||
attachTimerInterrupt(softISR, 100);
|
||||
#endif
|
||||
DDSB();
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Restore interrupts, if they were on.
|
||||
if(irestore) interrupts();
|
||||
return rc;
|
||||
}
|
||||
#elif defined(ARDUINO_ARCH_PIC32)
|
||||
|
||||
/**
|
||||
* Initialize the Dynamic (class) Software Interrupt
|
||||
*/
|
||||
static void Init_dyn_SWI() {
|
||||
if(!dyn_SWI_initied) {
|
||||
uint32_t sreg = disableInterrupts();
|
||||
|
||||
setIntVector(SWI_VECTOR, softISR);
|
||||
setIntPriority(SWI_VECTOR, 1, 1); // Lowest priority, ever.
|
||||
ifs->clr = swibit;
|
||||
iec->clr = swibit;
|
||||
iec->set = swibit;
|
||||
restoreInterrupts(sreg);
|
||||
#ifdef __DYN_SWI_DEBUG_LED__
|
||||
pinMode(__DYN_SWI_DEBUG_LED__, OUTPUT);
|
||||
UHS_PIN_WRITE(__DYN_SWI_DEBUG_LED__, LOW);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param klass class that extends dyn_SWI
|
||||
* @return 0 on queue full, else returns queue position (ones based)
|
||||
*/
|
||||
int exec_SWI(const dyn_SWI* klass) {
|
||||
int rc = 0;
|
||||
uint32_t sreg = disableInterrupts();
|
||||
for(int i = 0; i < SWI_MAXIMUM_ALLOWED; i++) {
|
||||
if(!dyn_SWI_LIST[i]) {
|
||||
rc = 1 + i; // Success!
|
||||
dyn_SWI_LIST[i] = (dyn_SWI*)klass;
|
||||
if(!(ifs->reg & swibit)) ifs->set = swibit;
|
||||
;
|
||||
break;
|
||||
}
|
||||
}
|
||||
restoreInterrupts(sreg);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* defined(__arm__) */
|
||||
#endif /* SWI_INLINE_H */
|
||||
#else
|
||||
#error "Never include SWI_INLINE.h directly, include dyn_SWI.h instead"
|
||||
#endif
|
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* File: dyn_SWI.h
|
||||
* Author: xxxajk@gmail.com
|
||||
*
|
||||
* Created on December 5, 2014, 9:12 AM
|
||||
*
|
||||
* This program 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef DYN_SWI_H
|
||||
#define DYN_SWI_H
|
||||
|
||||
|
||||
#if defined(__arm__) || defined(ARDUINO_ARCH_PIC32)
|
||||
#ifdef ARDUINO_ARCH_PIC32
|
||||
#include <p32xxxx.h>
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
|
||||
#ifdef true
|
||||
#undef true
|
||||
#endif
|
||||
|
||||
#ifdef false
|
||||
#undef false
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef ARDUINO_spresense_ast
|
||||
#define SWI_IRQ_NUM 666 // because this board is totally evil.
|
||||
#elif defined(ARDUINO_ARCH_PIC32)
|
||||
#ifndef SWI_IRQ_NUM
|
||||
#ifdef _DSPI0_IPL_ISR
|
||||
#define SWI_IPL _DSPI0_IPL_ISR
|
||||
#define SWI_VECTOR _DSPI0_ERR_IRQ
|
||||
#define SWI_IRQ_NUM _DSPI0_ERR_IRQ
|
||||
#elif defined(_PMP_ERROR_IRQ)
|
||||
#define SWI_IRQ_NUM _PMP_ERROR_IRQ
|
||||
#define SWI_VECTOR _PMP_VECTOR
|
||||
#else
|
||||
#error SWI_IRQ_NUM and SWI_VECTOR need a definition
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
void
|
||||
#ifdef __PIC32MZXX__
|
||||
__attribute__((nomips16,at_vector(SWI_VECTOR),interrupt(SWI_IPL)))
|
||||
#else
|
||||
__attribute__((interrupt(),nomips16))
|
||||
#endif
|
||||
softISR();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#elif !defined(NVIC_NUM_INTERRUPTS)
|
||||
// Assume CMSIS
|
||||
#define __USE_CMSIS_VECTORS__
|
||||
#ifdef NUMBER_OF_INT_VECTORS
|
||||
#define NVIC_NUM_INTERRUPTS (NUMBER_OF_INT_VECTORS-16)
|
||||
#else
|
||||
#define NVIC_NUM_INTERRUPTS ((int)PERIPH_COUNT_IRQn)
|
||||
#endif
|
||||
#define VECTORTABLE_SIZE (NVIC_NUM_INTERRUPTS+16)
|
||||
#define VECTORTABLE_ALIGNMENT (0x100UL)
|
||||
#define NVIC_GET_ACTIVE(n) NVIC_GetActive((IRQn_Type)n)
|
||||
#define NVIC_GET_PENDING(n) NVIC_GetPendingIRQ((IRQn_Type)n)
|
||||
#define NVIC_SET_PENDING(n) NVIC_SetPendingIRQ((IRQn_Type)n)
|
||||
#define NVIC_ENABLE_IRQ(n) NVIC_EnableIRQ((IRQn_Type)n)
|
||||
#define NVIC_SET_PRIORITY(n ,p) NVIC_SetPriority((IRQn_Type)n, (uint32_t) p)
|
||||
//extern "C" {
|
||||
// extern uint32_t _VectorsRam[VECTORTABLE_SIZE] __attribute__((aligned(VECTORTABLE_ALIGNMENT)));
|
||||
//}
|
||||
|
||||
#ifndef SWI_IRQ_NUM
|
||||
#if defined(__SAM3X8E__) && defined(_VARIANT_ARDUINO_DUE_X_)
|
||||
// DUE
|
||||
// Choices available:
|
||||
// HSMCI_IRQn Multimedia Card Interface (HSMCI)
|
||||
// EMAC_IRQn Ethernet MAC (EMAC)
|
||||
// EMAC is not broken out on the official DUE, but is on clones.
|
||||
// SPI0_IRQn Serial Peripheral Interface (SPI0)
|
||||
// SPI0_IRQn seems to be the best choice, as long as nobody uses an ISR based master
|
||||
#define SWI_IRQ_NUM SPI0_IRQn
|
||||
#elif defined(ARDUINO_SAMD_ZERO)
|
||||
// Just use sercom4's unused IRQ vector.
|
||||
#define SWI_IRQ_NUM I2S_IRQn
|
||||
//#define SWI_IRQ_NUM SERCOM4_IRQn
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef SWI_IRQ_NUM
|
||||
#error SWI_IRQ_NUM not defined (CMSIS)
|
||||
#endif
|
||||
|
||||
#elif defined(CORE_TEENSY)
|
||||
|
||||
#ifndef NVIC_GET_ACTIVE
|
||||
#define NVIC_GET_ACTIVE(n) (*((volatile uint32_t *)0xE000E300 + ((n) >> 5)) & (1 << ((n) & 31)))
|
||||
#endif
|
||||
#ifndef NVIC_GET_PENDING
|
||||
#define NVIC_GET_PENDING(n) (*((volatile uint32_t *)0xE000E200 + ((n) >> 5)) & (1 << ((n) & 31)))
|
||||
#ifndef SWI_IRQ_NUM
|
||||
#ifdef __MK20DX256__
|
||||
#define SWI_IRQ_NUM 17
|
||||
#elif defined(__MK20DX128__)
|
||||
#define SWI_IRQ_NUM 5
|
||||
#elif defined(__MKL26Z64__)
|
||||
#define SWI_IRQ_NUM 4
|
||||
#elif defined(__MK66FX1M0__)
|
||||
#define SWI_IRQ_NUM 30
|
||||
#elif defined(__MK64FX512__)
|
||||
#define SWI_IRQ_NUM 30
|
||||
#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)
|
||||
#define SWI_IRQ_NUM 71
|
||||
#else
|
||||
#error Do not know how to relocate IRQ vectors for this pjrc product
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#else // Not CMSIS or PJRC CORE_TEENSY or PIC32 or SPRESENSE
|
||||
#error Do not know how to relocate IRQ vectors or perform SWI
|
||||
#endif // SWI_IRQ_NUM
|
||||
|
||||
|
||||
#ifndef SWI_IRQ_NUM
|
||||
#error SWI_IRQ_NUM not defined
|
||||
#else
|
||||
/**
|
||||
* Use this class to extend your class, in order to provide
|
||||
* a C++ context callable SWI.
|
||||
*/
|
||||
class dyn_SWI {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Override this method with your code.
|
||||
*/
|
||||
virtual void dyn_SWISR() {
|
||||
};
|
||||
};
|
||||
|
||||
extern int exec_SWI(const dyn_SWI* klass);
|
||||
|
||||
#include "SWI_INLINE.h"
|
||||
|
||||
// IMPORTANT! Define this so that you do NOT end up with a NULL stub!
|
||||
#define SWI_NO_STUB
|
||||
#endif /* SWI_IRQ_NUM */
|
||||
#endif /* __arm__ */
|
||||
|
||||
// if no SWI for CPU (e.g. AVR) make a void stub.
|
||||
#ifndef SWI_NO_STUB
|
||||
#define Init_dyn_SWI() (void(0))
|
||||
#ifndef DDSB
|
||||
#define DDSB() (void(0))
|
||||
#endif
|
||||
#endif
|
||||
#endif /* DYN_SWI_H */
|
Reference in New Issue
Block a user