diff --git a/firmware/3.0/.gitignore b/firmware/3.0/.gitignore old mode 100644 new mode 100755 index 89cc49c..b9f3806 --- a/firmware/3.0/.gitignore +++ b/firmware/3.0/.gitignore @@ -1,5 +1,2 @@ .pio -.vscode/.browse.c_cpp.db* -.vscode/c_cpp_properties.json -.vscode/launch.json -.vscode/ipch +.vscode diff --git a/firmware/3.0/.vscode/extensions.json b/firmware/3.0/.vscode/extensions.json deleted file mode 100644 index e80666b..0000000 --- a/firmware/3.0/.vscode/extensions.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - // See http://go.microsoft.com/fwlink/?LinkId=827846 - // for the documentation about the extensions.json format - "recommendations": [ - "platformio.platformio-ide" - ] -} diff --git a/firmware/3.0/.vscode/settings.json b/firmware/3.0/.vscode/settings.json deleted file mode 100644 index e10f25c..0000000 --- a/firmware/3.0/.vscode/settings.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files.associations": { - "*.tcc": "cpp", - "functional": "cpp", - "typeinfo": "cpp" - } -} \ No newline at end of file diff --git a/firmware/3.0/lib/ADC/AnalogBufferDMA.cpp b/firmware/3.0/lib/ADC/AnalogBufferDMA.cpp old mode 100644 new mode 100755 index 2a11c31..7db96c8 --- a/firmware/3.0/lib/ADC/AnalogBufferDMA.cpp +++ b/firmware/3.0/lib/ADC/AnalogBufferDMA.cpp @@ -172,7 +172,7 @@ void AnalogBufferDMA::init(ADC *adc, int8_t adc_num) _dmachannel_adc.enable(); adc->startContinuous(adc_num); - adc->enableDMA(adc_num); + adc->adc[adc_num]->enableDMA(); #ifdef DEBUG_DUMP_DATA dumpDMA_TCD(&_dmachannel_adc); #endif diff --git a/firmware/3.0/lib/Bounce/Bounce.cpp b/firmware/3.0/lib/Bounce/Bounce.cpp old mode 100644 new mode 100755 index 06f100c..4883003 --- a/firmware/3.0/lib/Bounce/Bounce.cpp +++ b/firmware/3.0/lib/Bounce/Bounce.cpp @@ -1,88 +1,88 @@ - -// Please read Bounce.h for information about the liscence and authors - -#include -#include "Bounce.h" - - -Bounce::Bounce(uint8_t pin,unsigned long interval_millis) -{ - interval(interval_millis); - previous_millis = millis(); - state = digitalRead(pin); - this->pin = pin; -} - - -void Bounce::write(int new_state) - { - this->state = new_state; - digitalWrite(pin,state); - } - - -void Bounce::interval(unsigned long interval_millis) -{ - this->interval_millis = interval_millis; - this->rebounce_millis = 0; -} - -void Bounce::rebounce(unsigned long interval) -{ - this->rebounce_millis = interval; -} - - - -int Bounce::update() -{ - if ( debounce() ) { - rebounce(0); - return stateChanged = 1; - } - - // We need to rebounce, so simulate a state change - - if ( rebounce_millis && (millis() - previous_millis >= rebounce_millis) ) { - previous_millis = millis(); - rebounce(0); - return stateChanged = 1; - } - - return stateChanged = 0; -} - - -unsigned long Bounce::duration() -{ - return millis() - previous_millis; -} - - -int Bounce::read() -{ - return (int)state; -} - - -// Protected: debounces the pin -int Bounce::debounce() { - - uint8_t newState = digitalRead(pin); - if (state != newState ) { - if (millis() - previous_millis >= interval_millis) { - previous_millis = millis(); - state = newState; - return 1; - } - } - - return 0; - -} - -// The risingEdge method is true for one scan after the de-bounced input goes from off-to-on. -bool Bounce::risingEdge() { return stateChanged && state; } -// The fallingEdge method it true for one scan after the de-bounced input goes from on-to-off. -bool Bounce::fallingEdge() { return stateChanged && !state; } - + +// Please read Bounce.h for information about the liscence and authors + +#include +#include "Bounce.h" + + +Bounce::Bounce(uint8_t pin,unsigned long interval_millis) +{ + interval(interval_millis); + previous_millis = millis(); + state = digitalRead(pin); + this->pin = pin; +} + + +void Bounce::write(int new_state) + { + this->state = new_state; + digitalWrite(pin,state); + } + + +void Bounce::interval(unsigned long interval_millis) +{ + this->interval_millis = interval_millis; + this->rebounce_millis = 0; +} + +void Bounce::rebounce(unsigned long interval) +{ + this->rebounce_millis = interval; +} + + + +int Bounce::update() +{ + if ( debounce() ) { + rebounce(0); + return stateChanged = 1; + } + + // We need to rebounce, so simulate a state change + + if ( rebounce_millis && (millis() - previous_millis >= rebounce_millis) ) { + previous_millis = millis(); + rebounce(0); + return stateChanged = 1; + } + + return stateChanged = 0; +} + + +unsigned long Bounce::duration() +{ + return millis() - previous_millis; +} + + +int Bounce::read() +{ + return (int)state; +} + + +// Protected: debounces the pin +int Bounce::debounce() { + + uint8_t newState = digitalRead(pin); + if (state != newState ) { + if (millis() - previous_millis >= interval_millis) { + previous_millis = millis(); + state = newState; + return 1; + } + } + + return 0; + +} + +// The risingEdge method is true for one scan after the de-bounced input goes from off-to-on. +bool Bounce::risingEdge() { return stateChanged && state; } +// The fallingEdge method it true for one scan after the de-bounced input goes from on-to-off. +bool Bounce::fallingEdge() { return stateChanged && !state; } + diff --git a/firmware/3.0/lib/EEPROM/EEPROM.cpp b/firmware/3.0/lib/EEPROM/EEPROM.cpp old mode 100644 new mode 100755 index de9e13c..ec716dd --- a/firmware/3.0/lib/EEPROM/EEPROM.cpp +++ b/firmware/3.0/lib/EEPROM/EEPROM.cpp @@ -1,40 +1 @@ -#include -#include - -// put - Specialization for Arduino Strings ------------------------------- -// to put an Arduino String to the EEPROM we copy its internal buffer -// including the trailing \0 to the eprom - -template <> -const String &EEPROMClass::put(int idx, const String &s) -{ - const uint8_t *ptr = (uint8_t *)s.c_str(); - -#ifdef __arm__ - eeprom_write_block(ptr, (void *)idx, s.length() + 1); // length() doesn't account for the trailing \0 -#else - EEPtr e = idx; - for (int count = s.length() + 1; count; --count, ++e) - (*e).update(*ptr++); -#endif - return s; -} - -// get - Specialization for Arduino Strings ------------------------------- -// to "get" an Arduino String from the EEPROM we append chars from the EEPROM -// into it until we find the delimiting /0. -// String.append is not very efficient, code could probably be opitimized if required... - -template <> -String &EEPROMClass::get(int idx, String &s){ - s = ""; // just in case... - EEPtr e = idx; - - char c = *e; // read in bytes until we find the terminating \0 - while (c != '\0') { - s.append(c); - c = *(++e); - } - return s; -} - +// this file no longer used diff --git a/firmware/3.0/lib/EEPROM/EEPROM.h b/firmware/3.0/lib/EEPROM/EEPROM.h old mode 100644 new mode 100755 index 909c59e..236ec7a --- a/firmware/3.0/lib/EEPROM/EEPROM.h +++ b/firmware/3.0/lib/EEPROM/EEPROM.h @@ -30,6 +30,7 @@ #include #endif +#include // need to include this so String is defined /*** EERef class. @@ -149,7 +150,7 @@ struct EEPROMClass{ template< typename T > const T &put( int idx, const T &t ){ #if defined(__has_include) && __has_include() - static_assert(std::is_trivially_copyable::value, "You can not use this type with EEPROM.get"); // the code below only makes sense if you can "memcpy" T + static_assert(std::is_trivially_copyable::value, "You can not use this type with EEPROM.put"); // the code below only makes sense if you can "memcpy" T #endif const uint8_t *ptr = (const uint8_t*) &t; #ifdef __arm__ @@ -163,5 +164,44 @@ struct EEPROMClass{ }; +// put - Specialization for Arduino Strings ------------------------------- +// to put an Arduino String to the EEPROM we copy its internal buffer +// including the trailing \0 to the eprom + +template <> +inline const String &EEPROMClass::put(int idx, const String &s) +{ + const uint8_t *ptr = (uint8_t *)s.c_str(); + +#ifdef __arm__ + eeprom_write_block(ptr, (void *)idx, s.length() + 1); // length() doesn't account for the trailing \0 +#else + EEPtr e = idx; + for (int count = s.length() + 1; count; --count, ++e) + (*e).update(*ptr++); +#endif + return s; +} + +// get - Specialization for Arduino Strings ------------------------------- +// to "get" an Arduino String from the EEPROM we append chars from the EEPROM +// into it until we find the delimiting /0. +// String.append is not very efficient, code could probably be opitimized if required... + +template <> +inline String &EEPROMClass::get(int idx, String &s){ + s = ""; // just in case... + EEPtr e = idx; + + char c = *e; // read in bytes until we find the terminating \0 + while (c != '\0') + { + s.append(c); + c = *(++e); + } + return s; +} + + static EEPROMClass EEPROM __attribute__ ((unused)); #endif diff --git a/firmware/3.0/lib/LittleFS/LittleFS.cpp b/firmware/3.0/lib/LittleFS/LittleFS.cpp old mode 100644 new mode 100755 index 36e5afc..5be9276 --- a/firmware/3.0/lib/LittleFS/LittleFS.cpp +++ b/firmware/3.0/lib/LittleFS/LittleFS.cpp @@ -32,28 +32,37 @@ PROGMEM static const struct chipinfo { uint8_t addrbits; // number of address bits, 24 or 32 uint16_t progsize; // page size for programming, in bytes uint32_t erasesize; // sector size for erasing, in bytes + uint8_t erasecmd; // command to use for sector erase uint32_t chipsize; // total number of bytes in the chip uint32_t progtime; // maximum microseconds to wait for page programming uint32_t erasetime; // maximum microseconds to wait for sector erase + const char pn[22]; //flash name } known_chips[] = { - {{0xEF, 0x40, 0x15}, 24, 256, 4096, 2097152, 3000, 400000}, // Winbond W25Q16JV*IQ/W25Q16FV - {{0xEF, 0x40, 0x16}, 24, 256, 4096, 4194304, 3000, 400000}, // Winbond W25Q32JV*IQ/W25Q32FV - {{0xEF, 0x40, 0x17}, 24, 256, 4096, 8388608, 3000, 400000}, // Winbond W25Q64JV*IQ/W25Q64FV - {{0xEF, 0x40, 0x18}, 24, 256, 4096, 16777216, 3000, 400000}, // Winbond W25Q128JV*IQ/W25Q128FV - {{0xEF, 0x40, 0x19}, 32, 256, 4096, 33554432, 3000, 400000}, // Winbond W25Q256JV*IQ - {{0xEF, 0x40, 0x20}, 32, 256, 4096, 67108864, 3500, 400000}, // Winbond W25Q512JV*IQ - {{0xEF, 0x70, 0x17}, 24, 256, 4096, 8388608, 3000, 400000}, // Winbond W25Q64JV*IM (DTR) - {{0xEF, 0x70, 0x18}, 24, 256, 4096, 16777216, 3000, 400000}, // Winbond W25Q128JV*IM (DTR) - {{0xEF, 0x70, 0x19}, 32, 256, 4096, 33554432, 3000, 400000}, // Winbond W25Q256JV*IM (DTR) - {{0xEF, 0x70, 0x20}, 32, 256, 4096, 67108864, 3500, 400000}, // Winbond W25Q512JV*IM (DTR) - {{0x1F, 0x84, 0x01}, 24, 256, 4096, 524288, 2500, 300000}, // Adesto/Atmel AT25SF041 - {{0x01, 0x40, 0x14}, 24, 256, 4096, 1048576, 5000, 300000}, // Spansion S25FL208K - //FRAM - {{0x03, 0x2E, 0xC2}, 24, 64, 128, 1048576, 250, 1200}, //Cypress 8Mb FRAM - {{0xC2, 0x24, 0x00}, 24, 64, 128, 131072, 250, 1200}, //Cypress 1Mb FRAM - {{0xC2, 0x24, 0x01}, 24, 64, 128, 131072, 250, 1200}, //Cypress 1Mb FRAM, rev1 - {{0xAE, 0x83, 0x09}, 24, 64, 128, 131072, 250, 1200}, //ROHM MR45V100A 1 Mbit FeRAM Memory - {{0xC2, 0x26, 0x08}, 24, 64, 128, 131072, 250, 1200}, //Cypress 4Mb FRAM +{{0xEF, 0x40, 0x15}, 24, 256, 32768, 0x52, 2097152, 3000, 1600000, "W25Q16JV*Q/W25Q16FV"}, // Winbond W25Q16JV*Q/W25Q16FV +{{0xEF, 0x40, 0x16}, 24, 256, 32768, 0x52, 4194304, 3000, 1600000, "W25Q32JV*Q/W25Q32FV"}, // Winbond W25Q32JV*Q/W25Q32FV +{{0xEF, 0x40, 0x17}, 24, 256, 65536, 0xD8, 8388608, 3000, 2000000, "W25Q64JV*Q/W25Q64FV"}, // Winbond W25Q64JV*Q/W25Q64FV +{{0xEF, 0x40, 0x18}, 24, 256, 65536, 0xD8, 16777216, 3000, 2000000, "W25Q128JV*Q/W25Q128FV"}, // Winbond W25Q128JV*Q/W25Q128FV +{{0xEF, 0x40, 0x19}, 32, 256, 65536, 0xDC, 33554432, 3000, 2000000, "W25Q256JV*Q"}, // Winbond W25Q256JV*Q +{{0xEF, 0x40, 0x20}, 32, 256, 65536, 0xDC, 67108864, 3500, 2000000, "W25Q512JV*Q"}, // Winbond W25Q512JV*Q +{{0xEF, 0x40, 0x21}, 32, 256, 65536, 0xDC, 134217728, 3500, 2000000, "W25Q01JV*Q"},// Winbond W25Q01JV*Q +{{0x62, 0x06, 0x13}, 24, 256, 4096, 0x20, 524288, 5000, 300000, "SST25PF040C"}, // Microchip SST25PF040C +//{{0xEF, 0x40, 0x14}, 24, 256, 4096, 0x20, 1048576, 5000, 300000, "W25Q80DV"}, // Winbond W25Q80DV not tested +{{0xEF, 0x70, 0x17}, 24, 256, 65536, 0xD8, 8388608, 3000, 2000000, "W25Q64JV*M (DTR)"}, // Winbond W25Q64JV*M (DTR) +{{0xEF, 0x70, 0x18}, 24, 256, 65536, 0xD8, 16777216, 3000, 2000000, "W25Q128JV*M (DTR)"}, // Winbond W25Q128JV*M (DTR) +{{0xEF, 0x70, 0x19}, 32, 256, 65536, 0xDC, 33554432, 3000, 2000000, "W25Q256JV*M (DTR)"}, // Winbond W25Q256JV*M (DTR) +{{0xEF, 0x80, 0x19}, 32, 256, 65536, 0xDC, 33554432, 3000, 2000000, "W25Q256JW*M"}, // Winbond (W25Q256JW*M) +{{0xEF, 0x70, 0x20}, 32, 256, 65536, 0xDC, 67108864, 3500, 2000000, "W25Q512JV*M (DTR)"}, // Winbond W25Q512JV*M (DTR) +{{0x1F, 0x84, 0x01}, 24, 256, 4096, 0x20, 524288, 2500, 300000, "AT25SF041"}, // Adesto/Atmel AT25SF041 +{{0x01, 0x40, 0x14}, 24, 256, 4096, 0x20, 1048576, 5000, 300000, "S25FL208K"}, // Spansion S25FL208K +//FRAM +{{0x03, 0x2E, 0xC2}, 24, 64, 128, 0, 1048576, 250, 1200, "CY15B108QN"}, //Cypress 8Mb FRAM, CY15B108QN +{{0xC2, 0x24, 0x00}, 24, 64, 128, 0, 131072, 250, 1200, "FM25V10-G"}, //Cypress 1Mb FRAM, FM25V10-G +{{0xC2, 0x24, 0x01}, 24, 64, 128, 0, 131072, 250, 1200, "FM25V10-G (rev 1)"}, //Cypress 1Mb FRAM, rev1 +{{0xAE, 0x83, 0x09}, 24, 64, 128, 0, 131072, 250, 1200, "MR45V100A"}, //ROHM MR45V100A 1 Mbit FeRAM Memory +{{0xC2, 0x26, 0x08}, 24, 64, 128, 0, 524288, 250, 1200, "CY15B104Q"}, //Cypress 4Mb FRAM, CY15B104Q +{{0x60, 0x2A, 0xC2}, 24, 64, 128, 0, 262144, 250, 1200, "CY15B102Q"}, //Cypress 2Mb FRAM, CY15B102Q +{{0x60, 0x2A, 0xC2}, 24, 64, 128, 0, 262144, 250, 1200, "CY15B102Q"}, //Cypress 2Mb FRAM, CY15B102Q +{{0x04, 0x7F, 0x48}, 24, 64, 128, 0, 262144, 250, 1200, "MB85RS2MTAPNF"}, //Fujitsu 2Mb FRAM, MB85RS2MTAPNF }; @@ -69,6 +78,19 @@ static const struct chipinfo * chip_lookup(const uint8_t *id) return nullptr; } + +const char * LittleFS_RAM::getMediaName() { + PROGMEM static const char ram_pn_name[] = "MEMORY"; +#if defined(__IMXRT1062__) + PROGMEM static const char ext_pn_name[] = "EXTMEM"; + PROGMEM static const char dma_pn_name[] = "DMAMEM"; + + if ((uint32_t)config.context >= 0x70000000) return ext_pn_name; + if ((uint32_t)config.context >= 0x20200000) return dma_pn_name; +#endif + return ram_pn_name; +} + FLASHMEM bool LittleFS_SPIFlash::begin(uint8_t cspin, SPIClass &spiport) { @@ -112,6 +134,7 @@ bool LittleFS_SPIFlash::begin(uint8_t cspin, SPIClass &spiport) addrbits = info->addrbits; progtime = info->progtime; erasetime = info->erasetime; + erasecmd = info->erasecmd; configured = true; //Serial.println("attempting to mount existing media"); @@ -134,13 +157,28 @@ bool LittleFS_SPIFlash::begin(uint8_t cspin, SPIClass &spiport) return true; } +FLASHMEM +const char * LittleFS_SPIFlash::getMediaName(){ + const uint8_t cmd_buf[4] = {0x9F, 0, 0, 0}; + uint8_t buf[5]; + port->beginTransaction(SPICONFIG); + digitalWrite(pin, LOW); + port->transfer(cmd_buf, buf, 4); + digitalWrite(pin, HIGH); + port->endTransaction(); + + const struct chipinfo *info = chip_lookup(buf + 1); + + return info->pn; +} + FLASHMEM bool LittleFS_SPIFram::begin(uint8_t cspin, SPIClass &spiport) { pin = cspin; port = &spiport; - //Serial.println("flash begin"); + //Serial.printf("flash begin cs:%u\n", pin); configured = false; digitalWrite(pin, HIGH); pinMode(pin, OUTPUT); @@ -150,21 +188,21 @@ bool LittleFS_SPIFram::begin(uint8_t cspin, SPIClass &spiport) uint8_t buf[9]; port->beginTransaction(SPICONFIG); - digitalWrite(pin, LOW); + digitalWrite(pin, LOW); delayNanoseconds(50); - port->transfer(0x9f); //0x9f - JEDEC register - for(uint8_t i = 0; i<9; i++) - buf[i] = port->transfer(0); + port->transfer(0x9f); //0x9f - JEDEC register + for(uint8_t i = 0; i<9; i++) { + buf[i] = port->transfer(0); + } //delayNanoseconds(50); - digitalWriteFast(pin, HIGH); // Chip deselect - port->endTransaction(); - + digitalWriteFast(pin, HIGH); // Chip deselect + port->endTransaction(); - if(buf[0] == 0x7F){ + if (buf[0] == 0x7F) { buf[0] = buf[6]; buf[1] = buf[7]; buf[2] = buf[8]; - } + } //Serial.printf("Flash ID: %02X %02X %02X\n", buf[0], buf[1], buf[2]); const struct chipinfo *info = chip_lookup(buf ); if (!info) return false; @@ -210,6 +248,31 @@ bool LittleFS_SPIFram::begin(uint8_t cspin, SPIClass &spiport) return true; } +FLASHMEM +const char * LittleFS_SPIFram::getMediaName(){ + uint8_t buf[9]; + + port->beginTransaction(SPICONFIG); + digitalWrite(pin, LOW); + delayNanoseconds(50); + port->transfer(0x9f); //0x9f - JEDEC register + for(uint8_t i = 0; i<9; i++) { + buf[i] = port->transfer(0); + } + //delayNanoseconds(50); + digitalWriteFast(pin, HIGH); // Chip deselect + port->endTransaction(); + + if (buf[0] == 0x7F) { + buf[0] = buf[6]; + buf[1] = buf[7]; + buf[2] = buf[8]; + } + //Serial.printf("Flash ID: %02X %02X %02X\n", buf[0], buf[1], buf[2]); + const struct chipinfo *info = chip_lookup(buf ); + + return info->pn; +} FLASHMEM bool LittleFS::quickFormat() @@ -417,9 +480,8 @@ int LittleFS_SPIFlash::erase(lfs_block_t block) free(buffer); } const uint32_t addr = block * config.block_size; - const uint8_t cmd = (addrbits == 24) ? 0x20 : 0x21; // erase sector uint8_t cmdaddr[5]; - make_command_and_address(cmdaddr, cmd, addr, addrbits); + make_command_and_address(cmdaddr, erasecmd, addr, addrbits); //printtbuf(cmdaddr, 1 + (addrbits >> 3)); port->beginTransaction(SPICONFIG); digitalWrite(pin, LOW); @@ -457,7 +519,7 @@ int LittleFS_SPIFram::read(lfs_block_t block, lfs_off_t offset, void *buf, lfs_s if (!port) return LFS_ERR_IO; const uint32_t addr = block * config.block_size + offset; - //FRAM READ OPERATION + //FRAM READ OPERATION uint8_t cmdaddr[5]; //Serial.printf(" addrbits=%d\n", addrbits); make_command_and_address(cmdaddr, 0x03, addr, addrbits); @@ -478,7 +540,7 @@ int LittleFS_SPIFram::prog(lfs_block_t block, lfs_off_t offset, const void *buf, if (!port) return LFS_ERR_IO; const uint32_t addr = block * config.block_size + offset; - // F-RAM WRITE ENABLE COMMAND + // F-RAM WRITE ENABLE COMMAND uint8_t cmdaddr[5]; //Serial.printf(" addrbits=%d\n", addrbits); make_command_and_address(cmdaddr, 0x02, addr, addrbits); @@ -486,7 +548,7 @@ int LittleFS_SPIFram::prog(lfs_block_t block, lfs_off_t offset, const void *buf, port->beginTransaction(SPICONFIG); digitalWrite(pin,LOW); //chip select delayNanoseconds(50); - SPI.transfer(0x06); //transmit write enable opcode + port->transfer(0x06); //transmit write enable opcode digitalWrite(pin,HIGH); //release chip, signal end transfer delayNanoseconds(50); // F-RAM WRITE OPERATION @@ -522,7 +584,7 @@ int LittleFS_SPIFram::erase(lfs_block_t block) // F-RAM WRITE ENABLE COMMAND port->beginTransaction(SPICONFIG); digitalWrite(pin,LOW); //chip select - SPI.transfer(0x06); //transmit write enable opcode + port->transfer(0x06); //transmit write enable opcode digitalWrite(pin,HIGH); //release chip, signal end transfer delayNanoseconds(50); // F-RAM WRITE OPERATION @@ -744,7 +806,7 @@ bool LittleFS_QSPIFlash::begin() FLEXSPI2_LUT44 = LUT0(CMD_SDR, PINS1, 0x32) | LUT1(ADDR_SDR, PINS1, 24); FLEXSPI2_LUT45 = LUT0(WRITE_SDR, PINS4, 1); // cmd index 12 = sector erase - FLEXSPI2_LUT48 = LUT0(CMD_SDR, PINS1, 0x20) | LUT1(ADDR_SDR, PINS1, 24); + FLEXSPI2_LUT48 = LUT0(CMD_SDR, PINS1, info->erasecmd) | LUT1(ADDR_SDR, PINS1, 24); FLEXSPI2_LUT49 = 0; } else { // cmd index 9 = read QSPI (1-1-4) @@ -755,7 +817,7 @@ bool LittleFS_QSPIFlash::begin() FLEXSPI2_LUT44 = LUT0(CMD_SDR, PINS1, 0x34) | LUT1(ADDR_SDR, PINS1, 32); FLEXSPI2_LUT45 = LUT0(WRITE_SDR, PINS4, 1); // cmd index 12 = sector erase - FLEXSPI2_LUT48 = LUT0(CMD_SDR, PINS1, 0x21) | LUT1(ADDR_SDR, PINS1, 32); + FLEXSPI2_LUT48 = LUT0(CMD_SDR, PINS1, info->erasecmd) | LUT1(ADDR_SDR, PINS1, 32); FLEXSPI2_LUT49 = 0; // cmd index 9 = read SPI (1-1-1) //FLEXSPI2_LUT36 = LUT0(CMD_SDR, PINS1, 0x13) | LUT1(ADDR_SDR, PINS1, 32); @@ -839,6 +901,20 @@ int LittleFS_QSPIFlash::wait(uint32_t microseconds) return 0; // success } + +FLASHMEM +const char * LittleFS_QSPIFlash::getMediaName(){ + uint8_t buf[4] = {0, 0, 0, 0}; + + flexspi2_ip_read(8, 0x00800000, buf, 3); + + //Serial.printf("Flash ID: %02X %02X %02X\n", buf[0], buf[1], buf[2]); + const struct chipinfo *info = chip_lookup(buf); + + return info->pn; +} + + #endif // __IMXRT1062__ @@ -851,10 +927,13 @@ int LittleFS_QSPIFlash::wait(uint32_t microseconds) #if defined(ARDUINO_TEENSY40) #define FLASH_SIZE 0x1F0000 +#define SECTOR_SIZE 32768 #elif defined(ARDUINO_TEENSY41) #define FLASH_SIZE 0x7C0000 +#define SECTOR_SIZE 65536 #elif defined(ARDUINO_TEENSY_MICROMOD) #define FLASH_SIZE 0xFC0000 +#define SECTOR_SIZE 65536 #endif extern unsigned long _flashimagelen; uint32_t LittleFS_Program::baseaddr = 0; @@ -863,18 +942,21 @@ FLASHMEM bool LittleFS_Program::begin(uint32_t size) { //Serial.println("Program flash begin"); + //Serial.printf("size in bytes - %u \n", size); + configured = false; baseaddr = 0; - size = size & 0xFFFF0000; + //size = size & 0xFFFF0000; + size = (size + 0xFFFF) & 0xFFFF0000; if (size == 0) return false; - const uint32_t program_size = (uint32_t)&_flashimagelen + 4096; // extra 4K for CSF + const uint32_t program_size = (uint32_t)&_flashimagelen; if (program_size >= FLASH_SIZE) return false; const uint32_t available_space = FLASH_SIZE - program_size; + //Serial.printf("FLASH_SIZE - %u, program_size - %u\n", FLASH_SIZE, program_size); //Serial.printf("available_space = %u\n", available_space); if (size > available_space) return false; - baseaddr = 0x60000000 + FLASH_SIZE - size; - //Serial.printf("baseaddr = %x\n", baseaddr); + //Serial.printf("size - %u, baseaddr = %x\n", size, baseaddr); memset(&lfs, 0, sizeof(lfs)); memset(&config, 0, sizeof(config)); @@ -885,8 +967,8 @@ bool LittleFS_Program::begin(uint32_t size) config.sync = &static_sync; config.read_size = 128; config.prog_size = 128; - config.block_size = 4096; - config.block_count = size >> 12; + config.block_size = SECTOR_SIZE; + config.block_count = size / SECTOR_SIZE; config.block_cycles = 800; config.cache_size = 128; config.lookahead_size = 128; @@ -914,20 +996,27 @@ int LittleFS_Program::static_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t offset, void *buffer, lfs_size_t size) { //Serial.printf(" prog rd: block=%d, offset=%d, size=%d\n", block, offset, size); - const uint8_t *p = (uint8_t *)(baseaddr + block * 4096 + offset); + const uint8_t *p = (uint8_t *)(baseaddr + block * SECTOR_SIZE + offset); memcpy(buffer, p, size); return 0; } +const char * LittleFS_Program::getMediaName() { + PROGMEM static const char prog_pn_name[] = "PROGRAM"; + return prog_pn_name; +} + // from eeprom.c extern "C" void eepromemu_flash_write(void *addr, const void *data, uint32_t len); extern "C" void eepromemu_flash_erase_sector(void *addr); +extern "C" void eepromemu_flash_erase_32K_block(void *addr); +extern "C" void eepromemu_flash_erase_64K_block(void *addr); int LittleFS_Program::static_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t offset, const void *buffer, lfs_size_t size) { //Serial.printf(" prog wr: block=%d, offset=%d, size=%d\n", block, offset, size); - uint8_t *p = (uint8_t *)(baseaddr + block * 4096 + offset); + uint8_t *p = (uint8_t *)(baseaddr + block * SECTOR_SIZE + offset); eepromemu_flash_write(p, buffer, size); return 0; } @@ -935,15 +1024,60 @@ int LittleFS_Program::static_prog(const struct lfs_config *c, lfs_block_t block, int LittleFS_Program::static_erase(const struct lfs_config *c, lfs_block_t block) { //Serial.printf(" prog er: block=%d\n", block); - uint8_t *p = (uint8_t *)(baseaddr + block * 4096); + uint8_t *p = (uint8_t *)(baseaddr + block * SECTOR_SIZE); +#if SECTOR_SIZE == 4096 eepromemu_flash_erase_sector(p); +#elif SECTOR_SIZE == 32768 + eepromemu_flash_erase_32K_block(p); +#elif SECTOR_SIZE == 65536 + eepromemu_flash_erase_64K_block(p); +#else +#error "Program SECTOR_SIZE must be 4096, 32768, or 65536" +#endif return 0; } #endif // __IMXRT1062__ +//----------------------------------------------------------------------------- +// Wrapper classes begin methods +//----------------------------------------------------------------------------- +bool LittleFS_SPI::begin(uint8_t cspin, SPIClass &spiport) { + if (cspin != 0xff) csPin_ = cspin; + if (flash.begin(csPin_, spiport)) { + sprintf(display_name, (const char *)F("Flash_%u"), csPin_); + pfs = &flash; + return true; + } else if (fram.begin(csPin_, spiport)) { + sprintf(display_name, (const char *)F("Fram_%u"), csPin_); + pfs = &fram; + return true; + } else if (nand.begin(csPin_, spiport)) { + sprintf(display_name, (const char *)F("NAND_%u"), csPin_); + pfs = &nand; + return true; + } + // none of the above. + pfs = &fsnone; + return false; +} - - - - +#ifdef __IMXRT1062__ +bool LittleFS_QSPI::begin() { + //Serial.printf("Try QSPI"); + if (flash.begin()) { + //Serial.println(" *** Flash ***"); + strcpy(display_name, (const char *)F("QFlash")); + pfs = &flash; + return true; + } else if (nand.begin()) { + //Serial.println(" *** Nand ***"); + strcpy(display_name, (const char *)F("QNAND")); + pfs = &nand; + return true; + } + //Serial.println(" ### Failed ###"); + pfs = &fsnone; + return false; +} +#endif // __IMXRT1062__ diff --git a/firmware/3.0/lib/LittleFS/LittleFS.h b/firmware/3.0/lib/LittleFS/LittleFS.h old mode 100644 new mode 100755 index a9c3da9..665b5d1 --- a/firmware/3.0/lib/LittleFS/LittleFS.h +++ b/firmware/3.0/lib/LittleFS/LittleFS.h @@ -27,10 +27,10 @@ #include "littlefs/lfs.h" //#include -class LittleFSFile : public File +class LittleFSFile : public FileImpl { private: - // Classes derived from File are never meant to be constructed from + // Classes derived from FileImpl are never meant to be constructed from // anywhere other than openNextFile() and open() in their parent FS // class. Only the abstract File class which references these // derived classes is meant to have a public constructor! @@ -54,12 +54,38 @@ class LittleFSFile : public File //Serial.printf(" LittleFSFile dtor, this=%x\n", (int)this); close(); } -#ifdef FILE_WHOAMI - virtual void whoami() { - Serial.printf(" LittleFSFile this=%x, refcount=%u\n", - (int)this, getRefcount()); + + // These will all return false as only some FS support it. + + virtual bool getCreateTime(DateTimeFields &tm){ + uint32_t mdt = getCreationTime(); + if (mdt == 0) { return false;} // did not retrieve a date; + breakTime(mdt, tm); + return true; } + virtual bool getModifyTime(DateTimeFields &tm){ + uint32_t mdt = getModifiedTime(); + if (mdt == 0) {return false;} // did not retrieve a date; + breakTime(mdt, tm); + return true; + } + virtual bool setCreateTime(const DateTimeFields &tm) { + if (tm.year < 80 || tm.year > 207) return false; + bool success = true; + uint32_t mdt = makeTime(tm); + int rcode = lfs_setattr(lfs, name(), 'c', (const void *) &mdt, sizeof(mdt)); + if(rcode < 0) + success = false; + return success; + } + virtual bool setModifyTime(const DateTimeFields &tm) { + if (tm.year < 80 || tm.year > 207) return false; + bool success = true; + uint32_t mdt = makeTime(tm); + int rcode = lfs_setattr(lfs, name(), 'm', (const void *) &mdt, sizeof(mdt)); + if(rcode < 0) + success = false; + return success; } -#endif virtual size_t write(const void *buf, size_t size) { //Serial.println("write"); if (!file) return 0; @@ -130,7 +156,7 @@ class LittleFSFile : public File } //Serial.println(" end of close"); } - virtual operator bool() { + virtual bool isOpen() { return file || dir; } virtual const char * name() { @@ -148,7 +174,7 @@ class LittleFSFile : public File memset(&info, 0, sizeof(info)); // is this necessary? if (lfs_dir_read(lfs, dir, &info) <= 0) return File(); } while (strcmp(info.name, ".") == 0 || strcmp(info.name, "..") == 0); - //Serial.printf(" next name = \"%s\"\n", info.name); + //Serial.printf("ONF:: next name = \"%s\"\n", info.name); char pathname[128]; strlcpy(pathname, fullpath, sizeof(pathname)); size_t len = strlen(pathname); @@ -158,6 +184,7 @@ class LittleFSFile : public File pathname[len] = 0; } strlcpy(pathname + len, info.name, sizeof(pathname) - len); + //Serial.print("ONF:: pathname --- "); Serial.println(pathname); if (info.type == LFS_TYPE_REG) { lfs_file_t *f = (lfs_file_t *)malloc(sizeof(lfs_file_t)); if (!f) return File(); @@ -179,13 +206,28 @@ class LittleFSFile : public File if (dir) lfs_dir_rewind(lfs, dir); } - using Print::write; private: lfs_t *lfs; lfs_file_t *file; lfs_dir_t *dir; char *filename; char fullpath[128]; + + uint32_t getCreationTime() { + uint32_t filetime = 0; + int rc = lfs_getattr(lfs, fullpath, 'c', (void *)&filetime, sizeof(filetime)); + if(rc != sizeof(filetime)) + filetime = 0; // Error so clear read value + return filetime; + } + uint32_t getModifiedTime() { + uint32_t filetime = 0; + int rc = lfs_getattr(lfs, fullpath, 'm', (void *)&filetime, sizeof(filetime)); + if(rc != sizeof(filetime)) + filetime = 0; // Error so clear read value + return filetime; + } + }; @@ -199,10 +241,19 @@ class LittleFS : public FS mounted = false; config.context = nullptr; } + virtual bool format(int type=0, char progressChar=0, Print& pr=Serial) { + if(type == 0) { return quickFormat(); } + if(type == 1) { return lowLevelFormat(progressChar, &pr); } + return true; + } + + virtual const char * getMediaName() {return (const char*)F("");} + bool quickFormat(); bool lowLevelFormat(char progressChar=0, Print* pr=&Serial); uint32_t formatUnused(uint32_t blockCnt, uint32_t blockStart); File open(const char *filepath, uint8_t mode = FILE_READ) { + int rcode; //Serial.println("LittleFS open"); if (!mounted) return File(); if (mode == FILE_READ) { @@ -210,7 +261,6 @@ class LittleFS : public FS if (lfs_stat(&lfs, filepath, &info) < 0) return File(); //Serial.printf("LittleFS open got info, name=%s\n", info.name); if (info.type == LFS_TYPE_REG) { - //Serial.println(" regular file"); lfs_file_t *file = (lfs_file_t *)malloc(sizeof(lfs_file_t)); if (!file) return File(); if (lfs_file_open(&lfs, file, filepath, LFS_O_RDONLY) >= 0) { @@ -218,7 +268,6 @@ class LittleFS : public FS } free(file); } else { // LFS_TYPE_DIR - //Serial.println(" directory"); lfs_dir_t *dir = (lfs_dir_t *)malloc(sizeof(lfs_dir_t)); if (!dir) return File(); if (lfs_dir_open(&lfs, dir, filepath) >= 0) { @@ -230,8 +279,19 @@ class LittleFS : public FS lfs_file_t *file = (lfs_file_t *)malloc(sizeof(lfs_file_t)); if (!file) return File(); if (lfs_file_open(&lfs, file, filepath, LFS_O_RDWR | LFS_O_CREAT) >= 0) { + //attributes get written when the file is closed + uint32_t filetime = 0; + uint32_t _now = Teensy3Clock.get(); + rcode = lfs_getattr(&lfs, filepath, 'c', (void *)&filetime, sizeof(filetime)); + if(rcode != sizeof(filetime)) { + rcode = lfs_setattr(&lfs, filepath, 'c', (const void *) &_now, sizeof(_now)); + if(rcode < 0) + Serial.println("FO:: set attribute creation failed"); + } + rcode = lfs_setattr(&lfs, filepath, 'm', (const void *) &_now, sizeof(_now)); + if(rcode < 0) + Serial.println("FO:: set attribute modified failed"); if (mode == FILE_WRITE) { - // FILE_WRITE opens at end of file lfs_file_seek(&lfs, file, 0, LFS_SEEK_END); } // else FILE_WRITE_BEGIN return File(new LittleFSFile(&lfs, file, filepath)); @@ -246,13 +306,25 @@ class LittleFS : public FS return true; } bool mkdir(const char *filepath) { + int rcode; if (!mounted) return false; if (lfs_mkdir(&lfs, filepath) < 0) return false; + uint32_t _now = Teensy3Clock.get(); + rcode = lfs_setattr(&lfs, filepath, 'c', (const void *) &_now, sizeof(_now)); + if(rcode < 0) + Serial.println("FD:: set attribute creation failed"); + rcode = lfs_setattr(&lfs, filepath, 'm', (const void *) &_now, sizeof(_now)); + if(rcode < 0) + Serial.println("FD:: set attribute modified failed"); return true; } bool rename(const char *oldfilepath, const char *newfilepath) { if (!mounted) return false; if (lfs_rename(&lfs, oldfilepath, newfilepath) < 0) return false; + uint32_t _now = Teensy3Clock.get(); + int rcode = lfs_setattr(&lfs, newfilepath, 'm', (const void *) &_now, sizeof(_now)); + if(rcode < 0) + Serial.println("FD:: set attribute modified failed"); return true; } bool remove(const char *filepath) { @@ -273,11 +345,14 @@ class LittleFS : public FS if (!mounted) return 0; return config.block_count * config.block_size; } + + protected: bool configured; bool mounted; lfs_t lfs; lfs_config config; + }; @@ -299,7 +374,7 @@ class LittleFS_RAM : public LittleFS //Serial.println("configure "); delay(5); configured = false; if (!ptr) return false; - // memset(ptr, 0xFF, size); // always start with blank slate + memset(ptr, 0xFF, size); // always start with blank slate size = size & 0xFFFFFF00; memset(&lfs, 0, sizeof(lfs)); memset(&config, 0, sizeof(config)); @@ -330,12 +405,9 @@ class LittleFS_RAM : public LittleFS config.file_max = 0; config.attr_max = 0; configured = true; - if (lfs_mount(&lfs, &config) < 0) { - memset(ptr, 0xFF, size); // always start with blank slate - if (lfs_format(&lfs, &config) < 0) return false; - //Serial.println("formatted"); - if (lfs_mount(&lfs, &config) < 0) return false; - } + if (lfs_format(&lfs, &config) < 0) return false; + //Serial.println("formatted"); + if (lfs_mount(&lfs, &config) < 0) return false; //Serial.println("mounted atfer format"); mounted = true; return true; @@ -344,6 +416,9 @@ class LittleFS_RAM : public LittleFS uint32_t formatUnused(uint32_t blockCnt, uint32_t blockStart) { return 0; } + FLASHMEM + const char * getMediaName(); + private: static int static_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t offset, void *buffer, lfs_size_t size) { @@ -365,10 +440,6 @@ class LittleFS_RAM : public LittleFS return 0; } static int static_sync(const struct lfs_config *c) { - if ( c->context >= (void *)0x20200000 ) { - //Serial.printf(" arm_dcache_flush_delete: ptr=0x%x, size=%d\n", c->context, c->block_count * c->block_size); - arm_dcache_flush_delete(c->context, c->block_count * c->block_size ); - } return 0; } }; @@ -381,6 +452,7 @@ class LittleFS_SPIFlash : public LittleFS port = nullptr; } bool begin(uint8_t cspin, SPIClass &spiport=SPI); + const char * getMediaName(); private: int read(lfs_block_t block, lfs_off_t offset, void *buf, lfs_size_t size); int prog(lfs_block_t block, lfs_off_t offset, const void *buf, lfs_size_t size); @@ -406,6 +478,7 @@ class LittleFS_SPIFlash : public LittleFS SPIClass *port; uint8_t pin; uint8_t addrbits; + uint8_t erasecmd; uint32_t progtime; uint32_t erasetime; }; @@ -419,6 +492,7 @@ class LittleFS_SPIFram : public LittleFS port = nullptr; } bool begin(uint8_t cspin, SPIClass &spiport=SPI); + const char * getMediaName(); private: int read(lfs_block_t block, lfs_off_t offset, void *buf, lfs_size_t size); int prog(lfs_block_t block, lfs_off_t offset, const void *buf, lfs_size_t size); @@ -458,6 +532,7 @@ class LittleFS_QSPIFlash : public LittleFS public: LittleFS_QSPIFlash() { } bool begin(); + const char * getMediaName(); private: int read(lfs_block_t block, lfs_off_t offset, void *buf, lfs_size_t size); int prog(lfs_block_t block, lfs_off_t offset, const void *buf, lfs_size_t size); @@ -501,6 +576,7 @@ class LittleFS_Program : public LittleFS public: LittleFS_Program() { } bool begin(uint32_t size); + const char * getMediaName(); private: static int static_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t offset, void *buffer, lfs_size_t size); @@ -517,6 +593,7 @@ class LittleFS_Program : public LittleFS public: LittleFS_Program() { } bool begin(uint32_t size) { return false; } + const char * getMediaName() { return (const char *)F("PROGRAM"); } }; #endif @@ -531,7 +608,7 @@ class LittleFS_SPINAND : public LittleFS void readBBLUT(uint16_t *LBA, uint16_t *PBA, uint8_t *linkStatus); bool lowLevelFormat(char progressChar, Print* pr=&Serial); uint8_t addBBLUT(uint32_t block_address); //temporary for testing - + const char * getMediaName(); private: int read(lfs_block_t block, lfs_off_t offset, void *buf, lfs_size_t size); int prog(lfs_block_t block, lfs_off_t offset, const void *buf, lfs_size_t size); @@ -594,7 +671,7 @@ class LittleFS_QPINAND : public LittleFS void readBBLUT(uint16_t *LBA, uint16_t *PBA, uint8_t *linkStatus); bool lowLevelFormat(char progressChar); uint8_t addBBLUT(uint32_t block_address); //temporary for testing - + const char * getMediaName(); private: int read(lfs_block_t block, lfs_off_t offset, void *buf, lfs_size_t size); int prog(lfs_block_t block, lfs_off_t offset, const void *buf, lfs_size_t size); @@ -642,11 +719,87 @@ class LittleFS_QPINAND : public LittleFS }; #endif +//---------------------------------------------------------------------------- +// Simple SPI wrapper that allows you to specify an IO pin and the +// begin method will try the known types of SPI LittleFS file systems +// begin methods until it finds one that return true. +// you can then query which one using the fs() method. +//---------------------------------------------------------------------------- +// This FS simply errors out all calls... +class FS_NONE : public FS { + virtual File open(const char *filename, uint8_t mode = FILE_READ) { return File();} + virtual bool exists(const char *filepath) {return false;} + virtual bool mkdir(const char *filepath) {return false;} + virtual bool rename(const char *oldfilepath, const char *newfilepath) { return false;} + virtual bool remove(const char *filepath) { return false;} + virtual bool rmdir(const char *filepath) { return false;} + virtual uint64_t usedSize() { return 0;} + virtual uint64_t totalSize() { return 0;} +}; +class LittleFS_SPI : public FS { +public: + LittleFS_SPI(uint8_t pin=0xff) : csPin_(pin) {} + bool begin(uint8_t cspin=0xff, SPIClass &spiport=SPI); + inline LittleFS * fs() { return (pfs == &fsnone)? nullptr : (LittleFS*)pfs ;} + inline const char * displayName() {return display_name;} + inline const char * getMediaName() {return (pfs == &fsnone)? (const char *)F("") : ((LittleFS*)pfs)->getMediaName();} + + // You have full access to internals. + uint8_t csPin_; + LittleFS_SPIFlash flash; + LittleFS_SPIFram fram; + LittleFS_SPINAND nand; + FS_NONE fsnone; + + // FS overrides + virtual File open(const char *filename, uint8_t mode = FILE_READ) { return pfs->open(filename, mode); } + virtual bool exists(const char *filepath) { return pfs->exists(filepath); } + virtual bool mkdir(const char *filepath) { return pfs->mkdir(filepath); } + virtual bool rename(const char *oldfilepath, const char *newfilepath) { return pfs->rename(oldfilepath, newfilepath); } + virtual bool remove(const char *filepath) { return pfs->remove(filepath); } + virtual bool rmdir(const char *filepath) { return pfs->rmdir(filepath); } + virtual uint64_t usedSize() { return pfs->usedSize(); } + virtual uint64_t totalSize() { return pfs->totalSize(); } + virtual bool format(int type=0, char progressChar=0, Print& pr=Serial) { return pfs->format(type, progressChar, pr); } +private: + FS *pfs = &fsnone; + char display_name[10]; +}; - - - +//---------------------------------------------------------------------------- +// Simple QSPI wraper for T4.1 +//---------------------------------------------------------------------------- +#ifdef __IMXRT1062__ +class LittleFS_QSPI : public FS { +public: + LittleFS_QSPI(){} + bool begin(); + inline LittleFS * fs() { return (pfs == &fsnone)? nullptr : (LittleFS*)pfs ;} + inline const char * displayName() {return display_name;} + inline const char * getMediaName() {return (pfs == &fsnone)? (const char *)F("") : ((LittleFS*)pfs)->getMediaName();} + // You have full access to internals. + uint8_t csPin; + LittleFS_QSPIFlash flash; + LittleFS_QPINAND nand; + FS_NONE fsnone; + + + // FS overrides + virtual File open(const char *filename, uint8_t mode = FILE_READ) { return pfs->open(filename, mode); } + virtual bool exists(const char *filepath) { return pfs->exists(filepath); } + virtual bool mkdir(const char *filepath) { return pfs->mkdir(filepath); } + virtual bool rename(const char *oldfilepath, const char *newfilepath) { return pfs->rename(oldfilepath, newfilepath); } + virtual bool remove(const char *filepath) { return pfs->remove(filepath); } + virtual bool rmdir(const char *filepath) { return pfs->rmdir(filepath); } + virtual uint64_t usedSize() { return pfs->usedSize(); } + virtual uint64_t totalSize() { return pfs->totalSize();} + virtual bool format(int type=0, char progressChar=0, Print& pr=Serial) { return pfs->format(type, progressChar, pr); } +private: + FS *pfs = &fsnone; + char display_name[10]; +}; +#endif diff --git a/firmware/3.0/lib/LittleFS/LittleFS_NAND.cpp b/firmware/3.0/lib/LittleFS/LittleFS_NAND.cpp old mode 100644 new mode 100755 index c44793b..812624a --- a/firmware/3.0/lib/LittleFS/LittleFS_NAND.cpp +++ b/firmware/3.0/lib/LittleFS/LittleFS_NAND.cpp @@ -62,7 +62,7 @@ -#define SPICONFIG_NAND SPISettings(55000000, MSBFIRST, SPI_MODE0) +#define SPICONFIG_NAND SPISettings(30000000, MSBFIRST, SPI_MODE0) PROGMEM static const struct chipinfo { @@ -70,18 +70,20 @@ PROGMEM static const struct chipinfo { uint8_t addrbits; // number of address bits, 24 or 32 uint16_t progsize; // page size for programming, in bytes uint32_t erasesize; // sector size for erasing, in bytes + uint8_t erasecmd; // command to use for sector erase uint32_t chipsize; // total number of bytes in the chip uint32_t progtime; // maximum microseconds to wait for page programming uint32_t erasetime; // maximum microseconds to wait for sector erase + const char pn[14]; //flash name } known_chips[] = { //NAND //{{0xEF, 0xAA, 0x21}, 24, 2048, 131072, 134217728, 2000, 15000}, //Winbond W25N01G //Upper 24 blocks * 128KB/block will be used for bad block replacement area //so reducing total chip size: 134217728 - 24*131072 - {{0xEF, 0xAA, 0x21}, 24, 2048, 131072, 131596288, 2000, 15000}, //Winbond W25N01G + {{0xEF, 0xAA, 0x21}, 24, 2048, 131072, 0, 131596288, 2000, 15000, "W25N01GVZEIG"}, //Winbond W25N01G //{{0xEF, 0xAA, 0x22}, 24, 2048, 131072, 134217728*2, 2000, 15000}, //Winbond W25N02G - {{0xEF, 0xAA, 0x22}, 24, 2048, 131072, 265289728, 2000, 15000}, //Winbond W25N02G - {{0xEF, 0xBB, 0x21}, 24, 2048, 131072, 265289728, 2000, 15000}, //Winbond W25M02 + {{0xEF, 0xAA, 0x22}, 24, 2048, 131072, 0, 265289728, 2000, 15000, "W25N02KVZEIR"}, //Winbond W25N02G + {{0xEF, 0xBB, 0x21}, 24, 2048, 131072, 0, 265289728, 2000, 15000, "W25M02"}, //Winbond W25M02 }; volatile uint32_t currentPage = UINT32_MAX; @@ -774,6 +776,22 @@ bool LittleFS_SPINAND::lowLevelFormat(char progressChar, Print* pr) } +const char * LittleFS_SPINAND::getMediaName(){ + const uint8_t cmd_buf[5] = {0x9F, 0, 0, 0, 0}; + uint8_t buf[5]; + + SPI.beginTransaction(SPICONFIG_NAND); + digitalWrite(pin, LOW); + SPI.transfer(cmd_buf, buf, 5); + digitalWrite(pin, HIGH); + SPI.endTransaction(); + + const struct chipinfo *info = chip_lookup(buf+2); + + return info->pn; +} + + #if defined(__IMXRT1062__) #define LUT0(opcode, pads, operand) (FLEXSPI_LUT_INSTRUCTION((opcode), (pads), (operand))) @@ -1353,7 +1371,7 @@ uint8_t LittleFS_QPINAND::readECC(uint32_t targetPage, uint8_t *buf, int size) case 3: // Uncorrectable ECC in multiple pages //addError(address, eccCode); //Serial.printf("ECC Error (addr, code): %x, %x\n", address, eccCode); - addBBLUT(LINEAR_TO_BLOCK(targetPage*eccSize)); + //addBBLUT(LINEAR_TO_BLOCK(targetPage*eccSize)); //deviceReset(); break; } @@ -1497,4 +1515,11 @@ bool LittleFS_QPINAND::lowLevelFormat(char progressChar) return val; } +const char * LittleFS_QPINAND::getMediaName(){ + uint8_t buf[5] = {0, 0, 0, 0, 0}; + flexspi2_ip_read(8, 0x00800000, buf, 4); + const struct chipinfo *info = chip_lookup(buf+1); + + return info->pn; +} #endif // __IMXRT1062__ \ No newline at end of file diff --git a/firmware/3.0/lib/LittleFS/littlefs/README.md b/firmware/3.0/lib/LittleFS/littlefs/README.md old mode 100644 new mode 100755 index f900674..584ada3 --- a/firmware/3.0/lib/LittleFS/littlefs/README.md +++ b/firmware/3.0/lib/LittleFS/littlefs/README.md @@ -192,7 +192,7 @@ More details on how littlefs works can be found in [DESIGN.md](DESIGN.md) and ## Testing The littlefs comes with a test suite designed to run on a PC using the -[emulated block device](emubd/lfs_emubd.h) found in the emubd directory. +[emulated block device](bd/lfs_testbd.h) found in the `bd` directory. The tests assume a Linux environment and can be started with make: ``` bash @@ -221,6 +221,11 @@ License Identifiers that are here available: http://spdx.org/licenses/ - [littlefs-js] - A javascript wrapper for littlefs. I'm not sure why you would want this, but it is handy for demos. You can see it in action [here][littlefs-js-demo]. + +- [littlefs-python] - A Python wrapper for littlefs. The project allows you + to create images of the filesystem on your PC. Check if littlefs will fit + your needs, create images for a later download to the target memory or + inspect the content of a binary image of the target memory. - [mklfs] - A command line tool built by the [Lua RTOS] guys for making littlefs images from a host PC. Supports Windows, Mac OS, and Linux. @@ -250,3 +255,4 @@ License Identifiers that are here available: http://spdx.org/licenses/ [LittleFileSystem]: https://os.mbed.com/docs/mbed-os/v5.12/apis/littlefilesystem.html [SPIFFS]: https://github.com/pellepl/spiffs [Dhara]: https://github.com/dlbeer/dhara +[littlefs-python]: https://pypi.org/project/littlefs-python/ diff --git a/firmware/3.0/lib/LittleFS/littlefs/lfs.c b/firmware/3.0/lib/LittleFS/littlefs/lfs.c old mode 100644 new mode 100755 index b1f445e..d976389 --- a/firmware/3.0/lib/LittleFS/littlefs/lfs.c +++ b/firmware/3.0/lib/LittleFS/littlefs/lfs.c @@ -6,7 +6,6 @@ */ #include "lfs.h" #include "lfs_util.h" -#include "wiring.h" #define LFS_BLOCK_NULL ((lfs_block_t)-1) #define LFS_BLOCK_INLINE ((lfs_block_t)-2) @@ -119,24 +118,29 @@ static int lfs_bd_cmp(lfs_t *lfs, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size) { const uint8_t *data = buffer; + lfs_size_t diff = 0; - for (lfs_off_t i = 0; i < size; i++) { - uint8_t dat; - int err = lfs_bd_read(lfs, + for (lfs_off_t i = 0; i < size; i += diff) { + uint8_t dat[8]; + + diff = lfs_min(size-i, sizeof(dat)); + int res = lfs_bd_read(lfs, pcache, rcache, hint-i, - block, off+i, &dat, 1); - if (err) { - return err; + block, off+i, &dat, diff); + if (res) { + return res; } - if (dat != data[i]) { - return (dat < data[i]) ? LFS_CMP_LT : LFS_CMP_GT; + res = memcmp(dat, data + i, diff); + if (res) { + return res < 0 ? LFS_CMP_LT : LFS_CMP_GT; } } return LFS_CMP_EQ; } +#ifndef LFS_READONLY static int lfs_bd_flush(lfs_t *lfs, lfs_cache_t *pcache, lfs_cache_t *rcache, bool validate) { if (pcache->block != LFS_BLOCK_NULL && pcache->block != LFS_BLOCK_INLINE) { @@ -169,7 +173,9 @@ static int lfs_bd_flush(lfs_t *lfs, return 0; } +#endif +#ifndef LFS_READONLY static int lfs_bd_sync(lfs_t *lfs, lfs_cache_t *pcache, lfs_cache_t *rcache, bool validate) { lfs_cache_drop(lfs, rcache); @@ -183,7 +189,9 @@ static int lfs_bd_sync(lfs_t *lfs, LFS_ASSERT(err <= 0); return err; } +#endif +#ifndef LFS_READONLY static int lfs_bd_prog(lfs_t *lfs, lfs_cache_t *pcache, lfs_cache_t *rcache, bool validate, lfs_block_t block, lfs_off_t off, @@ -229,13 +237,16 @@ static int lfs_bd_prog(lfs_t *lfs, return 0; } +#endif +#ifndef LFS_READONLY static int lfs_bd_erase(lfs_t *lfs, lfs_block_t block) { LFS_ASSERT(block < lfs->cfg->block_count); int err = lfs->cfg->erase(lfs->cfg, block); LFS_ASSERT(err <= 0); return err; } +#endif /// Small type-level utilities /// @@ -389,10 +400,12 @@ static void lfs_ctz_fromle32(struct lfs_ctz *ctz) { ctz->size = lfs_fromle32(ctz->size); } +#ifndef LFS_READONLY static void lfs_ctz_tole32(struct lfs_ctz *ctz) { ctz->head = lfs_tole32(ctz->head); ctz->size = lfs_tole32(ctz->size); } +#endif static inline void lfs_superblock_fromle32(lfs_superblock_t *superblock) { superblock->version = lfs_fromle32(superblock->version); @@ -412,16 +425,49 @@ static inline void lfs_superblock_tole32(lfs_superblock_t *superblock) { superblock->attr_max = lfs_tole32(superblock->attr_max); } +#ifndef LFS_NO_ASSERT +static bool lfs_mlist_isopen(struct lfs_mlist *head, + struct lfs_mlist *node) { + for (struct lfs_mlist **p = &head; *p; p = &(*p)->next) { + if (*p == (struct lfs_mlist*)node) { + return true; + } + } + + return false; +} +#endif + +static void lfs_mlist_remove(lfs_t *lfs, struct lfs_mlist *mlist) { + for (struct lfs_mlist **p = &lfs->mlist; *p; p = &(*p)->next) { + if (*p == mlist) { + *p = (*p)->next; + break; + } + } +} + +static void lfs_mlist_append(lfs_t *lfs, struct lfs_mlist *mlist) { + mlist->next = lfs->mlist; + lfs->mlist = mlist; +} + /// Internal operations predeclared here /// +#ifndef LFS_READONLY static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount); static int lfs_dir_compact(lfs_t *lfs, lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount, lfs_mdir_t *source, uint16_t begin, uint16_t end); + +static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file, + const void *buffer, lfs_size_t size); +static int lfs_file_rawsync(lfs_t *lfs, lfs_file_t *file); static int lfs_file_outline(lfs_t *lfs, lfs_file_t *file); static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file); -static void lfs_fs_preporphans(lfs_t *lfs, int8_t orphans); + +static int lfs_fs_preporphans(lfs_t *lfs, int8_t orphans); static void lfs_fs_prepmove(lfs_t *lfs, uint16_t id, const lfs_block_t pair[2]); static int lfs_fs_pred(lfs_t *lfs, const lfs_block_t dir[2], @@ -430,17 +476,32 @@ static lfs_stag_t lfs_fs_parent(lfs_t *lfs, const lfs_block_t dir[2], lfs_mdir_t *parent); static int lfs_fs_relocate(lfs_t *lfs, const lfs_block_t oldpair[2], lfs_block_t newpair[2]); -int lfs_fs_traverseraw(lfs_t *lfs, - int (*cb)(void *data, lfs_block_t block), void *data, - bool includeorphans); static int lfs_fs_forceconsistency(lfs_t *lfs); -static int lfs_deinit(lfs_t *lfs); +#endif + #ifdef LFS_MIGRATE static int lfs1_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data); #endif +static int lfs_dir_rawrewind(lfs_t *lfs, lfs_dir_t *dir); + +static lfs_ssize_t lfs_file_rawread(lfs_t *lfs, lfs_file_t *file, + void *buffer, lfs_size_t size); +static int lfs_file_rawclose(lfs_t *lfs, lfs_file_t *file); +static lfs_soff_t lfs_file_rawsize(lfs_t *lfs, lfs_file_t *file); + +static lfs_ssize_t lfs_fs_rawsize(lfs_t *lfs); +static int lfs_fs_rawtraverse(lfs_t *lfs, + int (*cb)(void *data, lfs_block_t block), void *data, + bool includeorphans); + +static int lfs_deinit(lfs_t *lfs); +static int lfs_rawunmount(lfs_t *lfs); + + /// Block allocator /// +#ifndef LFS_READONLY static int lfs_alloc_lookahead(void *p, lfs_block_t block) { lfs_t *lfs = (lfs_t*)p; lfs_block_t off = ((block - lfs->free.off) @@ -452,20 +513,24 @@ static int lfs_alloc_lookahead(void *p, lfs_block_t block) { return 0; } +#endif +// indicate allocated blocks have been committed into the filesystem, this +// is to prevent blocks from being garbage collected in the middle of a +// commit operation static void lfs_alloc_ack(lfs_t *lfs) { lfs->free.ack = lfs->cfg->block_count; } -// Invalidate the lookahead buffer. This is done during mounting and -// failed traversals -static void lfs_alloc_reset(lfs_t *lfs) { - lfs->free.off = lfs->seed % lfs->cfg->block_size; +// drop the lookahead buffer, this is done during mounting and failed +// traversals in order to avoid invalid lookahead state +static void lfs_alloc_drop(lfs_t *lfs) { lfs->free.size = 0; lfs->free.i = 0; lfs_alloc_ack(lfs); } +#ifndef LFS_READONLY static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { while (true) { while (lfs->free.i != lfs->free.size) { @@ -504,13 +569,14 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { // find mask of free blocks from tree memset(lfs->free.buffer, 0, lfs->cfg->lookahead_size); - int err = lfs_fs_traverseraw(lfs, lfs_alloc_lookahead, lfs, true); + int err = lfs_fs_rawtraverse(lfs, lfs_alloc_lookahead, lfs, true); if (err) { - lfs_alloc_reset(lfs); + lfs_alloc_drop(lfs); return err; } } } +#endif /// Metadata pair and directory operations /// static lfs_stag_t lfs_dir_getslice(lfs_t *lfs, const lfs_mdir_t *dir, @@ -643,6 +709,7 @@ static int lfs_dir_getread(lfs_t *lfs, const lfs_mdir_t *dir, return 0; } +#ifndef LFS_READONLY static int lfs_dir_traverse_filter(void *p, lfs_tag_t tag, const void *buffer) { lfs_tag_t *filtertag = p; @@ -670,7 +737,9 @@ static int lfs_dir_traverse_filter(void *p, return false; } +#endif +#ifndef LFS_READONLY static int lfs_dir_traverse(lfs_t *lfs, const lfs_mdir_t *dir, lfs_off_t off, lfs_tag_t ptag, const struct lfs_mattr *attrs, int attrcount, @@ -764,6 +833,7 @@ static int lfs_dir_traverse(lfs_t *lfs, } } } +#endif static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs, lfs_mdir_t *dir, const lfs_block_t pair[2], @@ -871,8 +941,10 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs, ptag ^= (lfs_tag_t)(lfs_tag_chunk(tag) & 1U) << 31; // toss our crc into the filesystem seed for - // pseudorandom numbers - lfs->seed ^= crc; + // pseudorandom numbers, note we use another crc here + // as a collection function because it is sufficiently + // random and convenient + lfs->seed = lfs_crc(lfs->seed, &crc, sizeof(crc)); // update with what's found so far besttag = tempbesttag; @@ -1201,6 +1273,7 @@ struct lfs_commit { lfs_off_t end; }; +#ifndef LFS_READONLY static int lfs_dir_commitprog(lfs_t *lfs, struct lfs_commit *commit, const void *buffer, lfs_size_t size) { int err = lfs_bd_prog(lfs, @@ -1215,7 +1288,9 @@ static int lfs_dir_commitprog(lfs_t *lfs, struct lfs_commit *commit, commit->off += size; return 0; } +#endif +#ifndef LFS_READONLY static int lfs_dir_commitattr(lfs_t *lfs, struct lfs_commit *commit, lfs_tag_t tag, const void *buffer) { // check if we fit @@ -1260,14 +1335,17 @@ static int lfs_dir_commitattr(lfs_t *lfs, struct lfs_commit *commit, commit->ptag = tag & 0x7fffffff; return 0; } +#endif +#ifndef LFS_READONLY static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) { - const lfs_off_t off1 = commit->off; - const uint32_t crc1 = commit->crc; // align to program units - const lfs_off_t end = lfs_alignup(off1 + 2*sizeof(uint32_t), + const lfs_off_t end = lfs_alignup(commit->off + 2*sizeof(uint32_t), lfs->cfg->prog_size); + lfs_off_t off1 = 0; + uint32_t crc1 = 0; + // create crc tags to fill up remainder of commit, note that // padding is not crced, which lets fetches skip padding but // makes committing a bit more complicated @@ -1303,6 +1381,12 @@ static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) { return err; } + // keep track of non-padding checksum to verify + if (off1 == 0) { + off1 = commit->off + sizeof(uint32_t); + crc1 = commit->crc; + } + commit->off += sizeof(tag)+lfs_tag_size(tag); commit->ptag = tag ^ ((lfs_tag_t)reset << 31); commit->crc = 0xffffffff; // reset crc for next "commit" @@ -1316,7 +1400,7 @@ static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) { // successful commit, check checksums to make sure lfs_off_t off = commit->begin; - lfs_off_t noff = off1 + sizeof(uint32_t); + lfs_off_t noff = off1; while (off < end) { uint32_t crc = 0xffffffff; for (lfs_off_t i = off; i < noff+sizeof(uint32_t); i++) { @@ -1353,7 +1437,9 @@ static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) { return 0; } +#endif +#ifndef LFS_READONLY static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir) { // allocate pair of dir blocks (backwards, so we write block 1 first) for (int i = 0; i < 2; i++) { @@ -1376,8 +1462,12 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir) { return err; } - // make sure we don't immediately evict - dir->rev += dir->rev & 1; + // to make sure we don't immediately evict, align the new revision count + // to our block_cycles modulus, see lfs_dir_compact for why our modulus + // is tweaked this way + if (lfs->cfg->block_cycles > 0) { + dir->rev = lfs_alignup(dir->rev, ((lfs->cfg->block_cycles+1)|1)); + } // set defaults dir->off = sizeof(dir->rev); @@ -1391,7 +1481,9 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir) { // don't write out yet, let caller take care of that return 0; } +#endif +#ifndef LFS_READONLY static int lfs_dir_drop(lfs_t *lfs, lfs_mdir_t *dir, lfs_mdir_t *tail) { // steal state int err = lfs_dir_getgstate(lfs, tail, &lfs->gdelta); @@ -1410,7 +1502,9 @@ static int lfs_dir_drop(lfs_t *lfs, lfs_mdir_t *dir, lfs_mdir_t *tail) { return 0; } +#endif +#ifndef LFS_READONLY static int lfs_dir_split(lfs_t *lfs, lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount, lfs_mdir_t *source, uint16_t split, uint16_t end) { @@ -1443,7 +1537,9 @@ static int lfs_dir_split(lfs_t *lfs, return 0; } +#endif +#ifndef LFS_READONLY static int lfs_dir_commit_size(void *p, lfs_tag_t tag, const void *buffer) { lfs_size_t *size = p; (void)buffer; @@ -1451,17 +1547,23 @@ static int lfs_dir_commit_size(void *p, lfs_tag_t tag, const void *buffer) { *size += lfs_tag_dsize(tag); return 0; } +#endif +#ifndef LFS_READONLY struct lfs_dir_commit_commit { lfs_t *lfs; struct lfs_commit *commit; }; +#endif +#ifndef LFS_READONLY static int lfs_dir_commit_commit(void *p, lfs_tag_t tag, const void *buffer) { struct lfs_dir_commit_commit *commit = p; return lfs_dir_commitattr(commit->lfs, commit->commit, tag, buffer); } +#endif +#ifndef LFS_READONLY static int lfs_dir_compact(lfs_t *lfs, lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount, lfs_mdir_t *source, uint16_t begin, uint16_t end) { @@ -1489,7 +1591,8 @@ static int lfs_dir_compact(lfs_t *lfs, // for metadata updates. if (end - begin < 0xff && size <= lfs_min(lfs->cfg->block_size - 36, - lfs_alignup(lfs->cfg->block_size/2, + lfs_alignup((lfs->cfg->metadata_max ? + lfs->cfg->metadata_max : lfs->cfg->block_size)/2, lfs->cfg->prog_size))) { break; } @@ -1526,7 +1629,7 @@ static int lfs_dir_compact(lfs_t *lfs, if (lfs_pair_cmp(dir->pair, (const lfs_block_t[2]){0, 1}) == 0) { // oh no! we're writing too much to the superblock, // should we expand? - lfs_ssize_t res = lfs_fs_size(lfs); + lfs_ssize_t res = lfs_fs_rawsize(lfs); if (res < 0) { return res; } @@ -1574,7 +1677,8 @@ static int lfs_dir_compact(lfs_t *lfs, .crc = 0xffffffff, .begin = 0, - .end = lfs->cfg->block_size - 8, + .end = (lfs->cfg->metadata_max ? + lfs->cfg->metadata_max : lfs->cfg->block_size) - 8, }; // erase block to write to @@ -1716,7 +1820,9 @@ static int lfs_dir_compact(lfs_t *lfs, return 0; } +#endif +#ifndef LFS_READONLY static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount) { // check for any inline files that aren't RAM backed and @@ -1782,7 +1888,8 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, .crc = 0xffffffff, .begin = dir->off, - .end = lfs->cfg->block_size - 8, + .end = (lfs->cfg->metadata_max ? + lfs->cfg->metadata_max : lfs->cfg->block_size) - 8, }; // traverse attrs that need to be written out @@ -1904,15 +2011,15 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, return 0; } +#endif /// Top level directory operations /// -int lfs_mkdir(lfs_t *lfs, const char *path) { - LFS_TRACE("lfs_mkdir(%p, \"%s\")", (void*)lfs, path); +#ifndef LFS_READONLY +static int lfs_rawmkdir(lfs_t *lfs, const char *path) { // deorphan if we haven't yet, needed at most once after poweron int err = lfs_fs_forceconsistency(lfs); if (err) { - LFS_TRACE("lfs_mkdir -> %d", err); return err; } @@ -1921,14 +2028,12 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { uint16_t id; err = lfs_dir_find(lfs, &cwd.m, &path, &id); if (!(err == LFS_ERR_NOENT && id != 0x3ff)) { - LFS_TRACE("lfs_mkdir -> %d", (err < 0) ? err : LFS_ERR_EXIST); return (err < 0) ? err : LFS_ERR_EXIST; } // check that name fits lfs_size_t nlen = strlen(path); if (nlen > lfs->name_max) { - LFS_TRACE("lfs_mkdir -> %d", LFS_ERR_NAMETOOLONG); return LFS_ERR_NAMETOOLONG; } @@ -1937,7 +2042,6 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { lfs_mdir_t dir; err = lfs_dir_alloc(lfs, &dir); if (err) { - LFS_TRACE("lfs_mkdir -> %d", err); return err; } @@ -1946,7 +2050,6 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { while (pred.split) { err = lfs_dir_fetch(lfs, &pred, pred.tail); if (err) { - LFS_TRACE("lfs_mkdir -> %d", err); return err; } } @@ -1957,14 +2060,16 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { {LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), pred.tail})); lfs_pair_fromle32(pred.tail); if (err) { - LFS_TRACE("lfs_mkdir -> %d", err); return err; } // current block end of list? if (cwd.m.split) { // update tails, this creates a desync - lfs_fs_preporphans(lfs, +1); + err = lfs_fs_preporphans(lfs, +1); + if (err) { + return err; + } // it's possible our predecessor has to be relocated, and if // our parent is our predecessor's predecessor, this could have @@ -1980,12 +2085,14 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { lfs_pair_fromle32(dir.pair); if (err) { lfs->mlist = cwd.next; - LFS_TRACE("lfs_mkdir -> %d", err); return err; } lfs->mlist = cwd.next; - lfs_fs_preporphans(lfs, -1); + err = lfs_fs_preporphans(lfs, -1); + if (err) { + return err; + } } // now insert into our parent block @@ -1998,24 +2105,20 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { LFS_TYPE_SOFTTAIL, 0x3ff, 8), dir.pair})); lfs_pair_fromle32(dir.pair); if (err) { - LFS_TRACE("lfs_mkdir -> %d", err); return err; } - LFS_TRACE("lfs_mkdir -> %d", 0); return 0; } +#endif -int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) { - LFS_TRACE("lfs_dir_open(%p, %p, \"%s\")", (void*)lfs, (void*)dir, path); +static int lfs_dir_rawopen(lfs_t *lfs, lfs_dir_t *dir, const char *path) { lfs_stag_t tag = lfs_dir_find(lfs, &dir->m, &path, NULL); if (tag < 0) { - LFS_TRACE("lfs_dir_open -> %"PRId32, tag); return tag; } if (lfs_tag_type3(tag) != LFS_TYPE_DIR) { - LFS_TRACE("lfs_dir_open -> %d", LFS_ERR_NOTDIR); return LFS_ERR_NOTDIR; } @@ -2029,7 +2132,6 @@ int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) { lfs_stag_t res = lfs_dir_get(lfs, &dir->m, LFS_MKTAG(0x700, 0x3ff, 0), LFS_MKTAG(LFS_TYPE_STRUCT, lfs_tag_id(tag), 8), pair); if (res < 0) { - LFS_TRACE("lfs_dir_open -> %"PRId32, res); return res; } lfs_pair_fromle32(pair); @@ -2038,7 +2140,6 @@ int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) { // fetch first pair int err = lfs_dir_fetch(lfs, &dir->m, pair); if (err) { - LFS_TRACE("lfs_dir_open -> %d", err); return err; } @@ -2050,30 +2151,19 @@ int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) { // add to list of mdirs dir->type = LFS_TYPE_DIR; - dir->next = (lfs_dir_t*)lfs->mlist; - lfs->mlist = (struct lfs_mlist*)dir; + lfs_mlist_append(lfs, (struct lfs_mlist *)dir); - LFS_TRACE("lfs_dir_open -> %d", 0); return 0; } -int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir) { - LFS_TRACE("lfs_dir_close(%p, %p)", (void*)lfs, (void*)dir); +static int lfs_dir_rawclose(lfs_t *lfs, lfs_dir_t *dir) { // remove from list of mdirs - for (struct lfs_mlist **p = &lfs->mlist; *p; p = &(*p)->next) { - if (*p == (struct lfs_mlist*)dir) { - *p = (*p)->next; - break; - } - } + lfs_mlist_remove(lfs, (struct lfs_mlist *)dir); - LFS_TRACE("lfs_dir_close -> %d", 0); return 0; } -int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) { - LFS_TRACE("lfs_dir_read(%p, %p, %p)", - (void*)lfs, (void*)dir, (void*)info); +static int lfs_dir_rawread(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) { memset(info, 0, sizeof(*info)); // special offset for '.' and '..' @@ -2081,26 +2171,22 @@ int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) { info->type = LFS_TYPE_DIR; strcpy(info->name, "."); dir->pos += 1; - LFS_TRACE("lfs_dir_read -> %d", true); return true; } else if (dir->pos == 1) { info->type = LFS_TYPE_DIR; strcpy(info->name, ".."); dir->pos += 1; - LFS_TRACE("lfs_dir_read -> %d", true); return true; } while (true) { if (dir->id == dir->m.count) { if (!dir->m.split) { - LFS_TRACE("lfs_dir_read -> %d", false); return false; } int err = lfs_dir_fetch(lfs, &dir->m, dir->m.tail); if (err) { - LFS_TRACE("lfs_dir_read -> %d", err); return err; } @@ -2109,7 +2195,6 @@ int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) { int err = lfs_dir_getinfo(lfs, &dir->m, dir->id, info); if (err && err != LFS_ERR_NOENT) { - LFS_TRACE("lfs_dir_read -> %d", err); return err; } @@ -2120,17 +2205,13 @@ int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) { } dir->pos += 1; - LFS_TRACE("lfs_dir_read -> %d", true); return true; } -int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) { - LFS_TRACE("lfs_dir_seek(%p, %p, %"PRIu32")", - (void*)lfs, (void*)dir, off); +static int lfs_dir_rawseek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) { // simply walk from head dir - int err = lfs_dir_rewind(lfs, dir); + int err = lfs_dir_rawrewind(lfs, dir); if (err) { - LFS_TRACE("lfs_dir_seek -> %d", err); return err; } @@ -2149,13 +2230,11 @@ int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) { if (dir->id == dir->m.count) { if (!dir->m.split) { - LFS_TRACE("lfs_dir_seek -> %d", LFS_ERR_INVAL); return LFS_ERR_INVAL; } err = lfs_dir_fetch(lfs, &dir->m, dir->m.tail); if (err) { - LFS_TRACE("lfs_dir_seek -> %d", err); return err; } @@ -2163,29 +2242,23 @@ int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) { } } - LFS_TRACE("lfs_dir_seek -> %d", 0); return 0; } -lfs_soff_t lfs_dir_tell(lfs_t *lfs, lfs_dir_t *dir) { - LFS_TRACE("lfs_dir_tell(%p, %p)", (void*)lfs, (void*)dir); +static lfs_soff_t lfs_dir_rawtell(lfs_t *lfs, lfs_dir_t *dir) { (void)lfs; - LFS_TRACE("lfs_dir_tell -> %"PRId32, dir->pos); return dir->pos; } -int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir) { - LFS_TRACE("lfs_dir_rewind(%p, %p)", (void*)lfs, (void*)dir); +static int lfs_dir_rawrewind(lfs_t *lfs, lfs_dir_t *dir) { // reload the head dir int err = lfs_dir_fetch(lfs, &dir->m, dir->head); if (err) { - LFS_TRACE("lfs_dir_rewind -> %d", err); return err; } dir->id = 0; dir->pos = 0; - LFS_TRACE("lfs_dir_rewind -> %d", 0); return 0; } @@ -2238,6 +2311,7 @@ static int lfs_ctz_find(lfs_t *lfs, return 0; } +#ifndef LFS_READONLY static int lfs_ctz_extend(lfs_t *lfs, lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_block_t head, lfs_size_t size, @@ -2335,6 +2409,7 @@ static int lfs_ctz_extend(lfs_t *lfs, lfs_cache_drop(lfs, pcache); } } +#endif static int lfs_ctz_traverse(lfs_t *lfs, const lfs_cache_t *pcache, lfs_cache_t *rcache, @@ -2381,27 +2456,25 @@ static int lfs_ctz_traverse(lfs_t *lfs, /// Top level file operations /// -int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, +static int lfs_file_rawopencfg(lfs_t *lfs, lfs_file_t *file, const char *path, int flags, const struct lfs_file_config *cfg) { - LFS_TRACE("lfs_file_opencfg(%p, %p, \"%s\", %x, %p {" - ".buffer=%p, .attrs=%p, .attr_count=%"PRIu32"})", - (void*)lfs, (void*)file, path, flags, - (void*)cfg, cfg->buffer, (void*)cfg->attrs, cfg->attr_count); - +#ifndef LFS_READONLY // deorphan if we haven't yet, needed at most once after poweron - if ((flags & 3) != LFS_O_RDONLY) { + if ((flags & LFS_O_WRONLY) == LFS_O_WRONLY) { int err = lfs_fs_forceconsistency(lfs); if (err) { - LFS_TRACE("lfs_file_opencfg -> %d", err); return err; } } +#else + LFS_ASSERT((flags & LFS_O_RDONLY) == LFS_O_RDONLY); +#endif // setup simple file details int err; file->cfg = cfg; - file->flags = flags | LFS_F_OPENED; + file->flags = flags; file->pos = 0; file->off = 0; file->cache.buffer = NULL; @@ -2415,9 +2488,13 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, // get id, add to list of mdirs to catch update changes file->type = LFS_TYPE_REG; - file->next = (lfs_file_t*)lfs->mlist; - lfs->mlist = (struct lfs_mlist*)file; + lfs_mlist_append(lfs, (struct lfs_mlist *)file); +#ifdef LFS_READONLY + if (tag == LFS_ERR_NOENT) { + err = LFS_ERR_NOENT; + goto cleanup; +#else if (tag == LFS_ERR_NOENT) { if (!(flags & LFS_O_CREAT)) { err = LFS_ERR_NOENT; @@ -2445,13 +2522,16 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, } else if (flags & LFS_O_EXCL) { err = LFS_ERR_EXIST; goto cleanup; +#endif } else if (lfs_tag_type3(tag) != LFS_TYPE_REG) { err = LFS_ERR_ISDIR; goto cleanup; +#ifndef LFS_READONLY } else if (flags & LFS_O_TRUNC) { // truncate if requested tag = LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0); file->flags |= LFS_F_DIRTY; +#endif } else { // try to load what's on disk, if it's inlined we'll fix it later tag = lfs_dir_get(lfs, &file->m, LFS_MKTAG(0x700, 0x3ff, 0), @@ -2465,7 +2545,8 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, // fetch attrs for (unsigned i = 0; i < file->cfg->attr_count; i++) { - if ((file->flags & 3) != LFS_O_WRONLY) { + // if opened for read / read-write operations + if ((file->flags & LFS_O_RDONLY) == LFS_O_RDONLY) { lfs_stag_t res = lfs_dir_get(lfs, &file->m, LFS_MKTAG(0x7ff, 0x3ff, 0), LFS_MKTAG(LFS_TYPE_USERATTR + file->cfg->attrs[i].type, @@ -2477,7 +2558,9 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, } } - if ((file->flags & 3) != LFS_O_RDONLY) { +#ifndef LFS_READONLY + // if opened for write / read-write operations + if ((file->flags & LFS_O_WRONLY) == LFS_O_WRONLY) { if (file->cfg->attrs[i].size > lfs->attr_max) { err = LFS_ERR_NOSPC; goto cleanup; @@ -2485,6 +2568,7 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, file->flags |= LFS_F_DIRTY; } +#endif } // allocate buffer if needed @@ -2524,54 +2608,45 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, } } - LFS_TRACE("lfs_file_opencfg -> %d", 0); return 0; cleanup: // clean up lingering resources +#ifndef LFS_READONLY file->flags |= LFS_F_ERRED; - lfs_file_close(lfs, file); - LFS_TRACE("lfs_file_opencfg -> %d", err); +#endif + lfs_file_rawclose(lfs, file); return err; } -int lfs_file_open(lfs_t *lfs, lfs_file_t *file, +static int lfs_file_rawopen(lfs_t *lfs, lfs_file_t *file, const char *path, int flags) { - LFS_TRACE("lfs_file_open(%p, %p, \"%s\", %x)", - (void*)lfs, (void*)file, path, flags); static const struct lfs_file_config defaults = {0}; - int err = lfs_file_opencfg(lfs, file, path, flags, &defaults); - LFS_TRACE("lfs_file_open -> %d", err); + int err = lfs_file_rawopencfg(lfs, file, path, flags, &defaults); return err; } -int lfs_file_close(lfs_t *lfs, lfs_file_t *file) { - LFS_TRACE("lfs_file_close(%p, %p)", (void*)lfs, (void*)file); - LFS_ASSERT(file->flags & LFS_F_OPENED); - - int err = lfs_file_sync(lfs, file); +static int lfs_file_rawclose(lfs_t *lfs, lfs_file_t *file) { +#ifndef LFS_READONLY + int err = lfs_file_rawsync(lfs, file); +#else + int err = 0; +#endif // remove from list of mdirs - for (struct lfs_mlist **p = &lfs->mlist; *p; p = &(*p)->next) { - if (*p == (struct lfs_mlist*)file) { - *p = (*p)->next; - break; - } - } + lfs_mlist_remove(lfs, (struct lfs_mlist*)file); // clean up memory if (!file->cfg->buffer) { lfs_free(file->cache.buffer); } - file->flags &= ~LFS_F_OPENED; - LFS_TRACE("lfs_file_close -> %d", err); return err; } -static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) { - LFS_ASSERT(file->flags & LFS_F_OPENED); +#ifndef LFS_READONLY +static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) { while (true) { // just relocate what exists into new block lfs_block_t nblock; @@ -2639,7 +2714,9 @@ static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) { lfs_cache_drop(lfs, &lfs->pcache); } } +#endif +#ifndef LFS_READONLY static int lfs_file_outline(lfs_t *lfs, lfs_file_t *file) { file->off = file->pos; lfs_alloc_ack(lfs); @@ -2651,10 +2728,10 @@ static int lfs_file_outline(lfs_t *lfs, lfs_file_t *file) { file->flags &= ~LFS_F_INLINE; return 0; } +#endif +#ifndef LFS_READONLY static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { - LFS_ASSERT(file->flags & LFS_F_OPENED); - if (file->flags & LFS_F_READING) { if (!(file->flags & LFS_F_INLINE)) { lfs_cache_drop(lfs, &file->cache); @@ -2670,7 +2747,7 @@ static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { lfs_file_t orig = { .ctz.head = file->ctz.head, .ctz.size = file->ctz.size, - .flags = LFS_O_RDONLY | LFS_F_OPENED, + .flags = LFS_O_RDONLY, .pos = file->pos, .cache = lfs->rcache, }; @@ -2680,12 +2757,12 @@ static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { // copy over a byte at a time, leave it up to caching // to make this efficient uint8_t data; - lfs_ssize_t res = lfs_file_read(lfs, &orig, &data, 1); + lfs_ssize_t res = lfs_file_rawread(lfs, &orig, &data, 1); if (res < 0) { return res; } - res = lfs_file_write(lfs, file, &data, 1); + res = lfs_file_rawwrite(lfs, file, &data, 1); if (res < 0) { return res; } @@ -2731,24 +2808,22 @@ static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { return 0; } +#endif -int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { - LFS_TRACE("lfs_file_sync(%p, %p)", (void*)lfs, (void*)file); - LFS_ASSERT(file->flags & LFS_F_OPENED); - +#ifndef LFS_READONLY +static int lfs_file_rawsync(lfs_t *lfs, lfs_file_t *file) { if (file->flags & LFS_F_ERRED) { // it's not safe to do anything if our file errored - LFS_TRACE("lfs_file_sync -> %d", 0); return 0; } int err = lfs_file_flush(lfs, file); if (err) { file->flags |= LFS_F_ERRED; - LFS_TRACE("lfs_file_sync -> %d", err); return err; } + if ((file->flags & LFS_F_DIRTY) && !lfs_pair_isnull(file->m.pair)) { // update dir entry @@ -2778,39 +2853,35 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { file->cfg->attr_count), file->cfg->attrs})); if (err) { file->flags |= LFS_F_ERRED; - LFS_TRACE("lfs_file_sync -> %d", err); return err; } file->flags &= ~LFS_F_DIRTY; } - LFS_TRACE("lfs_file_sync -> %d", 0); return 0; } +#endif -lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, +static lfs_ssize_t lfs_file_rawread(lfs_t *lfs, lfs_file_t *file, void *buffer, lfs_size_t size) { - LFS_TRACE("lfs_file_read(%p, %p, %p, %"PRIu32")", - (void*)lfs, (void*)file, buffer, size); - LFS_ASSERT(file->flags & LFS_F_OPENED); - LFS_ASSERT((file->flags & 3) != LFS_O_WRONLY); + LFS_ASSERT((file->flags & LFS_O_RDONLY) == LFS_O_RDONLY); uint8_t *data = buffer; lfs_size_t nsize = size; +#ifndef LFS_READONLY if (file->flags & LFS_F_WRITING) { // flush out any writes int err = lfs_file_flush(lfs, file); if (err) { - LFS_TRACE("lfs_file_read -> %d", err); return err; } } +#endif if (file->pos >= file->ctz.size) { // eof if past end - LFS_TRACE("lfs_file_read -> %d", 0); return 0; } @@ -2826,7 +2897,6 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, file->ctz.head, file->ctz.size, file->pos, &file->block, &file->off); if (err) { - LFS_TRACE("lfs_file_read -> %d", err); return err; } } else { @@ -2846,7 +2916,6 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0), file->off, data, diff); if (err) { - LFS_TRACE("lfs_file_read -> %d", err); return err; } } else { @@ -2854,7 +2923,6 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, NULL, &file->cache, lfs->cfg->block_size, file->block, file->off, data, diff); if (err) { - LFS_TRACE("lfs_file_read -> %d", err); return err; } } @@ -2865,16 +2933,13 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, nsize -= diff; } - LFS_TRACE("lfs_file_read -> %"PRId32, size); return size; } -lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, +#ifndef LFS_READONLY +static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file, const void *buffer, lfs_size_t size) { - LFS_TRACE("lfs_file_write(%p, %p, %p, %"PRIu32")", - (void*)lfs, (void*)file, buffer, size); - LFS_ASSERT(file->flags & LFS_F_OPENED); - LFS_ASSERT((file->flags & 3) != LFS_O_RDONLY); + LFS_ASSERT((file->flags & LFS_O_WRONLY) == LFS_O_WRONLY); const uint8_t *data = buffer; lfs_size_t nsize = size; @@ -2883,7 +2948,6 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, // drop any reads int err = lfs_file_flush(lfs, file); if (err) { - LFS_TRACE("lfs_file_write -> %d", err); return err; } } @@ -2894,7 +2958,6 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, if (file->pos + size > lfs->file_max) { // Larger than file limit? - LFS_TRACE("lfs_file_write -> %d", LFS_ERR_FBIG); return LFS_ERR_FBIG; } @@ -2904,9 +2967,8 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, file->pos = file->ctz.size; while (file->pos < pos) { - lfs_ssize_t res = lfs_file_write(lfs, file, &(uint8_t){0}, 1); + lfs_ssize_t res = lfs_file_rawwrite(lfs, file, &(uint8_t){0}, 1); if (res < 0) { - LFS_TRACE("lfs_file_write -> %"PRId32, res); return res; } } @@ -2915,12 +2977,13 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, if ((file->flags & LFS_F_INLINE) && lfs_max(file->pos+nsize, file->ctz.size) > lfs_min(0x3fe, lfs_min( - lfs->cfg->cache_size, lfs->cfg->block_size/8))) { + lfs->cfg->cache_size, + (lfs->cfg->metadata_max ? + lfs->cfg->metadata_max : lfs->cfg->block_size) / 8))) { // inline file doesn't fit anymore int err = lfs_file_outline(lfs, file); if (err) { file->flags |= LFS_F_ERRED; - LFS_TRACE("lfs_file_write -> %d", err); return err; } } @@ -2937,7 +3000,6 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, file->pos-1, &file->block, &file->off); if (err) { file->flags |= LFS_F_ERRED; - LFS_TRACE("lfs_file_write -> %d", err); return err; } @@ -2952,7 +3014,6 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, &file->block, &file->off); if (err) { file->flags |= LFS_F_ERRED; - LFS_TRACE("lfs_file_write -> %d", err); return err; } } else { @@ -2973,7 +3034,6 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, goto relocate; } file->flags |= LFS_F_ERRED; - LFS_TRACE("lfs_file_write -> %d", err); return err; } @@ -2982,7 +3042,6 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, err = lfs_file_relocate(lfs, file); if (err) { file->flags |= LFS_F_ERRED; - LFS_TRACE("lfs_file_write -> %d", err); return err; } } @@ -2996,23 +3055,12 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, } file->flags &= ~LFS_F_ERRED; - LFS_TRACE("lfs_file_write -> %"PRId32, size); return size; } +#endif -lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, +static lfs_soff_t lfs_file_rawseek(lfs_t *lfs, lfs_file_t *file, lfs_soff_t off, int whence) { - LFS_TRACE("lfs_file_seek(%p, %p, %"PRId32", %d)", - (void*)lfs, (void*)file, off, whence); - LFS_ASSERT(file->flags & LFS_F_OPENED); - - // write out everything beforehand, may be noop if rdonly - int err = lfs_file_flush(lfs, file); - if (err) { - LFS_TRACE("lfs_file_seek -> %d", err); - return err; - } - // find new pos lfs_off_t npos = file->pos; if (whence == LFS_SEEK_SET) { @@ -3020,39 +3068,46 @@ lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, } else if (whence == LFS_SEEK_CUR) { npos = file->pos + off; } else if (whence == LFS_SEEK_END) { - npos = file->ctz.size + off; + npos = lfs_file_rawsize(lfs, file) + off; } if (npos > lfs->file_max) { // file position out of range - LFS_TRACE("lfs_file_seek -> %d", LFS_ERR_INVAL); return LFS_ERR_INVAL; } + if (file->pos == npos) { + // noop - position has not changed + return npos; + } + +#ifndef LFS_READONLY + // write out everything beforehand, may be noop if rdonly + int err = lfs_file_flush(lfs, file); + if (err) { + return err; + } +#endif + // update pos file->pos = npos; - LFS_TRACE("lfs_file_seek -> %"PRId32, npos); return npos; } -int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { - LFS_TRACE("lfs_file_truncate(%p, %p, %"PRIu32")", - (void*)lfs, (void*)file, size); - LFS_ASSERT(file->flags & LFS_F_OPENED); - LFS_ASSERT((file->flags & 3) != LFS_O_RDONLY); +#ifndef LFS_READONLY +static int lfs_file_rawtruncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { + LFS_ASSERT((file->flags & LFS_O_WRONLY) == LFS_O_WRONLY); if (size > LFS_FILE_MAX) { - LFS_TRACE("lfs_file_truncate -> %d", LFS_ERR_INVAL); return LFS_ERR_INVAL; } lfs_off_t pos = file->pos; - lfs_off_t oldsize = lfs_file_size(lfs, file); + lfs_off_t oldsize = lfs_file_rawsize(lfs, file); if (size < oldsize) { // need to flush since directly changing metadata int err = lfs_file_flush(lfs, file); if (err) { - LFS_TRACE("lfs_file_truncate -> %d", err); return err; } @@ -3061,107 +3116,90 @@ int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { file->ctz.head, file->ctz.size, size, &file->block, &file->off); if (err) { - LFS_TRACE("lfs_file_truncate -> %d", err); return err; } + // need to set pos/block/off consistently so seeking back to + // the old position does not get confused + file->pos = size; file->ctz.head = file->block; file->ctz.size = size; file->flags |= LFS_F_DIRTY | LFS_F_READING; } else if (size > oldsize) { // flush+seek if not already at end - if (file->pos != oldsize) { - lfs_soff_t res = lfs_file_seek(lfs, file, 0, LFS_SEEK_END); - if (res < 0) { - LFS_TRACE("lfs_file_truncate -> %"PRId32, res); - return (int)res; - } + lfs_soff_t res = lfs_file_rawseek(lfs, file, 0, LFS_SEEK_END); + if (res < 0) { + return (int)res; } // fill with zeros while (file->pos < size) { - lfs_ssize_t res = lfs_file_write(lfs, file, &(uint8_t){0}, 1); + res = lfs_file_rawwrite(lfs, file, &(uint8_t){0}, 1); if (res < 0) { - LFS_TRACE("lfs_file_truncate -> %"PRId32, res); return (int)res; } } } // restore pos - lfs_soff_t res = lfs_file_seek(lfs, file, pos, LFS_SEEK_SET); + lfs_soff_t res = lfs_file_rawseek(lfs, file, pos, LFS_SEEK_SET); if (res < 0) { - LFS_TRACE("lfs_file_truncate -> %"PRId32, res); return (int)res; } - LFS_TRACE("lfs_file_truncate -> %d", 0); return 0; } +#endif -lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file) { - LFS_TRACE("lfs_file_tell(%p, %p)", (void*)lfs, (void*)file); - LFS_ASSERT(file->flags & LFS_F_OPENED); +static lfs_soff_t lfs_file_rawtell(lfs_t *lfs, lfs_file_t *file) { (void)lfs; - LFS_TRACE("lfs_file_tell -> %"PRId32, file->pos); return file->pos; } -int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file) { - LFS_TRACE("lfs_file_rewind(%p, %p)", (void*)lfs, (void*)file); - lfs_soff_t res = lfs_file_seek(lfs, file, 0, LFS_SEEK_SET); +static int lfs_file_rawrewind(lfs_t *lfs, lfs_file_t *file) { + lfs_soff_t res = lfs_file_rawseek(lfs, file, 0, LFS_SEEK_SET); if (res < 0) { - LFS_TRACE("lfs_file_rewind -> %"PRId32, res); return (int)res; } - LFS_TRACE("lfs_file_rewind -> %d", 0); return 0; } -lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file) { - LFS_TRACE("lfs_file_size(%p, %p)", (void*)lfs, (void*)file); - LFS_ASSERT(file->flags & LFS_F_OPENED); +static lfs_soff_t lfs_file_rawsize(lfs_t *lfs, lfs_file_t *file) { (void)lfs; + +#ifndef LFS_READONLY if (file->flags & LFS_F_WRITING) { - LFS_TRACE("lfs_file_size -> %"PRId32, - lfs_max(file->pos, file->ctz.size)); return lfs_max(file->pos, file->ctz.size); - } else { - LFS_TRACE("lfs_file_size -> %"PRId32, file->ctz.size); - return file->ctz.size; } +#endif + + return file->ctz.size; } /// General fs operations /// -int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) { - LFS_TRACE("lfs_stat(%p, \"%s\", %p)", (void*)lfs, path, (void*)info); +static int lfs_rawstat(lfs_t *lfs, const char *path, struct lfs_info *info) { lfs_mdir_t cwd; lfs_stag_t tag = lfs_dir_find(lfs, &cwd, &path, NULL); if (tag < 0) { - LFS_TRACE("lfs_stat -> %"PRId32, tag); return (int)tag; } - int err = lfs_dir_getinfo(lfs, &cwd, lfs_tag_id(tag), info); - LFS_TRACE("lfs_stat -> %d", err); - return err; + return lfs_dir_getinfo(lfs, &cwd, lfs_tag_id(tag), info); } -int lfs_remove(lfs_t *lfs, const char *path) { - LFS_TRACE("lfs_remove(%p, \"%s\")", (void*)lfs, path); +#ifndef LFS_READONLY +static int lfs_rawremove(lfs_t *lfs, const char *path) { // deorphan if we haven't yet, needed at most once after poweron int err = lfs_fs_forceconsistency(lfs); if (err) { - LFS_TRACE("lfs_remove -> %d", err); return err; } lfs_mdir_t cwd; lfs_stag_t tag = lfs_dir_find(lfs, &cwd, &path, NULL); if (tag < 0 || lfs_tag_id(tag) == 0x3ff) { - LFS_TRACE("lfs_remove -> %"PRId32, (tag < 0) ? tag : LFS_ERR_INVAL); return (tag < 0) ? (int)tag : LFS_ERR_INVAL; } @@ -3173,24 +3211,24 @@ int lfs_remove(lfs_t *lfs, const char *path) { lfs_stag_t res = lfs_dir_get(lfs, &cwd, LFS_MKTAG(0x700, 0x3ff, 0), LFS_MKTAG(LFS_TYPE_STRUCT, lfs_tag_id(tag), 8), pair); if (res < 0) { - LFS_TRACE("lfs_remove -> %"PRId32, res); return (int)res; } lfs_pair_fromle32(pair); err = lfs_dir_fetch(lfs, &dir.m, pair); if (err) { - LFS_TRACE("lfs_remove -> %d", err); return err; } if (dir.m.count > 0 || dir.m.split) { - LFS_TRACE("lfs_remove -> %d", LFS_ERR_NOTEMPTY); return LFS_ERR_NOTEMPTY; } // mark fs as orphaned - lfs_fs_preporphans(lfs, +1); + err = lfs_fs_preporphans(lfs, +1); + if (err) { + return err; + } // I know it's crazy but yes, dir can be changed by our parent's // commit (if predecessor is child) @@ -3204,39 +3242,37 @@ int lfs_remove(lfs_t *lfs, const char *path) { {LFS_MKTAG(LFS_TYPE_DELETE, lfs_tag_id(tag), 0), NULL})); if (err) { lfs->mlist = dir.next; - LFS_TRACE("lfs_remove -> %d", err); return err; } lfs->mlist = dir.next; if (lfs_tag_type3(tag) == LFS_TYPE_DIR) { // fix orphan - lfs_fs_preporphans(lfs, -1); + err = lfs_fs_preporphans(lfs, -1); + if (err) { + return err; + } err = lfs_fs_pred(lfs, dir.m.pair, &cwd); if (err) { - LFS_TRACE("lfs_remove -> %d", err); return err; } err = lfs_dir_drop(lfs, &cwd, &dir.m); if (err) { - LFS_TRACE("lfs_remove -> %d", err); return err; } } - LFS_TRACE("lfs_remove -> %d", 0); return 0; } +#endif -int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { - LFS_TRACE("lfs_rename(%p, \"%s\", \"%s\")", (void*)lfs, oldpath, newpath); - +#ifndef LFS_READONLY +static int lfs_rawrename(lfs_t *lfs, const char *oldpath, const char *newpath) { // deorphan if we haven't yet, needed at most once after poweron int err = lfs_fs_forceconsistency(lfs); if (err) { - LFS_TRACE("lfs_rename -> %d", err); return err; } @@ -3244,8 +3280,6 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { lfs_mdir_t oldcwd; lfs_stag_t oldtag = lfs_dir_find(lfs, &oldcwd, &oldpath, NULL); if (oldtag < 0 || lfs_tag_id(oldtag) == 0x3ff) { - LFS_TRACE("lfs_rename -> %"PRId32, - (oldtag < 0) ? oldtag : LFS_ERR_INVAL); return (oldtag < 0) ? (int)oldtag : LFS_ERR_INVAL; } @@ -3255,8 +3289,6 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { lfs_stag_t prevtag = lfs_dir_find(lfs, &newcwd, &newpath, &newid); if ((prevtag < 0 || lfs_tag_id(prevtag) == 0x3ff) && !(prevtag == LFS_ERR_NOENT && newid != 0x3ff)) { - LFS_TRACE("lfs_rename -> %"PRId32, - (prevtag < 0) ? prevtag : LFS_ERR_INVAL); return (prevtag < 0) ? (int)prevtag : LFS_ERR_INVAL; } @@ -3270,7 +3302,6 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { // check that name fits lfs_size_t nlen = strlen(newpath); if (nlen > lfs->name_max) { - LFS_TRACE("lfs_rename -> %d", LFS_ERR_NAMETOOLONG); return LFS_ERR_NAMETOOLONG; } @@ -3281,11 +3312,9 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { newoldid += 1; } } else if (lfs_tag_type3(prevtag) != lfs_tag_type3(oldtag)) { - LFS_TRACE("lfs_rename -> %d", LFS_ERR_ISDIR); return LFS_ERR_ISDIR; } else if (samepair && newid == newoldid) { // we're renaming to ourselves?? - LFS_TRACE("lfs_rename -> %d", 0); return 0; } else if (lfs_tag_type3(prevtag) == LFS_TYPE_DIR) { // must be empty before removal @@ -3293,7 +3322,6 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { lfs_stag_t res = lfs_dir_get(lfs, &newcwd, LFS_MKTAG(0x700, 0x3ff, 0), LFS_MKTAG(LFS_TYPE_STRUCT, newid, 8), prevpair); if (res < 0) { - LFS_TRACE("lfs_rename -> %"PRId32, res); return (int)res; } lfs_pair_fromle32(prevpair); @@ -3301,17 +3329,18 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { // must be empty before removal err = lfs_dir_fetch(lfs, &prevdir.m, prevpair); if (err) { - LFS_TRACE("lfs_rename -> %d", err); return err; } if (prevdir.m.count > 0 || prevdir.m.split) { - LFS_TRACE("lfs_rename -> %d", LFS_ERR_NOTEMPTY); return LFS_ERR_NOTEMPTY; } // mark fs as orphaned - lfs_fs_preporphans(lfs, +1); + err = lfs_fs_preporphans(lfs, +1); + if (err) { + return err; + } // I know it's crazy but yes, dir can be changed by our parent's // commit (if predecessor is child) @@ -3335,7 +3364,6 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { LFS_TYPE_DELETE, newoldid, 0), NULL})); if (err) { lfs->mlist = prevdir.next; - LFS_TRACE("lfs_rename -> %d", err); return err; } @@ -3348,7 +3376,6 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { {LFS_MKTAG(LFS_TYPE_DELETE, lfs_tag_id(oldtag), 0), NULL})); if (err) { lfs->mlist = prevdir.next; - LFS_TRACE("lfs_rename -> %d", err); return err; } } @@ -3356,33 +3383,31 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { lfs->mlist = prevdir.next; if (prevtag != LFS_ERR_NOENT && lfs_tag_type3(prevtag) == LFS_TYPE_DIR) { // fix orphan - lfs_fs_preporphans(lfs, -1); + err = lfs_fs_preporphans(lfs, -1); + if (err) { + return err; + } err = lfs_fs_pred(lfs, prevdir.m.pair, &newcwd); if (err) { - LFS_TRACE("lfs_rename -> %d", err); return err; } err = lfs_dir_drop(lfs, &newcwd, &prevdir.m); if (err) { - LFS_TRACE("lfs_rename -> %d", err); return err; } } - LFS_TRACE("lfs_rename -> %d", 0); return 0; } +#endif -lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, +static lfs_ssize_t lfs_rawgetattr(lfs_t *lfs, const char *path, uint8_t type, void *buffer, lfs_size_t size) { - LFS_TRACE("lfs_getattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")", - (void*)lfs, path, type, buffer, size); lfs_mdir_t cwd; lfs_stag_t tag = lfs_dir_find(lfs, &cwd, &path, NULL); if (tag < 0) { - LFS_TRACE("lfs_getattr -> %"PRId32, tag); return tag; } @@ -3392,7 +3417,6 @@ lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, id = 0; int err = lfs_dir_fetch(lfs, &cwd, lfs->root); if (err) { - LFS_TRACE("lfs_getattr -> %d", err); return err; } } @@ -3403,19 +3427,16 @@ lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, buffer); if (tag < 0) { if (tag == LFS_ERR_NOENT) { - LFS_TRACE("lfs_getattr -> %d", LFS_ERR_NOATTR); return LFS_ERR_NOATTR; } - LFS_TRACE("lfs_getattr -> %"PRId32, tag); return tag; } - size = lfs_tag_size(tag); - LFS_TRACE("lfs_getattr -> %"PRId32, size); - return size; + return lfs_tag_size(tag); } +#ifndef LFS_READONLY static int lfs_commitattr(lfs_t *lfs, const char *path, uint8_t type, const void *buffer, lfs_size_t size) { lfs_mdir_t cwd; @@ -3437,27 +3458,24 @@ static int lfs_commitattr(lfs_t *lfs, const char *path, return lfs_dir_commit(lfs, &cwd, LFS_MKATTRS( {LFS_MKTAG(LFS_TYPE_USERATTR + type, id, size), buffer})); } +#endif -int lfs_setattr(lfs_t *lfs, const char *path, +#ifndef LFS_READONLY +static int lfs_rawsetattr(lfs_t *lfs, const char *path, uint8_t type, const void *buffer, lfs_size_t size) { - LFS_TRACE("lfs_setattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")", - (void*)lfs, path, type, buffer, size); if (size > lfs->attr_max) { - LFS_TRACE("lfs_setattr -> %d", LFS_ERR_NOSPC); return LFS_ERR_NOSPC; } - int err = lfs_commitattr(lfs, path, type, buffer, size); - LFS_TRACE("lfs_setattr -> %d", err); - return err; + return lfs_commitattr(lfs, path, type, buffer, size); } +#endif -int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type) { - LFS_TRACE("lfs_removeattr(%p, \"%s\", %"PRIu8")", (void*)lfs, path, type); - int err = lfs_commitattr(lfs, path, type, NULL, 0x3ff); - LFS_TRACE("lfs_removeattr -> %d", err); - return err; +#ifndef LFS_READONLY +static int lfs_rawremoveattr(lfs_t *lfs, const char *path, uint8_t type) { + return lfs_commitattr(lfs, path, type, NULL, 0x3ff); } +#endif /// Filesystem operations /// @@ -3549,6 +3567,8 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { lfs->attr_max = LFS_ATTR_MAX; } + LFS_ASSERT(lfs->cfg->metadata_max <= lfs->cfg->block_size); + // setup default state lfs->root[0] = LFS_BLOCK_NULL; lfs->root[1] = LFS_BLOCK_NULL; @@ -3585,28 +3605,12 @@ static int lfs_deinit(lfs_t *lfs) { return 0; } -int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { - LFS_TRACE("lfs_format(%p, %p {.context=%p, " - ".read=%p, .prog=%p, .erase=%p, .sync=%p, " - ".read_size=%"PRIu32", .prog_size=%"PRIu32", " - ".block_size=%"PRIu32", .block_count=%"PRIu32", " - ".block_cycles=%"PRIu32", .cache_size=%"PRIu32", " - ".lookahead_size=%"PRIu32", .read_buffer=%p, " - ".prog_buffer=%p, .lookahead_buffer=%p, " - ".name_max=%"PRIu32", .file_max=%"PRIu32", " - ".attr_max=%"PRIu32"})", - (void*)lfs, (void*)cfg, cfg->context, - (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, - (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, - cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, - cfg->block_cycles, cfg->cache_size, cfg->lookahead_size, - cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, - cfg->name_max, cfg->file_max, cfg->attr_max); +#ifndef LFS_READONLY +static int lfs_rawformat(lfs_t *lfs, const struct lfs_config *cfg) { int err = 0; { err = lfs_init(lfs, cfg); if (err) { - LFS_TRACE("lfs_format -> %d", err); return err; } @@ -3645,12 +3649,6 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { goto cleanup; } - // sanity check that fetch works - err = lfs_dir_fetch(lfs, &root, (const lfs_block_t[2]){0, 1}); - if (err) { - goto cleanup; - } - // force compaction to prevent accidentally mounting any // older version of littlefs that may live on disk root.erased = false; @@ -3658,34 +3656,24 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { if (err) { goto cleanup; } + + // sanity check that fetch works + err = lfs_dir_fetch(lfs, &root, (const lfs_block_t[2]){0, 1}); + if (err) { + goto cleanup; + } } cleanup: lfs_deinit(lfs); - LFS_TRACE("lfs_format -> %d", err); return err; + } +#endif -int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { - LFS_TRACE("lfs_mount(%p, %p {.context=%p, " - ".read=%p, .prog=%p, .erase=%p, .sync=%p, " - ".read_size=%"PRIu32", .prog_size=%"PRIu32", " - ".block_size=%"PRIu32", .block_count=%"PRIu32", " - ".block_cycles=%"PRIu32", .cache_size=%"PRIu32", " - ".lookahead_size=%"PRIu32", .read_buffer=%p, " - ".prog_buffer=%p, .lookahead_buffer=%p, " - ".name_max=%"PRIu32", .file_max=%"PRIu32", " - ".attr_max=%"PRIu32"})", - (void*)lfs, (void*)cfg, cfg->context, - (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, - (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, - cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, - cfg->block_cycles, cfg->cache_size, cfg->lookahead_size, - cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, - cfg->name_max, cfg->file_max, cfg->attr_max); +static int lfs_rawmount(lfs_t *lfs, const struct lfs_config *cfg) { int err = lfs_init(lfs, cfg); if (err) { - LFS_TRACE("lfs_mount -> %d", err); return err; } @@ -3798,28 +3786,25 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { lfs->gstate.tag += !lfs_tag_isvalid(lfs->gstate.tag); lfs->gdisk = lfs->gstate; - // setup free lookahead - lfs_alloc_reset(lfs); + // setup free lookahead, to distribute allocations uniformly across + // boots, we start the allocator at a random location + lfs->free.off = lfs->seed % lfs->cfg->block_count; + lfs_alloc_drop(lfs); - LFS_TRACE("lfs_mount -> %d", 0); return 0; cleanup: - lfs_unmount(lfs); - LFS_TRACE("lfs_mount -> %d", err); + lfs_rawunmount(lfs); return err; } -int lfs_unmount(lfs_t *lfs) { - LFS_TRACE("lfs_unmount(%p)", (void*)lfs); - int err = lfs_deinit(lfs); - LFS_TRACE("lfs_unmount -> %d", err); - return err; +static int lfs_rawunmount(lfs_t *lfs) { + return lfs_deinit(lfs); } /// Filesystem filesystem operations /// -int lfs_fs_traverseraw(lfs_t *lfs, +int lfs_fs_rawtraverse(lfs_t *lfs, int (*cb)(void *data, lfs_block_t block), void *data, bool includeorphans) { // iterate over metadata pairs @@ -3877,7 +3862,7 @@ int lfs_fs_traverseraw(lfs_t *lfs, if (err) { return err; } - } else if (includeorphans && + } else if (includeorphans && lfs_tag_type3(tag) == LFS_TYPE_DIRSTRUCT) { for (int i = 0; i < 2; i++) { err = cb(data, (&ctz.head)[i]); @@ -3889,6 +3874,7 @@ int lfs_fs_traverseraw(lfs_t *lfs, } } +#ifndef LFS_READONLY // iterate over any open files for (lfs_file_t *f = (lfs_file_t*)lfs->mlist; f; f = f->next) { if (f->type != LFS_TYPE_REG) { @@ -3911,19 +3897,12 @@ int lfs_fs_traverseraw(lfs_t *lfs, } } } +#endif return 0; } -int lfs_fs_traverse(lfs_t *lfs, - int (*cb)(void *data, lfs_block_t block), void *data) { - LFS_TRACE("lfs_fs_traverse(%p, %p, %p)", - (void*)lfs, (void*)(uintptr_t)cb, data); - int err = lfs_fs_traverseraw(lfs, cb, data, true); - LFS_TRACE("lfs_fs_traverse -> %d", 0); - return err; -} - +#ifndef LFS_READONLY static int lfs_fs_pred(lfs_t *lfs, const lfs_block_t pair[2], lfs_mdir_t *pdir) { // iterate over all directory directory entries @@ -3949,12 +3928,16 @@ static int lfs_fs_pred(lfs_t *lfs, return LFS_ERR_NOENT; } +#endif +#ifndef LFS_READONLY struct lfs_fs_parent_match { lfs_t *lfs; const lfs_block_t pair[2]; }; +#endif +#ifndef LFS_READONLY static int lfs_fs_parent_match(void *data, lfs_tag_t tag, const void *buffer) { struct lfs_fs_parent_match *find = data; @@ -3973,7 +3956,9 @@ static int lfs_fs_parent_match(void *data, lfs_pair_fromle32(child); return (lfs_pair_cmp(child, find->pair) == 0) ? LFS_CMP_EQ : LFS_CMP_LT; } +#endif +#ifndef LFS_READONLY static lfs_stag_t lfs_fs_parent(lfs_t *lfs, const lfs_block_t pair[2], lfs_mdir_t *parent) { // use fetchmatch with callback to find pairs @@ -4000,7 +3985,9 @@ static lfs_stag_t lfs_fs_parent(lfs_t *lfs, const lfs_block_t pair[2], return LFS_ERR_NOENT; } +#endif +#ifndef LFS_READONLY static int lfs_fs_relocate(lfs_t *lfs, const lfs_block_t oldpair[2], lfs_block_t newpair[2]) { // update internal root @@ -4032,7 +4019,10 @@ static int lfs_fs_relocate(lfs_t *lfs, if (tag != LFS_ERR_NOENT) { // update disk, this creates a desync - lfs_fs_preporphans(lfs, +1); + int err = lfs_fs_preporphans(lfs, +1); + if (err) { + return err; + } // fix pending move in this pair? this looks like an optimization but // is in fact _required_ since relocating may outdate the move. @@ -4049,7 +4039,7 @@ static int lfs_fs_relocate(lfs_t *lfs, } lfs_pair_tole32(newpair); - int err = lfs_dir_commit(lfs, &parent, LFS_MKATTRS( + err = lfs_dir_commit(lfs, &parent, LFS_MKATTRS( {LFS_MKTAG_IF(moveid != 0x3ff, LFS_TYPE_DELETE, moveid, 0), NULL}, {tag, newpair})); @@ -4059,7 +4049,10 @@ static int lfs_fs_relocate(lfs_t *lfs, } // next step, clean up orphans - lfs_fs_preporphans(lfs, -1); + err = lfs_fs_preporphans(lfs, -1); + if (err) { + return err; + } } // find pred @@ -4095,14 +4088,20 @@ static int lfs_fs_relocate(lfs_t *lfs, return 0; } +#endif -static void lfs_fs_preporphans(lfs_t *lfs, int8_t orphans) { +#ifndef LFS_READONLY +static int lfs_fs_preporphans(lfs_t *lfs, int8_t orphans) { LFS_ASSERT(lfs_tag_size(lfs->gstate.tag) > 0 || orphans >= 0); lfs->gstate.tag += orphans; lfs->gstate.tag = ((lfs->gstate.tag & ~LFS_MKTAG(0x800, 0, 0)) | ((uint32_t)lfs_gstate_hasorphans(&lfs->gstate) << 31)); + + return 0; } +#endif +#ifndef LFS_READONLY static void lfs_fs_prepmove(lfs_t *lfs, uint16_t id, const lfs_block_t pair[2]) { lfs->gstate.tag = ((lfs->gstate.tag & ~LFS_MKTAG(0x7ff, 0x3ff, 0)) | @@ -4110,7 +4109,9 @@ static void lfs_fs_prepmove(lfs_t *lfs, lfs->gstate.pair[0] = (id != 0x3ff) ? pair[0] : 0; lfs->gstate.pair[1] = (id != 0x3ff) ? pair[1] : 0; } +#endif +#ifndef LFS_READONLY static int lfs_fs_demove(lfs_t *lfs) { if (!lfs_gstate_hasmove(&lfs->gdisk)) { return 0; @@ -4140,7 +4141,9 @@ static int lfs_fs_demove(lfs_t *lfs) { return 0; } +#endif +#ifndef LFS_READONLY static int lfs_fs_deorphan(lfs_t *lfs) { if (!lfs_gstate_hasorphans(&lfs->gstate)) { return 0; @@ -4211,10 +4214,11 @@ static int lfs_fs_deorphan(lfs_t *lfs) { } // mark orphans as fixed - lfs_fs_preporphans(lfs, -lfs_gstate_getorphans(&lfs->gstate)); - return 0; + return lfs_fs_preporphans(lfs, -lfs_gstate_getorphans(&lfs->gstate)); } +#endif +#ifndef LFS_READONLY static int lfs_fs_forceconsistency(lfs_t *lfs) { int err = lfs_fs_demove(lfs); if (err) { @@ -4228,6 +4232,7 @@ static int lfs_fs_forceconsistency(lfs_t *lfs) { return 0; } +#endif static int lfs_fs_size_count(void *p, lfs_block_t block) { (void)block; @@ -4236,16 +4241,13 @@ static int lfs_fs_size_count(void *p, lfs_block_t block) { return 0; } -lfs_ssize_t lfs_fs_size(lfs_t *lfs) { - LFS_TRACE("lfs_fs_size(%p)", (void*)lfs); +static lfs_ssize_t lfs_fs_rawsize(lfs_t *lfs) { lfs_size_t size = 0; - int err = lfs_fs_traverseraw(lfs, lfs_fs_size_count, &size, false); + int err = lfs_fs_rawtraverse(lfs, lfs_fs_size_count, &size, false); if (err) { - LFS_TRACE("lfs_fs_size -> %d", err); return err; } - LFS_TRACE("lfs_fs_size -> %d", err); return size; } @@ -4670,27 +4672,10 @@ static int lfs1_unmount(lfs_t *lfs) { } /// v1 migration /// -int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg) { - LFS_TRACE("lfs_migrate(%p, %p {.context=%p, " - ".read=%p, .prog=%p, .erase=%p, .sync=%p, " - ".read_size=%"PRIu32", .prog_size=%"PRIu32", " - ".block_size=%"PRIu32", .block_count=%"PRIu32", " - ".block_cycles=%"PRIu32", .cache_size=%"PRIu32", " - ".lookahead_size=%"PRIu32", .read_buffer=%p, " - ".prog_buffer=%p, .lookahead_buffer=%p, " - ".name_max=%"PRIu32", .file_max=%"PRIu32", " - ".attr_max=%"PRIu32"})", - (void*)lfs, (void*)cfg, cfg->context, - (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, - (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, - cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, - cfg->block_cycles, cfg->cache_size, cfg->lookahead_size, - cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, - cfg->name_max, cfg->file_max, cfg->attr_max); +static int lfs_rawmigrate(lfs_t *lfs, const struct lfs_config *cfg) { struct lfs1 lfs1; int err = lfs1_mount(lfs, &lfs1, cfg); if (err) { - LFS_TRACE("lfs_migrate -> %d", err); return err; } @@ -4778,7 +4763,7 @@ int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg) { lfs1_entry_tole32(&entry1.d); err = lfs_dir_commit(lfs, &dir2, LFS_MKATTRS( - {LFS_MKTAG(LFS_TYPE_CREATE, id, 0)}, + {LFS_MKTAG(LFS_TYPE_CREATE, id, 0), NULL}, {LFS_MKTAG_IF_ELSE(isdir, LFS_TYPE_DIR, id, entry1.d.nlen, LFS_TYPE_REG, id, entry1.d.nlen), @@ -4883,7 +4868,7 @@ int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg) { lfs_superblock_tole32(&superblock); err = lfs_dir_commit(lfs, &dir2, LFS_MKATTRS( - {LFS_MKTAG(LFS_TYPE_CREATE, 0, 0)}, + {LFS_MKTAG(LFS_TYPE_CREATE, 0, 0), NULL}, {LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 8), "littlefs"}, {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)), &superblock})); @@ -4907,8 +4892,539 @@ int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg) { cleanup: lfs1_unmount(lfs); - LFS_TRACE("lfs_migrate -> %d", err); return err; } #endif + + +/// Public API wrappers /// + +// Here we can add tracing/thread safety easily + +// Thread-safe wrappers if enabled +#ifdef LFS_THREADSAFE +#define LFS_LOCK(cfg) cfg->lock(cfg) +#define LFS_UNLOCK(cfg) cfg->unlock(cfg) +#else +#define LFS_LOCK(cfg) ((void)cfg, 0) +#define LFS_UNLOCK(cfg) ((void)cfg) +#endif + +// Public API +#ifndef LFS_READONLY +int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { + int err = LFS_LOCK(cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_format(%p, %p {.context=%p, " + ".read=%p, .prog=%p, .erase=%p, .sync=%p, " + ".read_size=%"PRIu32", .prog_size=%"PRIu32", " + ".block_size=%"PRIu32", .block_count=%"PRIu32", " + ".block_cycles=%"PRIu32", .cache_size=%"PRIu32", " + ".lookahead_size=%"PRIu32", .read_buffer=%p, " + ".prog_buffer=%p, .lookahead_buffer=%p, " + ".name_max=%"PRIu32", .file_max=%"PRIu32", " + ".attr_max=%"PRIu32"})", + (void*)lfs, (void*)cfg, cfg->context, + (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, + (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, + cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, + cfg->block_cycles, cfg->cache_size, cfg->lookahead_size, + cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, + cfg->name_max, cfg->file_max, cfg->attr_max); + + err = lfs_rawformat(lfs, cfg); + + LFS_TRACE("lfs_format -> %d", err); + LFS_UNLOCK(cfg); + return err; +} +#endif + +int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { + int err = LFS_LOCK(cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_mount(%p, %p {.context=%p, " + ".read=%p, .prog=%p, .erase=%p, .sync=%p, " + ".read_size=%"PRIu32", .prog_size=%"PRIu32", " + ".block_size=%"PRIu32", .block_count=%"PRIu32", " + ".block_cycles=%"PRIu32", .cache_size=%"PRIu32", " + ".lookahead_size=%"PRIu32", .read_buffer=%p, " + ".prog_buffer=%p, .lookahead_buffer=%p, " + ".name_max=%"PRIu32", .file_max=%"PRIu32", " + ".attr_max=%"PRIu32"})", + (void*)lfs, (void*)cfg, cfg->context, + (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, + (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, + cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, + cfg->block_cycles, cfg->cache_size, cfg->lookahead_size, + cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, + cfg->name_max, cfg->file_max, cfg->attr_max); + + err = lfs_rawmount(lfs, cfg); + + LFS_TRACE("lfs_mount -> %d", err); + LFS_UNLOCK(cfg); + return err; +} + +int lfs_unmount(lfs_t *lfs) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_unmount(%p)", (void*)lfs); + + err = lfs_rawunmount(lfs); + + LFS_TRACE("lfs_unmount -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} + +#ifndef LFS_READONLY +int lfs_remove(lfs_t *lfs, const char *path) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_remove(%p, \"%s\")", (void*)lfs, path); + + err = lfs_rawremove(lfs, path); + + LFS_TRACE("lfs_remove -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} +#endif + +#ifndef LFS_READONLY +int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_rename(%p, \"%s\", \"%s\")", (void*)lfs, oldpath, newpath); + + err = lfs_rawrename(lfs, oldpath, newpath); + + LFS_TRACE("lfs_rename -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} +#endif + +int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_stat(%p, \"%s\", %p)", (void*)lfs, path, (void*)info); + + err = lfs_rawstat(lfs, path, info); + + LFS_TRACE("lfs_stat -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} + +lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, + uint8_t type, void *buffer, lfs_size_t size) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_getattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")", + (void*)lfs, path, type, buffer, size); + + lfs_ssize_t res = lfs_rawgetattr(lfs, path, type, buffer, size); + + LFS_TRACE("lfs_getattr -> %"PRId32, res); + LFS_UNLOCK(lfs->cfg); + return res; +} + +#ifndef LFS_READONLY +int lfs_setattr(lfs_t *lfs, const char *path, + uint8_t type, const void *buffer, lfs_size_t size) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_setattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")", + (void*)lfs, path, type, buffer, size); + + err = lfs_rawsetattr(lfs, path, type, buffer, size); + + LFS_TRACE("lfs_setattr -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} +#endif + +#ifndef LFS_READONLY +int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_removeattr(%p, \"%s\", %"PRIu8")", (void*)lfs, path, type); + + err = lfs_rawremoveattr(lfs, path, type); + + LFS_TRACE("lfs_removeattr -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} +#endif + +int lfs_file_open(lfs_t *lfs, lfs_file_t *file, const char *path, int flags) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_file_open(%p, %p, \"%s\", %x)", + (void*)lfs, (void*)file, path, flags); + LFS_ASSERT(!lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); + + err = lfs_file_rawopen(lfs, file, path, flags); + + LFS_TRACE("lfs_file_open -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} + +int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, + const char *path, int flags, + const struct lfs_file_config *cfg) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_file_opencfg(%p, %p, \"%s\", %x, %p {" + ".buffer=%p, .attrs=%p, .attr_count=%"PRIu32"})", + (void*)lfs, (void*)file, path, flags, + (void*)cfg, cfg->buffer, (void*)cfg->attrs, cfg->attr_count); + LFS_ASSERT(!lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); + + err = lfs_file_rawopencfg(lfs, file, path, flags, cfg); + + LFS_TRACE("lfs_file_opencfg -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} + +int lfs_file_close(lfs_t *lfs, lfs_file_t *file) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_file_close(%p, %p)", (void*)lfs, (void*)file); + LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); + + err = lfs_file_rawclose(lfs, file); + + LFS_TRACE("lfs_file_close -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} + +#ifndef LFS_READONLY +int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_file_sync(%p, %p)", (void*)lfs, (void*)file); + LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); + + err = lfs_file_rawsync(lfs, file); + + LFS_TRACE("lfs_file_sync -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} +#endif + +lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, + void *buffer, lfs_size_t size) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_file_read(%p, %p, %p, %"PRIu32")", + (void*)lfs, (void*)file, buffer, size); + LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); + + lfs_ssize_t res = lfs_file_rawread(lfs, file, buffer, size); + + LFS_TRACE("lfs_file_read -> %"PRId32, res); + LFS_UNLOCK(lfs->cfg); + return res; +} + +#ifndef LFS_READONLY +lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, + const void *buffer, lfs_size_t size) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_file_write(%p, %p, %p, %"PRIu32")", + (void*)lfs, (void*)file, buffer, size); + LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); + + lfs_ssize_t res = lfs_file_rawwrite(lfs, file, buffer, size); + + LFS_TRACE("lfs_file_write -> %"PRId32, res); + LFS_UNLOCK(lfs->cfg); + return res; +} +#endif + +lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, + lfs_soff_t off, int whence) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_file_seek(%p, %p, %"PRId32", %d)", + (void*)lfs, (void*)file, off, whence); + LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); + + lfs_soff_t res = lfs_file_rawseek(lfs, file, off, whence); + + LFS_TRACE("lfs_file_seek -> %"PRId32, res); + LFS_UNLOCK(lfs->cfg); + return res; +} + +#ifndef LFS_READONLY +int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_file_truncate(%p, %p, %"PRIu32")", + (void*)lfs, (void*)file, size); + LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); + + err = lfs_file_rawtruncate(lfs, file, size); + + LFS_TRACE("lfs_file_truncate -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} +#endif + +lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_file_tell(%p, %p)", (void*)lfs, (void*)file); + LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); + + lfs_soff_t res = lfs_file_rawtell(lfs, file); + + LFS_TRACE("lfs_file_tell -> %"PRId32, res); + LFS_UNLOCK(lfs->cfg); + return res; +} + +int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_file_rewind(%p, %p)", (void*)lfs, (void*)file); + + err = lfs_file_rawrewind(lfs, file); + + LFS_TRACE("lfs_file_rewind -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} + +lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_file_size(%p, %p)", (void*)lfs, (void*)file); + LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); + + lfs_soff_t res = lfs_file_rawsize(lfs, file); + + LFS_TRACE("lfs_file_size -> %"PRId32, res); + LFS_UNLOCK(lfs->cfg); + return res; +} + +#ifndef LFS_READONLY +int lfs_mkdir(lfs_t *lfs, const char *path) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_mkdir(%p, \"%s\")", (void*)lfs, path); + + err = lfs_rawmkdir(lfs, path); + + LFS_TRACE("lfs_mkdir -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} +#endif + +int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_dir_open(%p, %p, \"%s\")", (void*)lfs, (void*)dir, path); + LFS_ASSERT(!lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)dir)); + + err = lfs_dir_rawopen(lfs, dir, path); + + LFS_TRACE("lfs_dir_open -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} + +int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_dir_close(%p, %p)", (void*)lfs, (void*)dir); + + err = lfs_dir_rawclose(lfs, dir); + + LFS_TRACE("lfs_dir_close -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} + +int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_dir_read(%p, %p, %p)", + (void*)lfs, (void*)dir, (void*)info); + + err = lfs_dir_rawread(lfs, dir, info); + + LFS_TRACE("lfs_dir_read -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} + +int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_dir_seek(%p, %p, %"PRIu32")", + (void*)lfs, (void*)dir, off); + + err = lfs_dir_rawseek(lfs, dir, off); + + LFS_TRACE("lfs_dir_seek -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} + +lfs_soff_t lfs_dir_tell(lfs_t *lfs, lfs_dir_t *dir) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_dir_tell(%p, %p)", (void*)lfs, (void*)dir); + + lfs_soff_t res = lfs_dir_rawtell(lfs, dir); + + LFS_TRACE("lfs_dir_tell -> %"PRId32, res); + LFS_UNLOCK(lfs->cfg); + return res; +} + +int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_dir_rewind(%p, %p)", (void*)lfs, (void*)dir); + + err = lfs_dir_rawrewind(lfs, dir); + + LFS_TRACE("lfs_dir_rewind -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} + +lfs_ssize_t lfs_fs_size(lfs_t *lfs) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_fs_size(%p)", (void*)lfs); + + lfs_ssize_t res = lfs_fs_rawsize(lfs); + + LFS_TRACE("lfs_fs_size -> %"PRId32, res); + LFS_UNLOCK(lfs->cfg); + return res; +} + +int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void *, lfs_block_t), void *data) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_fs_traverse(%p, %p, %p)", + (void*)lfs, (void*)(uintptr_t)cb, data); + + err = lfs_fs_rawtraverse(lfs, cb, data, true); + + LFS_TRACE("lfs_fs_traverse -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} + +#ifdef LFS_MIGRATE +int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg) { + int err = LFS_LOCK(cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_migrate(%p, %p {.context=%p, " + ".read=%p, .prog=%p, .erase=%p, .sync=%p, " + ".read_size=%"PRIu32", .prog_size=%"PRIu32", " + ".block_size=%"PRIu32", .block_count=%"PRIu32", " + ".block_cycles=%"PRIu32", .cache_size=%"PRIu32", " + ".lookahead_size=%"PRIu32", .read_buffer=%p, " + ".prog_buffer=%p, .lookahead_buffer=%p, " + ".name_max=%"PRIu32", .file_max=%"PRIu32", " + ".attr_max=%"PRIu32"})", + (void*)lfs, (void*)cfg, cfg->context, + (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, + (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, + cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, + cfg->block_cycles, cfg->cache_size, cfg->lookahead_size, + cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, + cfg->name_max, cfg->file_max, cfg->attr_max); + + err = lfs_rawmigrate(lfs, cfg); + + LFS_TRACE("lfs_migrate -> %d", err); + LFS_UNLOCK(cfg); + return err; +} +#endif + diff --git a/firmware/3.0/lib/LittleFS/littlefs/lfs.h b/firmware/3.0/lib/LittleFS/littlefs/lfs.h old mode 100644 new mode 100755 index 6153036..a618468 --- a/firmware/3.0/lib/LittleFS/littlefs/lfs.h +++ b/firmware/3.0/lib/LittleFS/littlefs/lfs.h @@ -9,6 +9,7 @@ #include #include +#include "lfs_util.h" #ifdef __cplusplus extern "C" @@ -21,7 +22,7 @@ extern "C" // Software library version // Major (top-nibble), incremented on backwards incompatible changes // Minor (bottom-nibble), incremented on feature additions -#define LFS_VERSION 0x00020002 +#define LFS_VERSION 0x00020004 #define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16)) #define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0)) @@ -48,8 +49,8 @@ typedef uint32_t lfs_block_t; // info struct. Limited to <= 1022. Stored in superblock and must be // respected by other littlefs drivers. #ifndef LFS_NAME_MAX -//#define LFS_NAME_MAX 255 -#define LFS_NAME_MAX 39 +#define LFS_NAME_MAX 255 +//#define LFS_NAME_MAX 39 #endif // Maximum size of a file in bytes, may be redefined to limit to support other @@ -124,20 +125,25 @@ enum lfs_type { enum lfs_open_flags { // open flags LFS_O_RDONLY = 1, // Open a file as read only +#ifndef LFS_READONLY LFS_O_WRONLY = 2, // Open a file as write only LFS_O_RDWR = 3, // Open a file as read and write LFS_O_CREAT = 0x0100, // Create a file if it does not exist LFS_O_EXCL = 0x0200, // Fail if a file already exists LFS_O_TRUNC = 0x0400, // Truncate the existing file to zero size LFS_O_APPEND = 0x0800, // Move to end of file on every write +#endif // internally used flags +#ifndef LFS_READONLY LFS_F_DIRTY = 0x010000, // File does not match storage LFS_F_WRITING = 0x020000, // File has been written since last flush +#endif LFS_F_READING = 0x040000, // File has been read since last flush - LFS_F_ERRED = 0x080000, // An error occured during write +#ifndef LFS_READONLY + LFS_F_ERRED = 0x080000, // An error occurred during write +#endif LFS_F_INLINE = 0x100000, // Currently inlined in directory entry - LFS_F_OPENED = 0x200000, // File has been opened }; // File seek flags @@ -175,6 +181,16 @@ struct lfs_config { // are propogated to the user. int (*sync)(const struct lfs_config *c); +#ifdef LFS_THREADSAFE + // Lock the underlying block device. Negative error codes + // are propogated to the user. + int (*lock)(const struct lfs_config *c); + + // Unlock the underlying block device. Negative error codes + // are propogated to the user. + int (*unlock)(const struct lfs_config *c); +#endif + // Minimum size of a block read. All read operations will be a // multiple of this value. lfs_size_t read_size; @@ -192,7 +208,7 @@ struct lfs_config { // Number of erasable blocks on the device. lfs_size_t block_count; - // Number of erase cycles before littlefs evicts metadata logs and moves + // Number of erase cycles before littlefs evicts metadata logs and moves // the metadata to another block. Suggested values are in the // range 100-1000, with large values having better performance at the cost // of less consistent wear distribution. @@ -241,6 +257,12 @@ struct lfs_config { // larger attributes size but must be <= LFS_ATTR_MAX. Defaults to // LFS_ATTR_MAX when zero. lfs_size_t attr_max; + + // Optional upper limit on total space given to metadata pairs in bytes. On + // devices with large blocks (e.g. 128kB) setting this to a low size (2-8kB) + // can help bound the metadata compaction time. Must be <= block_size. + // Defaults to block_size when zero. + lfs_size_t metadata_max; }; // File info structure @@ -400,6 +422,7 @@ typedef struct lfs { /// Filesystem functions /// +#ifndef LFS_READONLY // Format a block device with the littlefs // // Requires a littlefs object and config struct. This clobbers the littlefs @@ -408,6 +431,7 @@ typedef struct lfs { // // Returns a negative error code on failure. int lfs_format(lfs_t *lfs, const struct lfs_config *config); +#endif // Mounts a littlefs // @@ -427,12 +451,15 @@ int lfs_unmount(lfs_t *lfs); /// General operations /// +#ifndef LFS_READONLY // Removes a file or directory // // If removing a directory, the directory must be empty. // Returns a negative error code on failure. int lfs_remove(lfs_t *lfs, const char *path); +#endif +#ifndef LFS_READONLY // Rename or move a file or directory // // If the destination exists, it must match the source in type. @@ -440,6 +467,7 @@ int lfs_remove(lfs_t *lfs, const char *path); // // Returns a negative error code on failure. int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath); +#endif // Find info about a file or directory // @@ -462,6 +490,7 @@ int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info); lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, uint8_t type, void *buffer, lfs_size_t size); +#ifndef LFS_READONLY // Set custom attributes // // Custom attributes are uniquely identified by an 8-bit type and limited @@ -471,13 +500,16 @@ lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, // Returns a negative error code on failure. int lfs_setattr(lfs_t *lfs, const char *path, uint8_t type, const void *buffer, lfs_size_t size); +#endif +#ifndef LFS_READONLY // Removes a custom attribute // // If an attribute is not found, nothing happens. // // Returns a negative error code on failure. int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type); +#endif /// File operations /// @@ -526,6 +558,7 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file); lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, void *buffer, lfs_size_t size); +#ifndef LFS_READONLY // Write data to file // // Takes a buffer and size indicating the data to write. The file will not @@ -534,6 +567,7 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, // Returns the number of bytes written, or a negative error code on failure. lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, const void *buffer, lfs_size_t size); +#endif // Change the position of the file // @@ -542,10 +576,12 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, lfs_soff_t off, int whence); +#ifndef LFS_READONLY // Truncates the size of the file to the specified size // // Returns a negative error code on failure. int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size); +#endif // Return the position of the file // @@ -568,10 +604,12 @@ lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file); /// Directory operations /// +#ifndef LFS_READONLY // Create a directory // // Returns a negative error code on failure. int lfs_mkdir(lfs_t *lfs, const char *path); +#endif // Open a directory // @@ -633,6 +671,7 @@ lfs_ssize_t lfs_fs_size(lfs_t *lfs); // Returns a negative error code on failure. int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data); +#ifndef LFS_READONLY #ifdef LFS_MIGRATE // Attempts to migrate a previous version of littlefs // @@ -647,6 +686,7 @@ int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data); // Returns a negative error code on failure. int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg); #endif +#endif #ifdef __cplusplus diff --git a/firmware/3.0/lib/LittleFS/littlefs/lfs_util.h b/firmware/3.0/lib/LittleFS/littlefs/lfs_util.h old mode 100644 new mode 100755 index a0d2385..6241e3f --- a/firmware/3.0/lib/LittleFS/littlefs/lfs_util.h +++ b/firmware/3.0/lib/LittleFS/littlefs/lfs_util.h @@ -9,14 +9,12 @@ // Teensy specific use... -#define LFS_NAME_MAX 39 +#define LFS_NAME_MAX 255 #define LFS_NO_DEBUG #define LFS_NO_WARN #define LFS_NO_ERROR #define LFS_NO_ASSERT - - // Users can override lfs_util.h with their own configuration by defining // LFS_CONFIG as a header file to include (-DLFS_CONFIG=lfs_config.h). // @@ -59,6 +57,7 @@ extern "C" // code footprint // Logging functions +#ifndef LFS_TRACE #ifdef LFS_YES_TRACE #define LFS_TRACE_(fmt, ...) \ printf("%s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) @@ -66,7 +65,9 @@ extern "C" #else #define LFS_TRACE(...) #endif +#endif +#ifndef LFS_DEBUG #ifndef LFS_NO_DEBUG #define LFS_DEBUG_(fmt, ...) \ printf("%s:%d:debug: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) @@ -74,7 +75,9 @@ extern "C" #else #define LFS_DEBUG(...) #endif +#endif +#ifndef LFS_WARN #ifndef LFS_NO_WARN #define LFS_WARN_(fmt, ...) \ printf("%s:%d:warn: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) @@ -82,7 +85,9 @@ extern "C" #else #define LFS_WARN(...) #endif +#endif +#ifndef LFS_ERROR #ifndef LFS_NO_ERROR #define LFS_ERROR_(fmt, ...) \ printf("%s:%d:error: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) @@ -90,13 +95,16 @@ extern "C" #else #define LFS_ERROR(...) #endif +#endif // Runtime assertions +#ifndef LFS_ASSERT #ifndef LFS_NO_ASSERT #define LFS_ASSERT(test) assert(test) #else #define LFS_ASSERT(test) #endif +#endif // Builtin functions, these may be replaced by more efficient diff --git a/firmware/3.0/lib/MTP/MTP.cpp b/firmware/3.0/lib/MTP/MTP.cpp old mode 100644 new mode 100755 index db1047e..cc2f9f5 --- a/firmware/3.0/lib/MTP/MTP.cpp +++ b/firmware/3.0/lib/MTP/MTP.cpp @@ -1042,10 +1042,6 @@ const uint16_t supported_events[] = len=0; } } - if(len>0) - { push_packet(tx_data_buffer,MTP_TX_SIZE); - len=0; - } } return size; } @@ -1081,7 +1077,7 @@ const uint16_t supported_events[] = uint32_t dlen = FUN; \ \ MTPContainer header; \ - header.len = write_length_ + sizeof(MTPHeader)+4; \ + header.len = write_length_ + sizeof(MTPHeader); \ header.type = 2; \ header.op = CONTAINER->op; \ header.transaction_id = CONTAINER->transaction_id; \ diff --git a/firmware/3.0/lib/MTP/Storage.h b/firmware/3.0/lib/MTP/Storage.h old mode 100644 new mode 100755 index 92a96d1..53b5f34 --- a/firmware/3.0/lib/MTP/Storage.h +++ b/firmware/3.0/lib/MTP/Storage.h @@ -107,7 +107,7 @@ class MTPStorageInterface { virtual uint32_t Create(uint32_t storage, uint32_t parent, bool folder, const char* filename) = 0; virtual void read(uint32_t handle, uint32_t pos, char* buffer, uint32_t bytes) = 0; - virtual size_t write(const char* data, uint32_t size); + virtual size_t write(const char* data, uint32_t size) = 0; virtual void close() = 0; virtual bool DeleteObject(uint32_t object) = 0; virtual void CloseIndex() = 0; @@ -128,8 +128,6 @@ class MTPStorageInterface { uint8_t scanned; uint16_t store; // index int physical storage (0 ... num_storages-1) char name[MAX_FILENAME_LEN]; - - }; void mtp_yield(void); diff --git a/firmware/3.0/lib/SD/library.properties b/firmware/3.0/lib/SD/library.properties old mode 100644 new mode 100755 index cc6fd75..44ee265 --- a/firmware/3.0/lib/SD/library.properties +++ b/firmware/3.0/lib/SD/library.properties @@ -6,4 +6,4 @@ sentence=Arduino SD compatibility layer for SdFat. paragraph=To access SD cards, we now use Bill Greiman's SdFat library. This library just provides a thin wrapper so programs written for Arduino's SD library can use SdFat. None of the original Arduino SD library code is present in this compatibility library. category=Data Storage url=https://github.com/PaulStoffregen/SD -architectures=* +architectures=avr,* diff --git a/firmware/3.0/lib/SD/src/SD.cpp b/firmware/3.0/lib/SD/src/SD.cpp old mode 100644 new mode 100755 index f4c380c..b94ca76 --- a/firmware/3.0/lib/SD/src/SD.cpp +++ b/firmware/3.0/lib/SD/src/SD.cpp @@ -24,3 +24,177 @@ #include SDClass SD; + +#if defined(ARDUINO_TEENSY41) +#define _SD_DAT3 46 +#elif defined(ARDUINO_TEENSY40) +#define _SD_DAT3 38 +#elif defined(ARDUINO_TEENSY_MICROMOD) +#define _SD_DAT3 39 +#elif defined(ARDUINO_TEENSY35) || defined(ARDUINO_TEENSY36) +// #define _SD_DAT3 62 // currently not doing on 3.5/6... +#endif + +#ifdef __arm__ +void SDClass::dateTime(uint16_t *date, uint16_t *time) +{ + uint32_t now = Teensy3Clock.get(); + if (now < 315532800) { // before 1980 + *date = 0; + *time = 0; + } else { + DateTimeFields datetime; + breakTime(now, datetime); + *date = FS_DATE(datetime.year + 1900, datetime.mon + 1, datetime.mday); + *time = FS_TIME(datetime.hour, datetime.min, datetime.sec); + } +} +#endif + +bool SDClass::format(int type, char progressChar, Print& pr) +{ + SdCard *card = sdfs.card(); + if (!card) return false; // no SD card + uint32_t sectors = card->sectorCount(); + if (sectors <= 12288) return false; // card too small + uint8_t *buf = (uint8_t *)malloc(512); + if (!buf) return false; // unable to allocate memory + bool ret; + if (sectors > 67108864) { +#ifdef __arm__ + ExFatFormatter exFatFormatter; + ret = exFatFormatter.format(card, buf, &pr); +#else + ret = false; +#endif + } else { + FatFormatter fatFormatter; + ret = fatFormatter.format(card, buf, &pr); + } + free(buf); + if (ret) { + // TODO: Is begin() really necessary? Is a quicker way possible? + card->syncDevice(); + sdfs.restart(); // TODO: is sdfs.volumeBegin() enough?? + } + return ret; +} + +bool SDClass::begin(uint8_t csPin) { +#ifdef __arm__ + FsDateTime::setCallback(dateTime); +#endif + csPin_ = csPin; // remember which one passed in. +#ifdef BUILTIN_SDCARD + if (csPin == BUILTIN_SDCARD) { + bool ret = sdfs.begin(SdioConfig(FIFO_SDIO)); + cardPreviouslyPresent = ret; + #if defined(__IMXRT1062__) + // start off with just trying on T4.x + cdPin_ = _SD_DAT3; + if (!ret) pinMode(_SD_DAT3, INPUT_PULLDOWN); + #endif + return ret; + } +#endif + if (csPin < NUM_DIGITAL_PINS) { + bool ret = sdfs.begin(SdSpiConfig(csPin, SHARED_SPI, SD_SCK_MHZ(25))); + cardPreviouslyPresent = ret; + return ret; + } + return false; +} + +bool SDClass::mediaPresent() +{ + //Serial.print("mediaPresent: "); + bool ret; + SdCard *card = sdfs.card(); +// Serial.printf("mediaPresent: card:%x cs:%u cd:%u\n", (uint32_t)card, csPin_, cdPin_); + if (card) { + if (cardPreviouslyPresent) { + #ifdef BUILTIN_SDCARD + uint32_t s; + if (csPin_ == BUILTIN_SDCARD) { + #if defined(__MK64FX512__) || defined(__MK66FX1M0__) + card->syncDevice(); + #endif // defined(__MK64FX512__) || defined(__MK66FX1M0__) + s = card->status(); + } else s = 0xFFFFFFFF; + #else + const uint32_t s = 0xFFFFFFFF; + #endif + if (s == 0xFFFFFFFF) { + // see if we have digital pin to bypass... + if (cdPin_ < NUM_DIGITAL_PINS) ret = digitalRead(cdPin_); + else { + // SPI doesn't have 32 bit status, read CID register + cid_t cid; + ret = card->readCID(&cid); + } + //Serial.print(ret ? "CID=ok" : "CID=unreadable"); + } else if (s == 0) { + // assume zero status means card removed + // bits 12:9 are card state, which should + // normally be 101 = data transfer mode + //Serial.print("status=offline"); + ret = false; + #ifdef _SD_DAT3 + if (csPin_ == BUILTIN_SDCARD) + pinMode(_SD_DAT3, INPUT_PULLDOWN); + #endif + } else { + //Serial.print("status=present"); + ret = true; + } + } else { + // TODO: need a quick test, only call begin if likely present + ret = true; // assume we need to check + + #ifdef _SD_DAT3 + if (csPin_ == BUILTIN_SDCARD) ret = digitalReadFast(_SD_DAT3); + else + #endif + { + if (cdPin_ < NUM_DIGITAL_PINS) ret = digitalRead(cdPin_); + } + // now try to restart + if (ret) + { + ret = sdfs.restart(); + // bugbug:: if it fails and builtin may need to start pinMode again... + } + //Serial.print(ret ? "begin ok" : "begin nope"); + } + } else { + //Serial.print("no card"); + ret = false; + } + //Serial.println(); + cardPreviouslyPresent = ret; + return ret; +} + +bool SDClass::setMediaDetectPin(uint8_t pin) +{ + Serial.printf("SDClass::setMediaDetectPin(%u)", pin); + #if defined(BUILTIN_SDCARD) + if (pin == BUILTIN_SDCARD) { + csPin_ = BUILTIN_SDCARD; // force it in case user did begin using sdCard + #if defined(_SD_DAT3) + cdPin_ = _SD_DAT3; + if (!cardPreviouslyPresent) pinMode(_SD_DAT3, INPUT_PULLDOWN); + #else + cdPin_ = 0xff; + #endif + } + #endif + if (pin < NUM_DIGITAL_PINS) { + cdPin_ = pin; + pinMode(cdPin_, INPUT_PULLUP); + } else { + cdPin_ = 0xff; + return false; + } + return true; +} diff --git a/firmware/3.0/lib/SD/src/SD.h b/firmware/3.0/lib/SD/src/SD.h old mode 100644 new mode 100755 index c1deb92..27dedcb --- a/firmware/3.0/lib/SD/src/SD.h +++ b/firmware/3.0/lib/SD/src/SD.h @@ -25,6 +25,9 @@ #include #include +#if !defined(SD_FAT_TEENSY_MODIFIED) +#error "Teensy's SD library uses a custom modified copy of SdFat. Standard SdFat was mistakenly used. Arduino should print multiple libraries found for SdFat.h. To resolve this error, you will need to move or delete the copy Arduino is using, or otherwise take steps to cause Teensy's special copy of SdFat to be used." +#endif // Use FILE_READ & FILE_WRITE as defined by FS.h #if defined(FILE_READ) && !defined(FS_H) #undef FILE_READ @@ -50,7 +53,7 @@ #define MAX_FILENAME_LEN 64 #endif -class SDFile : public File +class SDFile : public FileImpl { private: // Classes derived from File are never meant to be constructed @@ -62,15 +65,8 @@ class SDFile : public File friend class SDClass; public: virtual ~SDFile(void) { - if (sdfatfile) sdfatfile.close(); - if (filename) free(filename); - } -#ifdef FILE_WHOAMI - virtual void whoami() { - Serial.printf(" SDFile this=%x, refcount=%u\n", - (int)this, getRefcount()); + close(); } -#endif virtual size_t write(const void *buf, size_t size) { return sdfatfile.write(buf, size); } @@ -106,9 +102,11 @@ class SDFile : public File free(filename); filename = nullptr; } - sdfatfile.close(); + if (sdfatfile.isOpen()) { + sdfatfile.close(); + } } - virtual operator bool() { + virtual bool isOpen() { return sdfatfile.isOpen(); } virtual const char * name() { @@ -134,7 +132,40 @@ class SDFile : public File virtual void rewindDirectory(void) { sdfatfile.rewindDirectory(); } - using Print::write; + virtual bool getCreateTime(DateTimeFields &tm) { + uint16_t fat_date, fat_time; + if (!sdfatfile.getCreateDateTime(&fat_date, &fat_time)) return false; + if ((fat_date == 0) && (fat_time == 0)) return false; + tm.sec = FS_SECOND(fat_time); + tm.min = FS_MINUTE(fat_time); + tm.hour = FS_HOUR(fat_time); + tm.mday = FS_DAY(fat_date); + tm.mon = FS_MONTH(fat_date) - 1; + tm.year = FS_YEAR(fat_date) - 1900; + return true; + } + virtual bool getModifyTime(DateTimeFields &tm) { + uint16_t fat_date, fat_time; + if (!sdfatfile.getModifyDateTime(&fat_date, &fat_time)) return false; + if ((fat_date == 0) && (fat_time == 0)) return false; + tm.sec = FS_SECOND(fat_time); + tm.min = FS_MINUTE(fat_time); + tm.hour = FS_HOUR(fat_time); + tm.mday = FS_DAY(fat_date); + tm.mon = FS_MONTH(fat_date) - 1; + tm.year = FS_YEAR(fat_date) - 1900; + return true; + } + virtual bool setCreateTime(const DateTimeFields &tm) { + if (tm.year < 80 || tm.year > 207) return false; + return sdfatfile.timestamp(T_CREATE, tm.year + 1900, tm.mon + 1, + tm.mday, tm.hour, tm.min, tm.sec); + } + virtual bool setModifyTime(const DateTimeFields &tm) { + if (tm.year < 80 || tm.year > 207) return false; + return sdfatfile.timestamp(T_WRITE, tm.year + 1900, tm.mon + 1, + tm.mday, tm.hour, tm.min, tm.sec); + } private: SDFAT_FILE sdfatfile; char *filename; @@ -146,16 +177,7 @@ class SDClass : public FS { public: SDClass() { } - bool begin(uint8_t csPin = 10) { -#ifdef BUILTIN_SDCARD - if (csPin == BUILTIN_SDCARD) { - return sdfs.begin(SdioConfig(FIFO_SDIO)); - //return sdfs.begin(SdioConfig(DMA_SDIO)); - } -#endif - return sdfs.begin(SdSpiConfig(csPin, SHARED_SPI, SD_SCK_MHZ(16))); - //return sdfs.begin(csPin, SD_SCK_MHZ(24)); - } + bool begin(uint8_t csPin = 10); File open(const char *filepath, uint8_t mode = FILE_READ) { oflag_t flags = O_READ; if (mode == FILE_WRITE) flags = O_RDWR | O_CREAT | O_AT_END; @@ -180,15 +202,32 @@ class SDClass : public FS return sdfs.rmdir(filepath); } uint64_t usedSize() { + if (!cardPreviouslyPresent) return (uint64_t)0; return (uint64_t)(sdfs.clusterCount() - sdfs.freeClusterCount()) * (uint64_t)sdfs.bytesPerCluster(); } uint64_t totalSize() { + if (!cardPreviouslyPresent) return (uint64_t)0; return (uint64_t)sdfs.clusterCount() * (uint64_t)sdfs.bytesPerCluster(); } + bool format(int type=0, char progressChar=0, Print& pr=Serial); + bool mediaPresent(); + + // call to allow you to specify if your SD reader has an IO pin that + // can be used to detect if an chip is inserted. On BUILTIN_SDCARD + // we will default to use it if you use the begin method, howver + // if you bypass this and call directly to SDFat begin, then you + // can use this to let us know. + bool setMediaDetectPin(uint8_t pin); + public: // allow access, so users can mix SD & SdFat APIs SDFAT_BASE sdfs; operator SDFAT_BASE & () { return sdfs; } + static void dateTime(uint16_t *date, uint16_t *time); +private: + bool cardPreviouslyPresent = false; + uint8_t csPin_ = 0xff; + uint8_t cdPin_ = 0xff; }; extern SDClass SD; @@ -227,6 +266,13 @@ class SdVolume uint32_t clusterCount() { return SD.sdfs.vol()->clusterCount(); } +#if defined(__arm__) + operator FsVolume * () __attribute__ ((deprecated("Use SD.begin() to access SD cards"))) { +#elif defined(__AVR__) + operator FatVolume * () __attribute__ ((deprecated("Use SD.begin() to access SD cards"))) { +#endif + return SD.sdfs.vol(); + } }; #endif diff --git a/firmware/3.0/lib/SdFat/src/BufferedPrint.h b/firmware/3.0/lib/SdFat/src/BufferedPrint.h old mode 100644 new mode 100755 index a6a3e1f..b248d1c --- a/firmware/3.0/lib/SdFat/src/BufferedPrint.h +++ b/firmware/3.0/lib/SdFat/src/BufferedPrint.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License diff --git a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatConfig.h b/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatConfig.h old mode 100644 new mode 100755 index 08ffd18..f04ff75 --- a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatConfig.h +++ b/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatConfig.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -24,11 +24,10 @@ */ #ifndef ExFatConfig_h #define ExFatConfig_h -#include "../SdFatConfig.h" -#ifndef USE_EXFAT_UNICODE_NAMES -#define USE_EXFAT_UNICODE_NAMES 0 -#endif // USE_EXFAT_UNICODE_NAMES -#ifndef READ_ONLY -#define READ_ONLY 0 -#endif // READ_ONLY +#include "SdFatConfig.h" + +#ifndef EXFAT_READ_ONLY +#define EXFAT_READ_ONLY 0 +#endif // EXFAT_READ_ONLY + #endif // ExFatConfig_h diff --git a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatDbg.cpp b/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatDbg.cpp old mode 100644 new mode 100755 index 73f602a..dcb3148 --- a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatDbg.cpp +++ b/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatDbg.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -23,8 +23,8 @@ * DEALINGS IN THE SOFTWARE. */ #include "ExFatVolume.h" -#include "upcase.h" -#include "ExFatFile.h" +#include "../common/upcase.h" +#include "ExFatLib.h" #ifndef DOXYGEN_SHOULD_SKIP_THIS //------------------------------------------------------------------------------ static void printHex(print_t* pr, uint8_t h); @@ -51,6 +51,20 @@ static uint16_t exFatDirChecksum(const void* dir, uint16_t checksum) { } return checksum; } + +//------------------------------------------------------------------------------ +static uint16_t hashDir(DirName_t* dir, uint16_t hash) { + for (uint8_t i = 0; i < 30; i += 2) { + uint16_t u = getLe16(dir->unicode + i); + if (!u) { + break; + } + uint16_t c = toUpcase(u); + hash = ((hash << 15) | (hash >> 1)) + (c & 0XFF); + hash = ((hash << 15) | (hash >> 1)) + (c >> 8); + } + return hash; +} //------------------------------------------------------------------------------ static void printDateTime(print_t* pr, uint32_t timeDate, uint8_t ms, int8_t tz) { @@ -105,8 +119,15 @@ static void printDirName(print_t* pr, DirName_t* dir) { pr->println(dir->type, HEX); pr->print(F("unicode: ")); for (size_t i = 0; i < 30; i += 2) { - if (dir->unicode[i] == 0) break; - pr->write(dir->unicode[i]); + uint16_t c = getLe16(dir->unicode + i); + if (c == 0) break; + if (c < 128) { + pr->print(static_cast(c)); + } else { + pr->print("0x"); + pr->print(c, HEX); + } + pr->print(' '); } pr->println(); } @@ -273,7 +294,7 @@ void ExFatPartition::checkUpcase(print_t* pr) { uint8_t* upcase = nullptr; uint32_t size = 0; uint32_t sector = clusterStartSector(m_rootDirectoryCluster); - uint8_t* cache = dataCacheGet(sector, FsCache::CACHE_FOR_READ); + uint8_t* cache = dataCachePrepare(sector, FsCache::CACHE_FOR_READ); if (!cache) { pr->println(F("read root failed")); return; @@ -294,7 +315,7 @@ void ExFatPartition::checkUpcase(print_t* pr) { } for (size_t i = 0; i < size/2; i++) { if ((i%256) == 0) { - upcase = dataCacheGet(sector++, FsCache::CACHE_FOR_READ); + upcase = dataCachePrepare(sector++, FsCache::CACHE_FOR_READ); if (!upcase) { pr->println(F("read upcase failed")); return; @@ -357,7 +378,7 @@ void ExFatPartition::dmpFat(print_t* pr, uint32_t start, uint32_t count) { uint32_t cluster = 128*start; pr->println(F("FAT:")); for (uint32_t i = 0; i < count; i++) { - uint8_t* cache = dataCacheGet(sector + i, FsCache::CACHE_FOR_READ); + uint8_t* cache = dataCachePrepare(sector + i, FsCache::CACHE_FOR_READ); if (!cache) { pr->println(F("cache read failed")); return; @@ -379,12 +400,12 @@ void ExFatPartition::dmpFat(print_t* pr, uint32_t start, uint32_t count) { } //------------------------------------------------------------------------------ void ExFatPartition::dmpSector(print_t* pr, uint32_t sector) { - uint8_t* cache = dataCacheGet(sector, FsCache::CACHE_FOR_READ); + uint8_t* cache = dataCachePrepare(sector, FsCache::CACHE_FOR_READ); if (!cache) { pr->println(F("dmpSector failed")); return; } - for (uint16_t i = 0; i < 512; i++) { + for (uint16_t i = 0; i < m_bytesPerSector; i++) { if (i%32 == 0) { if (i) { pr->println(); @@ -405,7 +426,7 @@ bool ExFatPartition::printDir(print_t* pr, ExFatFile* file) { uint16_t calcHash = 0; uint16_t nameHash = 0; uint16_t setChecksum = 0; - uint16_t calcChecksum = 0;; + uint16_t calcChecksum = 0; uint8_t nameLength = 0; uint8_t setCount = 0; uint8_t nUnicode; @@ -413,8 +434,8 @@ bool ExFatPartition::printDir(print_t* pr, ExFatFile* file) { #define RAW_ROOT #ifndef RAW_ROOT while (1) { - uint8_t buf[32]; - if (file->read(buf, 32) != 32) { + uint8_t buf[FS_DIR_SIZE]; + if (file->read(buf, FS_DIR_SIZE) != FS_DIR_SIZE) { break; } dir = reinterpret_cast(buf); @@ -425,7 +446,7 @@ bool ExFatPartition::printDir(print_t* pr, ExFatFile* file) { for (uint32_t iDir = 0; iDir < nDir; iDir++) { size_t i = iDir%16; if (i == 0) { - uint8_t* cache = dataCacheGet(sector++, FsCache::CACHE_FOR_READ); + uint8_t* cache = dataCachePrepare(sector++, FsCache::CACHE_FOR_READ); if (!cache) { return false; } @@ -475,8 +496,7 @@ bool ExFatPartition::printDir(print_t* pr, ExFatFile* file) { printDirName(pr, dirName); calcChecksum = exFatDirChecksum(dir, calcChecksum); nUnicode = nameLength > 15 ? 15 : nameLength; - calcHash = exFatHashName(reinterpret_cast - (dirName->unicode), nUnicode, calcHash); + calcHash = hashDir(dirName, calcHash); nameLength -= nUnicode; setCount--; if (nameLength == 0 || setCount == 0) { @@ -536,7 +556,7 @@ void ExFatPartition::printUpcase(print_t* pr) { uint32_t checksum = 0; DirUpcase_t* dir; sector = clusterStartSector(m_rootDirectoryCluster); - upcase = dataCacheGet(sector, FsCache::CACHE_FOR_READ); + upcase = dataCachePrepare(sector, FsCache::CACHE_FOR_READ); dir = reinterpret_cast(upcase); if (!dir) { pr->println(F("read root dir failed")); @@ -555,7 +575,7 @@ void ExFatPartition::printUpcase(print_t* pr) { } for (uint16_t i = 0; i < size/2; i++) { if ((i%256) == 0) { - upcase = dataCacheGet(sector++, FsCache::CACHE_FOR_READ); + upcase = dataCachePrepare(sector++, FsCache::CACHE_FOR_READ); if (!upcase) { pr->println(F("read upcase failed")); return; @@ -577,7 +597,7 @@ void ExFatPartition::printUpcase(print_t* pr) { } //------------------------------------------------------------------------------ bool ExFatPartition::printVolInfo(print_t* pr) { - uint8_t* cache = dataCacheGet(0, FsCache::CACHE_FOR_READ); + uint8_t* cache = dataCachePrepare(0, FsCache::CACHE_FOR_READ); if (!cache) { pr->println(F("read mbr failed")); return false; @@ -590,7 +610,7 @@ bool ExFatPartition::printVolInfo(print_t* pr) { pr->print(F("bad partition size")); return false; } - cache = dataCacheGet(volStart, FsCache::CACHE_FOR_READ); + cache = dataCachePrepare(volStart, FsCache::CACHE_FOR_READ); if (!cache) { pr->println(F("read pbs failed")); return false; diff --git a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatFile.cpp b/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatFile.cpp old mode 100644 new mode 100755 index 7b7832d..821ac15 --- a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatFile.cpp +++ b/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatFile.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -24,9 +24,30 @@ */ #define DBG_FILE "ExFatFile.cpp" #include "../common/DebugMacros.h" -#include "ExFatFile.h" -#include "ExFatVolume.h" -#include "upcase.h" +#include "../common/FsUtf.h" +#include "ExFatLib.h" +//------------------------------------------------------------------------------ +/** test for legal character. + * + * \param[in] c character to be tested. + * + * \return true for legal character else false. + */ +inline bool lfnLegalChar(uint8_t c) { +#if USE_UTF8_LONG_NAMES + return !lfnReservedChar(c); +#else // USE_UTF8_LONG_NAMES + return !(lfnReservedChar(c) || c & 0X80); +#endif // USE_UTF8_LONG_NAMES +} +//------------------------------------------------------------------------------ +uint8_t* ExFatFile::dirCache(uint8_t set, uint8_t options) { + DirPos_t pos = m_dirPos; + if (m_vol->dirSeek(&pos, FS_DIR_SIZE*set) != 1) { + return nullptr; + } + return m_vol->dirCache(&pos, options); +} //------------------------------------------------------------------------------ bool ExFatFile::close() { bool rtn = sync(); @@ -136,55 +157,19 @@ bool ExFatFile::getModifyDateTime(uint16_t* pdate, uint16_t* ptime) { return false; } //------------------------------------------------------------------------------ -size_t ExFatFile::getName(ExChar_t* name, size_t length) { - DirName_t* dn; - DirPos_t pos = m_dirPos; - size_t n = 0; - if (!isOpen()) { - DBG_FAIL_MACRO; - goto fail; - } - for (uint8_t is = 1; is < m_setCount; is++) { - if (m_vol->dirSeek(&pos, is == 1 ? 64: 32) != 1) { - DBG_FAIL_MACRO; - goto fail; - } - dn = reinterpret_cast - (m_vol->dirCache(&pos, FsCache::CACHE_FOR_READ)); - if (!dn || dn->type != EXFAT_TYPE_NAME) { - DBG_FAIL_MACRO; - goto fail; - } - for (uint8_t in = 0; in < 15; in++) { - uint16_t c = getLe16(dn->unicode + 2*in); - if (c == 0 || (n + 1) >= length) { - goto done; - } - name[n++] = sizeof(ExChar_t) > 1 || c < 0X7F ? c : '?'; - } - } - done: - name[n] = 0; - return n; - - fail: - *name = 0; - return 0; -} -//------------------------------------------------------------------------------ bool ExFatFile::isBusy() { return m_vol->isBusy(); } //------------------------------------------------------------------------------ -bool ExFatFile::open(const ExChar_t* path, int oflag) { +bool ExFatFile::open(const char* path, oflag_t oflag) { return open(ExFatVolume::cwv(), path, oflag); } //------------------------------------------------------------------------------ -bool ExFatFile::open(ExFatVolume* vol, const ExChar_t* path, int oflag) { +bool ExFatFile::open(ExFatVolume* vol, const char* path, oflag_t oflag) { return vol && open(vol->vwd(), path, oflag); } //------------------------------------------------------------------------------ -bool ExFatFile::open(ExFatFile* dirFile, const ExChar_t* path, oflag_t oflag) { +bool ExFatFile::open(ExFatFile* dirFile, const char* path, oflag_t oflag) { ExFatFile tmpDir; ExName_t fname; // error if already open @@ -213,22 +198,22 @@ bool ExFatFile::open(ExFatFile* dirFile, const ExChar_t* path, oflag_t oflag) { if (*path == 0) { break; } - if (!open(dirFile, &fname, O_RDONLY)) { - DBG_FAIL_MACRO; + if (!openPrivate(dirFile, &fname, O_RDONLY)) { + DBG_WARN_MACRO; goto fail; } tmpDir = *this; dirFile = &tmpDir; close(); } - return open(dirFile, &fname, oflag); + return openPrivate(dirFile, &fname, oflag); fail: return false; } //------------------------------------------------------------------------------ bool ExFatFile::open(ExFatFile* dirFile, uint32_t index, oflag_t oflag) { - if (dirFile->seekSet(32*index) && openNext(dirFile, oflag)) { + if (dirFile->seekSet(FS_DIR_SIZE*index) && openNext(dirFile, oflag)) { if (dirIndex() == index) { return true; } @@ -243,19 +228,15 @@ bool ExFatFile::openNext(ExFatFile* dir, oflag_t oflag) { DBG_FAIL_MACRO; goto fail; } - return openRootFile(dir, nullptr, 0, oflag); + return openPrivate(dir, nullptr, oflag); fail: return false; } //------------------------------------------------------------------------------ -bool ExFatFile::openRootFile(ExFatFile* dir, const ExChar_t* name, - uint8_t nameLength, oflag_t oflag) { +bool ExFatFile::openPrivate(ExFatFile* dir, ExName_t* fname, oflag_t oflag) { int n; - uint8_t nameOffset = 0; - uint8_t nCmp; uint8_t modeFlags; - uint16_t nameHash = 0; uint32_t curCluster __attribute__((unused)); uint8_t* cache __attribute__((unused)); DirPos_t freePos __attribute__((unused)); @@ -263,16 +244,17 @@ bool ExFatFile::openRootFile(ExFatFile* dir, const ExChar_t* name, DirFile_t* dirFile; DirStream_t* dirStream; DirName_t* dirName; - uint8_t buf[32]; + uint8_t buf[FS_DIR_SIZE]; uint8_t freeCount = 0; - uint8_t freeNeed; + uint8_t freeNeed = 3; bool inSet = false; - // error if already open + // error if already open, no access mode, or no directory. if (isOpen() || !dir->isDir()) { DBG_FAIL_MACRO; goto fail; } + switch (oflag & O_ACCMODE) { case O_RDONLY: modeFlags = FILE_FLAG_READ; @@ -288,32 +270,39 @@ bool ExFatFile::openRootFile(ExFatFile* dir, const ExChar_t* name, goto fail; } modeFlags |= oflag & O_APPEND ? FILE_FLAG_APPEND : 0; - if (name) { - nameHash = exFatHashName(name, nameLength, 0); + + if (fname) { + freeNeed = 2 + (fname->nameLength + 14)/15; dir->rewind(); } - freeNeed = 2 + (nameLength + 14)/15; while (1) { - n = dir->read(buf, 32); + n = dir->read(buf, FS_DIR_SIZE); if (n == 0) { goto create; } - if (n != 32) { + if (n != FS_DIR_SIZE) { DBG_FAIL_MACRO; goto fail; } if (!(buf[0] & 0x80)) { + // Unused entry. if (freeCount == 0) { - freePos.position = dir->curPosition() - 32; + freePos.position = dir->curPosition() - FS_DIR_SIZE; freePos.cluster = dir->curCluster(); } if (freeCount < freeNeed) { freeCount++; } if (!buf[0]) { - goto create; + if (fname) { + goto create; + } + // Likely openNext call. + DBG_WARN_MACRO; + goto fail; } + inSet = false; } else if (!inSet) { if (freeCount < freeNeed) { freeCount = 0; @@ -322,62 +311,45 @@ bool ExFatFile::openRootFile(ExFatFile* dir, const ExChar_t* name, continue; } inSet = true; - } - switch (buf[0]) { - case EXFAT_TYPE_FILE: - memset(this, 0, sizeof(ExFatFile)); - dirFile = reinterpret_cast(buf); - m_setCount = dirFile->setCount; - m_attributes = getLe16(dirFile->attributes) & FILE_ATTR_COPY; - if (!(m_attributes & EXFAT_ATTRIB_DIRECTORY)) { - m_attributes |= FILE_ATTR_FILE; - } - m_vol = dir->volume(); - - m_dirPos.cluster = dir->curCluster(); - m_dirPos.position = dir->curPosition() - 32; - m_dirPos.isContiguous = dir->isContiguous(); - break; - - case EXFAT_TYPE_STREAM: - dirStream = reinterpret_cast(buf); - m_flags = modeFlags; - if (dirStream->flags & EXFAT_FLAG_CONTIGUOUS) { - m_flags |= FILE_FLAG_CONTIGUOUS; - } - nameOffset = 0; - m_validLength = getLe64(dirStream->validLength); - m_firstCluster = getLe32(dirStream->firstCluster); - m_dataLength = getLe64(dirStream->dataLength); - if (!name) { - goto found; - } - if (nameLength != dirStream->nameLength || - nameHash != getLe16(dirStream->nameHash)) { - inSet = false; - break; - } - break; - - case EXFAT_TYPE_NAME: - dirName = reinterpret_cast(buf); - nCmp = nameLength - nameOffset; - if (nCmp > 15) { - nCmp = 15; - } - if (!exFatCmpName(dirName, name, nameOffset, nCmp)) { - inSet = false; - break; - } - nameOffset += nCmp; - - if (nameOffset == nameLength) { - goto found; - } - break; - - default: - break; + memset(this, 0, sizeof(ExFatFile)); + dirFile = reinterpret_cast(buf); + m_setCount = dirFile->setCount; + m_attributes = getLe16(dirFile->attributes) & FILE_ATTR_COPY; + if (!(m_attributes & EXFAT_ATTRIB_DIRECTORY)) { + m_attributes |= FILE_ATTR_FILE; + } + m_vol = dir->volume(); + m_dirPos.cluster = dir->curCluster(); + m_dirPos.position = dir->curPosition() - FS_DIR_SIZE; + m_dirPos.isContiguous = dir->isContiguous(); + } else if (buf[0] == EXFAT_TYPE_STREAM) { + dirStream = reinterpret_cast(buf); + m_flags = modeFlags; + if (dirStream->flags & EXFAT_FLAG_CONTIGUOUS) { + m_flags |= FILE_FLAG_CONTIGUOUS; + } + m_validLength = getLe64(dirStream->validLength); + m_firstCluster = getLe32(dirStream->firstCluster); + m_dataLength = getLe64(dirStream->dataLength); + if (!fname) { + goto found; + } + fname->reset(); + if (fname->nameLength != dirStream->nameLength || + fname->nameHash != getLe16(dirStream->nameHash)) { + inSet = false; + } + } else if (buf[0] == EXFAT_TYPE_NAME) { + dirName = reinterpret_cast(buf); + if (!cmpName(dirName, fname)) { + inSet = false; + continue; + } + if (fname->atEnd()) { + goto found; + } + } else { + inSet = false; } } @@ -389,13 +361,13 @@ bool ExFatFile::openRootFile(ExFatFile* dir, const ExChar_t* name, } // Write, truncate, or at end is an error for a directory or read-only file. if ((oflag & (O_TRUNC | O_AT_END)) || (m_flags & FILE_FLAG_WRITE)) { - if (isSubDir() || isReadOnly() || READ_ONLY) { + if (isSubDir() || isReadOnly() || EXFAT_READ_ONLY) { DBG_FAIL_MACRO; goto fail; } } -#if !READ_ONLY +#if !EXFAT_READ_ONLY if (oflag & O_TRUNC) { if (!(m_flags & FILE_FLAG_WRITE)) { DBG_FAIL_MACRO; @@ -409,21 +381,21 @@ bool ExFatFile::openRootFile(ExFatFile* dir, const ExChar_t* name, DBG_FAIL_MACRO; goto fail; } -#endif // READ_ONLY +#endif // !EXFAT_READ_ONLY return true; create: -#if READ_ONLY +#if EXFAT_READ_ONLY DBG_FAIL_MACRO; goto fail; -#else // READ_ONLY +#else // EXFAT_READ_ONLY // don't create unless O_CREAT and write - if (!(oflag & O_CREAT) || !(modeFlags & FILE_FLAG_WRITE) || !name) { - DBG_FAIL_MACRO; + if (!(oflag & O_CREAT) || !(modeFlags & FILE_FLAG_WRITE) || !fname) { + DBG_WARN_MACRO; goto fail; } while (freeCount < freeNeed) { - n = dir->read(buf, 32); + n = dir->read(buf, FS_DIR_SIZE); if (n == 0) { curCluster = dir->m_curCluster; if (!dir->addDirCluster()) { @@ -433,35 +405,29 @@ bool ExFatFile::openRootFile(ExFatFile* dir, const ExChar_t* name, dir->m_curCluster = curCluster; continue; } - if (n != 32) { + if (n != FS_DIR_SIZE) { DBG_FAIL_MACRO; goto fail; } if (freeCount == 0) { - freePos.position = dir->curPosition() - 32; + freePos.position = dir->curPosition() - FS_DIR_SIZE; freePos.cluster = dir->curCluster(); } freeCount++; } - freePos.isContiguous = dir->isContiguous(); memset(this, 0, sizeof(ExFatFile)); m_vol = dir->volume(); m_attributes = FILE_ATTR_FILE; m_dirPos = freePos; + fname->reset(); for (uint8_t i = 0; i < freeNeed; i++) { - if (i) { - if (1 != m_vol->dirSeek(&freePos, 32)) { - DBG_FAIL_MACRO; - goto fail; - } - } - cache = m_vol->dirCache(&freePos, FsCache::CACHE_FOR_WRITE); + cache = dirCache(i, FsCache::CACHE_FOR_WRITE); if (!cache || (cache[0] & 0x80)) { DBG_FAIL_MACRO; goto fail; } - memset(cache, 0 , 32); + memset(cache, 0 , FS_DIR_SIZE); if (i == 0) { dirFile = reinterpret_cast(cache); dirFile->type = EXFAT_TYPE_FILE; @@ -488,28 +454,26 @@ bool ExFatFile::openRootFile(ExFatFile* dir, const ExChar_t* name, } else if (i == 1) { dirStream = reinterpret_cast(cache); dirStream->type = EXFAT_TYPE_STREAM; - dirStream->flags = EXFAT_FLAG_ALWAYS1 | EXFAT_FLAG_CONTIGUOUS; - m_flags = modeFlags | FILE_FLAG_CONTIGUOUS | FILE_FLAG_DIR_DIRTY; - - dirStream->nameLength = nameLength; - setLe16(dirStream->nameHash, nameHash); + dirStream->flags = EXFAT_FLAG_ALWAYS1; + m_flags = modeFlags | FILE_FLAG_DIR_DIRTY; + dirStream->nameLength = fname->nameLength; + setLe16(dirStream->nameHash, fname->nameHash); } else { dirName = reinterpret_cast(cache); dirName->type = EXFAT_TYPE_NAME; - nameOffset = 15*(i - 2); - nCmp = nameLength - nameOffset; - if (nCmp > 15) { - nCmp = 15; - } - for (size_t k = 0; k < nCmp; k++) { - setLe16(dirName->unicode + 2*k, name[k + nameOffset]); + for (size_t k = 0; k < 15; k++) { + if (fname->atEnd()) { + break; + } + uint16_t u = fname->get16(); + setLe16(dirName->unicode + 2*k, u); } } } return sync(); -#endif // READ_ONLY - fail: +#endif // EXFAT_READ_ONLY + fail: // close file m_attributes = FILE_ATTR_CLOSED; m_flags = 0; @@ -531,45 +495,32 @@ bool ExFatFile::openRoot(ExFatVolume* vol) { return false; } //------------------------------------------------------------------------------ -bool ExFatFile::parsePathName(const ExChar_t* path, - ExName_t* fname, const ExChar_t** ptr) { - ExChar_t c; - int end; - int len = 0; - +bool ExFatFile::parsePathName(const char* path, + ExName_t* fname, const char** ptr) { // Skip leading spaces. while (*path == ' ') { path++; } - fname->lfn = path; - - for (len = 0; ; len++) { - c = path[len]; - if (c == 0 || isDirSeparator(c)) { - break; - } + fname->begin = path; + fname->end = path; + while (*path && !isDirSeparator(*path)) { + uint8_t c = *path++; if (!lfnLegalChar(c)) { - return false; + DBG_FAIL_MACRO; + goto fail; } - } - // Advance to next path component. - for (end = len; path[end] == ' ' || isDirSeparator(path[end]); end++) {} - *ptr = &path[end]; - - // Back over spaces and dots. - while (len) { - c = path[len - 1]; if (c != '.' && c != ' ') { - break; + // Need to trim trailing dots spaces. + fname->end = path; } - len--; - } - // Max length of LFN is 255. - if (len > EXFAT_MAX_NAME_LENGTH) { - return false; } - fname->len = len; - return true; + // Advance to next path component. + for (; *path == ' ' || isDirSeparator(*path); path++) {} + *ptr = path; + return hashName(fname); + + fail: + return false; } //------------------------------------------------------------------------------ int ExFatFile::peek() { @@ -634,7 +585,7 @@ int ExFatFile::read(void* buf, size_t count) { n = toRead; } // read sector to cache and copy data to caller - cache = m_vol->dataCacheGet(sector, FsCache::CACHE_FOR_READ); + cache = m_vol->dataCachePrepare(sector, FsCache::CACHE_FOR_READ); if (!cache) { DBG_FAIL_MACRO; goto fail; @@ -675,7 +626,7 @@ int ExFatFile::read(void* buf, size_t count) { return -1; } //------------------------------------------------------------------------------ -bool ExFatFile::remove(const ExChar_t* path) { +bool ExFatFile::remove(const char* path) { ExFatFile file; if (!file.open(this, path, O_WRONLY)) { DBG_FAIL_MACRO; diff --git a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatFile.h b/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatFile.h old mode 100644 new mode 100755 index 629a5b5..34154a7 --- a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatFile.h +++ b/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatFile.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -30,58 +30,27 @@ */ #include #include -#include "ExFatConfig.h" #include "../common/FsDateTime.h" -#include "../common/FsStructs.h" #include "../common/FsApiConstants.h" #include "../common/FmtNumber.h" -#include "ExFatTypes.h" +#include "../common/FsName.h" #include "ExFatPartition.h" class ExFatVolume; - //------------------------------------------------------------------------------ /** Expression for path name separator. */ #define isDirSeparator(c) ((c) == '/') //------------------------------------------------------------------------------ -/** test for legal character. - * - * \param[in] c character to be tested. - * - * \return true for legal character else false. - */ -inline bool lfnLegalChar(ExChar_t c) { - if (c == '/' || c == '\\' || c == '"' || c == '*' || - c == ':' || c == '<' || c == '>' || c == '?' || c == '|') { - return false; - } -#if USE_EXFAT_UNICODE_NAMES - return 0X1F < c; -#else // USE_EXFAT_UNICODE_NAMES - return 0X1F < c && c < 0X7F; -#endif // USE_EXFAT_UNICODE_NAMES -} -//------------------------------------------------------------------------------ /** - * \struct ExName_t + * \class ExName_t * \brief Internal type for file name - do not use in user apps. */ -struct ExName_t { - /** length of Long File Name */ - size_t len; - /** Long File Name start. */ - const ExChar_t* lfn; -}; -//------------------------------------------------------------------------------ -/** - * \struct ExFatPos_t - * \brief Internal type for file position - do not use in user apps. - */ -struct ExFatPos_t { - /** stream position */ - uint64_t position; - /** cluster for position */ - uint32_t cluster; +class ExName_t : public FsName { + public: + /** Length of UTF-16 name */ + size_t nameLength; + /** Hash for UTF-16 name */ + uint16_t nameHash; }; //------------------------------------------------------------------------------ /** @@ -153,7 +122,7 @@ class ExFatFile { /** Check for contiguous file and return its raw sector range. * * \param[out] bgnSector the first sector address for the file. - * \param[out] endSector the last sector address for the file. + * \param[out] endSector the last sector address for the file. * * Parameters may be nullptr. * @@ -166,22 +135,22 @@ class ExFatFile { /** \return Total data length for file. */ uint64_t dataLength() const {return m_dataLength;} /** \return Directory entry index. */ - uint32_t dirIndex() const {return m_dirPos.position/32;} + uint32_t dirIndex() const {return m_dirPos.position/FS_DIR_SIZE;} /** Test for the existence of a file in a directory * * \param[in] path Path of the file to be tested for. * * The calling instance must be an open directory file. * - * dirFile.exists("TOFIND.TXT") searches for "TOFIND.TXT" in the directory + * dirFile.exists("TOFIND.TXT") searches for "TOFIND.TXT" in the directory * dirFile. * * \return true if the file exists else false. */ - bool exists(const ExChar_t* path) { - ExFatFile file; - return file.open(this, path, O_RDONLY); - } + bool exists(const char* path) { + ExFatFile file; + return file.open(this, path, O_RDONLY); + } /** get position for streams * \param[out] pos struct to receive position */ @@ -247,19 +216,41 @@ class ExFatFile { */ bool getModifyDateTime(uint16_t* pdate, uint16_t* ptime); /** - * Get a file's name followed by a zero byte. + * Get a file's name followed by a zero. * * \param[out] name An array of characters for the file's name. * \param[in] size The size of the array in characters. * \return the name length. */ - size_t getName(ExChar_t* name, size_t size); + size_t getName(char* name, size_t size) { +#if USE_UTF8_LONG_NAMES + return getName8(name, size); +#else // USE_UTF8_LONG_NAMES + return getName7(name, size); +#endif // USE_UTF8_LONG_NAMES + } + /** + * Get a file's ASCII name followed by a zero. + * + * \param[out] name An array of characters for the file's name. + * \param[in] size The size of the array in characters. + * \return the name length. + */ + size_t getName7(char* name, size_t size); + /** + * Get a file's UTF-8 name followed by a zero. + * + * \param[out] name An array of characters for the file's name. + * \param[in] size The size of the array in characters. + * \return the name length. + */ + size_t getName8(char* name, size_t size); /** \return value of writeError */ bool getWriteError() const { return isOpen() ? m_error & WRITE_ERROR : true; } /** - * Check for BlockDevice busy. + * Check for FsBlockDevice busy. * * \return true if busy else false. */ @@ -319,7 +310,7 @@ class ExFatFile { * * \return true for success or false for failure. */ - bool mkdir(ExFatFile* parent, const ExChar_t* path, bool pFlag = true); + bool mkdir(ExFatFile* parent, const char* path, bool pFlag = true); /** Open a file or directory by name. * * \param[in] dirFile An open directory containing the file to be opened. @@ -364,7 +355,7 @@ class ExFatFile { * * \return true for success or false for failure. */ - bool open(ExFatFile* dirFile, const ExChar_t* path, oflag_t oflag); + bool open(ExFatFile* dirFile, const char* path, oflag_t oflag); /** Open a file in the volume working directory. * * \param[in] vol Volume where the file is located. @@ -376,7 +367,7 @@ class ExFatFile { * * \return true for success or false for failure. */ - bool open(ExFatVolume* vol, const ExChar_t* path, int oflag); + bool open(ExFatVolume* vol, const char* path, oflag_t oflag); /** Open a file by index. * * \param[in] dirFile An open ExFatFile instance for the directory. @@ -385,7 +376,7 @@ class ExFatFile { * opened. The value for \a index is (directory file position)/32. * * \param[in] oflag bitwise-inclusive OR of open flags. - * See see ExFatFile::open(ExFatFile*, const ExChar_t*, uint8_t). + * See see ExFatFile::open(ExFatFile*, const char*, uint8_t). * * See open() by path for definition of flags. * \return true for success or false for failure. @@ -400,7 +391,7 @@ class ExFatFile { * * \return true for success or false for failure. */ - bool open(const ExChar_t* path, int oflag = O_RDONLY); + bool open(const char* path, oflag_t oflag = O_RDONLY); /** Open the next file or subdirectory in a directory. * * \param[in] dirFile An open instance for the directory @@ -520,12 +511,32 @@ class ExFatFile { */ size_t printModifyDateTime(print_t* pr); /** Print a file's name + * + * \param[in] pr Print stream for output. + * + * \return length for success or zero for failure. + */ + size_t printName(print_t* pr) { +#if USE_UTF8_LONG_NAMES + return printName8(pr); +#else // USE_UTF8_LONG_NAMES + return printName7(pr); +#endif // USE_UTF8_LONG_NAMES + } + /** Print a file's ASCII name * * \param[in] pr Print stream for output. * * \return true for success or false for failure. */ - size_t printName(print_t* pr); + size_t printName7(print_t* pr); + /** Print a file's UTF-8 name + * + * \param[in] pr Print stream for output. + * + * \return true for success or false for failure. + */ + size_t printName8(print_t* pr); /** Read the next byte from a file. * * \return For success read returns the next byte in the file as an int. @@ -572,14 +583,14 @@ class ExFatFile { * * \return true for success or false for failure. */ - bool remove(const ExChar_t* path); + bool remove(const char* path); /** Rename a file or subdirectory. * * \param[in] newPath New path name for the file/directory. * * \return true for success or false for failure. */ - bool rename(const ExChar_t* newPath); + bool rename(const char* newPath); /** Rename a file or subdirectory. * * \param[in] dirFile Directory for the new path. @@ -587,7 +598,7 @@ class ExFatFile { * * \return true for success or false for failure. */ - bool rename(ExFatFile* dirFile, const ExChar_t* newPath); + bool rename(ExFatFile* dirFile, const char* newPath); /** Set the file's current position to zero. */ void rewind() { seekSet(0); @@ -627,6 +638,8 @@ class ExFatFile { * \return true for success or false for failure. */ bool seekSet(uint64_t pos); + /** \return directory set count */ + uint8_t setCount() const {return m_setCount;} /** The sync() call causes all modified data and directory fields * to be written to the storage device. * @@ -714,37 +727,48 @@ class ExFatFile { * \param[in] count Number of bytes to write. * * \return For success write() returns the number of bytes written, always - * \a count. + * \a count. If an error occurs, write() returns zero and writeError is set. */ size_t write(const void* buf, size_t count); - //============================================================================ -#if USE_EXFAT_UNICODE_NAMES - // Not Implemented when Unicode is selected. - bool exists(const char* path); - size_t getName(char *name, size_t size); - bool mkdir(ExFatFile* parent, const char* path, bool pFlag = true); - bool open(ExFatVolume* vol, const char* path, int oflag); - bool open(ExFatFile* dir, const char* path, int oflag); - bool open(const char* path, int oflag = O_RDONLY); - bool remove(const char* path); - bool rename(const char* newPath); - bool rename(ExFatFile* dirFile, const char* newPath); -#endif // USE_EXFAT_UNICODE_NAMES +//------------------------------------------------------------------------------ +#if ENABLE_ARDUINO_SERIAL + /** List directory contents. + * + * \param[in] flags The inclusive OR of + * + * LS_DATE - %Print file modification date + * + * LS_SIZE - %Print file size. + * + * LS_R - Recursive list of subdirectories. + * + * \return true for success or false for failure. + */ + bool ls(uint8_t flags = 0) { + return ls(&Serial, flags); + } + /** Print a file's name. + * + * \return length for success or zero for failure. + */ + size_t printName() { + return ExFatFile::printName(&Serial); + } +#endif // ENABLE_ARDUINO_SERIAL private: /** ExFatVolume allowed access to private members. */ friend class ExFatVolume; bool addCluster(); bool addDirCluster(); - uint8_t setCount() const {return m_setCount;} + bool cmpName(const DirName_t* dirName, ExName_t* fname); + uint8_t* dirCache(uint8_t set, uint8_t options); + bool hashName(ExName_t* fname); bool mkdir(ExFatFile* parent, ExName_t* fname); - bool openRootFile(ExFatFile* dir, - const ExChar_t* name, uint8_t nameLength, oflag_t oflag); - bool open(ExFatFile* dirFile, ExName_t* fname, oflag_t oflag) { - return openRootFile(dirFile, fname->lfn, fname->len, oflag); - } - bool parsePathName(const ExChar_t* path, - ExName_t* fname, const ExChar_t** ptr); + + bool openPrivate(ExFatFile* dir, ExName_t* fname, oflag_t oflag); + bool parsePathName(const char* path, + ExName_t* fname, const char** ptr); uint32_t curCluster() const {return m_curCluster;} ExFatVolume* volume() const {return m_vol;} bool syncDir(); diff --git a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatFilePrint.cpp b/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatFilePrint.cpp old mode 100644 new mode 100755 index 5b10df4..69a9330 --- a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatFilePrint.cpp +++ b/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatFilePrint.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -24,9 +24,8 @@ */ #define DBG_FILE "ExFatFilePrint.cpp" #include "../common/DebugMacros.h" -#include "ExFatFile.h" -#include "upcase.h" -#include "ExFatVolume.h" +#include "ExFatLib.h" +#include "../common/FsUtf.h" //------------------------------------------------------------------------------ bool ExFatFile::ls(print_t* pr) { ExFatFile file; @@ -143,9 +142,8 @@ size_t ExFatFile::printModifyDateTime(print_t* pr) { return 0; } //------------------------------------------------------------------------------ -size_t ExFatFile::printName(print_t* pr) { +size_t ExFatFile::printName7(print_t* pr) { DirName_t* dn; - DirPos_t pos = m_dirPos; size_t n = 0; uint8_t in; uint8_t buf[15]; @@ -153,13 +151,9 @@ size_t ExFatFile::printName(print_t* pr) { DBG_FAIL_MACRO; goto fail; } - for (uint8_t is = 1; is < m_setCount; is++) { - if (m_vol->dirSeek(&pos, is == 1 ? 64: 32) != 1) { - DBG_FAIL_MACRO; - goto fail; - } + for (uint8_t is = 2; is <= m_setCount; is++) { dn = reinterpret_cast - (m_vol->dirCache(&pos, FsCache::CACHE_FOR_READ)); + (dirCache(is, FsCache::CACHE_FOR_READ)); if (!dn || dn->type != EXFAT_TYPE_NAME) { DBG_FAIL_MACRO; goto fail; @@ -167,9 +161,9 @@ size_t ExFatFile::printName(print_t* pr) { for (in = 0; in < 15; in++) { uint16_t c = getLe16(dn->unicode + 2*in); if (!c) { - break;; + break; } - buf[in] = c < 0X7f ? c : '?'; + buf[in] = c < 0X7F ? c : '?'; n++; } pr->write(buf, in); @@ -179,3 +173,56 @@ size_t ExFatFile::printName(print_t* pr) { fail: return 0; } +//------------------------------------------------------------------------------ +size_t ExFatFile::printName8(print_t *pr) { + DirName_t* dn; + uint16_t hs = 0; + uint32_t cp; + size_t n = 0; + uint8_t in; + char buf[5]; + if (!isOpen()) { + DBG_FAIL_MACRO; + goto fail; + } + for (uint8_t is = 2; is <= m_setCount; is++) { + dn = reinterpret_cast + (dirCache(is, FsCache::CACHE_FOR_READ)); + if (!dn || dn->type != EXFAT_TYPE_NAME) { + DBG_FAIL_MACRO; + goto fail; + } + for (in = 0; in < 15; in++) { + uint16_t c = getLe16(dn->unicode + 2*in); + if (hs) { + if (!FsUtf::isLowSurrogate(c)) { + DBG_FAIL_MACRO; + goto fail; + } + cp = FsUtf::u16ToCp(hs, c); + hs = 0; + } else if (!FsUtf::isSurrogate(c)) { + if (c == 0) { + break; + } + cp = c; + } else if (FsUtf::isHighSurrogate(c)) { + hs = c; + continue; + } else { + DBG_FAIL_MACRO; + goto fail; + } + char* str = FsUtf::cpToMb(cp, buf, buf + sizeof(buf)); + if (!str) { + DBG_FAIL_MACRO; + goto fail; + } + n += pr->write(buf, str - buf); + } + } + return n; + + fail: + return 0; +} diff --git a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatFileWrite.cpp b/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatFileWrite.cpp old mode 100644 new mode 100755 index 88731ea..8356f42 --- a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatFileWrite.cpp +++ b/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatFileWrite.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -24,12 +24,10 @@ */ #define DBG_FILE "ExFatFileWrite.cpp" #include "../common/DebugMacros.h" -#include "ExFatFile.h" -#include "ExFatVolume.h" -#include "upcase.h" +#include "ExFatLib.h" //============================================================================== -#if READ_ONLY -bool ExFatFile::mkdir(ExFatFile* parent, const ExChar_t* path, bool pFlag) { +#if EXFAT_READ_ONLY +bool ExFatFile::mkdir(ExFatFile* parent, const char* path, bool pFlag) { (void) parent; (void)path; (void)pFlag; @@ -39,11 +37,11 @@ bool ExFatFile::preAllocate(uint64_t length) { (void)length; return false; } -bool ExFatFile::rename(const ExChar_t* newPath) { +bool ExFatFile::rename(const char* newPath) { (void)newPath; return false; } -bool ExFatFile::rename(ExFatFile* dirFile, const ExChar_t* newPath) { +bool ExFatFile::rename(ExFatFile* dirFile, const char* newPath) { (void)dirFile; (void)newPath; return false; @@ -60,7 +58,7 @@ size_t ExFatFile::write(const void* buf, size_t nbyte) { return false; } //============================================================================== -#else // READ_ONLY +#else // EXFAT_READ_ONLY //------------------------------------------------------------------------------ static uint16_t exFatDirChecksum(const uint8_t* data, uint16_t checksum) { bool skip = data[0] == EXFAT_TYPE_FILE; @@ -132,18 +130,15 @@ bool ExFatFile::addDirCluster() { DBG_FAIL_MACRO; goto fail; } - cache = m_vol->cacheClear(); - if (!cache) { - DBG_FAIL_MACRO; - goto fail; - } - memset(cache, 0, m_vol->bytesPerSector()); sector = m_vol->clusterStartSector(m_curCluster); - for (uint32_t i = 0; i < m_vol->sectorsPerCluster(); i++) { - if (!m_vol->writeSector(sector + i, cache)) { + for (uint32_t i = 0; i < m_vol->sectorsPerCluster(); i++) { + cache = m_vol->dataCachePrepare(sector + i, + FsCache::CACHE_RESERVE_FOR_WRITE); + if (!cache) { DBG_FAIL_MACRO; goto fail; } + memset(cache, 0, m_vol->bytesPerSector()); } if (!isRoot()) { m_flags |= FILE_FLAG_DIR_DIRTY; @@ -156,7 +151,7 @@ bool ExFatFile::addDirCluster() { return false; } //------------------------------------------------------------------------------ -bool ExFatFile::mkdir(ExFatFile* parent, const ExChar_t* path, bool pFlag) { +bool ExFatFile::mkdir(ExFatFile* parent, const char* path, bool pFlag) { ExName_t fname; ExFatFile tmpDir; @@ -182,7 +177,7 @@ bool ExFatFile::mkdir(ExFatFile* parent, const ExChar_t* path, bool pFlag) { if (!*path) { break; } - if (!open(parent, &fname, O_RDONLY)) { + if (!openPrivate(parent, &fname, O_RDONLY)) { if (!pFlag || !mkdir(parent, &fname)) { DBG_FAIL_MACRO; goto fail; @@ -204,12 +199,11 @@ bool ExFatFile::mkdir(ExFatFile* parent, ExName_t* fname) { goto fail; } // create a normal file - if (!open(parent, fname, O_CREAT | O_EXCL | O_RDWR)) { + if (!openPrivate(parent, fname, O_CREAT | O_EXCL | O_RDWR)) { DBG_FAIL_MACRO; goto fail; } // convert file to directory - m_attributes = FILE_ATTR_SUBDIR; // allocate and zero first cluster @@ -259,7 +253,6 @@ bool ExFatFile::preAllocate(uint64_t length) { } //------------------------------------------------------------------------------ bool ExFatFile::remove() { - DirPos_t pos = m_dirPos; uint8_t* cache; if (!isWritable()) { DBG_FAIL_MACRO; @@ -281,12 +274,8 @@ bool ExFatFile::remove() { } } - for (uint8_t i = 0; i <= m_setCount; i++) { - if (i && m_vol->dirSeek(&pos, 32) != 1) { - DBG_FAIL_MACRO; - goto fail; - } - cache = m_vol->dirCache(&pos, FsCache::CACHE_FOR_WRITE); + for (uint8_t is = 0; is <= m_setCount; is++) { + cache = dirCache(is, FsCache::CACHE_FOR_WRITE); if (!cache) { DBG_FAIL_MACRO; goto fail; @@ -305,11 +294,11 @@ bool ExFatFile::remove() { return false; } //------------------------------------------------------------------------------ -bool ExFatFile::rename(const ExChar_t* newPath) { +bool ExFatFile::rename(const char* newPath) { return rename(m_vol->vwd(), newPath); } //------------------------------------------------------------------------------ -bool ExFatFile::rename(ExFatFile* dirFile, const ExChar_t* newPath) { +bool ExFatFile::rename(ExFatFile* dirFile, const char* newPath) { ExFatFile file; ExFatFile oldFile; @@ -347,7 +336,7 @@ bool ExFatFile::rename(ExFatFile* dirFile, const ExChar_t* newPath) { //------------------------------------------------------------------------------ bool ExFatFile::rmdir() { int n; - uint8_t dir[32]; + uint8_t dir[FS_DIR_SIZE]; // must be open subdirectory if (!isSubDir()) { DBG_FAIL_MACRO; @@ -357,11 +346,11 @@ bool ExFatFile::rmdir() { // make sure directory is empty while (1) { - n = read(dir, 32); + n = read(dir, FS_DIR_SIZE); if (n == 0) { break; } - if (n != 32 || dir[0] & 0X80) { + if (n != FS_DIR_SIZE || dir[0] & 0X80) { DBG_FAIL_MACRO; goto fail; } @@ -403,12 +392,9 @@ bool ExFatFile::syncDir() { DirStream_t* ds; uint8_t* cache; uint16_t checksum = 0; - uint8_t setCount = 0; - DirPos_t pos = m_dirPos; - - for (uint8_t i = 0;; i++) { - cache = m_vol->dirCache(&pos, FsCache::CACHE_FOR_READ); + for (uint8_t is = 0; is <= m_setCount ; is++) { + cache = dirCache(is, FsCache::CACHE_FOR_READ); if (!cache) { DBG_FAIL_MACRO; goto fail; @@ -416,7 +402,6 @@ bool ExFatFile::syncDir() { switch (cache[0]) { case EXFAT_TYPE_FILE: df = reinterpret_cast(cache); - setCount = df->setCount; setLe16(df->attributes, m_attributes & FILE_ATTR_COPY); if (FsDateTime::callback) { uint16_t date, time; @@ -453,11 +438,6 @@ bool ExFatFile::syncDir() { break; } checksum = exFatDirChecksum(cache, checksum); - if (i == setCount) break; - if (m_vol->dirSeek(&pos, 32) != 1) { - DBG_FAIL_MACRO; - goto fail; - } } df = reinterpret_cast (m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_WRITE)); @@ -482,11 +462,9 @@ bool ExFatFile::timestamp(uint8_t flags, uint16_t year, uint8_t month, DirFile_t* df; uint8_t* cache; uint16_t checksum = 0; - uint8_t setCount = 0; uint16_t date; uint16_t time; uint8_t ms10; - DirPos_t pos; if (!isFile() || year < 1980 @@ -510,10 +488,9 @@ bool ExFatFile::timestamp(uint8_t flags, uint16_t year, uint8_t month, date = FS_DATE(year, month, day); time = FS_TIME(hour, minute, second); ms10 = second & 1 ? 100 : 0; - pos = m_dirPos; - for (uint8_t i = 0;; i++) { - cache = m_vol->dirCache(&pos, FsCache::CACHE_FOR_READ); + for (uint8_t is = 0; is <= m_setCount; is++) { + cache = dirCache(is, FsCache::CACHE_FOR_READ); if (!cache) { DBG_FAIL_MACRO; goto fail; @@ -521,7 +498,6 @@ bool ExFatFile::timestamp(uint8_t flags, uint16_t year, uint8_t month, switch (cache[0]) { case EXFAT_TYPE_FILE: df = reinterpret_cast(cache); - setCount = df->setCount; setLe16(df->attributes, m_attributes & FILE_ATTR_COPY); m_vol->dataCacheDirty(); if (flags & T_ACCESS) { @@ -552,11 +528,6 @@ bool ExFatFile::timestamp(uint8_t flags, uint16_t year, uint8_t month, break; } checksum = exFatDirChecksum(cache, checksum); - if (i == setCount) break; - if (m_vol->dirSeek(&pos, 32) != 1) { - DBG_FAIL_MACRO; - goto fail; - } } df = reinterpret_cast (m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_WRITE)); @@ -722,7 +693,7 @@ size_t ExFatFile::write(const void* buf, size_t nbyte) { // rewrite part of sector cacheOption = FsCache::CACHE_FOR_WRITE; } - cache = m_vol->dataCacheGet(sector, cacheOption); + cache = m_vol->dataCachePrepare(sector, cacheOption); if (!cache) { DBG_FAIL_MACRO; goto fail; @@ -780,6 +751,6 @@ size_t ExFatFile::write(const void* buf, size_t nbyte) { fail: // return for write error m_error |= WRITE_ERROR; - return -1; + return 0; } -#endif // READ_ONLY +#endif // EXFAT_READ_ONLY diff --git a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatFormatter.cpp b/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatFormatter.cpp old mode 100644 new mode 100755 index c465661..f424b1f --- a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatFormatter.cpp +++ b/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatFormatter.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -24,7 +24,8 @@ */ #define DBG_FILE "ExFatFormatter.cpp" #include "../common/DebugMacros.h" -#include "ExFatFormatter.h" +#include "../common/upcase.h" +#include "ExFatLib.h" //------------------------------------------------------------------------------ // Formatter assumes 512 byte sectors. const uint32_t BOOT_BACKUP_OFFSET = 12; @@ -45,7 +46,7 @@ const uint32_t ROOT_CLUSTER = 4; #define writeMsg(pr, str) if (pr) pr->write(str) #endif // PRINT_FORMAT_PROGRESS //------------------------------------------------------------------------------ -bool ExFatFormatter::format(BlockDevice* dev, uint8_t* secBuf, print_t* pr) { +bool ExFatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) { #if !PRINT_FORMAT_PROGRESS (void)pr; #endif // !PRINT_FORMAT_PROGRESS @@ -201,7 +202,7 @@ bool ExFatFormatter::format(BlockDevice* dev, uint8_t* secBuf, print_t* pr) { memset(secBuf, 0, BYTES_PER_SECTOR); // Allocate two reserved clusters, bitmap, upcase, and root clusters. secBuf[0] = 0XF8; - for (size_t i = 0; i < 20; i++) { + for (size_t i = 1; i < 20; i++) { secBuf[i] = 0XFF; } for (uint32_t i = 0; i < ns; i++) { @@ -257,14 +258,14 @@ bool ExFatFormatter::format(BlockDevice* dev, uint8_t* secBuf, print_t* pr) { label = reinterpret_cast(secBuf); label->type = EXFAT_TYPE_LABEL & 0X7F; - // bitmap directory entry. + // bitmap directory entry. dbm = reinterpret_cast(secBuf + 32); dbm->type = EXFAT_TYPE_BITMAP; setLe32(dbm->firstCluster, BITMAP_CLUSTER); setLe64(dbm->size, bitmapSize); // upcase directory entry. - dup = reinterpret_cast(secBuf +64); + dup = reinterpret_cast(secBuf + 64); dup->type = EXFAT_TYPE_UPCASE; setLe32(dup->checksum, m_upcaseChecksum); setLe32(dup->firstCluster, UPCASE_CLUSTER); diff --git a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatFormatter.h b/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatFormatter.h old mode 100644 new mode 100755 index 5b65c70..89e81e4 --- a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatFormatter.h +++ b/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatFormatter.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -24,10 +24,7 @@ */ #ifndef ExFatFormatter_h #define ExFatFormatter_h -#include "ExFatConfig.h" -#include "../common/SysCall.h" -#include "../common/BlockDevice.h" -#include "upcase.h" +#include "../common/FsBlockDevice.h" /** * \class ExFatFormatter * \brief Format an exFAT volume. @@ -43,7 +40,7 @@ class ExFatFormatter { * * \return true for success or false for failure. */ - bool format(BlockDevice* dev, uint8_t* secBuf, print_t* pr = nullptr); + bool format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr = nullptr); private: bool syncUpcase(); bool writeUpcase(uint32_t sector); @@ -52,7 +49,7 @@ class ExFatFormatter { uint32_t m_upcaseSector; uint32_t m_upcaseChecksum; uint32_t m_upcaseSize; - BlockDevice* m_dev; + FsBlockDevice* m_dev; uint8_t* m_secBuf; }; #endif // ExFatFormatter_h diff --git a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatLib.h b/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatLib.h old mode 100644 new mode 100755 index a004180..9a39615 --- a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatLib.h +++ b/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatLib.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -25,6 +25,5 @@ #ifndef ExFatLib_h #define ExFatLib_h #include "ExFatVolume.h" -#include "ExFatFile.h" #include "ExFatFormatter.h" #endif // ExFatLib_h diff --git a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatName.cpp b/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatName.cpp new file mode 100755 index 0000000..32c96af --- /dev/null +++ b/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatName.cpp @@ -0,0 +1,194 @@ +/** + * Copyright (c) 2011-2021 Bill Greiman + * This file is part of the SdFat library for SD memory cards. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#define DBG_FILE "ExFatName.cpp" +#include "../common/DebugMacros.h" +#include "../common/upcase.h" +#include "../common/FsUtf.h" +#include "ExFatLib.h" +//------------------------------------------------------------------------------ +static char toUpper(char c) { + return 'a' <= c && c <= 'z' ? c - 'a' + 'A' : c; +} +//------------------------------------------------------------------------------ +inline uint16_t exFatHash(char c, uint16_t hash) { + uint8_t u = toUpper(c); + hash = ((hash << 15) | (hash >> 1)) + u; + hash = ((hash << 15) | (hash >> 1)); + return hash; +} +//------------------------------------------------------------------------------ +inline uint16_t exFatHash(uint16_t u, uint16_t hash) { + uint16_t c = toUpcase(u); + hash = ((hash << 15) | (hash >> 1)) + (c & 0XFF); + hash = ((hash << 15) | (hash >> 1)) + (c >> 8); + return hash; +} +//------------------------------------------------------------------------------ +bool ExFatFile::cmpName(const DirName_t* dirName, ExName_t* fname) { + for (uint8_t i = 0; i < 15; i++) { + uint16_t u = getLe16(dirName->unicode + 2*i); + if (fname->atEnd()) { + return u == 0; + } +#if USE_UTF8_LONG_NAMES + uint16_t cp = fname->get16(); + if (toUpcase(cp) != toUpcase(u)) { + return false; + } +#else // USE_UTF8_LONG_NAMES + char c = fname->getch(); + if (u >= 0x7F || toUpper(c) != toUpper(u)) { + return false; + } +#endif // USE_UTF8_LONG_NAMES + } + return true; +} +//------------------------------------------------------------------------------ +size_t ExFatFile::getName7(char* name, size_t count) { + DirName_t* dn; + size_t n = 0; + if (!isOpen()) { + DBG_FAIL_MACRO; + goto fail; + } + for (uint8_t is = 2; is <= m_setCount; is++) { + dn = reinterpret_cast + (dirCache(is, FsCache::CACHE_FOR_READ)); + if (!dn || dn->type != EXFAT_TYPE_NAME) { + DBG_FAIL_MACRO; + goto fail; + } + for (uint8_t in = 0; in < 15; in++) { + uint16_t c = getLe16(dn->unicode + 2*in); + if (c == 0) { + goto done; + } + if ((n + 1) >= count) { + DBG_FAIL_MACRO; + goto fail; + } + name[n++] = c < 0X7F ? c : '?'; + } + } + done: + name[n] = 0; + return n; + + fail: + *name = 0; + return 0; +} +//------------------------------------------------------------------------------ +size_t ExFatFile::getName8(char* name, size_t count) { + char* end = name + count; + char* str = name; + char* ptr; + DirName_t* dn; + uint16_t hs = 0; + uint32_t cp; + if (!isOpen()) { + DBG_FAIL_MACRO; + goto fail; + } + for (uint8_t is = 2; is <= m_setCount; is++) { + dn = reinterpret_cast + (dirCache(is, FsCache::CACHE_FOR_READ)); + if (!dn || dn->type != EXFAT_TYPE_NAME) { + DBG_FAIL_MACRO; + goto fail; + } + for (uint8_t in = 0; in < 15; in++) { + uint16_t c = getLe16(dn->unicode + 2*in); + if (hs) { + if (!FsUtf::isLowSurrogate(c)) { + DBG_FAIL_MACRO; + goto fail; + } + cp = FsUtf::u16ToCp(hs, c); + hs = 0; + } else if (!FsUtf::isSurrogate(c)) { + if (c == 0) { + goto done; + } + cp = c; + } else if (FsUtf::isHighSurrogate(c)) { + hs = c; + continue; + } else { + DBG_FAIL_MACRO; + goto fail; + } + // Save space for zero byte. + ptr = FsUtf::cpToMb(cp, str, end - 1); + if (!ptr) { + DBG_FAIL_MACRO; + goto fail; + } + str = ptr; + } + } + done: + *str = '\0'; + return str - name; + + fail: + *name = 0; + return 0; +} +//------------------------------------------------------------------------------ +bool ExFatFile::hashName(ExName_t* fname) { + uint16_t hash = 0; + fname->reset(); +#if USE_UTF8_LONG_NAMES + fname->nameLength = 0; + while (!fname->atEnd()) { + uint16_t u = fname->get16(); + if (u == 0XFFFF) { + DBG_FAIL_MACRO; + goto fail; + } + hash = exFatHash(u, hash); + fname->nameLength++; + } +#else // USE_UTF8_LONG_NAMES + while (!fname->atEnd()) { + // Convert to byte for smaller exFatHash. + char c = fname->getch(); + hash = exFatHash(c, hash); + } + fname->nameLength = fname->end - fname->begin; +#endif // USE_UTF8_LONG_NAMES + fname->nameHash = hash; + if (!fname->nameLength || fname->nameLength > EXFAT_MAX_NAME_LENGTH) { + DBG_FAIL_MACRO; + goto fail; + } + return true; + + fail: + return false; +} + diff --git a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatPartition.cpp b/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatPartition.cpp old mode 100644 new mode 100755 index a86fd4e..0d3a105 --- a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatPartition.cpp +++ b/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatPartition.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -24,8 +24,7 @@ */ #define DBG_FILE "ExFatPartition.cpp" #include "../common/DebugMacros.h" -#include "ExFatVolume.h" -#include "../common/FsStructs.h" +#include "ExFatLib.h" //------------------------------------------------------------------------------ // return 0 if error, 1 if no space, else start cluster. uint32_t ExFatPartition::bitmapFind(uint32_t cluster, uint32_t count) { @@ -42,7 +41,7 @@ uint32_t ExFatPartition::bitmapFind(uint32_t cluster, uint32_t count) { while (true) { uint32_t sector = m_clusterHeapStartSector + (endAlloc >> (m_bytesPerSectorShift + 3)); - cache = bitmapCacheGet(sector, FsCache::CACHE_FOR_READ); + cache = bitmapCachePrepare(sector, FsCache::CACHE_FOR_READ); if (!cache) { return 0; } @@ -102,7 +101,7 @@ bool ExFatPartition::bitmapModify(uint32_t cluster, (start >> (m_bytesPerSectorShift + 3)); i = (start >> 3) & m_sectorMask; while (true) { - cache = bitmapCacheGet(sector++, FsCache::CACHE_FOR_WRITE); + cache = bitmapCachePrepare(sector++, FsCache::CACHE_FOR_WRITE); if (!cache) { DBG_FAIL_MACRO; goto fail; @@ -141,7 +140,7 @@ uint32_t ExFatPartition::chainSize(uint32_t cluster) { uint8_t* ExFatPartition::dirCache(DirPos_t* pos, uint8_t options) { uint32_t sector = clusterStartSector(pos->cluster); sector += (m_clusterMask & pos->position) >> m_bytesPerSectorShift; - uint8_t* cache = dataCacheGet(sector, options); + uint8_t* cache = dataCachePrepare(sector, options); return cache ? cache + (pos->position & m_sectorMask) : nullptr; } //------------------------------------------------------------------------------ @@ -164,7 +163,8 @@ int8_t ExFatPartition::dirSeek(DirPos_t* pos, uint32_t offset) { return 1; } //------------------------------------------------------------------------------ -uint8_t ExFatPartition::fatGet(uint32_t cluster, uint32_t* value) { +// return -1 error, 0 EOC, 1 OK +int8_t ExFatPartition::fatGet(uint32_t cluster, uint32_t* value) { uint8_t* cache; uint32_t next; uint32_t sector; @@ -175,12 +175,11 @@ uint8_t ExFatPartition::fatGet(uint32_t cluster, uint32_t* value) { } sector = m_fatStartSector + (cluster >> (m_bytesPerSectorShift - 2)); - cache = dataCacheGet(sector, FsCache::CACHE_FOR_READ); + cache = dataCachePrepare(sector, FsCache::CACHE_FOR_READ); if (!cache) { return -1; } next = getLe32(cache + ((cluster << 2) & m_sectorMask)); - if (next == EXFAT_EOC) { return 0; } @@ -196,7 +195,7 @@ bool ExFatPartition::fatPut(uint32_t cluster, uint32_t value) { goto fail; } sector = m_fatStartSector + (cluster >> (m_bytesPerSectorShift - 2)); - cache = dataCacheGet(sector, FsCache::CACHE_FOR_WRITE); + cache = dataCachePrepare(sector, FsCache::CACHE_FOR_WRITE); if (!cache) { DBG_FAIL_MACRO; goto fail; @@ -222,7 +221,7 @@ bool ExFatPartition::freeChain(uint32_t cluster) { DBG_FAIL_MACRO; goto fail; } - if ((cluster + 1) != next || status == 0) { + if (status == 0 || (cluster + 1) != next) { if (!bitmapModify(start, cluster - start + 1, 0)) { DBG_FAIL_MACRO; goto fail; @@ -245,7 +244,7 @@ uint32_t ExFatPartition::freeClusterCount() { uint8_t* cache; while (true) { - cache = dataCacheGet(sector++, FsCache::CACHE_FOR_READ); + cache = dataCachePrepare(sector++, FsCache::CACHE_FOR_READ); if (!cache) { return 0; } @@ -267,7 +266,7 @@ uint32_t ExFatPartition::freeClusterCount() { } } //------------------------------------------------------------------------------ -bool ExFatPartition::init(BlockDevice* dev, uint8_t part) { +bool ExFatPartition::init(FsBlockDevice* dev, uint8_t part) { uint32_t volStart = 0; uint8_t* cache; pbs_t* pbs; @@ -278,7 +277,7 @@ bool ExFatPartition::init(BlockDevice* dev, uint8_t part) { m_fatType = 0; m_blockDev = dev; cacheInit(m_blockDev); - cache = dataCacheGet(0, FsCache::CACHE_FOR_READ); + cache = dataCachePrepare(0, FsCache::CACHE_FOR_READ); if (part > 4 || !cache) { DBG_FAIL_MACRO; goto fail; @@ -291,7 +290,7 @@ bool ExFatPartition::init(BlockDevice* dev, uint8_t part) { goto fail; } volStart = getLe32(mp->relativeSectors); - cache = dataCacheGet(volStart, FsCache::CACHE_FOR_READ); + cache = dataCachePrepare(volStart, FsCache::CACHE_FOR_READ); if (!cache) { DBG_FAIL_MACRO; goto fail; @@ -325,6 +324,48 @@ bool ExFatPartition::init(BlockDevice* dev, uint8_t part) { return false; } //------------------------------------------------------------------------------ +bool ExFatPartition::init(FsBlockDevice* dev, uint32_t firstSector, uint32_t numSectors) { + uint32_t volStart = firstSector; + uint8_t* cache; + pbs_t* pbs; + BpbExFat_t* bpb; + + m_fatType = 0; + m_blockDev = dev; + cacheInit(m_blockDev); + cache = dataCachePrepare(volStart, FsCache::CACHE_FOR_READ); + if (!cache) { + DBG_FAIL_MACRO; + goto fail; + } + pbs = reinterpret_cast(cache); + if (strncmp(pbs->oemName, "EXFAT", 5)) { + DBG_FAIL_MACRO; + goto fail; + } + bpb = reinterpret_cast(pbs->bpb); + if (bpb->bytesPerSectorShift != m_bytesPerSectorShift) { + DBG_FAIL_MACRO; + goto fail; + } + m_fatStartSector = volStart + getLe32(bpb->fatOffset); + m_fatLength = getLe32(bpb->fatLength); + m_clusterHeapStartSector = volStart + getLe32(bpb->clusterHeapOffset); + m_clusterCount = getLe32(bpb->clusterCount); + m_rootDirectoryCluster = getLe32(bpb->rootDirectoryCluster); + m_sectorsPerClusterShift = bpb->sectorsPerClusterShift; + m_bytesPerCluster = 1UL << (m_bytesPerSectorShift + m_sectorsPerClusterShift); + m_clusterMask = m_bytesPerCluster - 1; + // Set m_bitmapStart to first free cluster. + m_bitmapStart = 0; + bitmapFind(0, 1); + m_fatType = FAT_TYPE_EXFAT; + return true; + + fail: + return false; +} +//------------------------------------------------------------------------------ uint32_t ExFatPartition::rootLength() { uint32_t nc = chainSize(m_rootDirectoryCluster); return nc << bytesPerClusterShift(); diff --git a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatPartition.h b/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatPartition.h old mode 100644 new mode 100755 index e2f0bcf..0f74c3b --- a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatPartition.h +++ b/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatPartition.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -29,15 +29,30 @@ * \brief ExFatPartition include file. */ #include "../common/SysCall.h" -#include "../common/BlockDevice.h" +#include "../common/FsBlockDevice.h" #include "../common/FsCache.h" -#include "ExFatConfig.h" -#include "ExFatTypes.h" +#include "../common/FsStructs.h" +/** Set EXFAT_READ_ONLY non-zero for read only */ +#ifndef EXFAT_READ_ONLY +#define EXFAT_READ_ONLY 0 +#endif // EXFAT_READ_ONLY /** Type for exFAT partition */ const uint8_t FAT_TYPE_EXFAT = 64; class ExFatFile; - +//------------------------------------------------------------------------------ +/** + * \struct DirPos_t + * \brief Internal type for position in directory file. + */ +struct DirPos_t { + /** current cluster */ + uint32_t cluster; + /** offset */ + uint32_t position; + /** directory is contiguous */ + bool isContiguous; +}; //============================================================================== /** * \class ExFatPartition @@ -67,6 +82,13 @@ class ExFatPartition { uint32_t clusterCount() const {return m_clusterCount;} /** \return the cluster heap start sector. */ uint32_t clusterHeapStartSector() const {return m_clusterHeapStartSector;} + /** End access to volume + * \return pointer to sector size buffer for format. + */ + uint8_t* end() { + m_fatType = 0; + return cacheClear(); + } /** \return the FAT length in sectors */ uint32_t fatLength() const {return m_fatLength;} /** \return the FAT start sector number. */ @@ -84,9 +106,10 @@ class ExFatPartition { * * \return true for success or false for failure. */ - bool init(BlockDevice* dev, uint8_t part); + bool init(FsBlockDevice* dev, uint8_t part); + bool init(FsBlockDevice* dev, uint32_t firstSector, uint32_t numberSectors); /** - * Check for BlockDevice busy. + * Check for device busy. * * \return true if busy else false. */ @@ -98,8 +121,7 @@ class ExFatPartition { /** \return the number of sectors in a cluster. */ uint32_t sectorsPerCluster() const {return 1UL << m_sectorsPerClusterShift;} #ifndef DOXYGEN_SHOULD_SKIP_THIS - // Use sectorsPerCluster(). blocksPerCluster() will be removed in the future. - uint32_t blocksPerCluster() __attribute__ ((deprecated)) {return sectorsPerCluster();} //NOLINT + uint32_t __attribute__((error("use sectorsPerCluster()"))) blocksPerCluster(); #endif // DOXYGEN_SHOULD_SKIP_THIS /** \return the power of two for sectors per cluster. */ uint8_t sectorsPerClusterShift() const {return m_sectorsPerClusterShift;} @@ -124,14 +146,14 @@ class ExFatPartition { bool bitmapModify(uint32_t cluster, uint32_t count, bool value); //---------------------------------------------------------------------------- // Cache functions. - uint8_t* bitmapCacheGet(uint32_t sector, uint8_t option) { + uint8_t* bitmapCachePrepare(uint32_t sector, uint8_t option) { #if USE_EXFAT_BITMAP_CACHE - return m_bitmapCache.get(sector, option); + return m_bitmapCache.prepare(sector, option); #else // USE_EXFAT_BITMAP_CACHE - return m_dataCache.get(sector, option); + return m_dataCache.prepare(sector, option); #endif // USE_EXFAT_BITMAP_CACHE } - void cacheInit(BlockDevice* dev) { + void cacheInit(FsBlockDevice* dev) { #if USE_EXFAT_BITMAP_CACHE m_bitmapCache.init(dev); #endif // USE_EXFAT_BITMAP_CACHE @@ -146,8 +168,8 @@ class ExFatPartition { } void dataCacheDirty() {m_dataCache.dirty();} void dataCacheInvalidate() {m_dataCache.invalidate();} - uint8_t* dataCacheGet(uint32_t sector, uint8_t option) { - return m_dataCache.get(sector, option); + uint8_t* dataCachePrepare(uint32_t sector, uint8_t option) { + return m_dataCache.prepare(sector, option); } uint32_t dataCacheSector() {return m_dataCache.sector();} bool dataCacheSync() {return m_dataCache.sync();} @@ -159,7 +181,7 @@ class ExFatPartition { } uint8_t* dirCache(DirPos_t* pos, uint8_t options); int8_t dirSeek(DirPos_t* pos, uint32_t offset); - uint8_t fatGet(uint32_t cluster, uint32_t* value); + int8_t fatGet(uint32_t cluster, uint32_t* value); bool fatPut(uint32_t cluster, uint32_t value); uint32_t chainSize(uint32_t cluster); bool freeChain(uint32_t cluster); @@ -187,8 +209,8 @@ class ExFatPartition { } //---------------------------------------------------------------------------- static const uint8_t m_bytesPerSectorShift = 9; - static const uint16_t m_bytesPerSector = 512; - static const uint16_t m_sectorMask = 0x1FF; + static const uint16_t m_bytesPerSector = 1 << m_bytesPerSectorShift; + static const uint16_t m_sectorMask = m_bytesPerSector - 1; //---------------------------------------------------------------------------- #if USE_EXFAT_BITMAP_CACHE FsCache m_bitmapCache; @@ -202,7 +224,7 @@ class ExFatPartition { uint32_t m_rootDirectoryCluster; uint32_t m_clusterMask; uint32_t m_bytesPerCluster; - BlockDevice* m_blockDev; + FsBlockDevice* m_blockDev; uint8_t m_fatType = 0; uint8_t m_sectorsPerClusterShift; }; diff --git a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatVolume.cpp b/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatVolume.cpp old mode 100644 new mode 100755 index 0cb015a..3b32be5 --- a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatVolume.cpp +++ b/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatVolume.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -22,15 +22,19 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -#include "ExFatVolume.h" +#define DBG_FILE "ExFatVolume.cpp" +#include "../common/DebugMacros.h" +#include "ExFatLib.h" ExFatVolume* ExFatVolume::m_cwv = nullptr; //----------------------------------------------------------------------------- -bool ExFatVolume::chdir(const ExChar_t* path) { +bool ExFatVolume::chdir(const char* path) { ExFatFile dir; if (!dir.open(vwd(), path, O_RDONLY)) { + DBG_FAIL_MACRO; goto fail; } if (!dir.isDir()) { + DBG_FAIL_MACRO; goto fail; } m_vwd = dir; diff --git a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatVolume.h b/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatVolume.h old mode 100644 new mode 100755 index 254bd32..26a0ebd --- a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatVolume.h +++ b/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatVolume.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -24,7 +24,6 @@ */ #ifndef ExFatVolume_h #define ExFatVolume_h -#include "ExFatPartition.h" #include "ExFatFile.h" //============================================================================== /** @@ -41,7 +40,7 @@ class ExFatVolume : public ExFatPartition { * \param[in] part partition to initialize. * \return true for success or false for failure. */ - bool begin(BlockDevice* dev, bool setCwv = true, uint8_t part = 1) { + bool begin(FsBlockDevice* dev, bool setCwv = true, uint8_t part = 1) { if (!init(dev, part)) { return false; } @@ -53,6 +52,18 @@ class ExFatVolume : public ExFatPartition { } return true; } + bool begin(FsBlockDevice* dev, bool setCwv, uint32_t firstSector, uint32_t numSectors) { + if (!init(dev, firstSector, numSectors)) { + return false; + } + if (!chdir()) { + return false; + } + if (setCwv || !m_cwv) { + m_cwv = this; + } + return true; + } /** * Set volume working directory to root. * \return true for success or false for failure. @@ -66,7 +77,7 @@ class ExFatVolume : public ExFatPartition { * \param[in] path Path for volume working directory. * \return true for success or false for failure. */ - bool chdir(const ExChar_t* path); + bool chdir(const char* path); /** Change global working volume to this volume. */ void chvol() {m_cwv = this;} @@ -78,11 +89,10 @@ class ExFatVolume : public ExFatPartition { * * \return true if the file exists else false. */ - bool exists(const ExChar_t* path) { + bool exists(const char* path) { ExFatFile tmp; return tmp.open(this, path, O_RDONLY); } - //---------------------------------------------------------------------------- /** List the directory contents of the root directory. * @@ -117,7 +127,7 @@ class ExFatVolume : public ExFatPartition { * * \return true for success or false for failure. */ - bool ls(print_t* pr, const ExChar_t* path, uint8_t flags) { + bool ls(print_t* pr, const char* path, uint8_t flags) { ExFatFile dir; return dir.open(this, path, O_RDONLY) && dir.ls(pr, flags); } @@ -129,7 +139,7 @@ class ExFatVolume : public ExFatPartition { * * \return true for success or false for failure. */ - bool mkdir(const ExChar_t* path, bool pFlag = true) { + bool mkdir(const char* path, bool pFlag = true) { ExFatFile sub; return sub.mkdir(vwd(), path, pFlag); } @@ -139,7 +149,7 @@ class ExFatVolume : public ExFatPartition { * \param[in] oflag open flags. * \return a ExFile object. */ - ExFile open(const ExChar_t* path, oflag_t oflag = O_RDONLY) { + ExFile open(const char* path, oflag_t oflag = O_RDONLY) { ExFile tmpFile; tmpFile.open(this, path, oflag); return tmpFile; @@ -150,7 +160,7 @@ class ExFatVolume : public ExFatPartition { * * \return true for success or false for failure. */ - bool remove(const ExChar_t* path) { + bool remove(const char* path) { ExFatFile tmp; return tmp.open(this, path, O_WRONLY) && tmp.remove(); } @@ -168,7 +178,7 @@ class ExFatVolume : public ExFatPartition { * * \return true for success or false for failure. */ - bool rename(const ExChar_t* oldPath, const ExChar_t* newPath) { + bool rename(const char* oldPath, const char* newPath) { ExFatFile file; return file.open(vwd(), oldPath, O_RDONLY) && file.rename(vwd(), newPath); } @@ -180,7 +190,7 @@ class ExFatVolume : public ExFatPartition { * * \return true for success or false for failure. */ - bool rmdir(const ExChar_t* path) { + bool rmdir(const char* path) { ExFatFile sub; return sub.open(this, path, O_RDONLY) && sub.rmdir(); } @@ -192,7 +202,7 @@ class ExFatVolume : public ExFatPartition { * * \return true for success or false for failure. */ - bool truncate(const ExChar_t* path, uint64_t length) { + bool truncate(const char* path, uint64_t length) { ExFatFile file; if (!file.open(this, path, O_WRONLY)) { return false; @@ -236,7 +246,7 @@ class ExFatVolume : public ExFatPartition { * * \return true for success or false for failure. */ - bool ls(const ExChar_t* path, uint8_t flags = 0) { + bool ls(const char* path, uint8_t flags = 0) { return ls(&Serial, path, flags); } #endif // ENABLE_ARDUINO_SERIAL @@ -327,15 +337,6 @@ class ExFatVolume : public ExFatPartition { return truncate(path.c_str(), length); } #endif // ENABLE_ARDUINO_STRING - //============================================================================ -#if USE_EXFAT_UNICODE_NAMES - // Not implemented when Unicode is selected. - bool exists(const char* path); - bool mkdir(const char* path, bool pFlag = true); - bool remove(const char* path); - bool rename(const char* oldPath, const char* newPath); - bool rmdir(const char* path); -#endif // USE_EXFAT_UNICODE_NAMES private: friend ExFatFile; diff --git a/firmware/3.0/lib/SdFat/src/ExFatLib/upcase.cpp b/firmware/3.0/lib/SdFat/src/ExFatLib/upcase.cpp old mode 100644 new mode 100755 index 5edd9d8..ec716dd --- a/firmware/3.0/lib/SdFat/src/ExFatLib/upcase.cpp +++ b/firmware/3.0/lib/SdFat/src/ExFatLib/upcase.cpp @@ -1,277 +1 @@ -/** - * Copyright (c) 2011-2020 Bill Greiman - * This file is part of the SdFat library for SD memory cards. - * - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ -#include "upcase.h" - -#ifdef __AVR__ -#include -#define TABLE_MEM PROGMEM -#define readTable8(sym) pgm_read_byte(&sym) -#define readTable16(sym) pgm_read_word(&sym) -#else // __AVR__ -#define TABLE_MEM -#define readTable8(sym) (sym) -#define readTable16(sym) (sym) -#endif // __AVR__ - -struct map16 { - uint16_t base; - int8_t off; - uint8_t count; -}; -typedef struct map16 map16_t; - -struct pair16 { - uint16_t key; - uint16_t val; -}; -typedef struct pair16 pair16_t; -//------------------------------------------------------------------------------ -static const map16_t mapTable[] TABLE_MEM = { - {0X0061, -32, 26}, - {0X00E0, -32, 23}, - {0X00F8, -32, 7 }, - {0X0100, 1, 48}, - {0X0132, 1, 6}, - {0X0139, 1, 16}, - {0X014A, 1, 46}, - {0X0179, 1, 6}, - {0X0182, 1, 4}, - {0X01A0, 1, 6}, - {0X01B3, 1, 4}, - {0X01CD, 1, 16}, - {0X01DE, 1, 18}, - {0X01F8, 1, 40}, - {0X0222, 1, 18}, - {0X0246, 1, 10}, - {0X03AD, -37, 3}, - {0X03B1, -32, 17}, - {0X03C3, -32, 9}, - {0X03D8, 1, 24}, - {0X0430, -32, 32}, - {0X0450, -80, 16}, - {0X0460, 1, 34}, - {0X048A, 1, 54}, - {0X04C1, 1, 14}, - {0X04D0, 1, 68}, - {0X0561, -48, 38}, - {0X1E00, 1, 150}, - {0X1EA0, 1, 90}, - {0X1F00, 8, 8}, - {0X1F10, 8, 6}, - {0X1F20, 8, 8}, - {0X1F30, 8, 8}, - {0X1F40, 8, 6}, - {0X1F60, 8, 8}, - {0X1F70, 74, 2}, - {0X1F72, 86, 4}, - {0X1F76, 100, 2}, - {0X1F7A, 112, 2}, - {0X1F7C, 126, 2}, - {0X1F80, 8, 8}, - {0X1F90, 8, 8}, - {0X1FA0, 8, 8}, - {0X1FB0, 8, 2}, - {0X1FD0, 8, 2}, - {0X1FE0, 8, 2}, - {0X2170, -16, 16}, - {0X24D0, -26, 26}, - {0X2C30, -48, 47}, - {0X2C67, 1, 6}, - {0X2C80, 1, 100}, - {0X2D00, 0, 38}, - {0XFF41, -32, 26}, -}; -const size_t MAP_DIM = sizeof(mapTable)/sizeof(map16_t); -//------------------------------------------------------------------------------ -static const pair16_t lookupTable[] TABLE_MEM = { - {0X00FF, 0X0178}, - {0X0180, 0X0243}, - {0X0188, 0X0187}, - {0X018C, 0X018B}, - {0X0192, 0X0191}, - {0X0195, 0X01F6}, - {0X0199, 0X0198}, - {0X019A, 0X023D}, - {0X019E, 0X0220}, - {0X01A8, 0X01A7}, - {0X01AD, 0X01AC}, - {0X01B0, 0X01AF}, - {0X01B9, 0X01B8}, - {0X01BD, 0X01BC}, - {0X01BF, 0X01F7}, - {0X01C6, 0X01C4}, - {0X01C9, 0X01C7}, - {0X01CC, 0X01CA}, - {0X01DD, 0X018E}, - {0X01F3, 0X01F1}, - {0X01F5, 0X01F4}, - {0X023A, 0X2C65}, - {0X023C, 0X023B}, - {0X023E, 0X2C66}, - {0X0242, 0X0241}, - {0X0253, 0X0181}, - {0X0254, 0X0186}, - {0X0256, 0X0189}, - {0X0257, 0X018A}, - {0X0259, 0X018F}, - {0X025B, 0X0190}, - {0X0260, 0X0193}, - {0X0263, 0X0194}, - {0X0268, 0X0197}, - {0X0269, 0X0196}, - {0X026B, 0X2C62}, - {0X026F, 0X019C}, - {0X0272, 0X019D}, - {0X0275, 0X019F}, - {0X027D, 0X2C64}, - {0X0280, 0X01A6}, - {0X0283, 0X01A9}, - {0X0288, 0X01AE}, - {0X0289, 0X0244}, - {0X028A, 0X01B1}, - {0X028B, 0X01B2}, - {0X028C, 0X0245}, - {0X0292, 0X01B7}, - {0X037B, 0X03FD}, - {0X037C, 0X03FE}, - {0X037D, 0X03FF}, - {0X03AC, 0X0386}, - {0X03C2, 0X03A3}, - {0X03CC, 0X038C}, - {0X03CD, 0X038E}, - {0X03CE, 0X038F}, - {0X03F2, 0X03F9}, - {0X03F8, 0X03F7}, - {0X03FB, 0X03FA}, - {0X04CF, 0X04C0}, - {0X1D7D, 0X2C63}, - {0X1F51, 0X1F59}, - {0X1F53, 0X1F5B}, - {0X1F55, 0X1F5D}, - {0X1F57, 0X1F5F}, - {0X1F78, 0X1FF8}, - {0X1F79, 0X1FF9}, - {0X1FB3, 0X1FBC}, - {0X1FCC, 0X1FC3}, - {0X1FE5, 0X1FEC}, - {0X1FFC, 0X1FF3}, - {0X214E, 0X2132}, - {0X2184, 0X2183}, - {0X2C61, 0X2C60}, - {0X2C76, 0X2C75}, -}; -const size_t LOOKUP_DIM = sizeof(lookupTable)/sizeof(pair16_t); -//------------------------------------------------------------------------------ -static size_t searchPair16(const pair16_t* table, size_t size, uint16_t key) { - size_t left = 0; - size_t right = size; - size_t mid; - while (right - left > 1) { - mid = left + (right - left)/2; - if (readTable16(table[mid].key) <= key) { - left = mid; - } else { - right = mid; - } - } - return left; -} -//------------------------------------------------------------------------------ -static char toUpper(char c) { - return c - ('a' <= c && c <= 'z' ? 'a' - 'A' : 0); -} -//------------------------------------------------------------------------------ -bool exFatCmpName(const DirName_t* unicode, - const ExChar16_t* name, size_t offset, size_t n) { - uint16_t u; - for (size_t i = 0; i < n; i++) { - u = getLe16(unicode->unicode + 2*i); - if (toUpcase(name[i + offset]) != toUpcase(u)) { - return false; - } - } - return true; -} -//------------------------------------------------------------------------------ -bool exFatCmpName(const DirName_t* unicode, - const char* name, size_t offset, size_t n) { - uint16_t u; - for (size_t i = 0; i < n; i++) { - u = getLe16(unicode->unicode + 2*i); - if (u >= 0x7F || toUpper(name[i + offset]) != toUpper(u)) { - return false; - } - } - return true; -} -//------------------------------------------------------------------------------ -uint16_t exFatHashName(const ExChar16_t* name, size_t n, uint16_t hash) { - for (size_t i = 0; i < n; i++) { - uint16_t c = toUpcase(name[i]); - hash = ((hash << 15) | (hash >> 1)) + (c & 0XFF); - hash = ((hash << 15) | (hash >> 1)) + (c >> 8); - } - return hash; -} -//------------------------------------------------------------------------------ -uint16_t exFatHashName(const char* name, size_t n, uint16_t hash) { - for (size_t i = 0; i < n; i++) { - uint8_t c = name[i]; - if ('a' <= c && c <= 'z') { - c -= 'a' - 'A'; - } - hash = ((hash << 15) | (hash >> 1)) + c; - hash = ((hash << 15) | (hash >> 1)); - } - return hash; -} -//------------------------------------------------------------------------------ -uint16_t toUpcase(uint16_t chr) { - uint16_t i, first; - // Optimize for simple ASCII. - if (chr < 127) { - return chr - ('a' <= chr && chr <= 'z' ? 'a' - 'A' : 0); - } - i = searchPair16(reinterpret_cast(mapTable), MAP_DIM, chr); - first = readTable16(mapTable[i].base); - if (first <= chr && (chr - first) < readTable8(mapTable[i].count)) { - int8_t off = readTable8(mapTable[i].off); - if (off == 1) { - return chr - ((chr - first) & 1); - } - return chr + (off ? off : -0x1C60); - } - i = searchPair16(lookupTable, LOOKUP_DIM, chr); - if (readTable16(lookupTable[i].key) == chr) { - return readTable16(lookupTable[i].val); - } - return chr; -} -//------------------------------------------------------------------------------ -uint32_t upcaseChecksum(uint16_t uc, uint32_t sum) { - sum = (sum << 31) + (sum >> 1) + (uc & 0XFF); - sum = (sum << 31) + (sum >> 1) + (uc >> 8); - return sum; -} +// this file no longer used diff --git a/firmware/3.0/lib/SdFat/src/FatLib/FatDbg.cpp b/firmware/3.0/lib/SdFat/src/FatLib/FatDbg.cpp old mode 100644 new mode 100755 index 164b4bd..0168602 --- a/firmware/3.0/lib/SdFat/src/FatLib/FatDbg.cpp +++ b/firmware/3.0/lib/SdFat/src/FatLib/FatDbg.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -22,10 +22,20 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -#include "FatVolume.h" -#include "FatFile.h" +#include "FatLib.h" #ifndef DOXYGEN_SHOULD_SKIP_THIS //------------------------------------------------------------------------------ +static uint16_t getLfnChar(DirLfn_t* ldir, uint8_t i) { + if (i < 5) { + return getLe16(ldir->unicode1 + 2*i); + } else if (i < 11) { + return getLe16(ldir->unicode2 + 2*i - 10); + } else if (i < 13) { + return getLe16(ldir->unicode3 + 2*i - 22); + } + return 0; +} +//------------------------------------------------------------------------------ static void printHex(print_t* pr, uint8_t h) { if (h < 16) { pr->write('0'); @@ -33,6 +43,18 @@ static void printHex(print_t* pr, uint8_t h) { pr->print(h, HEX); } //------------------------------------------------------------------------------ +static void printHex(print_t* pr, uint8_t w, uint16_t h) { + char buf[5]; + char* ptr = buf + sizeof(buf); + *--ptr = 0; + for (uint8_t i = 0; i < w; i++) { + char c = h & 0XF; + *--ptr = c < 10 ? c + '0' : c + 'A' - 10; + h >>= 4; + } + pr->write(ptr); +} +//------------------------------------------------------------------------------ static void printHex(print_t* pr, uint16_t val) { bool space = true; for (uint8_t i = 0; i < 4; i++) { @@ -63,13 +85,32 @@ static void printHex(print_t* pr, uint32_t val) { } } //------------------------------------------------------------------------------ -static void printDir(print_t* pr, DirFat_t* dir) { - if (!dir->name[0] || dir->name[0] == FAT_NAME_DELETED) { - pr->println(F("Not Used")); +template +static void printHexLn(print_t* pr, Uint val) { + printHex(pr, val); + pr->println(); +} +//------------------------------------------------------------------------------ +static bool printFatDir(print_t* pr, DirFat_t* dir) { + DirLfn_t* ldir = reinterpret_cast(dir); + if (!dir->name[0]) { + pr->println(F("Unused")); + return false; + } else if (dir->name[0] == FAT_NAME_DELETED) { + pr->println(F("Deleted")); } else if (isFileOrSubdir(dir)) { - pr->print(F("name: ")); + pr->print(F("SFN: ")); + for (uint8_t i = 0; i < 11; i++) { + printHex(pr, dir->name[i]); + pr->write(' '); + } + pr->write(' '); pr->write(dir->name, 11); pr->println(); + pr->print(F("attributes: 0X")); + printHexLn(pr, dir->attributes); + pr->print(F("caseFlags: 0X")); + printHexLn(pr, dir->caseFlags); uint32_t fc = ((uint32_t)getLe16(dir->firstClusterHigh) << 16) | getLe16(dir->firstClusterLow); pr->print(F("firstCluster: ")); @@ -77,24 +118,84 @@ static void printDir(print_t* pr, DirFat_t* dir) { pr->print(F("fileSize: ")); pr->println(getLe32(dir->fileSize)); } else if (isLongName(dir)) { - pr->println(F("LFN")); + pr->print(F("LFN: ")); + for (uint8_t i = 0; i < 13; i++) { + uint16_t c = getLfnChar(ldir, i); + if (15 < c && c < 128) { + pr->print(static_cast(c)); + } else { + pr->print("0X"); + pr->print(c, HEX); + } + pr->print(' '); + } + pr->println(); + pr->print(F("order: 0X")); + pr->println(ldir->order, HEX); + pr->print(F("attributes: 0X")); + pr->println(ldir->attributes, HEX); + pr->print(F("checksum: 0X")); + pr->println(ldir->checksum, HEX); } else { pr->println(F("Other")); } + pr->println(); + return true; } //------------------------------------------------------------------------------ -void FatPartition::dmpDirSector(print_t* pr, uint32_t sector) { +void FatFile::dmpFile(print_t* pr, uint32_t pos, size_t n) { + char text[17]; + text[16] = 0; + if (n >= 0XFFF0) { + n = 0XFFF0; + } + if (!seekSet(pos)) { + return; + } + for (size_t i = 0; i <= n; i++) { + if ((i & 15) == 0) { + if (i) { + pr->write(' '); + pr->write(text); + if (i == n) { + break; + } + } + pr->write('\r'); + pr->write('\n'); + if (i >= n) { + break; + } + printHex(pr, 4, i); + pr->write(' '); + } + int16_t h = read(); + if (h < 0) { + break; + } + pr->write(' '); + printHex(pr, 2, h); + text[i&15] = ' ' <= h && h < 0X7F ? h : '.'; + } + pr->write('\r'); + pr->write('\n'); +} +//------------------------------------------------------------------------------ +bool FatPartition::dmpDirSector(print_t* pr, uint32_t sector) { DirFat_t dir[16]; - if (!readSector(sector, reinterpret_cast(dir))) { + if (!cacheSafeRead(sector, reinterpret_cast(dir))) { pr->println(F("dmpDir failed")); - return; + return false; } for (uint8_t i = 0; i < 16; i++) { - printDir(pr, dir + i); + if (!printFatDir(pr, dir + i)) { + return false; + } } + return true; } //------------------------------------------------------------------------------ -void FatPartition::dmpRootDir(print_t* pr) { +bool FatPartition::dmpRootDir(print_t* pr, uint32_t n) { uint32_t sector; if (fatType() == 16) { sector = rootDirStart(); @@ -102,18 +203,18 @@ void FatPartition::dmpRootDir(print_t* pr) { sector = clusterStartSector(rootDirStart()); } else { pr->println(F("dmpRootDir failed")); - return; + return false; } - dmpDirSector(pr, sector); + return dmpDirSector(pr, sector + n); } //------------------------------------------------------------------------------ void FatPartition::dmpSector(print_t* pr, uint32_t sector, uint8_t bits) { - uint8_t data[512]; - if (!readSector(sector, data)) { + uint8_t data[FatPartition::m_bytesPerSector]; + if (!cacheSafeRead(sector, data)) { pr->println(F("dmpSector failed")); return; } - for (uint16_t i = 0; i < 512;) { + for (uint16_t i = 0; i < m_bytesPerSector;) { if (i%32 == 0) { if (i) { pr->println(); @@ -144,7 +245,7 @@ void FatPartition::dmpFat(print_t* pr, uint32_t start, uint32_t count) { uint32_t sector = m_fatStartSector + start; uint32_t cluster = nf*start; for (uint32_t i = 0; i < count; i++) { - cache_t* pc = cacheFetchFat(sector + i, FsCache::CACHE_FOR_READ); + uint8_t* pc = fatCachePrepare(sector + i, FsCache::CACHE_FOR_READ); if (!pc) { pr->println(F("cache read failed")); return; @@ -158,7 +259,7 @@ void FatPartition::dmpFat(print_t* pr, uint32_t start, uint32_t count) { } cluster++; pr->write(' '); - uint32_t v = fatType() == 32 ? pc->fat32[k] : pc->fat16[k]; + uint32_t v = fatType() == 32 ? getLe32(pc + 4*k) : getLe16(pc + 2*k); printHex(pr, v); } pr->println(); diff --git a/firmware/3.0/lib/SdFat/src/FatLib/FatFile.cpp b/firmware/3.0/lib/SdFat/src/FatLib/FatFile.cpp old mode 100644 new mode 100755 index ff9e579..c04e121 --- a/firmware/3.0/lib/SdFat/src/FatLib/FatFile.cpp +++ b/firmware/3.0/lib/SdFat/src/FatLib/FatFile.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -24,8 +24,7 @@ */ #define DBG_FILE "FatFile.cpp" #include "../common/DebugMacros.h" -#include "FatFile.h" -#include "FatVolume.h" +#include "FatLib.h" //------------------------------------------------------------------------------ // Add a cluster to a file. bool FatFile::addCluster() { @@ -55,7 +54,7 @@ bool FatFile::addCluster() { // Return with first sector of cluster in the cache. bool FatFile::addDirCluster() { uint32_t sector; - cache_t* pc; + uint8_t* pc; if (isRootFixed()) { DBG_FAIL_MACRO; @@ -71,18 +70,13 @@ bool FatFile::addDirCluster() { goto fail; } sector = m_vol->clusterStartSector(m_curCluster); - pc = m_vol->cacheFetchData(sector, FsCache::CACHE_RESERVE_FOR_WRITE); - if (!pc) { - DBG_FAIL_MACRO; - goto fail; - } - memset(pc, 0, m_vol->bytesPerSector()); - // zero rest of clusters - for (uint8_t i = 1; i < m_vol->sectorsPerCluster(); i++) { - if (!m_vol->writeSector(sector + i, pc->data)) { + for (uint8_t i = 0; i < m_vol->sectorsPerCluster(); i++) { + pc = m_vol->dataCachePrepare(sector + i, FsCache::CACHE_RESERVE_FOR_WRITE); + if (!pc) { DBG_FAIL_MACRO; goto fail; } + memset(pc, 0, m_vol->bytesPerSector()); } // Set position to EOF to avoid inconsistent curCluster/curPosition. m_curPosition += m_vol->bytesPerCluster(); @@ -95,13 +89,13 @@ bool FatFile::addDirCluster() { // cache a file's directory entry // return pointer to cached entry or null for failure DirFat_t* FatFile::cacheDirEntry(uint8_t action) { - cache_t* pc; - pc = m_vol->cacheFetchData(m_dirSector, action); - if (!pc) { + uint8_t* pc = m_vol->dataCachePrepare(m_dirSector, action); + DirFat_t* dir = reinterpret_cast(pc); + if (!dir) { DBG_FAIL_MACRO; goto fail; } - return pc->dir + (m_dirIndex & 0XF); + return dir + (m_dirIndex & 0XF); fail: return nullptr; @@ -206,7 +200,7 @@ uint32_t FatFile::dirSize() { return 0; } if (isRootFixed()) { - return 32*m_vol->rootDirEntryCount(); + return FS_DIR_SIZE*m_vol->rootDirEntryCount(); } uint16_t n = 0; uint32_t c = isRoot32() ? m_vol->rootDirStart() : m_firstCluster; @@ -308,7 +302,7 @@ bool FatFile::isBusy() { } //------------------------------------------------------------------------------ bool FatFile::mkdir(FatFile* parent, const char* path, bool pFlag) { - fname_t fname; + FatName_t fname; FatFile tmpDir; if (isOpen() || !parent->isDir()) { @@ -349,11 +343,11 @@ bool FatFile::mkdir(FatFile* parent, const char* path, bool pFlag) { return false; } //------------------------------------------------------------------------------ -bool FatFile::mkdir(FatFile* parent, fname_t* fname) { +bool FatFile::mkdir(FatFile* parent, FatName_t* fname) { uint32_t sector; DirFat_t dot; DirFat_t* dir; - cache_t* pc; + uint8_t* pc; if (!parent->isDir()) { DBG_FAIL_MACRO; @@ -387,7 +381,7 @@ bool FatFile::mkdir(FatFile* parent, fname_t* fname) { DBG_FAIL_MACRO; goto fail; } - // change directory entry attribute + // change directory entry attribute dir->attributes = FAT_ATTRIB_DIRECTORY; // make entry for '.' @@ -399,19 +393,20 @@ bool FatFile::mkdir(FatFile* parent, fname_t* fname) { // cache sector for '.' and '..' sector = m_vol->clusterStartSector(m_firstCluster); - pc = m_vol->cacheFetchData(sector, FsCache::CACHE_FOR_WRITE); - if (!pc) { + pc = m_vol->dataCachePrepare(sector, FsCache::CACHE_FOR_WRITE); + dir = reinterpret_cast(pc); + if (!dir) { DBG_FAIL_MACRO; goto fail; } // copy '.' to sector - memcpy(&pc->dir[0], &dot, sizeof(dot)); + memcpy(&dir[0], &dot, sizeof(dot)); // make entry for '..' dot.name[1] = '.'; setLe16(dot.firstClusterLow, parent->m_firstCluster & 0XFFFF); setLe16(dot.firstClusterHigh, parent->m_firstCluster >> 16); // copy '..' to sector - memcpy(&pc->dir[1], &dot, sizeof(dot)); + memcpy(&dir[1], &dot, sizeof(dot)); // write first sector return m_vol->cacheSync(); @@ -429,7 +424,7 @@ bool FatFile::open(FatVolume* vol, const char* path, oflag_t oflag) { //------------------------------------------------------------------------------ bool FatFile::open(FatFile* dirFile, const char* path, oflag_t oflag) { FatFile tmpDir; - fname_t fname; + FatName_t fname; // error if already open if (isOpen() || !dirFile->isDir()) { @@ -458,7 +453,7 @@ bool FatFile::open(FatFile* dirFile, const char* path, oflag_t oflag) { break; } if (!open(dirFile, &fname, O_RDONLY)) { - DBG_FAIL_MACRO; + DBG_WARN_MACRO; goto fail; } tmpDir = *this; @@ -477,11 +472,7 @@ bool FatFile::open(FatFile* dirFile, uint16_t index, oflag_t oflag) { DirLfn_t* ldir; uint8_t n = index < 20 ? index : 20; for (uint8_t i = 1; i <= n; i++) { - if (!dirFile->seekSet(32UL*(index - i))) { - DBG_FAIL_MACRO; - goto fail; - } - ldir = reinterpret_cast(dirFile->readDirCache()); + ldir = reinterpret_cast(dirFile->cacheDir(index - i)); if (!ldir) { DBG_FAIL_MACRO; goto fail; @@ -598,6 +589,18 @@ bool FatFile::openCachedEntry(FatFile* dirFile, uint16_t dirIndex, return false; } //------------------------------------------------------------------------------ +bool FatFile::openCluster(FatFile* file) { + if (file->m_dirCluster == 0) { + return openRoot(file->m_vol); + } + memset(this, 0, sizeof(FatFile)); + m_attributes = FILE_ATTR_SUBDIR; + m_flags = FILE_FLAG_READ; + m_vol = file->m_vol; + m_firstCluster = file->m_dirCluster; + return true; +} +//------------------------------------------------------------------------------ bool FatFile::openNext(FatFile* dirFile, oflag_t oflag) { uint8_t checksum = 0; DirLfn_t* ldir; @@ -611,7 +614,7 @@ bool FatFile::openNext(FatFile* dirFile, oflag_t oflag) { } while (1) { // read entry into cache - index = dirFile->curPosition()/32; + index = dirFile->curPosition()/FS_DIR_SIZE; DirFat_t* dir = dirFile->readDirCache(); if (!dir) { if (dirFile->getError()) { @@ -684,6 +687,15 @@ bool FatFile::openRoot(FatVolume* vol) { return false; } //------------------------------------------------------------------------------ +int FatFile::peek() { + uint32_t curPosition = m_curPosition; + uint32_t curCluster = m_curCluster; + int c = read(); + m_curPosition = curPosition; + m_curCluster = curCluster; + return c; +} +//------------------------------------------------------------------------------ bool FatFile::preAllocate(uint32_t length) { uint32_t need; if (!length || !isWritable() || m_firstCluster) { @@ -711,15 +723,6 @@ bool FatFile::preAllocate(uint32_t length) { return false; } //------------------------------------------------------------------------------ -int FatFile::peek() { - uint32_t curPosition = m_curPosition; - uint32_t curCluster = m_curCluster; - int c = read(); - m_curPosition = curPosition; - m_curCluster = curCluster; - return c; -} -//------------------------------------------------------------------------------ int FatFile::read(void* buf, size_t nbyte) { int8_t fg; uint8_t sectorOfCluster = 0; @@ -727,8 +730,7 @@ int FatFile::read(void* buf, size_t nbyte) { uint16_t offset; size_t toRead; uint32_t sector; // raw device sector number - cache_t* pc; - + uint8_t* pc; // error if not open for read if (!isReadable()) { DBG_FAIL_MACRO; @@ -741,7 +743,8 @@ int FatFile::read(void* buf, size_t nbyte) { nbyte = tmp32; } } else if (isRootFixed()) { - uint16_t tmp16 = 32*m_vol->m_rootDirEntryCount - (uint16_t)m_curPosition; + uint16_t tmp16 = + FS_DIR_SIZE*m_vol->m_rootDirEntryCount - (uint16_t)m_curPosition; if (nbyte > tmp16) { nbyte = tmp16; } @@ -790,12 +793,12 @@ int FatFile::read(void* buf, size_t nbyte) { n = toRead; } // read sector to cache and copy data to caller - pc = m_vol->cacheFetchData(sector, FsCache::CACHE_FOR_READ); + pc = m_vol->dataCachePrepare(sector, FsCache::CACHE_FOR_READ); if (!pc) { DBG_FAIL_MACRO; goto fail; } - uint8_t* src = pc->data + offset; + uint8_t* src = pc + offset; memcpy(dst, src, n); #if USE_MULTI_SECTOR_IO } else if (toRead >= 2*m_vol->bytesPerSector()) { @@ -858,9 +861,10 @@ int8_t FatFile::readDir(DirFat_t* dir) { } } //------------------------------------------------------------------------------ -// Read next directory entry into the cache -// Assumes file is correctly positioned +// Read next directory entry into the cache. +// Assumes file is correctly positioned. DirFat_t* FatFile::readDirCache(bool skipReadOk) { + DBG_HALT_IF(m_curPosition & 0X1F); uint8_t i = (m_curPosition >> 5) & 0XF; if (i == 0 || !skipReadOk) { @@ -871,9 +875,9 @@ DirFat_t* FatFile::readDirCache(bool skipReadOk) { } goto fail; } - m_curPosition += 31; + m_curPosition += FS_DIR_SIZE - 1; } else { - m_curPosition += 32; + m_curPosition += FS_DIR_SIZE; } // return pointer to entry return reinterpret_cast(m_vol->cacheAddress()) + i; @@ -903,7 +907,7 @@ bool FatFile::rename(FatFile* dirFile, const char* newPath) { uint32_t dirCluster = 0; FatFile file; FatFile oldFile; - cache_t* pc; + uint8_t* pc; DirFat_t* dir; // Must be an open file or subdirectory. @@ -971,12 +975,13 @@ bool FatFile::rename(FatFile* dirFile, const char* newPath) { if (dirCluster) { // get new dot dot uint32_t sector = m_vol->clusterStartSector(dirCluster); - pc = m_vol->cacheFetchData(sector, FsCache::CACHE_FOR_READ); - if (!pc) { + pc = m_vol->dataCachePrepare(sector, FsCache::CACHE_FOR_READ); + dir = reinterpret_cast(pc); + if (!dir) { DBG_FAIL_MACRO; goto fail; } - memcpy(&entry, &pc->dir[1], sizeof(entry)); + memcpy(&entry, &dir[1], sizeof(entry)); // free unused cluster if (!m_vol->freeChain(dirCluster)) { @@ -985,12 +990,13 @@ bool FatFile::rename(FatFile* dirFile, const char* newPath) { } // store new dot dot sector = m_vol->clusterStartSector(m_firstCluster); - pc = m_vol->cacheFetchData(sector, FsCache::CACHE_FOR_WRITE); - if (!pc) { + uint8_t* pc = m_vol->dataCachePrepare(sector, FsCache::CACHE_FOR_WRITE); + dir = reinterpret_cast(pc); + if (!dir) { DBG_FAIL_MACRO; goto fail; } - memcpy(&pc->dir[1], &entry, sizeof(entry)); + memcpy(&dir[1], &entry, sizeof(entry)); } // Remove old directory entry; oldFile.m_firstCluster = 0; @@ -1058,7 +1064,7 @@ bool FatFile::rmRfStar() { rewind(); while (1) { // remember position - index = m_curPosition/32; + index = m_curPosition/FS_DIR_SIZE; DirFat_t* dir = readDirCache(); if (!dir) { @@ -1147,7 +1153,7 @@ bool FatFile::seekSet(uint32_t pos) { goto fail; } } else if (isRootFixed()) { - if (pos <= 32*m_vol->rootDirEntryCount()) { + if (pos <= FS_DIR_SIZE*m_vol->rootDirEntryCount()) { goto done; } DBG_FAIL_MACRO; @@ -1205,7 +1211,6 @@ bool FatFile::sync() { if (isFile()) { setLe32(dir->fileSize, m_fileSize); } - // update first cluster fields setLe16(dir->firstClusterLow, m_firstCluster & 0XFFFF); setLe16(dir->firstClusterHigh, m_firstCluster >> 16); @@ -1318,12 +1323,7 @@ bool FatFile::truncate() { // need to update directory entry m_flags |= FILE_FLAG_DIR_DIRTY; - - if (!sync()) { - DBG_FAIL_MACRO; - goto fail; - } - return true; + return sync(); fail: return false; @@ -1332,7 +1332,7 @@ bool FatFile::truncate() { size_t FatFile::write(const void* buf, size_t nbyte) { // convert void* to uint8_t* - must be before goto statements const uint8_t* src = reinterpret_cast(buf); - cache_t* pc; + uint8_t* pc; uint8_t cacheOption; // number of bytes left to write - must be before goto statements size_t nToWrite = nbyte; @@ -1420,12 +1420,12 @@ size_t FatFile::write(const void* buf, size_t nbyte) { // rewrite part of sector cacheOption = FsCache::CACHE_FOR_WRITE; } - pc = m_vol->cacheFetchData(sector, cacheOption); + pc = m_vol->dataCachePrepare(sector, cacheOption); if (!pc) { DBG_FAIL_MACRO; goto fail; } - uint8_t* dst = pc->data + sectorOffset; + uint8_t* dst = pc + sectorOffset; memcpy(dst, src, n); if (m_vol->bytesPerSector() == (n + sectorOffset)) { // Force write if sector is full - improves large writes. @@ -1473,5 +1473,5 @@ size_t FatFile::write(const void* buf, size_t nbyte) { fail: // return for write error m_error |= WRITE_ERROR; - return -1; + return 0; } diff --git a/firmware/3.0/lib/SdFat/src/FatLib/FatFile.h b/firmware/3.0/lib/SdFat/src/FatLib/FatFile.h old mode 100644 new mode 100755 index 0e3b030..0415bc7 --- a/firmware/3.0/lib/SdFat/src/FatLib/FatFile.h +++ b/firmware/3.0/lib/SdFat/src/FatLib/FatFile.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -31,11 +31,10 @@ #include #include #include -#include "FatLibConfig.h" #include "../common/FmtNumber.h" #include "../common/FsApiConstants.h" #include "../common/FsDateTime.h" -#include "../common/FsStructs.h" +#include "../common/FsName.h" #include "FatPartition.h" class FatVolume; //------------------------------------------------------------------------------ @@ -76,21 +75,41 @@ struct FatPos_t { #define isDirSeparator(c) ((c) == '/') //------------------------------------------------------------------------------ /** - * \struct fname_t - * \brief Internal type for Short File Name - do not use in user apps. + * \class FatLfn_t + * \brief Internal type for Long File Name - do not use in user apps. */ -struct fname_t { - /** Flags for base and extension character case and LFN. */ - uint8_t flags; - /** length of Long File Name */ + +class FatLfn_t : public FsName { + public: + /** UTF-16 length of Long File Name */ size_t len; - /** Long File Name start. */ - const char* lfn; - /** position for sequence number */ + /** Position for sequence number. */ uint8_t seqPos; + /** Flags for base and extension character case and LFN. */ + uint8_t flags; + /** Short File Name */ + uint8_t sfn[11]; +}; +/** + * \class FatSfn_t + * \brief Internal type for Short 8.3 File Name - do not use in user apps. + */ +class FatSfn_t { + public: + /** Flags for base and extension character case and LFN. */ + uint8_t flags; /** Short File Name */ uint8_t sfn[11]; }; + +#if USE_LONG_FILE_NAMES +/** Internal class for file names */ +typedef FatLfn_t FatName_t; +#else // USE_LONG_FILE_NAMES +/** Internal class for file names */ +typedef FatSfn_t FatName_t; +#endif // USE_LONG_FILE_NAMES + /** Derived from a LFN with loss or conversion of characters. */ const uint8_t FNAME_FLAG_LOST_CHARS = 0X01; /** Base-name or extension has mixed case. */ @@ -102,6 +121,9 @@ const uint8_t FNAME_FLAG_NEED_LFN = const uint8_t FNAME_FLAG_LC_BASE = FAT_CASE_LC_BASE; /** Filename extension is all lower case. */ const uint8_t FNAME_FLAG_LC_EXT = FAT_CASE_LC_EXT; +#if FNAME_FLAG_NEED_LFN & (FAT_CASE_LC_BASE || FAT_CASE_LC_EXT) +#error FNAME_FLAG_NEED_LFN & (FAT_CASE_LC_BASE || FAT_CASE_LC_EXT) +#endif // FNAME_FLAG_NEED_LFN & (FAT_CASE_LC_BASE || FAT_CASE_LC_EXT) //============================================================================== /** * \class FatFile @@ -169,7 +191,7 @@ class FatFile { /** Check for contiguous file and return its raw sector range. * * \param[out] bgnSector the first sector address for the file. - * \param[out] endSector the last sector address for the file. + * \param[out] endSector the last sector address for the file. * * Set the contiguous flag if the file is contiguous. * The parameters may be nullptr to only set the flag. @@ -224,7 +246,7 @@ class FatFile { * * The calling instance must be an open directory file. * - * dirFile.exists("TOFIND.TXT") searches for "TOFIND.TXT" in the directory + * dirFile.exists("TOFIND.TXT") searches for "TOFIND.TXT" in the directory * dirFile. * * \return True if the file exists. @@ -322,20 +344,40 @@ class FatFile { * \return length for success or zero for failure. */ size_t getName(char* name, size_t size); + /** + * Get a file's ASCII name followed by a zero. + * + * \param[out] name An array of characters for the file's name. + * \param[in] size The size of the array in characters. + * \return the name length. + */ + size_t getName7(char* name, size_t size); + /** + * Get a file's UTF-8 name followed by a zero. + * + * \param[out] name An array of characters for the file's name. + * \param[in] size The size of the array in characters. + * \return the name length. + */ + size_t getName8(char* name, size_t size); +#ifndef DOXYGEN_SHOULD_SKIP_THIS + size_t __attribute__((error("use getSFN(name, size)"))) getSFN(char* name); +#endif // DOXYGEN_SHOULD_SKIP_THIS /** * Get a file's Short File Name followed by a zero byte. * * \param[out] name An array of characters for the file's name. - * The array must be at least 13 bytes long. + * The array should be at least 13 bytes long. + * \param[in] size size of name array. * \return true for success or false for failure. */ - size_t getSFN(char* name); + size_t getSFN(char* name, size_t size); /** \return value of writeError */ bool getWriteError() const { return isOpen() ? m_error & WRITE_ERROR : true; } /** - * Check for BlockDevice busy. + * Check for device busy. * * \return true if busy else false. */ @@ -370,28 +412,6 @@ class FatFile { bool isSystem() const {return m_attributes & FILE_ATTR_SYSTEM;} /** \return True file is writable. */ bool isWritable() const {return m_flags & FILE_FLAG_WRITE;} - /** Check for a legal 8.3 character. - * \param[in] c Character to be checked. - * \return true for a legal 8.3 character. - */ - static bool legal83Char(uint8_t c) { - if (c == '"' || c == '|') { - return false; - } - // *+,./ - if (0X2A <= c && c <= 0X2F && c != 0X2D) { - return false; - } - // :;<=>? - if (0X3A <= c && c <= 0X3F) { - return false; - } - // [\] - if (0X5B <= c && c <= 0X5D) { - return false; - } - return 0X20 < c && c < 0X7F; - } /** List directory contents. * * \param[in] pr Print stream for list. @@ -422,14 +442,6 @@ class FatFile { * \return true for success or false for failure. */ bool mkdir(FatFile* dir, const char* path, bool pFlag = true); - /** No longer implemented due to Long File Names. - * - * Use getName(char* name, size_t size). - * \return a pointer to replacement suggestion. - */ - const char* name() const { - return "use getName()"; - } /** Open a file in the volume root directory. * * \param[in] vol Volume where the file is located. @@ -512,6 +524,16 @@ class FatFile { * \return true for success or false for failure. */ bool open(const char* path, oflag_t oflag = O_RDONLY); + /** Open existing file wih Short 8.3 names. + * \param[in] path with short 8.3 names. + * + * the purpose of this function is to save flash on Uno + * and other small boards. + * + * Directories will be opened O_RDONLY, files O_RDWR. + * \return true for success or false for failure. + */ + bool openExistingSFN(const char* path); /** Open the next file or subdirectory in a directory. * * \param[in] dirFile An open FatFile instance for the directory @@ -530,6 +552,7 @@ class FatFile { * \return true for success or false for failure. */ bool openRoot(FatVolume* vol); + /** Return the next available byte without consuming it. * * \return The byte if no error and not at eof else -1; @@ -661,10 +684,23 @@ class FatFile { * * \param[in] pr Print stream for output. * - * \return true for success or false for failure. + * \return length for success or zero for failure. */ size_t printName(print_t* pr); - + /** Print a file's ASCII name + * + * \param[in] pr Print stream for output. + * + * \return true for success or false for failure. + */ + size_t printName7(print_t* pr); + /** Print a file's UTF-8 name + * + * \param[in] pr Print stream for output. + * + * \return true for success or false for failure. + */ + size_t printName8(print_t* pr); /** Print a file's Short File Name. * * \param[in] pr Print stream for output. @@ -885,10 +921,7 @@ class FatFile { * \param[in] count Number of bytes to write. * * \return For success write() returns the number of bytes written, always - * \a count. 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. + * \a count. If an error occurs, write() returns zero and writeError is set. * */ size_t write(const void* buf, size_t count); @@ -911,7 +944,7 @@ class FatFile { } /** Print a file's name. * - * \return true for success or false for failure. + * \return length for success or zero for failure. */ size_t printName() { return FatFile::printName(&Serial); @@ -949,15 +982,32 @@ class FatFile { FAT_ATTRIB_SYSTEM | FAT_ATTRIB_DIRECTORY; // private functions + bool addCluster(); bool addDirCluster(); + DirFat_t* cacheDir(uint16_t index) { + return seekSet(32UL*index) ? readDirCache() : nullptr; + } DirFat_t* cacheDirEntry(uint8_t action); - static uint8_t lfnChecksum(uint8_t* name); - bool lfnUniqueSfn(fname_t* fname); + bool cmpName(uint16_t index, FatLfn_t* fname, uint8_t lfnOrd); + bool createLFN(uint16_t index, FatLfn_t* fname, uint8_t lfnOrd); + uint16_t getLfnChar(DirLfn_t* ldir, uint8_t i); + uint8_t lfnChecksum(uint8_t* name) { + uint8_t sum = 0; + for (uint8_t i = 0; i < 11; i++) { + sum = (((sum & 1) << 7) | (sum >> 1)) + name[i]; + } + return sum; + } + static bool makeSFN(FatLfn_t* fname); + bool makeUniqueSfn(FatLfn_t* fname); bool openCluster(FatFile* file); - static bool parsePathName(const char* str, fname_t* fname, const char** ptr); - bool mkdir(FatFile* parent, fname_t* fname); - bool open(FatFile* dirFile, fname_t* fname, oflag_t oflag); + bool parsePathName(const char* str, FatLfn_t* fname, const char** ptr); + bool parsePathName(const char* str, FatSfn_t* fname, const char** ptr); + bool mkdir(FatFile* parent, FatName_t* fname); + bool open(FatFile* dirFile, FatLfn_t* fname, oflag_t oflag); + bool open(FatFile* dirFile, FatSfn_t* fname, oflag_t oflag); + bool openSFN(FatSfn_t* fname); bool openCachedEntry(FatFile* dirFile, uint16_t cacheIndex, oflag_t oflag, uint8_t lfnOrd); DirFat_t* readDirCache(bool skipReadOk = false); diff --git a/firmware/3.0/lib/SdFat/src/FatLib/FatFileLFN.cpp b/firmware/3.0/lib/SdFat/src/FatLib/FatFileLFN.cpp old mode 100644 new mode 100755 index 90c3feb..b74b7a7 --- a/firmware/3.0/lib/SdFat/src/FatLib/FatFileLFN.cpp +++ b/firmware/3.0/lib/SdFat/src/FatLib/FatFileLFN.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -24,78 +24,22 @@ */ #define DBG_FILE "FatFileLFN.cpp" #include "../common/DebugMacros.h" -#include "FatFile.h" -#include "FatVolume.h" -//------------------------------------------------------------------------------ -// -uint8_t FatFile::lfnChecksum(uint8_t* name) { - uint8_t sum = 0; - for (uint8_t i = 0; i < 11; i++) { - sum = (((sum & 1) << 7) | ((sum & 0xfe) >> 1)) + name[i]; - } - return sum; -} +#include "../common/upcase.h" +#include "../common/FsUtf.h" +#include "FatLib.h" #if USE_LONG_FILE_NAMES //------------------------------------------------------------------------------ -// Saves about 90 bytes of flash on 328 over tolower(). -inline char lfnToLower(char c) { - return 'A' <= c && c <= 'Z' ? c + 'a' - 'A' : c; -} -//------------------------------------------------------------------------------ -// Daniel Bernstein University of Illinois at Chicago. -// Original had + instead of ^ -static uint16_t Bernstein(uint16_t hash, const char *str, size_t len) { - for (size_t i = 0; i < len; i++) { - // hash = hash * 33 ^ str[i]; - hash = ((hash << 5) + hash) ^ str[i]; - } - return hash; -} -//------------------------------------------------------------------------------ -/** - * Fetch a 16-bit long file name character. - * - * \param[in] ldir Pointer to long file name directory entry. - * \param[in] i Index of character. - * \return The 16-bit character. - */ -static uint16_t lfnGetChar(DirLfn_t* ldir, uint8_t i) { - if (i < 5) { - return getLe16(ldir->unicode1 + 2*i); - } else if (i < 11) { - return getLe16(ldir->unicode2 + 2*i - 10); - } else if (i < 13) { - return getLe16(ldir->unicode3 + 2*i - 22); - } - return 0; +static bool isLower(char c) { + return 'a' <= c && c <= 'z'; } //------------------------------------------------------------------------------ -static size_t lfnGetName(DirLfn_t* ldir, char* name, size_t n) { - uint8_t i; - size_t k = 13*((ldir->order & 0X1F) - 1); - // https://github.com/greiman/SdFat-beta/issues/67#issuecomment-774508283 - for (i = 0; i < 13; i++) { - uint16_t c = lfnGetChar(ldir, i); - if (c == 0 || k >= (n - 1)) { - // k = n - 1; <<-------removed - break; - } - name[k++] = c >= 0X7F ? '?' : c; - } - // Terminate with zero byte. - if (k >= n) { // <<----------added - k = n - 1; // <<--------- added - } // <<---------added - name[k] = '\0'; - return k; +static bool isUpper(char c) { + return 'A' <= c && c <= 'Z'; } //------------------------------------------------------------------------------ -inline bool lfnLegalChar(uint8_t c) { - if (c == '/' || c == '\\' || c == '"' || c == '*' || - c == ':' || c == '<' || c == '>' || c == '?' || c == '|') { - return false; - } - return 0X1F < c && c < 0X7F; +// A bit smaller than toupper in AVR 328. +inline char toUpper(char c) { + return isLower(c) ? c - 'a' + 'A' : c; } //------------------------------------------------------------------------------ /** @@ -103,9 +47,9 @@ inline bool lfnLegalChar(uint8_t c) { * * \param[in] ldir Pointer to long file name directory entry. * \param[in] i Index of character. - * \param[in] c The 16-bit character. + * \param[in] c The 16-bit character. */ -static void lfnPutChar(DirLfn_t* ldir, uint8_t i, uint16_t c) { +static void putLfnChar(DirLfn_t* ldir, uint8_t i, uint16_t c) { if (i < 5) { setLe16(ldir->unicode1 + 2*i, c); } else if (i < 11) { @@ -115,167 +59,150 @@ static void lfnPutChar(DirLfn_t* ldir, uint8_t i, uint16_t c) { } } //------------------------------------------------------------------------------ -static void lfnPutName(DirLfn_t* ldir, const char* name, size_t n) { - size_t k = 13*((ldir->order & 0X1F) - 1); - for (uint8_t i = 0; i < 13; i++, k++) { - uint16_t c = k < n ? name[k] : k == n ? 0 : 0XFFFF; - lfnPutChar(ldir, i, c); +// Daniel Bernstein University of Illinois at Chicago. +// Original had + instead of ^ +__attribute__((unused)) +static uint16_t Bernstein(const char* bgn, const char* end, uint16_t hash) { + while (bgn < end) { + // hash = hash * 33 ^ str[i]; + hash = ((hash << 5) + hash) ^ (*bgn++); } + return hash; } //============================================================================== -size_t FatFile::getName(char* name, size_t size) { - size_t n = 0; - FatFile dirFile; +bool FatFile::cmpName(uint16_t index, FatLfn_t* fname, uint8_t lfnOrd) { + FatFile dir = *this; DirLfn_t* ldir; - if (!isOpen() || size < 13) { - DBG_FAIL_MACRO; - goto fail; - } - if (!isLFN()) { - return getSFN(name); - } - if (!dirFile.openCluster(this)) { - DBG_FAIL_MACRO; - goto fail; - } - for (uint8_t order = 1; order <= m_lfnOrd; order++) { - if (!dirFile.seekSet(32UL*(m_dirIndex - order))) { - DBG_FAIL_MACRO; - goto fail; - } - ldir = reinterpret_cast(dirFile.readDirCache()); + fname->reset(); + for (uint8_t order = 1; order <= lfnOrd; order++) { + ldir = reinterpret_cast(dir.cacheDir(index - order)); if (!ldir) { DBG_FAIL_MACRO; goto fail; } - if (ldir->attributes != FAT_ATTRIB_LONG_NAME) { - DBG_FAIL_MACRO; - goto fail; - } - if (order != (ldir->order & 0X1F)) { - DBG_FAIL_MACRO; - goto fail; - } - n = lfnGetName(ldir, name, size); - if (n == 0) { - DBG_FAIL_MACRO; - goto fail; - } - if (ldir->order & FAT_ORDER_LAST_LONG_ENTRY) { - return n; + // These should be checked in caller. + DBG_HALT_IF(ldir->attributes != FAT_ATTRIB_LONG_NAME); + DBG_HALT_IF(order != (ldir->order & 0X1F)); + for (uint8_t i = 0; i < 13; i++) { + uint16_t u = getLfnChar(ldir, i); + if (fname->atEnd()) { + return u == 0; + } +#if USE_UTF8_LONG_NAMES + uint16_t cp = fname->get16(); + // Make sure caller checked for valid UTF-8. + DBG_HALT_IF(cp == 0XFFFF); + if (toUpcase(u) != toUpcase(cp)) { + return false; + } +#else // USE_UTF8_LONG_NAMES + if (u > 0X7F || toUpper(u) != toUpper(fname->getch())) { + return false; + } +#endif // USE_UTF8_LONG_NAMES } } - // Fall into fail. - DBG_FAIL_MACRO; + return true; fail: - name[0] = '\0'; - return 0; + return false; } //------------------------------------------------------------------------------ -bool FatFile::openCluster(FatFile* file) { - if (file->m_dirCluster == 0) { - return openRoot(file->m_vol); +bool FatFile::createLFN(uint16_t index, FatLfn_t* fname, uint8_t lfnOrd) { + FatFile dir = *this; + DirLfn_t* ldir; + uint8_t checksum = lfnChecksum(fname->sfn); + uint8_t fc = 0; + fname->reset(); + + for (uint8_t order = 1; order <= lfnOrd; order++) { + ldir = reinterpret_cast(dir.cacheDir(index - order)); + if (!ldir) { + DBG_FAIL_MACRO; + goto fail; + } + dir.m_vol->cacheDirty(); + ldir->order = order == lfnOrd ? FAT_ORDER_LAST_LONG_ENTRY | order : order; + ldir->attributes = FAT_ATTRIB_LONG_NAME; + ldir->mustBeZero1 = 0; + ldir->checksum = checksum; + setLe16(ldir->mustBeZero2, 0); + for (uint8_t i = 0; i < 13; i++) { + uint16_t cp; + if (fname->atEnd()) { + cp = fc++ ? 0XFFFF : 0; + } else { + cp = fname->get16(); + // Verify caller checked for valid UTF-8. + DBG_HALT_IF(cp == 0XFFFF); + } + putLfnChar(ldir, i, cp); + } } - memset(this, 0, sizeof(FatFile)); - m_attributes = FILE_ATTR_SUBDIR; - m_flags = FILE_FLAG_READ; - m_vol = file->m_vol; - m_firstCluster = file->m_dirCluster; return true; + + fail: + return false; } //------------------------------------------------------------------------------ -bool FatFile::parsePathName(const char* path, - fname_t* fname, const char** ptr) { - char c; +bool FatFile::makeSFN(FatLfn_t* fname) { bool is83; +// char c; + uint8_t c; uint8_t bit = FAT_CASE_LC_BASE; uint8_t lc = 0; uint8_t uc = 0; uint8_t i = 0; uint8_t in = 7; - int end; - int len = 0; - int si; - int dot; + const char* dot; + const char* end = fname->end; + const char* ptr = fname->begin; - // Skip leading spaces. - while (*path == ' ') { - path++; - } - fname->lfn = path; + // Assume not zero length. + DBG_HALT_IF(end == ptr); + // Assume blanks removed from start and end. + DBG_HALT_IF(*ptr == ' ' || *(end - 1) == ' ' || *(end - 1) == '.'); - for (len = 0; ; len++) { - c = path[len]; - if (c == 0 || isDirSeparator(c)) { - break; - } - if (!lfnLegalChar(c)) { - DBG_FAIL_MACRO; - goto fail; - } - } - // Advance to next path component. - for (end = len; path[end] == ' ' || isDirSeparator(path[end]); end++) {} - *ptr = &path[end]; - - // Back over spaces and dots. - while (len) { - c = path[len - 1]; - if (c != '.' && c != ' ') { - break; - } - len--; - } - // Max length of LFN is 255. - if (len > 255) { - DBG_FAIL_MACRO; - goto fail; - } - fname->len = len; // Blank file short name. for (uint8_t k = 0; k < 11; k++) { fname->sfn[k] = ' '; } - // skip leading spaces and dots. - for (si = 0; path[si] == '.' || path[si] == ' '; si++) {} - // Not 8.3 if leading dot or space. - is83 = !si; + // Not 8.3 if starts with dot. + is83 = *ptr == '.' ? false : true; + // Skip leading dots. + for (; *ptr == '.'; ptr++) {} + // Find last dot. + for (dot = end - 1; dot > ptr && *dot != '.'; dot--) {} - // find last dot. - for (dot = len - 1; dot >= 0 && path[dot] != '.'; dot--) {} - for (; si < len; si++) { - c = path[si]; - if (c == ' ' || (c == '.' && dot != si)) { - is83 = false; - continue; - } - if (!legal83Char(c) && si != dot) { - is83 = false; - c = '_'; - } - if (si == dot || i > in) { - if (in == 10) { - // Done - extension longer than three characters. - is83 = false; - break; - } - if (si != dot) { - is83 = false; - } - // Break if no dot and base-name is longer than eight characters. - if (si > dot) { - break; - } - si = dot; + for (; ptr < end; ptr++) { + c = *ptr; + if (c == '.' && ptr == dot) { in = 10; // Max index for full 8.3 name. i = 8; // Place for extension. bit = FAT_CASE_LC_EXT; // bit for extension. } else { - if ('a' <= c && c <= 'z') { + if (sfnReservedChar(c)) { + is83 = false; + // Skip UTF-8 trailing characters. + if ((c & 0XC0) == 0X80) { + continue; + } + c = '_'; + } + if (i > in) { + is83 = false; + if (in == 10 || ptr > dot) { + // Done - extension longer than three characters or no extension. + break; + } + // Skip to dot. + ptr = dot - 1; + continue; + } + if (isLower(c)) { c += 'A' - 'a'; lc |= bit; - } else if ('A' <= c && c <= 'Z') { + } else if (isUpper(c)) { uc |= bit; } fname->sfn[i++] = c; @@ -285,10 +212,9 @@ bool FatFile::parsePathName(const char* path, } } if (fname->sfn[0] == ' ') { - DBG_FAIL_MACRO; + DBG_HALT_MACRO; goto fail; } - if (is83) { fname->flags = lc & uc ? FNAME_FLAG_MIXED_CASE : lc; } else { @@ -302,7 +228,63 @@ bool FatFile::parsePathName(const char* path, return false; } //------------------------------------------------------------------------------ -bool FatFile::open(FatFile* dirFile, fname_t* fname, oflag_t oflag) { +bool FatFile::makeUniqueSfn(FatLfn_t* fname) { + const uint8_t FIRST_HASH_SEQ = 2; // min value is 2 + uint8_t pos = fname->seqPos; + DirFat_t* dir; + uint16_t hex = 0; + + DBG_HALT_IF(!(fname->flags & FNAME_FLAG_LOST_CHARS)); + DBG_HALT_IF(fname->sfn[pos] != '~' && fname->sfn[pos + 1] != '1'); + + for (uint8_t seq = FIRST_HASH_SEQ; seq < 100; seq++) { + DBG_WARN_IF(seq > FIRST_HASH_SEQ); +#ifdef USE_LFN_HASH + hex = Bernstein(fname->begin, fname->end, seq); +#else + hex += millis(); +#endif + if (pos > 3) { + // Make space in name for ~HHHH. + pos = 3; + } + for (uint8_t i = pos + 4 ; i > pos; i--) { + uint8_t h = hex & 0XF; + fname->sfn[i] = h < 10 ? h + '0' : h + 'A' - 10; + hex >>= 4; + } + fname->sfn[pos] = '~'; + rewind(); + while (1) { + dir = readDirCache(true); + if (!dir) { + if (!getError()) { + // At EOF and name not found if no error. + goto done; + } + DBG_FAIL_MACRO; + goto fail; + } + if (dir->name[0] == FAT_NAME_FREE) { + goto done; + } + if (isFileOrSubdir(dir) && !memcmp(fname->sfn, dir->name, 11)) { + // Name found - try another. + break; + } + } + } + // fall inti fail - too many tries. + DBG_FAIL_MACRO; + + fail: + return false; + + done: + return true; +} +//------------------------------------------------------------------------------ +bool FatFile::open(FatFile* dirFile, FatLfn_t* fname, oflag_t oflag) { bool fnameFound = false; uint8_t lfnOrd = 0; uint8_t freeNeed; @@ -310,25 +292,26 @@ bool FatFile::open(FatFile* dirFile, fname_t* fname, oflag_t oflag) { uint8_t order = 0; uint8_t checksum = 0; uint8_t ms10; + uint8_t nameOrd; uint16_t freeIndex = 0; uint16_t curIndex; uint16_t date; uint16_t time; DirFat_t* dir; DirLfn_t* ldir; - size_t len = fname->len; + auto vol = dirFile->m_vol; if (!dirFile->isDir() || isOpen()) { DBG_FAIL_MACRO; goto fail; } // Number of directory entries needed. - freeNeed = fname->flags & FNAME_FLAG_NEED_LFN ? 1 + (len + 12)/13 : 1; - + nameOrd = (fname->len + 12)/13; + freeNeed = fname->flags & FNAME_FLAG_NEED_LFN ? 1 + nameOrd : 1; dirFile->rewind(); while (1) { - curIndex = dirFile->m_curPosition/32; - dir = dirFile->readDirCache(true); + curIndex = dirFile->m_curPosition/FS_DIR_SIZE; + dir = dirFile->readDirCache(); if (!dir) { if (dirFile->getError()) { DBG_FAIL_MACRO; @@ -358,34 +341,20 @@ bool FatFile::open(FatFile* dirFile, fname_t* fname, oflag_t oflag) { } else if (isLongName(dir)) { ldir = reinterpret_cast(dir); if (!lfnOrd) { - if ((ldir->order & FAT_ORDER_LAST_LONG_ENTRY) == 0) { + order = ldir->order & 0X1F; + if (order != nameOrd || + (ldir->order & FAT_ORDER_LAST_LONG_ENTRY) == 0) { continue; } - lfnOrd = order = ldir->order & 0X1F; + lfnOrd = nameOrd; checksum = ldir->checksum; } else if (ldir->order != --order || checksum != ldir->checksum) { lfnOrd = 0; continue; } - size_t k = 13*(order - 1); - if (k >= len) { - // Not found. - lfnOrd = 0; - continue; - } - for (uint8_t i = 0; i < 13; i++) { - uint16_t u = lfnGetChar(ldir, i); - if (k == len) { - if (u != 0) { - // Not found. - lfnOrd = 0; - } - break; - } - if (u > 255 || lfnToLower(u) != lfnToLower(fname->lfn[k++])) { - // Not found. + if (order == 1) { + if (!dirFile->cmpName(curIndex + 1, fname, lfnOrd)) { lfnOrd = 0; - break; } } } else if (isFileOrSubdir(dir)) { @@ -418,10 +387,10 @@ bool FatFile::open(FatFile* dirFile, fname_t* fname, oflag_t oflag) { create: // don't create unless O_CREAT and write mode if (!(oflag & O_CREAT) || !isWriteMode(oflag)) { - DBG_FAIL_MACRO; + DBG_WARN_MACRO; goto fail; } - // If at EOF start in next cluster. + // Keep found entries or start at current index if no free entries found. if (freeFound == 0) { freeIndex = curIndex; } @@ -444,38 +413,19 @@ bool FatFile::open(FatFile* dirFile, fname_t* fname, oflag_t oflag) { DBG_FAIL_MACRO; goto fail; } - // Done if more than one sector per cluster. Max freeNeed is 21. - if (dirFile->m_vol->sectorsPerCluster() > 1) { - break; - } - freeFound += 16; + freeFound += vol->dirEntriesPerCluster(); } if (fnameFound) { - if (!dirFile->lfnUniqueSfn(fname)) { + if (!dirFile->makeUniqueSfn(fname)) { goto fail; } } - if (!dirFile->seekSet(32UL*freeIndex)) { - DBG_FAIL_MACRO; - goto fail; - } lfnOrd = freeNeed - 1; - for (order = lfnOrd ; order ; order--) { - ldir = reinterpret_cast(dirFile->readDirCache()); - if (!ldir) { - DBG_FAIL_MACRO; - goto fail; - } - dirFile->m_vol->cacheDirty(); - ldir->order = order == lfnOrd ? FAT_ORDER_LAST_LONG_ENTRY | order : order; - ldir->attributes = FAT_ATTRIB_LONG_NAME; - ldir->mustBeZero1 = 0; - ldir->checksum = lfnChecksum(fname->sfn); - setLe16(ldir->mustBeZero2, 0); - lfnPutName(ldir, fname->lfn, len); + curIndex = freeIndex + lfnOrd; + if (!dirFile->createLFN(curIndex, fname, lfnOrd)) { + goto fail; } - curIndex = dirFile->m_curPosition/32; - dir = dirFile->readDirCache(); + dir = dirFile->cacheDir(curIndex); if (!dir) { DBG_FAIL_MACRO; goto fail; @@ -485,7 +435,7 @@ bool FatFile::open(FatFile* dirFile, fname_t* fname, oflag_t oflag) { memcpy(dir->name, fname->sfn, 11); // Set base-name and extension lower case bits. - dir->caseFlags = (FAT_CASE_LC_BASE | FAT_CASE_LC_EXT) & fname->flags; + dir->caseFlags = (FAT_CASE_LC_BASE | FAT_CASE_LC_EXT) & fname->flags; // Set timestamps. if (FsDateTime::callback) { @@ -504,7 +454,7 @@ bool FatFile::open(FatFile* dirFile, fname_t* fname, oflag_t oflag) { } } // Force write of entry to device. - dirFile->m_vol->cacheDirty(); + vol->cacheDirty(); open: // open entry in cache. @@ -518,51 +468,53 @@ bool FatFile::open(FatFile* dirFile, fname_t* fname, oflag_t oflag) { return false; } //------------------------------------------------------------------------------ -size_t FatFile::printName(print_t* pr) { - FatFile dirFile; - DirLfn_t* ldir; - size_t n = 0; - uint16_t u; - uint8_t buf[13]; - uint8_t i; - - if (!isLFN()) { - return printSFN(pr); - } - if (!dirFile.openCluster(this)) { - DBG_FAIL_MACRO; - goto fail; +bool FatFile::parsePathName(const char* path, + FatLfn_t* fname, const char** ptr) { + size_t len = 0; + // Skip leading spaces. + while (*path == ' ') { + path++; } - for (uint8_t order = 1; order <= m_lfnOrd; order++) { - if (!dirFile.seekSet(32UL*(m_dirIndex - order))) { + fname->begin = path; + while (*path && !isDirSeparator(*path)) { +#if USE_UTF8_LONG_NAMES + uint32_t cp; + // Allow end = path + 4 since path is zero terminated. + path = FsUtf::mbToCp(path, path + 4, &cp); + if (!path) { DBG_FAIL_MACRO; goto fail; } - ldir = reinterpret_cast(dirFile.readDirCache()); - if (!ldir) { + len += cp <= 0XFFFF ? 1 : 2; + if (cp < 0X80 && lfnReservedChar(cp)) { DBG_FAIL_MACRO; goto fail; } - if (ldir->attributes != FAT_ATTRIB_LONG_NAME || - order != (ldir->order & 0X1F)) { +#else // USE_UTF8_LONG_NAMES + uint8_t cp = *path++; + if (cp >= 0X80 || lfnReservedChar(cp)) { DBG_FAIL_MACRO; goto fail; } - for (i = 0; i < 13; i++) { - u = lfnGetChar(ldir, i); - if (u == 0) { - // End of name. - break; - } - buf[i] = u < 0X7F ? u : '?'; - n++; + len++; +#endif // USE_UTF8_LONG_NAMES + if (cp != '.' && cp != ' ') { + // Need to trim trailing dots spaces. + fname->len = len; + fname->end = path; } - pr->write(buf, i); } - return n; + if (!fname->len || fname->len > FAT_MAX_LFN_LENGTH) { + DBG_FAIL_MACRO; + goto fail; + } + // Advance to next path component. + for (; *path == ' ' || isDirSeparator(*path); path++) {} + *ptr = path; + return makeSFN(fname); fail: - return 0; + return false; } //------------------------------------------------------------------------------ bool FatFile::remove() { @@ -611,11 +563,7 @@ bool FatFile::remove() { goto fail; } for (uint8_t order = 1; order <= m_lfnOrd; order++) { - if (!dirFile.seekSet(32UL*(m_dirIndex - order))) { - DBG_FAIL_MACRO; - goto fail; - } - ldir = reinterpret_cast(dirFile.readDirCache()); + ldir = reinterpret_cast(dirFile.cacheDir(m_dirIndex - order)); if (!ldir) { DBG_FAIL_MACRO; goto fail; @@ -643,60 +591,4 @@ bool FatFile::remove() { fail: return false; } -//------------------------------------------------------------------------------ -bool FatFile::lfnUniqueSfn(fname_t* fname) { - const uint8_t FIRST_HASH_SEQ = 2; // min value is 2 - uint8_t pos = fname->seqPos;; - DirFat_t* dir; - uint16_t hex; - - DBG_HALT_IF(!(fname->flags & FNAME_FLAG_LOST_CHARS)); - DBG_HALT_IF(fname->sfn[pos] != '~' && fname->sfn[pos + 1] != '1'); - - for (uint8_t seq = 2; seq < 100; seq++) { - if (seq < FIRST_HASH_SEQ) { - fname->sfn[pos + 1] = '0' + seq; - } else { - DBG_PRINT_IF(seq > FIRST_HASH_SEQ); - hex = Bernstein(seq + fname->len, fname->lfn, fname->len); - if (pos > 3) { - // Make space in name for ~HHHH. - pos = 3; - } - for (uint8_t i = pos + 4 ; i > pos; i--) { - uint8_t h = hex & 0XF; - fname->sfn[i] = h < 10 ? h + '0' : h + 'A' - 10; - hex >>= 4; - } - } - fname->sfn[pos] = '~'; - rewind(); - while (1) { - dir = readDirCache(true); - if (!dir) { - if (!getError()) { - // At EOF and name not found if no error. - goto done; - } - DBG_FAIL_MACRO; - goto fail; - } - if (dir->name[0] == FAT_NAME_FREE) { - goto done; - } - if (isFileOrSubdir(dir) && !memcmp(fname->sfn, dir->name, 11)) { - // Name found - try another. - break; - } - } - } - // fall inti fail - too many tries. - DBG_FAIL_MACRO; - - fail: - return false; - - done: - return true; -} #endif // #if USE_LONG_FILE_NAMES diff --git a/firmware/3.0/lib/SdFat/src/FatLib/FatFilePrint.cpp b/firmware/3.0/lib/SdFat/src/FatLib/FatFilePrint.cpp old mode 100644 new mode 100755 index 158a59b..df57610 --- a/firmware/3.0/lib/SdFat/src/FatLib/FatFilePrint.cpp +++ b/firmware/3.0/lib/SdFat/src/FatLib/FatFilePrint.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -25,57 +25,8 @@ #include #define DBG_FILE "FatFilePrint.cpp" #include "../common/DebugMacros.h" -#include "FatFile.h" -//------------------------------------------------------------------------------ -static void printHex(print_t* pr, uint8_t w, uint16_t h) { - char buf[5]; - char* ptr = buf + sizeof(buf); - *--ptr = 0; - for (uint8_t i = 0; i < w; i++) { - char c = h & 0XF; - *--ptr = c < 10 ? c + '0' : c + 'A' - 10; - h >>= 4; - } - pr->write(ptr); -} -//------------------------------------------------------------------------------ -void FatFile::dmpFile(print_t* pr, uint32_t pos, size_t n) { - char text[17]; - text[16] = 0; - if (n >= 0XFFF0) { - n = 0XFFF0; - } - if (!seekSet(pos)) { - return; - } - for (size_t i = 0; i <= n; i++) { - if ((i & 15) == 0) { - if (i) { - pr->write(' '); - pr->write(text); - if (i == n) { - break; - } - } - pr->write('\r'); - pr->write('\n'); - if (i >= n) { - break; - } - printHex(pr, 4, i); - pr->write(' '); - } - int16_t h = read(); - if (h < 0) { - break; - } - pr->write(' '); - printHex(pr, 2, h); - text[i&15] = ' ' <= h && h < 0X7F ? h : '.'; - } - pr->write('\r'); - pr->write('\n'); -} +#include "FatLib.h" + //------------------------------------------------------------------------------ bool FatFile::ls(print_t* pr, uint8_t flags, uint8_t indent) { FatFile file; diff --git a/firmware/3.0/lib/SdFat/src/FatLib/FatFileSFN.cpp b/firmware/3.0/lib/SdFat/src/FatLib/FatFileSFN.cpp old mode 100644 new mode 100755 index 194bf8b..b9f1efd --- a/firmware/3.0/lib/SdFat/src/FatLib/FatFileSFN.cpp +++ b/firmware/3.0/lib/SdFat/src/FatLib/FatFileSFN.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -24,128 +24,11 @@ */ #define DBG_FILE "FatFileSFN.cpp" #include "../common/DebugMacros.h" -#include "../common/FsStructs.h" -#include "FatFile.h" -#include "FatVolume.h" -//------------------------------------------------------------------------------ -size_t FatFile::getSFN(char* name) { - uint8_t j = 0; - uint8_t lcBit = FAT_CASE_LC_BASE; - DirFat_t* dir; - - if (!isOpen()) { - DBG_FAIL_MACRO; - goto fail; - } - if (isRoot()) { - name[0] = '/'; - name[1] = '\0'; - return 1; - } - // cache entry - dir = reinterpret_cast(cacheDirEntry(FsCache::CACHE_FOR_READ)); - if (!dir) { - DBG_FAIL_MACRO; - goto fail; - } - // format name - for (uint8_t i = 0; i < 11; i++) { - if (dir->name[i] == ' ') { - continue; - } - if (i == 8) { - // Position bit for extension. - lcBit = FAT_CASE_LC_EXT; - name[j++] = '.'; - } - char c = dir->name[i]; - if ('A' <= c && c <= 'Z' && (lcBit & dir->caseFlags)) { - c += 'a' - 'A'; - } - name[j++] = c; - } - name[j] = '\0'; - return j; - - fail: - name[0] = '\0'; - return 0; -} -//------------------------------------------------------------------------------ -size_t FatFile::printSFN(print_t* pr) { - char name[13]; - if (!getSFN(name)) { - DBG_FAIL_MACRO; - goto fail; - } - return pr->write(name); - - fail: - return 0; -} -#if !USE_LONG_FILE_NAMES -//------------------------------------------------------------------------------ -size_t FatFile::getName(char* name, size_t size) { - return size < 13 ? 0 : getSFN(name); -} -//------------------------------------------------------------------------------ -// format directory name field from a 8.3 name string -bool FatFile::parsePathName(const char* path, fname_t* fname, - const char** ptr) { - uint8_t uc = 0; - uint8_t lc = 0; - uint8_t bit = FNAME_FLAG_LC_BASE; - // blank fill name and extension - for (uint8_t i = 0; i < 11; i++) { - fname->sfn[i] = ' '; - } - - for (uint8_t i = 0, n = 7;; path++) { - uint8_t c = *path; - if (c == 0 || isDirSeparator(c)) { - // Done. - break; - } - if (c == '.' && n == 7) { - n = 10; // max index for full 8.3 name - i = 8; // place for extension - - // bit for extension. - bit = FNAME_FLAG_LC_EXT; - } else { - if (!legal83Char(c) || i > n) { - DBG_FAIL_MACRO; - goto fail; - } - if ('a' <= c && c <= 'z') { - c += 'A' - 'a'; - lc |= bit; - } else if ('A' <= c && c <= 'Z') { - uc |= bit; - } - fname->sfn[i++] = c; - } - } - // must have a file name, extension is optional - if (fname->sfn[0] == ' ') { - DBG_FAIL_MACRO; - goto fail; - } - // Set base-name and extension bits. - fname->flags = lc & uc ? 0 : lc; - while (isDirSeparator(*path)) { - path++; - } - *ptr = path; - return true; - - fail: - return false; -} +#include "FatLib.h" //------------------------------------------------------------------------------ // open with filename in fname #define SFN_OPEN_USES_CHKSUM 0 -bool FatFile::open(FatFile* dirFile, fname_t* fname, oflag_t oflag) { +bool FatFile::open(FatFile* dirFile, FatSfn_t* fname, oflag_t oflag) { uint16_t date; uint16_t time; uint8_t ms10; @@ -154,17 +37,14 @@ bool FatFile::open(FatFile* dirFile, fname_t* fname, oflag_t oflag) { uint8_t checksum; #endif // SFN_OPEN_USES_CHKSUM uint8_t lfnOrd = 0; - uint16_t emptyIndex; + uint16_t emptyIndex = 0; uint16_t index = 0; DirFat_t* dir; DirLfn_t* ldir; dirFile->rewind(); - while (1) { - if (!emptyFound) { - emptyIndex = index; - } - dir = reinterpret_cast(dirFile->readDirCache(true)); + while (true) { + dir = dirFile->readDirCache(true); if (!dir) { if (dirFile->getError()) { DBG_FAIL_MACRO; @@ -173,13 +53,15 @@ bool FatFile::open(FatFile* dirFile, fname_t* fname, oflag_t oflag) { // At EOF if no error. break; } - if (dir->name[0] == FAT_NAME_FREE) { - emptyFound = true; - break; - } - if (dir->name[0] == FAT_NAME_DELETED) { + if (dir->name[0] == FAT_NAME_DELETED || dir->name[0] == FAT_NAME_FREE) { + if (!emptyFound) { + emptyIndex = index; + emptyFound = true; + } + if (dir->name[0] == FAT_NAME_FREE) { + break; + } lfnOrd = 0; - emptyFound = true; } else if (isFileOrSubdir(dir)) { if (!memcmp(fname->sfn, dir->name, 11)) { // don't open existing file if O_EXCL @@ -227,11 +109,7 @@ bool FatFile::open(FatFile* dirFile, fname_t* fname, oflag_t oflag) { goto fail; } } - if (!dirFile->seekSet(32UL*index)) { - DBG_FAIL_MACRO; - goto fail; - } - dir = reinterpret_cast(dirFile->readDirCache()); + dir = reinterpret_cast(dirFile->cacheDir(index)); if (!dir) { DBG_FAIL_MACRO; goto fail; @@ -269,10 +147,136 @@ bool FatFile::open(FatFile* dirFile, fname_t* fname, oflag_t oflag) { return false; } //------------------------------------------------------------------------------ -size_t FatFile::printName(print_t* pr) { - return printSFN(pr); +bool FatFile::openExistingSFN(const char* path) { + FatSfn_t fname; + auto vol = FatVolume::cwv(); + while (*path == '/') { + path++; + } + if (*path == 0) { + return openRoot(vol); + } + *this = *vol->vwd(); + do { + if (!parsePathName(path, &fname, &path)) { + DBG_FAIL_MACRO; + goto fail; + } + if (!openSFN(&fname)) { + DBG_FAIL_MACRO; + goto fail; + } + } while (*path); + return true; + + fail: + return false; } //------------------------------------------------------------------------------ +bool FatFile::openSFN(FatSfn_t* fname) { + DirFat_t dir; + DirLfn_t* ldir; + auto vol = m_vol; + uint8_t lfnOrd = 0; + if (!isDir()) { + DBG_FAIL_MACRO; + goto fail; + } + while (true) { + if (read(&dir, 32) != 32) { + DBG_FAIL_MACRO; + goto fail; + } + if (dir.name[0] == 0) { + DBG_FAIL_MACRO; + goto fail; + } + if (isFileOrSubdir(&dir) && memcmp(fname->sfn, dir.name, 11) == 0) { + uint16_t dirIndex = (m_curPosition - 32) >> 5; + uint32_t dirCluster = m_firstCluster; + memset(this, 0 , sizeof(FatFile)); + m_attributes = dir.attributes & FILE_ATTR_COPY; + if (isFileDir(&dir)) { + m_attributes |= FILE_ATTR_FILE; + } + m_lfnOrd = lfnOrd; + m_firstCluster = (uint32_t)getLe16(dir.firstClusterHigh) << 16; + m_firstCluster |= getLe16(dir.firstClusterLow); + m_fileSize = getLe32(dir.fileSize); + m_flags = isFile() ? FILE_FLAG_READ | FILE_FLAG_WRITE : FILE_FLAG_READ; + m_vol = vol; + m_dirCluster = dirCluster; + m_dirSector = m_vol->cacheSectorNumber(); + m_dirIndex = dirIndex; + return true; + } else if (isLongName(&dir)) { + ldir = reinterpret_cast(&dir); + if (ldir->order & FAT_ORDER_LAST_LONG_ENTRY) { + lfnOrd = ldir->order & 0X1F; + } + } else { + lfnOrd = 0; + } + } + + fail: + return false; +} +//------------------------------------------------------------------------------ +// format directory name field from a 8.3 name string +bool FatFile::parsePathName(const char* path, FatSfn_t* fname, + const char** ptr) { + uint8_t uc = 0; + uint8_t lc = 0; + uint8_t bit = FNAME_FLAG_LC_BASE; + // blank fill name and extension + for (uint8_t i = 0; i < 11; i++) { + fname->sfn[i] = ' '; + } + for (uint8_t i = 0, n = 7;; path++) { + uint8_t c = *path; + if (c == 0 || isDirSeparator(c)) { + // Done. + break; + } + if (c == '.' && n == 7) { + n = 10; // max index for full 8.3 name + i = 8; // place for extension + + // bit for extension. + bit = FNAME_FLAG_LC_EXT; + } else { + if (sfnReservedChar(c) || i > n) { + DBG_FAIL_MACRO; + goto fail; + } + if ('a' <= c && c <= 'z') { + c += 'A' - 'a'; + lc |= bit; + } else if ('A' <= c && c <= 'Z') { + uc |= bit; + } + fname->sfn[i++] = c; + } + } + // must have a file name, extension is optional + if (fname->sfn[0] == ' ') { + DBG_FAIL_MACRO; + goto fail; + } + // Set base-name and extension bits. + fname->flags = lc & uc ? 0 : lc; + while (isDirSeparator(*path)) { + path++; + } + *ptr = path; + return true; + + fail: + return false; +} +#if !USE_LONG_FILE_NAMES +//------------------------------------------------------------------------------ bool FatFile::remove() { DirFat_t* dir; // Can't remove if LFN or not open for write. @@ -286,7 +290,7 @@ bool FatFile::remove() { goto fail; } // Cache directory entry. - dir = reinterpret_cast(cacheDirEntry(FsCache::CACHE_FOR_WRITE)); + dir = cacheDirEntry(FsCache::CACHE_FOR_WRITE); if (!dir) { DBG_FAIL_MACRO; goto fail; diff --git a/firmware/3.0/lib/SdFat/src/FatLib/FatFormatter.cpp b/firmware/3.0/lib/SdFat/src/FatLib/FatFormatter.cpp old mode 100644 new mode 100755 index 0cbd7dc..768b18a --- a/firmware/3.0/lib/SdFat/src/FatLib/FatFormatter.cpp +++ b/firmware/3.0/lib/SdFat/src/FatLib/FatFormatter.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -22,7 +22,7 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -#include "FatFormatter.h" +#include "FatLib.h" // Set nonzero to use calculated CHS in MBR. Should not be required. #define USE_LBA_TO_CHS 1 @@ -45,7 +45,7 @@ const uint16_t FAT16_ROOT_SECTOR_COUNT = #define writeMsg(str) if (m_pr) m_pr->write(str) #endif // PRINT_FORMAT_PROGRESS //------------------------------------------------------------------------------ -bool FatFormatter::format(BlockDevice* dev, uint8_t* secBuf, print_t* pr) { +bool FatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) { bool rtn; m_dev = dev; m_secBuf = secBuf; @@ -72,7 +72,7 @@ bool FatFormatter::format(BlockDevice* dev, uint8_t* secBuf, print_t* pr) { // SDXC cards m_sectorsPerCluster = 128; } - rtn = m_sectorCount < 0X400000 ? makeFat16() :makeFat32(); + rtn = m_sectorCount < 0X400000 ? makeFat16() : makeFat32(); if (rtn) { writeMsg("Format Done\r\n"); } else { @@ -81,17 +81,31 @@ bool FatFormatter::format(BlockDevice* dev, uint8_t* secBuf, print_t* pr) { return rtn; } //------------------------------------------------------------------------------ +struct initFatDirState { + uint8_t * buffer; + print_t * pr; + uint16_t count; + uint16_t dotcount; +}; +static const uint8_t * initFatDirCallback(uint32_t sector, void *context) { + struct initFatDirState * state = (struct initFatDirState *)context; + if (state->pr && ++state->count >= state->dotcount) { + state->pr->write("."); + state->count = 0; + } + return state->buffer; +} bool FatFormatter::initFatDir(uint8_t fatType, uint32_t sectorCount) { size_t n; memset(m_secBuf, 0, BYTES_PER_SECTOR); writeMsg("Writing FAT "); - for (uint32_t i = 1; i < sectorCount; i++) { - if (!m_dev->writeSector(m_fatStart + i, m_secBuf)) { - return false; - } - if ((i%(sectorCount/32)) == 0) { - writeMsg("."); - } + struct initFatDirState state; + state.buffer = m_secBuf; + state.pr = m_pr; + state.count = 0; + state.dotcount = sectorCount/32; + if (!m_dev->writeSectorsCallback(m_fatStart + 1, sectorCount - 1, initFatDirCallback, &state)) { + return false; } writeMsg("\r\n"); // Allocate reserved clusters and root for FAT32. diff --git a/firmware/3.0/lib/SdFat/src/FatLib/FatFormatter.h b/firmware/3.0/lib/SdFat/src/FatLib/FatFormatter.h old mode 100644 new mode 100755 index e9663c5..2e7d55d --- a/firmware/3.0/lib/SdFat/src/FatLib/FatFormatter.h +++ b/firmware/3.0/lib/SdFat/src/FatLib/FatFormatter.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -24,10 +24,8 @@ */ #ifndef FatFormatter_h #define FatFormatter_h -#include "FatFile.h" #include "../common/SysCall.h" -#include "../common/BlockDevice.h" -#include "../common/FsStructs.h" +#include "../common/FsBlockDevice.h" /** * \class FatFormatter * \brief Format a FAT volume. @@ -43,7 +41,7 @@ class FatFormatter { * * \return true for success or false for failure. */ - bool format(BlockDevice* dev, uint8_t* secBuffer, print_t* pr = nullptr); + bool format(FsBlockDevice* dev, uint8_t* secBuffer, print_t* pr = nullptr); private: bool initFatDir(uint8_t fatType, uint32_t sectorCount); @@ -58,8 +56,8 @@ class FatFormatter { uint32_t m_relativeSectors; uint32_t m_sectorCount; uint32_t m_totalSectors; - BlockDevice* m_dev; - print_t*m_pr; + FsBlockDevice* m_dev; + print_t* m_pr; uint8_t* m_secBuf; uint16_t m_reservedSectorCount; uint8_t m_partType; diff --git a/firmware/3.0/lib/SdFat/src/FatLib/FatLib.h b/firmware/3.0/lib/SdFat/src/FatLib/FatLib.h old mode 100644 new mode 100755 index ceaa348..7b51c87 --- a/firmware/3.0/lib/SdFat/src/FatLib/FatLib.h +++ b/firmware/3.0/lib/SdFat/src/FatLib/FatLib.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -25,6 +25,5 @@ #ifndef FatLib_h #define FatLib_h #include "FatVolume.h" -#include "FatLibConfig.h" #include "FatFormatter.h" #endif // FatLib_h diff --git a/firmware/3.0/lib/SdFat/src/FatLib/FatName.cpp b/firmware/3.0/lib/SdFat/src/FatLib/FatName.cpp new file mode 100755 index 0000000..8a1205c --- /dev/null +++ b/firmware/3.0/lib/SdFat/src/FatLib/FatName.cpp @@ -0,0 +1,356 @@ +/** + * Copyright (c) 2011-2021 Bill Greiman + * This file is part of the SdFat library for SD memory cards. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#define DBG_FILE "FatName.cpp" +#include "../common/DebugMacros.h" +#include "../common/FsUtf.h" +#include "FatLib.h" +//------------------------------------------------------------------------------ +uint16_t FatFile::getLfnChar(DirLfn_t* ldir, uint8_t i) { + if (i < 5) { + return getLe16(ldir->unicode1 + 2*i); + } else if (i < 11) { + return getLe16(ldir->unicode2 + 2*i - 10); + } else if (i < 13) { + return getLe16(ldir->unicode3 + 2*i - 22); + } + DBG_HALT_IF(i >= 13); + return 0; +} +//------------------------------------------------------------------------------ +size_t FatFile::getName(char* name, size_t size) { +#if !USE_LONG_FILE_NAMES + return getSFN(name, size); +#elif USE_UTF8_LONG_NAMES + return getName8(name, size); +#else + return getName7(name, size); +#endif // !USE_LONG_FILE_NAMES +} +//------------------------------------------------------------------------------ +size_t FatFile::getName7(char* name, size_t size) { + FatFile dir; + DirLfn_t* ldir; + size_t n = 0; + if (!isOpen()) { + DBG_FAIL_MACRO; + goto fail; + } + if (!isLFN()) { + return getSFN(name, size); + } + if (!dir.openCluster(this)) { + DBG_FAIL_MACRO; + goto fail; + } + for (uint8_t order = 1; order <= m_lfnOrd; order++) { + ldir = reinterpret_cast(dir.cacheDir(m_dirIndex - order)); + if (!ldir) { + DBG_FAIL_MACRO; + goto fail; + } + if (ldir->attributes != FAT_ATTRIB_LONG_NAME || + order != (ldir->order & 0X1F)) { + DBG_FAIL_MACRO; + goto fail; + } + for (uint8_t i = 0; i < 13; i++) { + uint16_t c = getLfnChar(ldir, i); + if (c == 0) { + goto done; + } + if ((n + 1) >= size) { + DBG_FAIL_MACRO; + goto fail; + } + name[n++] = c >= 0X7F ? '?' : c; + } + } + done: + name[n] = 0; + return n; + + fail: + name[0] = '\0'; + return 0; +} +//------------------------------------------------------------------------------ +size_t FatFile::getName8(char* name, size_t size) { + char* end = name + size; + char* str = name; + char* ptr; + FatFile dir; + DirLfn_t* ldir; + uint16_t hs = 0; + uint32_t cp; + if (!isOpen()) { + DBG_FAIL_MACRO; + goto fail; + } + if (!isLFN()) { + return getSFN(name, size); + } + if (!dir.openCluster(this)) { + DBG_FAIL_MACRO; + goto fail; + } + for (uint8_t order = 1; order <= m_lfnOrd; order++) { + ldir = reinterpret_cast(dir.cacheDir(m_dirIndex - order)); + if (!ldir) { + DBG_FAIL_MACRO; + goto fail; + } + if (ldir->attributes != FAT_ATTRIB_LONG_NAME || + order != (ldir->order & 0X1F)) { + DBG_FAIL_MACRO; + goto fail; + } + for (uint8_t i = 0; i < 13; i++) { + uint16_t c = getLfnChar(ldir, i); + if (hs) { + if (!FsUtf::isLowSurrogate(c)) { + DBG_FAIL_MACRO; + goto fail; + } + cp = FsUtf::u16ToCp(hs, c); + hs = 0; + } else if (!FsUtf::isSurrogate(c)) { + if (c == 0) { + goto done; + } + cp = c; + } else if (FsUtf::isHighSurrogate(c)) { + hs = c; + continue; + } else { + DBG_FAIL_MACRO; + goto fail; + } + // Save space for zero byte. + ptr = FsUtf::cpToMb(cp, str, end - 1); + if (!ptr) { + DBG_FAIL_MACRO; + goto fail; + } + str = ptr; + } + } + done: + *str = '\0'; + return str - name; + + fail: + *name = 0; + return 0; +} +//------------------------------------------------------------------------------ +size_t FatFile::getSFN(char* name, size_t size) { + char c; + uint8_t j = 0; + uint8_t lcBit = FAT_CASE_LC_BASE; + uint8_t* ptr; + DirFat_t* dir; + if (!isOpen()) { + DBG_FAIL_MACRO; + goto fail; + } + if (isRoot()) { + if (size < 2) { + DBG_FAIL_MACRO; + goto fail; + } + name[0] = '/'; + name[1] = '\0'; + return 1; + } + // cache entry + dir = cacheDirEntry(FsCache::CACHE_FOR_READ); + if (!dir) { + DBG_FAIL_MACRO; + goto fail; + } + ptr = dir->name; + // format name + for (uint8_t i = 0; i < 12; i++) { + if (i == 8) { + if (*ptr == ' ') { + break; + } + lcBit = FAT_CASE_LC_EXT; + c = '.'; + } else { + c = *ptr++; + if ('A' <= c && c <= 'Z' && (lcBit & dir->caseFlags)) { + c += 'a' - 'A'; + } + if (c == ' ') { + continue; + } + } + if ((j + 1u) >= size) { + DBG_FAIL_MACRO; + goto fail; + } + name[j++] = c; + } + name[j] = '\0'; + return j; + + fail: + name[0] = '\0'; + return 0; +} +//------------------------------------------------------------------------------ +size_t FatFile::printName(print_t* pr) { +#if !USE_LONG_FILE_NAMES + return printSFN(pr); +#elif USE_UTF8_LONG_NAMES + return printName8(pr); +# else // USE_LONG_FILE_NAMES + return printName7(pr); +#endif // !USE_LONG_FILE_NAMES + } +//------------------------------------------------------------------------------ +size_t FatFile::printName7(print_t* pr) { + FatFile dir; + DirLfn_t* ldir; + size_t n = 0; + uint8_t buf[13]; + uint8_t i; + + if (!isOpen()) { + DBG_FAIL_MACRO; + goto fail; + } + if (!isLFN()) { + return printSFN(pr); + } + if (!dir.openCluster(this)) { + DBG_FAIL_MACRO; + goto fail; + } + for (uint8_t order = 1; order <= m_lfnOrd; order++) { + ldir = reinterpret_cast(dir.cacheDir(m_dirIndex - order)); + if (!ldir) { + DBG_FAIL_MACRO; + goto fail; + } + if (ldir->attributes != FAT_ATTRIB_LONG_NAME || + order != (ldir->order & 0X1F)) { + DBG_FAIL_MACRO; + goto fail; + } + for (i = 0; i < 13; i++) { + uint16_t u = getLfnChar(ldir, i); + if (u == 0) { + // End of name. + break; + } + buf[i] = u < 0X7F ? u : '?'; + n++; + } + pr->write(buf, i); + } + return n; + + fail: + return 0; +} +//------------------------------------------------------------------------------ +size_t FatFile::printName8(print_t *pr) { + FatFile dir; + DirLfn_t* ldir; + uint16_t hs = 0; + uint32_t cp; + size_t n = 0; + char buf[5]; + char* end = buf + sizeof(buf); + if (!isOpen()) { + DBG_FAIL_MACRO; + goto fail; + } + if (!isLFN()) { + return printSFN(pr); + } + if (!dir.openCluster(this)) { + DBG_FAIL_MACRO; + goto fail; + } + for (uint8_t order = 1; order <= m_lfnOrd; order++) { + ldir = reinterpret_cast(dir.cacheDir(m_dirIndex - order)); + if (!ldir) { + DBG_FAIL_MACRO; + goto fail; + } + if (ldir->attributes != FAT_ATTRIB_LONG_NAME || + order != (ldir->order & 0X1F)) { + DBG_FAIL_MACRO; + goto fail; + } + for (uint8_t i = 0; i < 13; i++) { + uint16_t c = getLfnChar(ldir, i);; + if (hs) { + if (!FsUtf::isLowSurrogate(c)) { + DBG_FAIL_MACRO; + goto fail; + } + cp = FsUtf::u16ToCp(hs, c); + hs = 0; + } else if (!FsUtf::isSurrogate(c)) { + if (c == 0) { + break; + } + cp = c; + } else if (FsUtf::isHighSurrogate(c)) { + hs = c; + continue; + } else { + DBG_FAIL_MACRO; + goto fail; + } + char* str = FsUtf::cpToMb(cp, buf, end); + if (!str) { + DBG_FAIL_MACRO; + goto fail; + } + n += pr->write(buf, str - buf); + } + } + return n; + + fail: + return 0; +} +//------------------------------------------------------------------------------ +size_t FatFile::printSFN(print_t* pr) { + char name[13]; + if (!getSFN(name, sizeof(name))) { + DBG_FAIL_MACRO; + goto fail; + } + return pr->write(name); + + fail: + return 0; +} diff --git a/firmware/3.0/lib/SdFat/src/FatLib/FatPartition.cpp b/firmware/3.0/lib/SdFat/src/FatLib/FatPartition.cpp old mode 100644 new mode 100755 index 4b0a2fc..bb4788a --- a/firmware/3.0/lib/SdFat/src/FatLib/FatPartition.cpp +++ b/firmware/3.0/lib/SdFat/src/FatLib/FatPartition.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -25,8 +25,8 @@ #include #define DBG_FILE "FatPartition.cpp" #include "../common/DebugMacros.h" -#include "../common/FsStructs.h" -#include "FatPartition.h" +#include "FatLib.h" + //------------------------------------------------------------------------------ bool FatPartition::allocateCluster(uint32_t current, uint32_t* next) { uint32_t find; @@ -158,7 +158,7 @@ bool FatPartition::allocContiguous(uint32_t count, uint32_t* firstCluster) { int8_t FatPartition::fatGet(uint32_t cluster, uint32_t* value) { uint32_t sector; uint32_t next; - cache_t* pc; + uint8_t* pc; // error if reserved cluster of beyond FAT if (cluster < 2 || cluster > m_lastCluster) { @@ -168,44 +168,44 @@ int8_t FatPartition::fatGet(uint32_t cluster, uint32_t* value) { if (fatType() == 32) { sector = m_fatStartSector + (cluster >> (m_bytesPerSectorShift - 2)); - pc = cacheFetchFat(sector, FsCache::CACHE_FOR_READ); + pc = fatCachePrepare(sector, FsCache::CACHE_FOR_READ); if (!pc) { DBG_FAIL_MACRO; goto fail; } - next = getLe32(reinterpret_cast - (&pc->fat32[cluster & (m_sectorMask >> 2)])); + uint16_t offset = (cluster << 2) & m_sectorMask; + next = getLe32(pc + offset); } else if (fatType() == 16) { cluster &= 0XFFFF; sector = m_fatStartSector + (cluster >> (m_bytesPerSectorShift - 1) ); - pc = cacheFetchFat(sector, FsCache::CACHE_FOR_READ); + pc = fatCachePrepare(sector, FsCache::CACHE_FOR_READ); if (!pc) { DBG_FAIL_MACRO; goto fail; } - next = getLe16(reinterpret_cast - (&pc->fat16[cluster & (m_sectorMask >> 1)])); + uint16_t offset = (cluster << 1) & m_sectorMask; + next = getLe16(pc + offset); } else if (FAT12_SUPPORT && fatType() == 12) { uint16_t index = cluster; index += index >> 1; sector = m_fatStartSector + (index >> m_bytesPerSectorShift); - pc = cacheFetchFat(sector, FsCache::CACHE_FOR_READ); + pc = fatCachePrepare(sector, FsCache::CACHE_FOR_READ); if (!pc) { DBG_FAIL_MACRO; goto fail; } index &= m_sectorMask; - uint16_t tmp = pc->data[index]; + uint16_t tmp = pc[index]; index++; if (index == m_bytesPerSector) { - pc = cacheFetchFat(sector + 1, FsCache::CACHE_FOR_READ); + pc = fatCachePrepare(sector + 1, FsCache::CACHE_FOR_READ); if (!pc) { DBG_FAIL_MACRO; goto fail; } index = 0; } - tmp |= pc->data[index] << 8; + tmp |= pc[index] << 8; next = cluster & 1 ? tmp >> 4 : tmp & 0XFFF; } else { DBG_FAIL_MACRO; @@ -224,7 +224,7 @@ int8_t FatPartition::fatGet(uint32_t cluster, uint32_t* value) { // Store a FAT entry bool FatPartition::fatPut(uint32_t cluster, uint32_t value) { uint32_t sector; - cache_t* pc; + uint8_t* pc; // error if reserved cluster of beyond FAT if (cluster < 2 || cluster > m_lastCluster) { @@ -234,26 +234,26 @@ bool FatPartition::fatPut(uint32_t cluster, uint32_t value) { if (fatType() == 32) { sector = m_fatStartSector + (cluster >> (m_bytesPerSectorShift - 2)); - pc = cacheFetchFat(sector, FsCache::CACHE_FOR_WRITE); + pc = fatCachePrepare(sector, FsCache::CACHE_FOR_WRITE); if (!pc) { DBG_FAIL_MACRO; goto fail; } - setLe32(reinterpret_cast - (&pc->fat32[cluster & (m_sectorMask >> 2)]), value); + uint16_t offset = (cluster << 2) & m_sectorMask; + setLe32(pc + offset, value); return true; } if (fatType() == 16) { cluster &= 0XFFFF; sector = m_fatStartSector + (cluster >> (m_bytesPerSectorShift - 1) ); - pc = cacheFetchFat(sector, FsCache::CACHE_FOR_WRITE); + pc = fatCachePrepare(sector, FsCache::CACHE_FOR_WRITE); if (!pc) { DBG_FAIL_MACRO; goto fail; } - setLe16(reinterpret_cast - (&pc->fat16[cluster & (m_sectorMask >> 1)]), value); + uint16_t offset = (cluster << 1) & m_sectorMask; + setLe16(pc + offset, value); return true; } @@ -261,7 +261,7 @@ bool FatPartition::fatPut(uint32_t cluster, uint32_t value) { uint16_t index = cluster; index += index >> 1; sector = m_fatStartSector + (index >> m_bytesPerSectorShift); - pc = cacheFetchFat(sector, FsCache::CACHE_FOR_WRITE); + pc = fatCachePrepare(sector, FsCache::CACHE_FOR_WRITE); if (!pc) { DBG_FAIL_MACRO; goto fail; @@ -269,15 +269,15 @@ bool FatPartition::fatPut(uint32_t cluster, uint32_t value) { index &= m_sectorMask; uint8_t tmp = value; if (cluster & 1) { - tmp = (pc->data[index] & 0XF) | tmp << 4; + tmp = (pc[index] & 0XF) | tmp << 4; } - pc->data[index] = tmp; + pc[index] = tmp; index++; if (index == m_bytesPerSector) { sector++; index = 0; - pc = cacheFetchFat(sector, FsCache::CACHE_FOR_WRITE); + pc = fatCachePrepare(sector, FsCache::CACHE_FOR_WRITE); if (!pc) { DBG_FAIL_MACRO; goto fail; @@ -285,9 +285,9 @@ bool FatPartition::fatPut(uint32_t cluster, uint32_t value) { } tmp = value >> 4; if (!(cluster & 1)) { - tmp = ((pc->data[index] & 0XF0)) | tmp >> 4; + tmp = ((pc[index] & 0XF0)) | tmp >> 4; } - pc->data[index] = tmp; + pc[index] = tmp; return true; } else { DBG_FAIL_MACRO; @@ -326,6 +326,39 @@ bool FatPartition::freeChain(uint32_t cluster) { fail: return false; } + +// Structure to use for doing free cluster count using callbacks +struct FreeClusterCountStruct { + uint32_t clusters_to_do; + uint32_t free_count; +}; + +//------------------------------------------------------------------------------ +void FatPartition::freeClusterCount_cb_fat16(uint32_t sector, uint8_t *buf, void *context) { + struct FreeClusterCountStruct *state = (struct FreeClusterCountStruct *)context; + uint16_t *p = (uint16_t *)buf; + unsigned int n = state->clusters_to_do; + if (n > 256) n = 256; + uint16_t *e = p + n; + while (p < e) { + if (*p++ == 0) state->free_count++; + } + state->clusters_to_do -= n; +} + +//------------------------------------------------------------------------------ +void FatPartition::freeClusterCount_cb_fat32(uint32_t sector, uint8_t *buf, void *context) { + struct FreeClusterCountStruct *state = (struct FreeClusterCountStruct *)context; + uint32_t *p = (uint32_t *)buf; + unsigned int n = state->clusters_to_do; + if (n > 128) n = 128; + uint32_t *e = p + n; + while (p < e) { + if (*p++ == 0) state->free_count++; + } + state->clusters_to_do -= n; +} + //------------------------------------------------------------------------------ int32_t FatPartition::freeClusterCount() { #if MAINTAIN_FREE_CLUSTER_COUNT @@ -333,63 +366,55 @@ int32_t FatPartition::freeClusterCount() { return m_freeClusterCount; } #endif // MAINTAIN_FREE_CLUSTER_COUNT - uint32_t free = 0; - uint32_t sector; - uint32_t todo = m_lastCluster + 1; - uint16_t n; - - if (FAT12_SUPPORT && fatType() == 12) { + if (FAT12_SUPPORT && fatType() == 12) { + uint32_t free = 0; + uint32_t todo = m_lastCluster + 1; for (unsigned i = 2; i < todo; i++) { uint32_t c; int8_t fg = fatGet(i, &c); if (fg < 0) { DBG_FAIL_MACRO; - goto fail; + return -1; } if (fg && c == 0) { free++; } } - } else if (fatType() == 16 || fatType() == 32) { - sector = m_fatStartSector; - while (todo) { - cache_t* pc = cacheFetchFat(sector++, FsCache::CACHE_FOR_READ); - if (!pc) { - DBG_FAIL_MACRO; - goto fail; - } - n = fatType() == 16 ? m_bytesPerSector/2 : m_bytesPerSector/4; - if (todo < n) { - n = todo; - } - if (fatType() == 16) { - for (uint16_t i = 0; i < n; i++) { - if (pc->fat16[i] == 0) { - free++; - } - } - } else { - for (uint16_t i = 0; i < n; i++) { - if (pc->fat32[i] == 0) { - free++; - } - } - } - todo -= n; - } + return free; + } + + struct FreeClusterCountStruct state; + + state.free_count = 0; + state.clusters_to_do = m_lastCluster + 1; + + uint32_t num_sectors; + + //num_sectors = SD.sdfs.m_fVol->sectorsPerFat(); // edit FsVolume.h for public + //Serial.printf(" num_sectors = %u\n", num_sectors); + + num_sectors = m_sectorsPerFat; + //Serial.printf(" num_sectors = %u\n", num_sectors); +#if USE_SEPARATE_FAT_CACHE + uint8_t *buf = m_fatCache.clear(); // will clear out anything and return buffer +#else + uint8_t *buf = m_cache.clear(); // will clear out anything and return buffer +#endif // USE_SEPARATE_FAT_CACHE + if (buf == nullptr) return -1; + if (fatType() == FAT_TYPE_FAT32) { + if (!m_blockDev->readSectorsCallback(m_fatStartSector, buf, num_sectors, freeClusterCount_cb_fat32, &state)) return -1; } else { - // invalid FAT type - DBG_FAIL_MACRO; - goto fail; + if (!m_blockDev->readSectorsCallback(m_fatStartSector, buf, num_sectors, freeClusterCount_cb_fat16, &state)) return -1; } - setFreeClusterCount(free); - return free; - fail: - return -1; + setFreeClusterCount(state.free_count); + return state.free_count; } + + //------------------------------------------------------------------------------ -bool FatPartition::init(BlockDevice* dev, uint8_t part) { +bool FatPartition::init(FsBlockDevice* dev, uint8_t part) { +// Serial.printf(" FatPartition::init(%x %u)\n", (uint32_t)dev, part); uint32_t clusterCount; uint32_t totalSectors; uint32_t volumeStartSector = 0; @@ -412,7 +437,7 @@ bool FatPartition::init(BlockDevice* dev, uint8_t part) { goto fail; } mbr = reinterpret_cast - (cacheFetchData(0, FsCache::CACHE_FOR_READ)); + (dataCachePrepare(0, FsCache::CACHE_FOR_READ)); MbrPart_t* mp = mbr->part + part - 1; if (!mbr || mp->type == 0 || (mp->boot != 0 && mp->boot != 0X80)) { @@ -422,9 +447,15 @@ bool FatPartition::init(BlockDevice* dev, uint8_t part) { volumeStartSector = getLe32(mp->relativeSectors); } pbs = reinterpret_cast - (cacheFetchData(volumeStartSector, FsCache::CACHE_FOR_READ)); + (dataCachePrepare(volumeStartSector, FsCache::CACHE_FOR_READ)); bpb = reinterpret_cast(pbs->bpb); - if (!pbs || bpb->fatCount != 2 || getLe16(bpb->bytesPerSector) != 512) { + if (!pbs || getLe16(bpb->bytesPerSector) != m_bytesPerSector) { + DBG_FAIL_MACRO; + goto fail; + } + // handle fat counts 1 or 2... + m_fatCount = bpb->fatCount; + if ((m_fatCount != 1) && (m_fatCount != 2)) { DBG_FAIL_MACRO; goto fail; } @@ -449,10 +480,10 @@ bool FatPartition::init(BlockDevice* dev, uint8_t part) { m_rootDirEntryCount = getLe16(bpb->rootDirEntryCount); // directory start for FAT16 dataStart for FAT32 - m_rootDirStart = m_fatStartSector + 2 * m_sectorsPerFat; + m_rootDirStart = m_fatStartSector + bpb->fatCount * m_sectorsPerFat; // data start for FAT16 and FAT32 m_dataStartSector = m_rootDirStart + - ((32 * m_rootDirEntryCount + m_bytesPerSector - 1)/m_bytesPerSector); + ((FS_DIR_SIZE*m_rootDirEntryCount + m_bytesPerSector - 1)/m_bytesPerSector); // total sectors for FAT16 or FAT32 totalSectors = getLe16(bpb->totalSectors16); @@ -490,3 +521,100 @@ bool FatPartition::init(BlockDevice* dev, uint8_t part) { fail: return false; } + +//------------------------------------------------------------------------------ +bool FatPartition::init(FsBlockDevice* dev, uint32_t firstSector, uint32_t numSectors) { +// Serial.printf(" FatPartition::init(%x %u %u)\n", (uint32_t)dev, firstSector, numSectors); + uint32_t clusterCount; + uint32_t totalSectors; + uint32_t volumeStartSector = firstSector; + m_blockDev = dev; + pbs_t* pbs; + BpbFat32_t* bpb; + uint8_t tmp; + + m_fatType = 0; + m_allocSearchStart = 1; + m_cache.init(dev); +#if USE_SEPARATE_FAT_CACHE + m_fatCache.init(dev); +#endif // USE_SEPARATE_FAT_CACHE + pbs = reinterpret_cast + (dataCachePrepare(volumeStartSector, FsCache::CACHE_FOR_READ)); + bpb = reinterpret_cast(pbs->bpb); + if (!pbs || getLe16(bpb->bytesPerSector) != m_bytesPerSector) { + DBG_FAIL_MACRO; + goto fail; + } + m_fatCount = bpb->fatCount; + // handle fat counts 1 or 2... + if ((m_fatCount != 1) && (m_fatCount != 2)) { + DBG_FAIL_MACRO; + goto fail; + } + m_sectorsPerCluster = bpb->sectorsPerCluster; + m_clusterSectorMask = m_sectorsPerCluster - 1; + // determine shift that is same as multiply by m_sectorsPerCluster + m_sectorsPerClusterShift = 0; + for (tmp = 1; m_sectorsPerCluster != tmp; tmp <<= 1) { + if (tmp == 0) { + DBG_FAIL_MACRO; + goto fail; + } + m_sectorsPerClusterShift++; + } + m_sectorsPerFat = getLe16(bpb->sectorsPerFat16); + if (m_sectorsPerFat == 0) { + m_sectorsPerFat = getLe32(bpb->sectorsPerFat32); + } + m_fatStartSector = volumeStartSector + getLe16(bpb->reservedSectorCount); + + // count for FAT16 zero for FAT32 + m_rootDirEntryCount = getLe16(bpb->rootDirEntryCount); + + // directory start for FAT16 dataStart for FAT32 + m_rootDirStart = m_fatStartSector + bpb->fatCount * m_sectorsPerFat; + // data start for FAT16 and FAT32 + m_dataStartSector = m_rootDirStart + + ((FS_DIR_SIZE*m_rootDirEntryCount + m_bytesPerSector - 1)/m_bytesPerSector); + + // total sectors for FAT16 or FAT32 + totalSectors = getLe16(bpb->totalSectors16); + if (totalSectors == 0) { + totalSectors = getLe32(bpb->totalSectors32); + } + if (totalSectors > numSectors) { + DBG_FAIL_MACRO; + goto fail; + } + // total data sectors + clusterCount = totalSectors - (m_dataStartSector - volumeStartSector); + + // divide by cluster size to get cluster count + clusterCount >>= m_sectorsPerClusterShift; + m_lastCluster = clusterCount + 1; + + // Indicate unknown number of free clusters. + setFreeClusterCount(-1); + // FAT type is determined by cluster count + if (clusterCount < 4085) { + m_fatType = 12; + if (!FAT12_SUPPORT) { + DBG_FAIL_MACRO; + goto fail; + } + } else if (clusterCount < 65525) { + m_fatType = 16; + } else { + m_rootDirStart = getLe32(bpb->fat32RootCluster); + m_fatType = 32; + } + m_cache.setMirrorOffset(m_sectorsPerFat); +#if USE_SEPARATE_FAT_CACHE + m_fatCache.setMirrorOffset(m_sectorsPerFat); +#endif // USE_SEPARATE_FAT_CACHE + return true; + + fail: + return false; +} diff --git a/firmware/3.0/lib/SdFat/src/FatLib/FatPartition.h b/firmware/3.0/lib/SdFat/src/FatLib/FatPartition.h old mode 100644 new mode 100755 index 0c019fb..462e6a1 --- a/firmware/3.0/lib/SdFat/src/FatLib/FatPartition.h +++ b/firmware/3.0/lib/SdFat/src/FatLib/FatPartition.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -29,9 +29,8 @@ * \brief FatPartition class */ #include -#include "FatLibConfig.h" #include "../common/SysCall.h" -#include "../common/BlockDevice.h" +#include "../common/FsBlockDevice.h" #include "../common/FsCache.h" #include "../common/FsStructs.h" @@ -44,20 +43,6 @@ const uint8_t FAT_TYPE_FAT16 = 16; /** Type for FAT12 partition */ const uint8_t FAT_TYPE_FAT32 = 32; -//------------------------------------------------------------------------------ -/** - * \brief Cache type for a sector. - */ -union cache_t { - /** Used to access cached file data sectors. */ - uint8_t data[512]; - /** Used to access cached FAT16 entries. */ - uint16_t fat16[256]; - /** Used to access cached FAT32 entries. */ - uint32_t fat32[128]; - /** Used to access cached directory entries. */ - DirFat_t dir[16]; -}; //============================================================================== /** * \class FatPartition @@ -85,6 +70,10 @@ class FatPartition { uint8_t bytesPerSectorShift() const { return m_bytesPerSectorShift; } + /** \return Number of directory entries per sector. */ + uint16_t dirEntriesPerCluster() const { + return m_sectorsPerCluster*(m_bytesPerSector/FS_DIR_SIZE); + } /** \return Mask for sector offset. */ uint16_t sectorMask() const { return m_sectorMask; @@ -94,8 +83,7 @@ class FatPartition { return m_sectorsPerCluster; } #ifndef DOXYGEN_SHOULD_SKIP_THIS - // Use sectorsPerCluster(). blocksPerCluster() will be removed in the future. - uint8_t blocksPerCluster() __attribute__ ((deprecated)) {return sectorsPerCluster();} //NOLINT + uint8_t __attribute__((error("use sectorsPerCluster()"))) blocksPerCluster(); #endif // DOXYGEN_SHOULD_SKIP_THIS /** \return The number of sectors in one FAT. */ uint32_t sectorsPerFat() const { @@ -119,9 +107,16 @@ class FatPartition { uint32_t dataStartSector() const { return m_dataStartSector; } + /** End access to volume + * \return pointer to sector size buffer for format. + */ + uint8_t* end() { + m_fatType = 0; + return cacheClear(); + } /** \return The number of File Allocation Tables. */ uint8_t fatCount() const { - return 2; + return m_fatCount; } /** \return The logical sector number for the start of the first FAT. */ uint32_t fatStartSector() const { @@ -138,7 +133,7 @@ class FatPartition { int32_t freeClusterCount(); /** Initialize a FAT partition. * - * \param[in] dev BlockDevice for this partition. + * \param[in] dev FsBlockDevice for this partition. * \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 @@ -146,7 +141,8 @@ class FatPartition { * * \return true for success or false for failure. */ - bool init(BlockDevice* dev, uint8_t part = 1); + bool init(FsBlockDevice* dev, uint8_t part = 1); + bool init(FsBlockDevice* dev, uint32_t firstSector, uint32_t numSectors); /** \return The number of entries in the root directory for FAT16 volumes. */ uint16_t rootDirEntryCount() const { return m_rootDirEntryCount; @@ -170,16 +166,16 @@ class FatPartition { return fatGet(n, v); } /** - * Check for BlockDevice busy. + * Check for FsBlockDevice busy. * * \return true if busy else false. */ bool isBusy() {return m_blockDev->isBusy();} //---------------------------------------------------------------------------- #ifndef DOXYGEN_SHOULD_SKIP_THIS - void dmpDirSector(print_t* pr, uint32_t sector); + bool dmpDirSector(print_t* pr, uint32_t sector); void dmpFat(print_t* pr, uint32_t start, uint32_t count); - void dmpRootDir(print_t* pr); + bool dmpRootDir(print_t* pr, uint32_t n = 0); void dmpSector(print_t* pr, uint32_t sector, uint8_t bits = 8); #endif // DOXYGEN_SHOULD_SKIP_THIS //---------------------------------------------------------------------------- @@ -188,14 +184,15 @@ class FatPartition { friend class FatFile; //---------------------------------------------------------------------------- static const uint8_t m_bytesPerSectorShift = 9; - static const uint16_t m_bytesPerSector = 512; - static const uint16_t m_sectorMask = 0x1FF; + static const uint16_t m_bytesPerSector = 1 << m_bytesPerSectorShift; + static const uint16_t m_sectorMask = m_bytesPerSector - 1; //---------------------------------------------------------------------------- - BlockDevice* m_blockDev; // sector device + FsBlockDevice* m_blockDev; // sector device uint8_t m_sectorsPerCluster; // Cluster size in sectors. uint8_t m_clusterSectorMask; // Mask to extract sector of cluster. uint8_t m_sectorsPerClusterShift; // Cluster count to sector count shift. uint8_t m_fatType = 0; // Volume type (12, 16, OR 32). + uint8_t m_fatCount = 2; // How many fats mostly 2 will support 1 uint16_t m_rootDirEntryCount; // Number of entries in FAT16 root dir. uint32_t m_allocSearchStart; // Start cluster for alloc search. uint32_t m_sectorsPerFat; // FAT size in sectors @@ -217,15 +214,9 @@ class FatPartition { bool cacheSafeWrite(uint32_t sector, const uint8_t* dst, size_t count) { return m_cache.cacheSafeWrite(sector, dst, count); } - bool readSector(uint32_t sector, uint8_t* dst) { - return m_blockDev->readSector(sector, dst); - } bool syncDevice() { return m_blockDev->syncDevice(); } - bool writeSector(uint32_t sector, const uint8_t* src) { - return m_blockDev->writeSector(sector, src); - } #if MAINTAIN_FREE_CLUSTER_COUNT int32_t m_freeClusterCount; // Count of free clusters in volume. void setFreeClusterCount(int32_t value) { @@ -246,26 +237,30 @@ class FatPartition { #endif // MAINTAIN_FREE_CLUSTER_COUNT // sector caches FsCache m_cache; + bool cachePrepare(uint32_t sector, uint8_t option) { + return m_cache.prepare(sector, option); + } + FsCache* dataCache() {return &m_cache;} #if USE_SEPARATE_FAT_CACHE FsCache m_fatCache; - cache_t* cacheFetchFat(uint32_t sector, uint8_t options) { - options |= FsCache::CACHE_STATUS_MIRROR_FAT; - return reinterpret_cast(m_fatCache.get(sector, options)); + uint8_t* fatCachePrepare(uint32_t sector, uint8_t options) { + if (m_fatCount == 2) options |= FsCache::CACHE_STATUS_MIRROR_FAT; + return m_fatCache.prepare(sector, options); } bool cacheSync() { return m_cache.sync() && m_fatCache.sync() && syncDevice(); } #else // USE_SEPARATE_FAT_CACHE - cache_t* cacheFetchFat(uint32_t sector, uint8_t options) { - options |= FsCache::CACHE_STATUS_MIRROR_FAT; - return cacheFetchData(sector, options); + uint8_t* fatCachePrepare(uint32_t sector, uint8_t options) { + if (m_fatCount == 2) options |= FsCache::CACHE_STATUS_MIRROR_FAT; + return dataCachePrepare(sector, options); } bool cacheSync() { return m_cache.sync() && syncDevice(); } #endif // USE_SEPARATE_FAT_CACHE - cache_t* cacheFetchData(uint32_t sector, uint8_t options) { - return reinterpret_cast(m_cache.get(sector, options)); + uint8_t* dataCachePrepare(uint32_t sector, uint8_t options) { + return m_cache.prepare(sector, options); } void cacheInvalidate() { m_cache.invalidate(); @@ -273,8 +268,8 @@ class FatPartition { bool cacheSyncData() { return m_cache.sync(); } - cache_t* cacheAddress() { - return reinterpret_cast(m_cache.cacheBuffer()); + uint8_t* cacheAddress() { + return m_cache.cacheBuffer(); } uint32_t cacheSectorNumber() { return m_cache.sector(); @@ -300,5 +295,9 @@ class FatPartition { bool isEOC(uint32_t cluster) const { return cluster > m_lastCluster; } + // freeClusterCount static helper functions + static void freeClusterCount_cb_fat16(uint32_t sector, uint8_t *buf, void *context); + static void freeClusterCount_cb_fat32(uint32_t sector, uint8_t *buf, void *context); }; + #endif // FatPartition diff --git a/firmware/3.0/lib/SdFat/src/FatLib/FatVolume.cpp b/firmware/3.0/lib/SdFat/src/FatLib/FatVolume.cpp old mode 100644 new mode 100755 index d6f59e2..29c1bc6 --- a/firmware/3.0/lib/SdFat/src/FatLib/FatVolume.cpp +++ b/firmware/3.0/lib/SdFat/src/FatLib/FatVolume.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -22,15 +22,19 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -#include "FatVolume.h" +#define DBG_FILE "FatVolume.cpp" +#include "../common/DebugMacros.h" +#include "FatLib.h" FatVolume* FatVolume::m_cwv = nullptr; //------------------------------------------------------------------------------ bool FatVolume::chdir(const char *path) { FatFile dir; if (!dir.open(vwd(), path, O_RDONLY)) { + DBG_FAIL_MACRO; goto fail; } if (!dir.isDir()) { + DBG_FAIL_MACRO; goto fail; } m_vwd = dir; diff --git a/firmware/3.0/lib/SdFat/src/FatLib/FatVolume.h b/firmware/3.0/lib/SdFat/src/FatLib/FatVolume.h old mode 100644 new mode 100755 index df8e4c1..b979ea3 --- a/firmware/3.0/lib/SdFat/src/FatLib/FatVolume.h +++ b/firmware/3.0/lib/SdFat/src/FatLib/FatVolume.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -24,7 +24,6 @@ */ #ifndef FatVolume_h #define FatVolume_h -#include "FatPartition.h" #include "FatFile.h" /** * \file @@ -44,7 +43,7 @@ class FatVolume : public FatPartition { * \param[in] part partition to initialize. * \return true for success or false for failure. */ - bool begin(BlockDevice* dev, bool setCwv = true, uint8_t part = 1) { + bool begin(FsBlockDevice* dev, bool setCwv = true, uint8_t part = 1) { if (!init(dev, part)) { return false; } @@ -56,6 +55,19 @@ class FatVolume : public FatPartition { } return true; } + bool begin(FsBlockDevice* dev, bool setCwv, uint32_t firstSector, uint32_t numSectors) { + if (!init(dev, firstSector, numSectors)) { + return false; + } + if (!chdir()) { + return false; + } + if (setCwv || !m_cwv) { + m_cwv = this; + } + return true; + } + /** Change global current working volume to this volume. */ void chvol() {m_cwv = this;} @@ -73,7 +85,6 @@ class FatVolume : public FatPartition { * \return true for success or false for failure. */ bool chdir(const char *path); - //---------------------------------------------------------------------------- /** * Test for the existence of a file. diff --git a/firmware/3.0/lib/SdFat/src/FreeStack.cpp b/firmware/3.0/lib/SdFat/src/FreeStack.cpp old mode 100644 new mode 100755 index 3d3c58c..af3ead4 --- a/firmware/3.0/lib/SdFat/src/FreeStack.cpp +++ b/firmware/3.0/lib/SdFat/src/FreeStack.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -39,7 +39,7 @@ inline char* stackBegin() { } //------------------------------------------------------------------------------ inline char* stackPointer() { -#if defined(__AVR__) +#if defined(__AVR__) return reinterpret_cast(SP); #elif defined(__arm__) register uint32_t sp asm("sp"); diff --git a/firmware/3.0/lib/SdFat/src/FreeStack.h b/firmware/3.0/lib/SdFat/src/FreeStack.h old mode 100644 new mode 100755 index 257f538..d0e7725 --- a/firmware/3.0/lib/SdFat/src/FreeStack.h +++ b/firmware/3.0/lib/SdFat/src/FreeStack.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License diff --git a/firmware/3.0/lib/SdFat/src/FsLib/FsFile.cpp b/firmware/3.0/lib/SdFat/src/FsLib/FsFile.cpp old mode 100644 new mode 100755 index e3a6da4..a6bf54b --- a/firmware/3.0/lib/SdFat/src/FsLib/FsFile.cpp +++ b/firmware/3.0/lib/SdFat/src/FsLib/FsFile.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License diff --git a/firmware/3.0/lib/SdFat/src/FsLib/FsFile.h b/firmware/3.0/lib/SdFat/src/FsLib/FsFile.h old mode 100644 new mode 100755 index 3d8e7a1..313abb3 --- a/firmware/3.0/lib/SdFat/src/FsLib/FsFile.h +++ b/firmware/3.0/lib/SdFat/src/FsLib/FsFile.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -239,7 +239,7 @@ class FsBaseFile { m_xFile ? m_xFile->getWriteError() : true; } /** - * Check for BlockDevice busy. + * Check for FsBlockDevice busy. * * \return true if busy else false. */ @@ -355,14 +355,6 @@ class FsBaseFile { * \return true for success or false for failure. */ bool mkdir(FsBaseFile* dir, const char* path, bool pFlag = true); - /** No longer implemented due to Long File Names. - * - * Use getName(char* name, size_t size). - * \return a pointer to replacement suggestion. - */ - const char* name() const { - return "use getName()"; - } /** Open a file or directory by name. * * \param[in] dir An open file instance for the directory containing @@ -761,6 +753,14 @@ class FsBaseFile { return m_fFile ? length < (1ULL << 32) && m_fFile->truncate(length) : m_xFile ? m_xFile->truncate(length) : false; } + /** Write a string to a file. Used by the Arduino Print class. + * \param[in] str Pointer to the string. + * Use getWriteError to check for errors. + * \return count of characters written for success or -1 for failure. + */ + size_t write(const char* str) { + return write(str, strlen(str)); + } /** Write a byte to a file. Required by the Arduino Print class. * \param[in] b the byte to be written. * Use getWriteError to check for errors. @@ -777,10 +777,7 @@ class FsBaseFile { * \param[in] count 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. + * \a nbyte. If an error occurs, write() returns zero and writeError is set. */ size_t write(const void* buf, size_t count) { return m_fFile ? m_fFile->write(buf, count) : diff --git a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatTypes.h b/firmware/3.0/lib/SdFat/src/FsLib/FsFormatter.h old mode 100644 new mode 100755 similarity index 57% rename from firmware/3.0/lib/SdFat/src/ExFatLib/ExFatTypes.h rename to firmware/3.0/lib/SdFat/src/FsLib/FsFormatter.h index 8724756..0c5d3a0 --- a/firmware/3.0/lib/SdFat/src/ExFatLib/ExFatTypes.h +++ b/firmware/3.0/lib/SdFat/src/FsLib/FsFormatter.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -22,35 +22,36 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -#ifndef ExFatTypes_h -#define ExFatTypes_h -#include "ExFatConfig.h" - -#if __cplusplus < 201103 -#warning no char16_t -typedef uint16_t ExChar16_t; -// #error C++11 Support required -#else // __cplusplus < 201103 -typedef char16_t ExChar16_t; -#endif // __cplusplus < 201103 - -#if USE_EXFAT_UNICODE_NAMES -/** exFAT API character type */ -typedef ExChar16_t ExChar_t; -#else // USE_EXFAT_UNICODE_NAMES -/** exFAT API character type */ -typedef char ExChar_t; -#endif // USE_EXFAT_UNICODE_NAMES +#ifndef FsFormatter_h +#define FsFormatter_h +#include "FatLib/FatLib.h" +#include "ExFatLib/ExFatLib.h" /** - * \struct DirPos_t - * \brief Internal type for position in directory file. + * \class FsFormatter + * \brief Format a exFAT/FAT volume. */ -struct DirPos_t { - /** current cluster */ - uint32_t cluster; - /** offset */ - uint32_t position; - /** directory is contiguous */ - bool isContiguous; +class FsFormatter { + public: + /** + * Format a FAT volume. + * + * \param[in] dev Block device for volume. + * \param[in] secBuffer buffer for writing to volume. + * \param[in] pr Print device for progress output. + * + * \return true for success or false for failure. + */ + bool format(FsBlockDevice* dev, uint8_t* secBuffer, print_t* pr = nullptr) { + uint32_t sectorCount = dev->sectorCount(); + if (sectorCount == 0) { + return false; + } + return sectorCount <= 67108864 ? + m_fFmt.format(dev, secBuffer, pr) : + m_xFmt.format(dev, secBuffer, pr); + } + private: + FatFormatter m_fFmt; + ExFatFormatter m_xFmt; }; -#endif // ExFatTypes_h +#endif // FsFormatter_h diff --git a/firmware/3.0/lib/SdFat/src/FsLib/FsLib.h b/firmware/3.0/lib/SdFat/src/FsLib/FsLib.h old mode 100644 new mode 100755 index a39f620..2539797 --- a/firmware/3.0/lib/SdFat/src/FsLib/FsLib.h +++ b/firmware/3.0/lib/SdFat/src/FsLib/FsLib.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -30,4 +30,5 @@ */ #include "FsVolume.h" #include "FsFile.h" +#include "FsFormatter.h" #endif // FsLib_h diff --git a/firmware/3.0/lib/SdFat/src/FsLib/FsNew.cpp b/firmware/3.0/lib/SdFat/src/FsLib/FsNew.cpp old mode 100644 new mode 100755 index 1b3c04e..f02acb7 --- a/firmware/3.0/lib/SdFat/src/FsLib/FsNew.cpp +++ b/firmware/3.0/lib/SdFat/src/FsLib/FsNew.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License diff --git a/firmware/3.0/lib/SdFat/src/FsLib/FsNew.h b/firmware/3.0/lib/SdFat/src/FsLib/FsNew.h old mode 100644 new mode 100755 index bd08a50..9ca13f2 --- a/firmware/3.0/lib/SdFat/src/FsLib/FsNew.h +++ b/firmware/3.0/lib/SdFat/src/FsLib/FsNew.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License diff --git a/firmware/3.0/lib/SdFat/src/FsLib/FsVolume.cpp b/firmware/3.0/lib/SdFat/src/FsLib/FsVolume.cpp old mode 100644 new mode 100755 index 3121486..09b7b09 --- a/firmware/3.0/lib/SdFat/src/FsLib/FsVolume.cpp +++ b/firmware/3.0/lib/SdFat/src/FsLib/FsVolume.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -25,16 +25,16 @@ #include "FsLib.h" FsVolume* FsVolume::m_cwv = nullptr; //------------------------------------------------------------------------------ -bool FsVolume::begin(BlockDevice* blockDev) { +bool FsVolume::begin(FsBlockDevice* blockDev, bool setCwv, uint8_t part) { m_blockDev = blockDev; m_fVol = nullptr; m_xVol = new (m_volMem) ExFatVolume; - if (m_xVol && m_xVol->begin(m_blockDev, false)) { + if (m_xVol && m_xVol->begin(m_blockDev, false, part)) { goto done; } m_xVol = nullptr; m_fVol = new (m_volMem) FatVolume; - if (m_fVol && m_fVol->begin(m_blockDev, false)) { + if (m_fVol && m_fVol->begin(m_blockDev, false, part)) { goto done; } m_cwv = nullptr; @@ -42,10 +42,37 @@ bool FsVolume::begin(BlockDevice* blockDev) { return false; done: - m_cwv = this; + if (setCwv || !m_cwv) { + m_cwv = this; + } + return true; +} +//------------------------------------------------------------------------------ +bool FsVolume::begin(FsBlockDevice* blockDev, bool setCwv, + uint32_t firstSector, uint32_t numSectors) { + m_blockDev = blockDev; + m_fVol = nullptr; + m_xVol = new (m_volMem) ExFatVolume; + if (m_xVol && m_xVol->begin(m_blockDev, false, firstSector, numSectors)) { + goto done; + } + m_xVol = nullptr; + m_fVol = new (m_volMem) FatVolume; + if (m_fVol && m_fVol->begin(m_blockDev, false, firstSector, numSectors)) { + goto done; + } + m_cwv = nullptr; + m_fVol = nullptr; + return false; + + done: + if (setCwv || !m_cwv) { + m_cwv = this; + } return true; } //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ bool FsVolume::ls(print_t* pr, const char* path, uint8_t flags) { FsBaseFile dir; return dir.open(this, path, O_RDONLY) && dir.ls(pr, flags); @@ -62,3 +89,247 @@ FsFile FsVolume::open(const String &path, oflag_t oflag) { return open(path.c_str(), oflag ); } #endif // ENABLE_ARDUINO_STRING + + +// getVolumeLabel & setVolumeLabel from UsbMscFat by Warren Watson +bool FsVolume::getVolumeLabel(char *volume_label, size_t cb) +{ + uint8_t buf[512]; + if (!volume_label || (cb < 12)) return false; // don't want to deal with it + *volume_label = 0; // make sure if we fail later we return empty string as well. + uint8_t fat_type = fatType(); + uint32_t root_dir; + // Lets go hard core here. + if (m_fVol) { + FatFile rootFat; + if (!rootFat.openRoot(m_fVol)) return false; + uint32_t root_dir_size = rootFat.dirSize(); // how big is this directory... + rootFat.close(); + + if (fat_type == FAT_TYPE_FAT32) { + root_dir = m_fVol->dataStartSector(); + } else { + root_dir = m_fVol->rootDirStart(); + } + //Serial.printf("\n$$$ PFsVolume::getVolumeLabel(%u): %u %u\n", fat_type, root_dir, root_dir_size); + uint16_t index_in_sector=0; + m_blockDev->readSector(root_dir, buf); + while (root_dir_size) { + DirFat_t *dir; + dir = reinterpret_cast(&buf[index_in_sector]); + if (dir->name[0] == FAT_NAME_FREE) break; // at end of list... + if (dir->attributes == 0x08) { + size_t i; + for (i = 0; i < 11; i++) { + volume_label[i] = dir->name[i]; + } + while ((i > 0) && (volume_label[i - 1] == ' ')) i--; // trim off trailing blanks + volume_label[i] = 0; + return true; + } + index_in_sector += 32; // increment to next entry... + root_dir_size-=32; + if (index_in_sector >= 512 && root_dir_size) { + root_dir++; + m_blockDev->readSector(root_dir, buf); + index_in_sector = 0; + } + } + } else if (m_xVol) { + + uint32_t chs = m_xVol->clusterHeapStartSector(); + uint32_t rdc = m_xVol->rootDirectoryCluster(); + uint32_t root_dir_size = m_xVol->rootLength(); + uint32_t spc = m_xVol->sectorsPerCluster(); + //Serial.printf("\n$$$ PFsVolume::getVolumeLabel(Ex): %u %x %x %u\n", root_dir_size, chs, rdc, spc); + uint32_t root_dir = chs + (rdc-2)*spc; + //Serial.printf(" $$$ Guess sector: %x\n", root_dir); + + uint16_t index_in_sector=0; + m_blockDev->readSector(root_dir, buf); + while (root_dir_size) { + DirLabel_t *dir; + dir = reinterpret_cast(&buf[index_in_sector]); + //if (dir->name[0] == 0) break; // at end of list... + if (dir->type == EXFAT_TYPE_LABEL) { + size_t i; + for (i = 0; i < dir->labelLength; i++) { + volume_label[i] = dir->unicode[2 * i]; + } + volume_label[i] = 0; + return true; + } else if (dir->type == 0) break; // I believe this marks the end... + + index_in_sector += 32; // increment to next entry... + root_dir_size-=32; + if (index_in_sector >= 512 && root_dir_size) { + root_dir++; + m_blockDev->readSector(root_dir, buf); + index_in_sector = 0; + } + } + } + return false; // no volume label was found +} + + +bool FsVolume::setVolumeLabel(const char *volume_label) +{ + uint8_t buf[512]; + uint8_t fat_type = fatType(); + uint32_t root_dir; + bool label_found = false; + + // Lets go hard core here. + if (m_fVol) { + FatFile rootFat; + DirFat_t *dir = nullptr; + if (!rootFat.openRoot(m_fVol)) return false; + uint32_t root_dir_size = rootFat.dirSize(); // how big is this directory... + rootFat.close(); + + if (fat_type == FAT_TYPE_FAT32) { + root_dir = m_fVol->dataStartSector(); + } else { + root_dir = m_fVol->rootDirStart(); + } + //Serial.printf("\n$$$ PFsVolume::setVolumeLabel(%u): %u %u\n", fat_type, root_dir, root_dir_size); + uint16_t index_in_sector=0; + uint32_t first_deleted_entry_sector = 0; + uint16_t first_deleted_entry_index = 0; + + m_blockDev->readSector(root_dir, buf); + //dump_hexbytes(buf, 512); + while (root_dir_size) { + dir = reinterpret_cast(&buf[index_in_sector]); + if (dir->name[0] == FAT_NAME_DELETED) { + if (!first_deleted_entry_sector) { + first_deleted_entry_sector = root_dir; + first_deleted_entry_index = index_in_sector; + } + } + else if (dir->name[0] == FAT_NAME_FREE) break; // at end of list... + else if (dir->attributes == 0x08) { + label_found = true; + break; + } + index_in_sector += 32; // increment to next entry... + root_dir_size-=32; + if (index_in_sector >= 512 && root_dir_size) { + root_dir++; + m_blockDev->readSector(root_dir, buf); + //Serial.printf(">> %x\n", root_dir); + //dump_hexbytes(buf, 512); + index_in_sector = 0; + } + } + // Lets see if we found something... + if (!volume_label || !*volume_label) { + if (label_found) { + Serial.printf("Found volume label - deleted\n"); + dir->name[0] = FAT_NAME_DELETED; // mark item as deleted + dir->attributes = 0; + m_blockDev->writeSector(root_dir, buf); + m_blockDev->syncDevice(); + } + return true; + } + // Lets see where we should write... + if (!label_found) { + if (first_deleted_entry_sector) { + if (first_deleted_entry_sector != root_dir) { + root_dir = first_deleted_entry_sector; + m_blockDev->readSector(root_dir, buf); + } + index_in_sector = first_deleted_entry_index; + dir = reinterpret_cast(&buf[index_in_sector]); + label_found = true; + } + else if (dir->name[0] == FAT_NAME_FREE) label_found = true; + } + if (label_found) { // or found a spot for it. + memset((void*)dir, 0, 32); // clear it out. + if (FsDateTime::callback) { + uint16_t cur_date; + uint16_t cur_time; + uint8_t cur_ms10; + FsDateTime::callback(&cur_date, &cur_time, &cur_ms10); + setLe16(dir->modifyTime, cur_time); + setLe16(dir->modifyDate, cur_date); + } + for (size_t i = 0; i < 11; i++) { + dir->name[i] = *volume_label? *volume_label++ : ' '; // fill in the 11 trailing blanks + } + dir->attributes = 8; // mark as a volume label. + m_blockDev->writeSector(root_dir, buf); + m_blockDev->syncDevice(); + return true; + } + + } else if (m_xVol) { + DirLabel_t *dir = nullptr; + uint32_t chs = m_xVol->clusterHeapStartSector(); + uint32_t rdc = m_xVol->rootDirectoryCluster(); + uint32_t root_dir_size = m_xVol->rootLength(); + uint32_t spc = m_xVol->sectorsPerCluster(); + //Serial.printf("\n$$$ PFsVolume::setVolumeLabel(Ex): %u %x %x %u\n", root_dir_size, chs, rdc, spc); + uint32_t root_dir = chs + (rdc-2)*spc; + //Serial.printf(" $$$ Guess sector: %x\n", root_dir); + + uint16_t index_in_sector=0; + m_blockDev->readSector(root_dir, buf); + //m_xVol->cacheSafeRead(root_dir, buf); + //dump_hexbytes(buf, 512); + while (root_dir_size) { + dir = reinterpret_cast(&buf[index_in_sector]); + //if (dir->name[0] == 0) break; // at end of list... + if (dir->type == EXFAT_TYPE_LABEL) { + label_found = true; + break; + } else if (dir->type == 0) break; + index_in_sector += 32; // increment to next entry... + root_dir_size-=32; + if (index_in_sector >= 512 && root_dir_size) { + root_dir++; + m_blockDev->readSector(root_dir, buf); + //m_xVol->cacheSafeRead(root_dir, buf); + index_in_sector = 0; + //Serial.println("---"); + //dump_hexbytes(buf, 512); + } + } + // Lets see if we found something... + if (!volume_label || !*volume_label) { + if (label_found) { + Serial.printf("Found volume label - deleted\n"); + dir->type &= 0x7f; // mark item as deleted + m_blockDev->writeSector(root_dir, buf); + //m_xVol->cacheSafeWrite(root_dir, buf); + m_xVol->cacheClear(); + m_blockDev->syncDevice(); + } + return true; + } + // Lets see where we should write... + // + if (label_found || (dir->type == 0)) { // or found a spot for it. + uint8_t cb = strlen(volume_label); + if (cb > 11) cb = 11; // truncate off. + dir->type = EXFAT_TYPE_LABEL; + dir->labelLength = cb; + uint8_t *puni = dir->unicode; + while (cb--) { + *puni = *volume_label++; + puni += 2; + } + //m_xVol->cacheSafeWrite(root_dir, buf); + m_blockDev->writeSector(root_dir, buf); + m_xVol->cacheClear(); + m_blockDev->syncDevice(); + return true; + } + } + return false; // no volume label was found +} + + diff --git a/firmware/3.0/lib/SdFat/src/FsLib/FsVolume.h b/firmware/3.0/lib/SdFat/src/FsLib/FsVolume.h old mode 100644 new mode 100755 index bcac166..4a9d5af --- a/firmware/3.0/lib/SdFat/src/FsLib/FsVolume.h +++ b/firmware/3.0/lib/SdFat/src/FsLib/FsVolume.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -46,12 +46,14 @@ class FsVolume { /** * Initialize an FatVolume object. * \param[in] blockDev Device block driver. + * \param[in] setCwv Set current working volume if true. + * \param[in] part partition to initialize. * \return true for success or false for failure. */ - bool begin(BlockDevice* blockDev); + bool begin(FsBlockDevice* blockDev, bool setCwv = true, uint8_t part = 1); + bool begin(FsBlockDevice* blockDev, bool setCwv, uint32_t firstSector, uint32_t numSectors); #ifndef DOXYGEN_SHOULD_SKIP_THIS - // Use sectorsPerCluster(). blocksPerCluster() will be removed in the future. - uint32_t blocksPerCluster() __attribute__ ((deprecated)) {return sectorsPerCluster();} //NOLINT + uint32_t __attribute__((error("use sectorsPerCluster()"))) blocksPerCluster(); #endif // DOXYGEN_SHOULD_SKIP_THIS /** \return the number of bytes in a cluster. */ uint32_t bytesPerCluster() const { @@ -87,10 +89,14 @@ class FsVolume { return m_fVol ? m_fVol->dataStartSector() : m_xVol ? m_xVol->clusterHeapStartSector() : 0; } - /** free dynamic memory and end access to volume */ - void end() { + /** End access to volume + * \return pointer to sector size buffer for format. + */ + uint8_t* end() { m_fVol = nullptr; m_xVol = nullptr; + static_assert(sizeof(m_volMem) >= 512, "m_volMem too small"); + return reinterpret_cast(m_volMem); } /** Test for the existence of a file in a directory * @@ -120,7 +126,7 @@ class FsVolume { m_xVol ? m_xVol->freeClusterCount() : 0; } /** - * Check for BlockDevice busy. + * Check for device busy. * * \return true if busy else false. */ @@ -367,6 +373,25 @@ class FsVolume { */ #endif // ENABLE_ARDUINO_STRING +// TODO: #if ENABLE_VOLUME_LABEL so this isn't compiled on limited memory boards + /** Retrieve a volume label name. + * + * \param[in] character buffer to re receive the name + * + * \param[in] size of buffer + * + * \return true for success or false for failure. + */ + bool getVolumeLabel(char *volume_label, size_t cb); + /** set a volume label name. + * + * \param[in] Null terminated string with new volume label + * + * \return true for success or false for failure. + */ + bool setVolumeLabel(const char *volume_label); + + protected: newalign_t m_volMem[FS_ALIGN_DIM(ExFatVolume, FatVolume)]; @@ -380,6 +405,6 @@ class FsVolume { static FsVolume* m_cwv; FatVolume* m_fVol = nullptr; ExFatVolume* m_xVol = nullptr; - BlockDevice* m_blockDev; + FsBlockDevice* m_blockDev; }; #endif // FsVolume_h diff --git a/firmware/3.0/lib/SdFat/src/MinimumSerial.cpp b/firmware/3.0/lib/SdFat/src/MinimumSerial.cpp old mode 100644 new mode 100755 index b4e928f..50eeb00 --- a/firmware/3.0/lib/SdFat/src/MinimumSerial.cpp +++ b/firmware/3.0/lib/SdFat/src/MinimumSerial.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License diff --git a/firmware/3.0/lib/SdFat/src/MinimumSerial.h b/firmware/3.0/lib/SdFat/src/MinimumSerial.h old mode 100644 new mode 100755 index 11dd05b..951db12 --- a/firmware/3.0/lib/SdFat/src/MinimumSerial.h +++ b/firmware/3.0/lib/SdFat/src/MinimumSerial.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License diff --git a/firmware/3.0/lib/SdFat/src/RingBuf.h b/firmware/3.0/lib/SdFat/src/RingBuf.h old mode 100644 new mode 100755 index 76ebef6..a224fdf --- a/firmware/3.0/lib/SdFat/src/RingBuf.h +++ b/firmware/3.0/lib/SdFat/src/RingBuf.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -28,7 +28,7 @@ * \file * \brief Ring buffer for data loggers. */ -#include "Arduino.h" +#include "common/SysCall.h" #include "common/FmtNumber.h" #ifndef DOXYGEN_SHOULD_SKIP_THIS @@ -142,7 +142,7 @@ class RingBuf : public Print { while (nread != count) { n = minSize(Size - m_head, count - nread); memcpyBuf(m_buf + m_head, src + nread, n); - m_head = advance(m_head, n);; + m_head = advance(m_head, n); nread += n; } m_count += nread; @@ -266,8 +266,7 @@ class RingBuf : public Print { } /** * Write all data in the RingBuf to the underlying file. - * \param[in] data Byte to be written. - * \return Number of bytes actually written. + * \return true for success. */ bool sync() { size_t n = bytesUsed(); @@ -291,6 +290,15 @@ class RingBuf : public Print { } return memcpyIn(buf, count); } + /** + * Copy str to RingBuf. + * + * \param[in] str Location of data to be written. + * \return Number of bytes actually written. + */ + size_t write(const char* str) { + return Print::write(str); + } /** * Override virtual function in Print for efficiency. * @@ -316,6 +324,9 @@ class RingBuf : public Print { * The number of bytes written may be less than count if * bytesUsed is less than count or if an error occurs. * + * This function may be used in non-interrupt code with + * memcopyIn() in an ISR. + * * \return Number of bytes actually written. */ size_t writeOut(size_t count) { diff --git a/firmware/3.0/lib/SdFat/src/SdCard/SdCard.h b/firmware/3.0/lib/SdFat/src/SdCard/SdCard.h old mode 100644 new mode 100755 index 7a7c68e..dd5172b --- a/firmware/3.0/lib/SdFat/src/SdCard/SdCard.h +++ b/firmware/3.0/lib/SdFat/src/SdCard/SdCard.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License diff --git a/firmware/3.0/lib/SdFat/src/SdCard/SdCardInfo.cpp b/firmware/3.0/lib/SdFat/src/SdCard/SdCardInfo.cpp old mode 100644 new mode 100755 index 3536800..5705a30 --- a/firmware/3.0/lib/SdFat/src/SdCard/SdCardInfo.cpp +++ b/firmware/3.0/lib/SdFat/src/SdCard/SdCardInfo.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License diff --git a/firmware/3.0/lib/SdFat/src/SdCard/SdCardInfo.h b/firmware/3.0/lib/SdFat/src/SdCard/SdCardInfo.h old mode 100644 new mode 100755 index d84f6cd..42e9df5 --- a/firmware/3.0/lib/SdFat/src/SdCard/SdCardInfo.h +++ b/firmware/3.0/lib/SdFat/src/SdCard/SdCardInfo.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -86,7 +86,7 @@ SD_CARD_ERROR(FUNCTION_NOT_SUPPORTED, "Unsupported SDIO command") enum { -#define SD_CARD_ERROR(e, m) SD_CARD_ERROR_##e, +#define SD_CARD_ERROR(e, m) SD_CARD_ERROR_##e, SD_ERROR_CODE_LIST #undef SD_CARD_ERROR SD_CARD_ERROR_UNKNOWN diff --git a/firmware/3.0/lib/SdFat/src/SdCard/SdCardInterface.h b/firmware/3.0/lib/SdFat/src/SdCard/SdCardInterface.h old mode 100644 new mode 100755 index 17562ba..1116103 --- a/firmware/3.0/lib/SdFat/src/SdCard/SdCardInterface.h +++ b/firmware/3.0/lib/SdFat/src/SdCard/SdCardInterface.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -24,14 +24,16 @@ */ #ifndef SdCardInterface_h #define SdCardInterface_h -#include "../common/BlockDeviceInterface.h" +#include "../common/FsBlockDeviceInterface.h" #include "SdCardInfo.h" /** * \class SdCardInterface * \brief Abstract interface for an SD card. */ -class SdCardInterface : public BlockDeviceInterface { +class SdCardInterface : public FsBlockDeviceInterface { public: + /** end use of card */ + virtual void end() = 0; /** Erase a range of sectors. * * \param[in] firstSector The address of the first sector in the range. @@ -46,6 +48,18 @@ class SdCardInterface : public BlockDeviceInterface { virtual uint32_t errorData() const = 0; /** \return true if card is busy. */ virtual bool isBusy() = 0; + /** \return false by default */ + virtual bool hasDedicatedSpi() {return false;} + /** \return false by default */ + bool virtual isDedicatedSpi() {return false;} + /** Set SPI sharing state + * \param[in] value desired state. + * \return false by default. + */ + virtual bool setDedicatedSpi(bool value) { + (void)value; + return false; + } /** * Read a card's CID register. * diff --git a/firmware/3.0/lib/SdFat/src/SdCard/SdSpiCard.cpp b/firmware/3.0/lib/SdFat/src/SdCard/SdSpiCard.cpp old mode 100644 new mode 100755 index dcae8f7..93f7eb6 --- a/firmware/3.0/lib/SdFat/src/SdCard/SdSpiCard.cpp +++ b/firmware/3.0/lib/SdFat/src/SdCard/SdSpiCard.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -24,111 +24,20 @@ */ #include "SdSpiCard.h" //============================================================================== -// Debug aids -#define DBG_PROFILE_STATS 0 -#if DBG_PROFILE_STATS - -#define DBG_TAG_LIST\ - DBG_TAG(DBG_CMD0_TIME, "CMD0 time")\ - DBG_TAG(DBG_ACMD41_TIME, "ACMD41 time")\ - DBG_TAG(DBG_CMD_BUSY, "cmd busy")\ - DBG_TAG(DBG_ERASE_BUSY, "erase busy")\ - DBG_TAG(DBG_WAIT_READ, "wait read")\ - DBG_TAG(DBG_WRITE_FLASH, "write flash")\ - DBG_TAG(DBG_WRITE_BUSY, "write busy")\ - DBG_TAG(DBG_WRITE_STOP, "write stop")\ - DBG_TAG(DBG_ACMD41_COUNT, "ACMD41 count")\ - DBG_TAG(DBG_CMD0_COUNT, "CMD0 count") - -#define DBG_TIME_DIM DBG_ACMD41_COUNT - -enum DbgTag { - #define DBG_TAG(tag, str) tag, - DBG_TAG_LIST - DBG_COUNT_DIM - #undef DBG_TAG +class Timeout { + public: + Timeout() {} + explicit Timeout(uint16_t ms) {set(ms);} + uint16_t millis16() {return millis();} + void set(uint16_t ms) { + m_endTime = ms + millis16(); + } + bool timedOut() { + return (int16_t)(m_endTime - millis16()) < 0; + } + private: + uint16_t m_endTime; }; - -static uint32_t dbgCount[DBG_COUNT_DIM]; -static uint32_t dbgBgnTime[DBG_TIME_DIM]; -static uint32_t dbgMaxTime[DBG_TIME_DIM]; -static uint32_t dbgMinTime[DBG_TIME_DIM]; -static uint32_t dbgTotalTime[DBG_TIME_DIM]; -//------------------------------------------------------------------------------ -static void dbgBeginTime(DbgTag tag) { - dbgBgnTime[tag] = micros(); -} -//------------------------------------------------------------------------------ -static void dbgClearStats() { - for (int i = 0; i < DBG_COUNT_DIM; i++) { - dbgCount[i] = 0; - if (i < DBG_TIME_DIM) { - dbgMaxTime[i] = 0; - dbgMinTime[i] = 9999999; - dbgTotalTime[i] = 0; - } - } -} -//------------------------------------------------------------------------------ -static void dbgEndTime(DbgTag tag) { - uint32_t m = micros() - dbgBgnTime[tag]; - dbgTotalTime[tag] += m; - if (m > dbgMaxTime[tag]) { - dbgMaxTime[tag] = m; - } - if (m < dbgMinTime[tag]) { - dbgMinTime[tag] = m; - } - dbgCount[tag]++; -} -//------------------------------------------------------------------------------ -static void dbgEventCount(DbgTag tag) { - dbgCount[tag]++; -} -//------------------------------------------------------------------------------ -static void dbgPrintTagText(uint8_t tag) { - #define DBG_TAG(e, m) case e: Serial.print(F(m)); break; - switch (tag) { - DBG_TAG_LIST - } - #undef DBG_TAG -} -//------------------------------------------------------------------------------ -static void dbgPrintStats() { - Serial.println(); - Serial.println(F("=======================")); - Serial.println(F("item,event,min,max,avg")); - Serial.println(F("tag,count,usec,usec,usec")); - for (int i = 0; i < DBG_COUNT_DIM; i++) { - if (dbgCount[i]) { - dbgPrintTagText(i); - Serial.print(','); - Serial.print(dbgCount[i]); - if (i < DBG_TIME_DIM) { - Serial.print(','); - Serial.print(dbgMinTime[i]); - Serial.print(','); - Serial.print(dbgMaxTime[i]); - Serial.print(','); - Serial.print(dbgTotalTime[i]/dbgCount[i]); - } - Serial.println(); - } - } - Serial.println(F("=======================")); - Serial.println(); -} -#undef DBG_TAG_LIST -#define DBG_BEGIN_TIME(tag) dbgBeginTime(tag) -#define DBG_END_TIME(tag) dbgEndTime(tag) -#define DBG_EVENT_COUNT(tag) dbgEventCount(tag) -#else // DBG_PROFILE_STATS -#define DBG_BEGIN_TIME(tag) -#define DBG_END_TIME(tag) -#define DBG_EVENT_COUNT(tag) -static void dbgClearStats() {} -static void dbgPrintStats() {} -#endif // DBG_PROFILE_STATS //============================================================================== #if USE_SD_CRC // CRC functions @@ -218,10 +127,10 @@ static uint16_t CRC_CCITT(const uint8_t* data, size_t n) { #endif // CRC_CCITT #endif // USE_SD_CRC //============================================================================== -// SdSpiCard member functions +// SharedSpiCard member functions //------------------------------------------------------------------------------ -bool SdSpiCard::begin(SdSpiConfig spiConfig) { - SdMillis_t t0 = SysCall::curTimeMS(); +bool SharedSpiCard::begin(SdSpiConfig spiConfig) { + Timeout timeout; m_spiActive = false; m_errorCode = SD_CARD_ERROR_NONE; m_type = 0; @@ -238,13 +147,7 @@ bool SdSpiCard::begin(SdSpiConfig spiConfig) { spiSetSckSpeed(1000UL*SD_MAX_INIT_RATE_KHZ); spiBegin(spiConfig); uint32_t arg; -#if ENABLE_DEDICATED_SPI - m_curState = IDLE_STATE; - m_sharedSpi = spiOptionShared(spiConfig.options); -#else // ENABLE_DEDICATED_SPI - // m_sharedSpi is a static const bool in this case. - static_assert(m_sharedSpi == true, "m_sharedSpi bug"); -#endif // ENABLE_DEDICATED_SPI + m_state = IDLE_STATE; spiStart(); // must supply min of 74 clock cycles with CS high. @@ -253,10 +156,8 @@ bool SdSpiCard::begin(SdSpiConfig spiConfig) { spiSend(0XFF); } spiSelect(); - DBG_BEGIN_TIME(DBG_CMD0_TIME); // command to go idle in SPI mode for (uint8_t i = 1;; i++) { - DBG_EVENT_COUNT(DBG_CMD0_COUNT); if (cardCommand(CMD0, 0) == R1_IDLE_STATE) { break; } @@ -264,14 +165,7 @@ bool SdSpiCard::begin(SdSpiConfig spiConfig) { error(SD_CARD_ERROR_CMD0); goto fail; } - // stop multi-block write - spiSend(STOP_TRAN_TOKEN); - // finish block transfer - for (int i = 0; i < 520; i++) { - spiReceive(); - } } - DBG_END_TIME(DBG_CMD0_TIME); #if USE_SD_CRC if (cardCommand(CMD59, 1) != R1_IDLE_STATE) { error(SD_CARD_ERROR_CMD59); @@ -294,16 +188,14 @@ bool SdSpiCard::begin(SdSpiConfig spiConfig) { } // initialize card and send host supports SDHC if SD2 arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0; - DBG_BEGIN_TIME(DBG_ACMD41_TIME); + timeout.set(SD_INIT_TIMEOUT); while (cardAcmd(ACMD41, arg) != R1_READY_STATE) { - DBG_EVENT_COUNT(DBG_ACMD41_COUNT); // check for timeout - if (isTimedOut(t0, SD_INIT_TIMEOUT)) { + if (timeout.timedOut()) { error(SD_CARD_ERROR_ACMD41); goto fail; } } - DBG_END_TIME(DBG_ACMD41_TIME); // if SD2 read OCR register to check for SDHC card if (type() == SD_CARD_TYPE_SD2) { @@ -329,21 +221,18 @@ bool SdSpiCard::begin(SdSpiConfig spiConfig) { } //------------------------------------------------------------------------------ // send command and return error code. Return zero for OK -uint8_t SdSpiCard::cardCommand(uint8_t cmd, uint32_t arg) { -#if ENABLE_DEDICATED_SPI - if (m_curState != IDLE_STATE && !syncDevice()) { +uint8_t SharedSpiCard::cardCommand(uint8_t cmd, uint32_t arg) { + if (!syncDevice()) { return 0XFF; } -#endif // ENABLE_DEDICATED_SPI // select card if (!m_spiActive) { spiStart(); } - // wait if busy unless CMD0 - if (cmd != CMD0) { - DBG_BEGIN_TIME(DBG_CMD_BUSY); - waitNotBusy(SD_CMD_TIMEOUT); - DBG_END_TIME(DBG_CMD_BUSY); + if (cmd != CMD12) { + if (!waitReady(SD_CMD_TIMEOUT) && cmd != CMD0) { + return 0XFF; + } } #if USE_SD_CRC @@ -378,16 +267,14 @@ uint8_t SdSpiCard::cardCommand(uint8_t cmd, uint32_t arg) { spiReceive(); // there are 1-8 fill bytes before response. fill bytes should be 0XFF. - for (uint8_t i = 0; ((m_status = spiReceive()) & 0X80) && i < 10; i++) { - } + uint16_t n = 0; + do { + m_status = spiReceive(); + } while (m_status & 0X80 && ++n < 10); return m_status; } //------------------------------------------------------------------------------ -void SdSpiCard::dbgClearStats() {::dbgClearStats();} -//------------------------------------------------------------------------------ -void SdSpiCard::dbgPrintStats() {::dbgPrintStats();} -//------------------------------------------------------------------------------ -bool SdSpiCard::erase(uint32_t firstSector, uint32_t lastSector) { +bool SharedSpiCard::erase(uint32_t firstSector, uint32_t lastSector) { csd_t csd; if (!readCSD(&csd)) { goto fail; @@ -412,12 +299,10 @@ bool SdSpiCard::erase(uint32_t firstSector, uint32_t lastSector) { error(SD_CARD_ERROR_ERASE); goto fail; } - DBG_BEGIN_TIME(DBG_ERASE_BUSY); - if (!waitNotBusy(SD_ERASE_TIMEOUT)) { + if (!waitReady(SD_ERASE_TIMEOUT)) { error(SD_CARD_ERROR_ERASE_TIMEOUT); goto fail; } - DBG_END_TIME(DBG_ERASE_BUSY); spiStop(); return true; @@ -426,64 +311,43 @@ bool SdSpiCard::erase(uint32_t firstSector, uint32_t lastSector) { return false; } //------------------------------------------------------------------------------ -bool SdSpiCard::eraseSingleSectorEnable() { +bool SharedSpiCard::eraseSingleSectorEnable() { csd_t csd; return readCSD(&csd) ? csd.v1.erase_blk_en : false; } //------------------------------------------------------------------------------ -bool SdSpiCard::isBusy() { -#if ENABLE_DEDICATED_SPI - if (m_curState == READ_STATE) { +bool SharedSpiCard::isBusy() { + if (m_state == READ_STATE) { return false; } -#endif // ENABLE_DEDICATED_SPI - bool rtn = true; bool spiActive = m_spiActive; if (!spiActive) { spiStart(); } - for (uint8_t i = 0; i < 8; i++) { - if (0XFF == spiReceive()) { - rtn = false; - break; - } - } + bool rtn = 0XFF != spiReceive(); if (!spiActive) { spiStop(); } return rtn; } //------------------------------------------------------------------------------ -bool SdSpiCard::isTimedOut(SdMillis_t startMS, SdMillis_t timeoutMS) { -#if WDT_YIELD_TIME_MILLIS - static SdMillis_t last; - if ((SysCall::curTimeMS() - last) > WDT_YIELD_TIME_MILLIS) { - SysCall::yield(); - last = SysCall::curTimeMS(); - } -#endif // WDT_YIELD_TIME_MILLIS - return (SysCall::curTimeMS() - startMS) > timeoutMS; -} -//------------------------------------------------------------------------------ -bool SdSpiCard::readData(uint8_t* dst) { +bool SharedSpiCard::readData(uint8_t* dst) { return readData(dst, 512); } //------------------------------------------------------------------------------ -bool SdSpiCard::readData(uint8_t* dst, size_t count) { +bool SharedSpiCard::readData(uint8_t* dst, size_t count) { #if USE_SD_CRC uint16_t crc; #endif // USE_SD_CRC - DBG_BEGIN_TIME(DBG_WAIT_READ); // wait for start sector token - SdMillis_t t0 = SysCall::curTimeMS(); + Timeout timeout(SD_READ_TIMEOUT); while ((m_status = spiReceive()) == 0XFF) { - if (isTimedOut(t0, SD_READ_TIMEOUT)) { + if (timeout.timedOut()) { error(SD_CARD_ERROR_READ_TIMEOUT); goto fail; } } - DBG_END_TIME(DBG_WAIT_READ); if (m_status != DATA_START_SECTOR) { error(SD_CARD_ERROR_READ_TOKEN); goto fail; @@ -513,7 +377,7 @@ bool SdSpiCard::readData(uint8_t* dst, size_t count) { return false; } //------------------------------------------------------------------------------ -bool SdSpiCard::readOCR(uint32_t* ocr) { +bool SharedSpiCard::readOCR(uint32_t* ocr) { uint8_t* p = reinterpret_cast(ocr); if (cardCommand(CMD58, 0)) { error(SD_CARD_ERROR_CMD58); @@ -531,7 +395,7 @@ bool SdSpiCard::readOCR(uint32_t* ocr) { } //------------------------------------------------------------------------------ /** read CID or CSR register */ -bool SdSpiCard::readRegister(uint8_t cmd, void* buf) { +bool SharedSpiCard::readRegister(uint8_t cmd, void* buf) { uint8_t* dst = reinterpret_cast(buf); if (cardCommand(cmd, 0)) { error(SD_CARD_ERROR_READ_REG); @@ -548,7 +412,7 @@ bool SdSpiCard::readRegister(uint8_t cmd, void* buf) { return false; } //------------------------------------------------------------------------------ -bool SdSpiCard::readSingle(uint32_t sector, uint8_t* dst) { +bool SharedSpiCard::readSector(uint32_t sector, uint8_t* dst) { // use address if not SDHC card if (type() != SD_CARD_TYPE_SDHC) { sector <<= 9; @@ -568,7 +432,38 @@ bool SdSpiCard::readSingle(uint32_t sector, uint8_t* dst) { return false; } //------------------------------------------------------------------------------ -bool SdSpiCard::readStart(uint32_t sector) { +bool SharedSpiCard::readSectors(uint32_t sector, uint8_t* dst, size_t ns) { + if (!readStart(sector)) { + goto fail; + } + for (size_t i = 0; i < ns; i++, dst += 512) { + if (!readData(dst, 512)) { + goto fail; + } + } + return readStop(); + fail: + return false; +} +//------------------------------------------------------------------------------ +bool SharedSpiCard::readSectorsCallback(uint32_t sector, uint8_t* dst, size_t ns, + void (*callback)(uint32_t sector, uint8_t *buf, void *context), void *context) { + if (!readStart(sector)) { + goto fail; + } + for (size_t i = 0; i < ns; i++) { + if (readData(dst, 512)) { + callback(sector + i, dst, context); + } else { + goto fail; + } + } + return readStop(); + fail: + return false; +} +//------------------------------------------------------------------------------ +bool SharedSpiCard::readStart(uint32_t sector) { if (type() != SD_CARD_TYPE_SDHC) { sector <<= 9; } @@ -576,7 +471,7 @@ bool SdSpiCard::readStart(uint32_t sector) { error(SD_CARD_ERROR_CMD18); goto fail; } -// spiStop(); + m_state = READ_STATE; return true; fail: @@ -584,7 +479,7 @@ bool SdSpiCard::readStart(uint32_t sector) { return false; } //------------------------------------------------------------------------------ -bool SdSpiCard::readStatus(uint8_t* status) { +bool SharedSpiCard::readStatus(uint8_t* status) { // retrun is R2 so read extra status byte. if (cardAcmd(ACMD13, 0) || spiReceive()) { error(SD_CARD_ERROR_ACMD13); @@ -601,38 +496,8 @@ bool SdSpiCard::readStatus(uint8_t* status) { return false; } //------------------------------------------------------------------------------ -bool SdSpiCard::readSectors(uint32_t sector, uint8_t* dst, size_t ns) { -#if ENABLE_DEDICATED_SPI - if (m_curState != READ_STATE || sector != m_curSector) { - if (!readStart(sector)) { - goto fail; - } - m_curSector = sector; - m_curState = READ_STATE; - } - for (size_t i = 0; i < ns; i++, dst += 512) { - if (!readData(dst, 512)) { - goto fail; - } - } - m_curSector += ns; - return m_sharedSpi ? syncDevice() : true; -#else // ENABLE_DEDICATED_SPI - if (!readStart(sector)) { - goto fail; - } - for (size_t i = 0; i < ns; i++, dst += 512) { - if (!readData(dst, 512)) { - goto fail; - } - } - return readStop(); -#endif // ENABLE_DEDICATED_SPI - fail: - return false; -} -//------------------------------------------------------------------------------ -bool SdSpiCard::readStop() { +bool SharedSpiCard::readStop() { + m_state = IDLE_STATE; if (cardCommand(CMD12, 0)) { error(SD_CARD_ERROR_CMD12); goto fail; @@ -645,73 +510,57 @@ bool SdSpiCard::readStop() { return false; } //------------------------------------------------------------------------------ -uint32_t SdSpiCard::sectorCount() { +uint32_t SharedSpiCard::sectorCount() { csd_t csd; return readCSD(&csd) ? sdCardCapacity(&csd) : 0; } //------------------------------------------------------------------------------ -void SdSpiCard::spiStart() { +void SharedSpiCard::spiStart() { if (!m_spiActive) { spiActivate(); spiSelect(); + // Dummy byte to drive MISO busy status. + spiSend(0XFF); m_spiActive = true; } } //------------------------------------------------------------------------------ -void SdSpiCard::spiStop() { +void SharedSpiCard::spiStop() { if (m_spiActive) { spiUnselect(); + // Insure MISO goes to low Z. spiSend(0XFF); spiDeactivate(); m_spiActive = false; } } //------------------------------------------------------------------------------ -bool SdSpiCard::syncDevice() { -#if ENABLE_DEDICATED_SPI - // Insure no recursive loop with cardCommand(). - uint8_t state = m_curState; - m_curState = IDLE_STATE; - if (state == WRITE_STATE) { +bool SharedSpiCard::syncDevice() { + if (m_state == WRITE_STATE) { return writeStop(); } - if (state == READ_STATE) { + if (m_state == READ_STATE) { return readStop(); } -#endif // ENABLE_DEDICATED_SPI return true; } //------------------------------------------------------------------------------ -// wait for card to go not busy -bool SdSpiCard::waitNotBusy(SdMillis_t timeoutMS) { - SdMillis_t t0 = SysCall::curTimeMS(); -#if WDT_YIELD_TIME_MILLIS - // Call isTimedOut first to insure yield is called. - while (!isTimedOut(t0, timeoutMS)) { - if (spiReceive() == 0XFF) { - return true; - } - } - return false; -#else // WDT_YIELD_TIME_MILLIS - // Check not busy first since yield is not called in isTimedOut. +bool SharedSpiCard::waitReady(uint16_t ms) { + Timeout timeout(ms); while (spiReceive() != 0XFF) { - if (isTimedOut(t0, timeoutMS)) { + if (timeout.timedOut()) { return false; } } return true; -#endif // WDT_YIELD_TIME_MILLIS } //------------------------------------------------------------------------------ -bool SdSpiCard::writeData(const uint8_t* src) { +bool SharedSpiCard::writeData(const uint8_t* src) { // wait for previous write to finish - DBG_BEGIN_TIME(DBG_WRITE_BUSY); - if (!waitNotBusy(SD_WRITE_TIMEOUT)) { + if (!waitReady(SD_WRITE_TIMEOUT)) { error(SD_CARD_ERROR_WRITE_TIMEOUT); goto fail; } - DBG_END_TIME(DBG_WRITE_BUSY); if (!writeData(WRITE_MULTIPLE_TOKEN, src)) { goto fail; } @@ -723,7 +572,7 @@ bool SdSpiCard::writeData(const uint8_t* src) { } //------------------------------------------------------------------------------ // send one sector of data for write sector or write multiple sectors -bool SdSpiCard::writeData(uint8_t token, const uint8_t* src) { +bool SharedSpiCard::writeData(uint8_t token, const uint8_t* src) { #if USE_SD_CRC uint16_t crc = CRC_CCITT(src, 512); #else // USE_SD_CRC @@ -746,7 +595,7 @@ bool SdSpiCard::writeData(uint8_t token, const uint8_t* src) { return false; } //------------------------------------------------------------------------------ -bool SdSpiCard::writeSingle(uint32_t sector, const uint8_t* src) { +bool SharedSpiCard::writeSector(uint32_t sector, const uint8_t* src) { // use address if not SDHC card if (type() != SD_CARD_TYPE_SDHC) { sector <<= 9; @@ -761,12 +610,10 @@ bool SdSpiCard::writeSingle(uint32_t sector, const uint8_t* src) { #if CHECK_FLASH_PROGRAMMING // wait for flash programming to complete - DBG_BEGIN_TIME(DBG_WRITE_FLASH); - if (!waitNotBusy(SD_WRITE_TIMEOUT)) { + if (!waitReady(SD_WRITE_TIMEOUT)) { error(SD_CARD_ERROR_WRITE_PROGRAMMING); goto fail; } - DBG_END_TIME(DBG_WRITE_FLASH); // response is r2 so get and check two bytes for nonzero if (cardCommand(CMD13, 0) || spiReceive()) { error(SD_CARD_ERROR_CMD13); @@ -782,40 +629,42 @@ bool SdSpiCard::writeSingle(uint32_t sector, const uint8_t* src) { return false; } //------------------------------------------------------------------------------ -bool SdSpiCard::writeSectors(uint32_t sector, const uint8_t* src, size_t ns) { -#if ENABLE_DEDICATED_SPI - if (m_curState != WRITE_STATE || m_curSector != sector) { - if (!writeStart(sector)) { - goto fail; - } - m_curSector = sector; - m_curState = WRITE_STATE; +bool SharedSpiCard::writeSectors(uint32_t sector, + const uint8_t* src, size_t ns) { + if (!writeStart(sector)) { + goto fail; } for (size_t i = 0; i < ns; i++, src += 512) { if (!writeData(src)) { goto fail; } } - m_curSector += ns; - return m_sharedSpi ? syncDevice() : true; -#else // ENABLE_DEDICATED_SPI + return writeStop(); + + fail: + spiStop(); + return false; +} +//------------------------------------------------------------------------------ +bool SharedSpiCard::writeSectorsCallback(uint32_t sector, size_t ns, + const uint8_t * (*callback)(uint32_t sector, void *context), void *context) { if (!writeStart(sector)) { goto fail; } - for (size_t i = 0; i < ns; i++, src += 512) { + for (size_t i = 0; i < ns; i++) { + const uint8_t *src = callback(sector + i, context); if (!writeData(src)) { goto fail; } } return writeStop(); -#endif // ENABLE_DEDICATED_SPI fail: spiStop(); return false; } //------------------------------------------------------------------------------ -bool SdSpiCard::writeStart(uint32_t sector) { +bool SharedSpiCard::writeStart(uint32_t sector) { // use address if not SDHC card if (type() != SD_CARD_TYPE_SDHC) { sector <<= 9; @@ -824,6 +673,7 @@ bool SdSpiCard::writeStart(uint32_t sector) { error(SD_CARD_ERROR_CMD25); goto fail; } + m_state = WRITE_STATE; return true; fail: @@ -831,39 +681,126 @@ bool SdSpiCard::writeStart(uint32_t sector) { return false; } //------------------------------------------------------------------------------ -bool SdSpiCard::writeStart(uint32_t sector, uint32_t eraseCount) { - // send pre-erase count - if (cardAcmd(ACMD23, eraseCount)) { - error(SD_CARD_ERROR_ACMD23); - goto fail; - } - // use address if not SDHC card - if (type() != SD_CARD_TYPE_SDHC) { - sector <<= 9; - } - if (cardCommand(CMD25, sector)) { - error(SD_CARD_ERROR_CMD25); +bool SharedSpiCard::writeStop() { + if (!waitReady(SD_WRITE_TIMEOUT)) { goto fail; } + spiSend(STOP_TRAN_TOKEN); + spiStop(); + m_state = IDLE_STATE; return true; fail: + error(SD_CARD_ERROR_STOP_TRAN); spiStop(); return false; } +//============================================================================== +bool DedicatedSpiCard::begin(SdSpiConfig spiConfig) { + if (!SharedSpiCard::begin(spiConfig)) { + return false; + } + m_dedicatedSpi = spiOptionDedicated(spiConfig.options); + return true; +} //------------------------------------------------------------------------------ -bool SdSpiCard::writeStop() { - DBG_BEGIN_TIME(DBG_WRITE_STOP); - if (!waitNotBusy(SD_WRITE_TIMEOUT)) { - goto fail; +bool DedicatedSpiCard::readSector(uint32_t sector, uint8_t* dst) { + return readSectors(sector, dst, 1); +} +//------------------------------------------------------------------------------ +bool DedicatedSpiCard::readSectors( + uint32_t sector, uint8_t* dst, size_t ns) { + if (sdState() != READ_STATE || sector != m_curSector) { + if (!readStart(sector)) { + goto fail; + } + m_curSector = sector; } - DBG_END_TIME(DBG_WRITE_STOP); - spiSend(STOP_TRAN_TOKEN); - spiStop(); + for (size_t i = 0; i < ns; i++, dst += 512) { + if (!readData(dst)) { + goto fail; + } + } + m_curSector += ns; + return m_dedicatedSpi ? true : readStop(); + + fail: + return false; +} +//------------------------------------------------------------------------------ +bool DedicatedSpiCard::readSectorsCallback(uint32_t sector, uint8_t* dst, size_t ns, + void (*callback)(uint32_t sector, uint8_t *buf, void *context), void *context) { + if (sdState() != READ_STATE || sector != m_curSector) { + if (!readStart(sector)) { + goto fail; + } + m_curSector = sector; + } + for (size_t i = 0; i < ns; i++) { + if (readData(dst)) { + callback(sector + i, dst, context); + } else { + goto fail; + } + } + m_curSector += ns; + return m_dedicatedSpi ? true : readStop(); + fail: + return false; +} +//------------------------------------------------------------------------------ +bool DedicatedSpiCard::setDedicatedSpi(bool value) { + if (!syncDevice()) { + return false; + } + m_dedicatedSpi = value; return true; +} +//------------------------------------------------------------------------------ +bool DedicatedSpiCard::writeSector(uint32_t sector, const uint8_t* src) { + if (m_dedicatedSpi) { + return writeSectors(sector, src, 1); + } + return SharedSpiCard::writeSector(sector, src); +} +//------------------------------------------------------------------------------ +bool DedicatedSpiCard::writeSectors( + uint32_t sector, const uint8_t* src, size_t ns) { + if (sdState() != WRITE_STATE || m_curSector != sector) { + if (!writeStart(sector)) { + goto fail; + } + m_curSector = sector; + } + for (size_t i = 0; i < ns; i++, src += 512) { + if (!writeData(src)) { + goto fail; + } + } + m_curSector += ns; + return m_dedicatedSpi ? true : writeStop(); + +fail: + return false; +} +//------------------------------------------------------------------------------ +bool DedicatedSpiCard::writeSectorsCallback(uint32_t sector, size_t ns, + const uint8_t * (*callback)(uint32_t sector, void *context), void *context) { + if (sdState() != WRITE_STATE || m_curSector != sector) { + if (!writeStart(sector)) { + goto fail; + } + m_curSector = sector; + } + for (size_t i = 0; i < ns; i++) { + const uint8_t *src = callback(sector + i, context); + if (!writeData(src)) { + goto fail; + } + } + m_curSector += ns; + return m_dedicatedSpi ? true : writeStop(); fail: - error(SD_CARD_ERROR_STOP_TRAN); - spiStop(); return false; } diff --git a/firmware/3.0/lib/SdFat/src/SdCard/SdSpiCard.h b/firmware/3.0/lib/SdFat/src/SdCard/SdSpiCard.h old mode 100644 new mode 100755 index a1ce6ce..b6c74ff --- a/firmware/3.0/lib/SdFat/src/SdCard/SdSpiCard.h +++ b/firmware/3.0/lib/SdFat/src/SdCard/SdSpiCard.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -35,39 +35,34 @@ #include "../SpiDriver/SdSpiDriver.h" //============================================================================== /** - * \class SdSpiCard - * \brief Raw access to SD and SDHC flash memory cards via SPI protocol. + * \class SharedSpiCard + * \brief Raw access to SD and SDHC flash memory cards via shared SPI port. */ #if HAS_SDIO_CLASS -class SdSpiCard : public SdCardInterface { +class SharedSpiCard : public SdCardInterface { #elif USE_BLOCK_DEVICE_INTERFACE -class SdSpiCard : public BlockDeviceInterface { +class SharedSpiCard : public FsBlockDeviceInterface { #else // HAS_SDIO_CLASS -class SdSpiCard { +class SharedSpiCard { #endif // HAS_SDIO_CLASS public: - /** Construct an instance of SdSpiCard. */ - SdSpiCard() {} + /** SD is in idle state */ + static const uint8_t IDLE_STATE = 0; + /** SD is in multi-sector read state. */ + static const uint8_t READ_STATE = 1; + /** SD is in multi-sector write state. */ + static const uint8_t WRITE_STATE = 2; + /** Construct an instance of SharedSpiCard. */ + SharedSpiCard() {} /** Initialize the SD card. * \param[in] spiConfig SPI card configuration. * \return true for success or false for failure. */ bool begin(SdSpiConfig spiConfig); - /** Clear debug stats. */ - void dbgClearStats(); - /** Print debug stats. */ - void dbgPrintStats(); - /** - * Determine the size of an SD flash memory card. - * - * \return The number of 512 byte data sectors in the card - * or zero if an error occurs. - */ - uint32_t sectorCount(); -#ifndef DOXYGEN_SHOULD_SKIP_THIS - // Use sectorCount(). cardSize() will be removed in the future. - uint32_t cardSize() __attribute__ ((deprecated)) {return sectorCount();} -#endif // DOXYGEN_SHOULD_SKIP_THIS + /** End use of card */ + void end() { + spiEnd(); + } /** Erase a range of sectors. * * \param[in] firstSector The address of the first sector in the range. @@ -92,6 +87,7 @@ class SdSpiCard { * \param[in] code value for error code. */ void error(uint8_t code) { +// (void)code; m_errorCode = code; } /** @@ -104,44 +100,16 @@ class SdSpiCard { uint32_t errorData() const { return m_status; } + /** \return false for shared class. */ + bool hasDedicatedSpi() {return false;} /** * Check for busy. MISO low indicates the card is busy. * * \return true if busy else false. */ bool isBusy(); - - /** - * Read a 512 byte sector from an SD card. - * - * \param[in] sector Logical sector to be read. - * \param[out] dst Pointer to the location that will receive the data. - * \return true for success or false for failure. - */ - bool readSector(uint32_t sector, uint8_t* dst) { -#if ENABLE_DEDICATED_SPI - return readSectors(sector, dst, 1); -#else // ENABLE_DEDICATED_SPI - return readSingle(sector, dst); -#endif // ENABLE_DEDICATED_SPI - } - /** - * Read a 512 byte sector from an SD card. - * - * \param[in] sector Logical sector to be read. - * \param[out] dst Pointer to the location that will receive the data. - * \return true for success or false for failure. - */ - bool readSingle(uint32_t sector, uint8_t* dst); - /** - * Read multiple 512 byte sectors from an SD card. - * - * \param[in] sector Logical sector to be read. - * \param[in] ns Number of sectors to be read. - * \param[out] dst Pointer to the location that will receive the data. - * \return true for success or false for failure. - */ - bool readSectors(uint32_t sector, uint8_t* dst, size_t ns); + /** \return false, can't be in dedicated state. */ + bool isDedicatedSpi() {return false;} /** * Read a card's CID register. The CID contains card identification * information such as Manufacturer ID, Product name, Product serial @@ -178,6 +146,36 @@ class SdSpiCard { * \return true for success or false for failure. */ bool readOCR(uint32_t* ocr); + /** + * Read a 512 byte sector from an SD card. + * + * \param[in] sector Logical sector to be read. + * \param[out] dst Pointer to the location that will receive the data. + * \return true for success or false for failure. + */ + bool readSector(uint32_t sector, uint8_t* dst); + /** + * Read multiple 512 byte sectors from an SD card. + * + * \param[in] sector Logical sector to be read. + * \param[in] ns Number of sectors to be read. + * \param[out] dst Pointer to the location that will receive the data. + * \return true for success or false for failure. + */ + bool readSectors(uint32_t sector, uint8_t* dst, size_t ns); + /** + * Read multiple sectors with callback as each sector's data + * + * \param[in] sector Logical sector to be read. + * \param[in] ns Number of sectors to be read. + * \param[out] dst Pointer to the location that will receive the data. + * \param[in] callback Function to be called with each sector's data + * \param[in] context Pointer to be passed to the callback function + * \return true for success or false for failure. + */ + bool readSectorsCallback(uint32_t sector, uint8_t* dst, size_t ns, + void (*callback)(uint32_t sector, uint8_t *buf, void *context), void *context); + /** Start a read multiple sector sequence. * * \param[in] sector Address of first sector in sequence. @@ -198,6 +196,32 @@ class SdSpiCard { * \return true for success or false for failure. */ bool readStop(); + /** \return SD multi-sector read/write state */ + uint8_t sdState() {return m_state;} + /** + * Determine the size of an SD flash memory card. + * + * \return The number of 512 byte data sectors in the card + * or zero if an error occurs. + */ + uint32_t sectorCount(); +#ifndef DOXYGEN_SHOULD_SKIP_THIS + // Use sectorCount(). cardSize() will be removed in the future. + uint32_t __attribute__((error("use sectorCount()"))) cardSize(); +#endif // DOXYGEN_SHOULD_SKIP_THIS + /** Set SPI sharing state + * \param[in] value desired state. + * \return false for shared card + */ + bool setDedicatedSpi(bool value) { + (void)value; + return false; + } + /** end a mult-sector transfer. + * + * \return true for success or false for failure. + */ + bool stopTransfer(); /** \return success if sync successful. Not for user apps. */ bool syncDevice(); /** Return the card type: SD V1, SD V2 or SDHC/SDXC @@ -207,36 +231,33 @@ class SdSpiCard { return m_type; } /** - * Writes a 512 byte sector to an SD card. + * Write a 512 byte sector to an SD card. * * \param[in] sector Logical sector to be written. * \param[in] src Pointer to the location of the data to be written. * \return true for success or false for failure. */ - bool writeSector(uint32_t sector, const uint8_t* src) { - if (m_sharedSpi) { - return writeSingle(sector, src); - } else { - return writeSectors(sector, src, 1); - } - } + bool writeSector(uint32_t sector, const uint8_t* src); /** - * Writes a 512 byte sector to an SD card. + * Write multiple 512 byte sectors to an SD card. * * \param[in] sector Logical sector to be written. + * \param[in] ns Number of sectors to be written. * \param[in] src Pointer to the location of the data to be written. * \return true for success or false for failure. */ - bool writeSingle(uint32_t sector, const uint8_t* src); + bool writeSectors(uint32_t sector, const uint8_t* src, size_t ns); /** - * Write multiple 512 byte sectors to an SD card. + * Write multiple sectors to SD card with callback to prep data. * * \param[in] sector Logical sector to be written. * \param[in] ns Number of sectors to be written. - * \param[in] src Pointer to the location of the data to be written. + * \param[in] callback Function to be called for each sector's data + * \param[in] context to pass to callback function * \return true for success or false for failure. */ - bool writeSectors(uint32_t sector, const uint8_t* src, size_t ns); + bool writeSectorsCallback(uint32_t sector, size_t ns, + const uint8_t * (*callback)(uint32_t sector, void *context), void *context); /** Write one data sector in a multiple sector write sequence. * \param[in] src Pointer to the location of the data to be written. * \return true for success or false for failure. @@ -253,26 +274,11 @@ class SdSpiCard { */ bool writeStart(uint32_t sector); - /** Start a write multiple sector sequence with pre-erase. - * - * \param[in] sector Address of first sector in sequence. - * \param[in] eraseCount The number of sectors to be pre-erased. - * - * \note This function is used with writeData() and writeStop() - * for optimized multiple sector writes. - * - * \return true for success or false for failure. - */ - bool writeStart(uint32_t sector, uint32_t eraseCount); /** End a write multiple sectors sequence. * * \return true for success or false for failure. */ bool writeStop(); - /** Set CS low and activate the card. */ - void spiStart(); - /** Set CS high and deactivate the card. */ - void spiStop(); private: // private functions @@ -281,21 +287,21 @@ class SdSpiCard { return cardCommand(cmd, arg); } uint8_t cardCommand(uint8_t cmd, uint32_t arg); - bool isTimedOut(SdMillis_t startMS, SdMillis_t timeoutMS); bool readData(uint8_t* dst, size_t count); bool readRegister(uint8_t cmd, void* buf); void spiSelect() { sdCsWrite(m_csPin, false); } - void type(uint8_t value) { - m_type = value; - } + void spiStart(); + void spiStop(); void spiUnselect() { sdCsWrite(m_csPin, true); } - bool waitNotBusy(SdMillis_t timeoutMS); + void type(uint8_t value) { + m_type = value; + } + bool waitReady(uint16_t ms); bool writeData(uint8_t token, const uint8_t* src); - #if SPI_DRIVER_SELECT < 2 void spiActivate() { m_spiDriver.activate(); @@ -306,11 +312,14 @@ class SdSpiCard { void spiDeactivate() { m_spiDriver.deactivate(); } + void spiEnd() { + m_spiDriver.end(); + } uint8_t spiReceive() { return m_spiDriver.receive(); } uint8_t spiReceive(uint8_t* buf, size_t n) { - return m_spiDriver.receive(buf, n); + return m_spiDriver.receive(buf, n); } void spiSend(uint8_t data) { m_spiDriver.send(data); @@ -332,11 +341,14 @@ class SdSpiCard { void spiDeactivate() { m_spiDriverPtr->deactivate(); } + void spiEnd() { + m_spiDriverPtr->end(); + } uint8_t spiReceive() { return m_spiDriverPtr->receive(); } uint8_t spiReceive(uint8_t* buf, size_t n) { - return m_spiDriverPtr->receive(buf, n); + return m_spiDriverPtr->receive(buf, n); } void spiSend(uint8_t data) { m_spiDriverPtr->send(data); @@ -349,20 +361,105 @@ class SdSpiCard { } SdSpiDriver* m_spiDriverPtr; #endif // SPI_DRIVER_SELECT < 2 -#if ENABLE_DEDICATED_SPI - static const uint8_t IDLE_STATE = 0; - static const uint8_t READ_STATE = 1; - static const uint8_t WRITE_STATE = 2; - uint32_t m_curSector; - uint8_t m_curState; - bool m_sharedSpi = true; -#else // ENABLE_DEDICATED_SPI - static const bool m_sharedSpi = true; -#endif // ENABLE_DEDICATED_SPI SdCsPin_t m_csPin; uint8_t m_errorCode = SD_CARD_ERROR_INIT_NOT_CALLED; bool m_spiActive; + uint8_t m_state; uint8_t m_status; uint8_t m_type = 0; }; + +//============================================================================== +/** + * \class DedicatedSpiCard + * \brief Raw access to SD and SDHC flash memory cards via dedicate SPI port. + */ +class DedicatedSpiCard : public SharedSpiCard { + public: + /** Construct an instance of DedicatedSpiCard. */ + DedicatedSpiCard() {} + /** Initialize the SD card. + * \param[in] spiConfig SPI card configuration. + * \return true for success or false for failure. + */ + bool begin(SdSpiConfig spiConfig); + /** \return true, can be in dedicaded state. */ + bool hasDedicatedSpi() {return true;} + /** \return true if in dedicated SPI state. */ + bool isDedicatedSpi() {return m_dedicatedSpi;} + /** + * Read a 512 byte sector from an SD card. + * + * \param[in] sector Logical sector to be read. + * \param[out] dst Pointer to the location that will receive the data. + * \return true for success or false for failure. + */ + bool readSector(uint32_t sector, uint8_t* dst); + /** + * Read multiple 512 byte sectors from an SD card. + * + * \param[in] sector Logical sector to be read. + * \param[in] ns Number of sectors to be read. + * \param[out] dst Pointer to the location that will receive the data. + * \return true for success or false for failure. + */ + bool readSectors(uint32_t sector, uint8_t* dst, size_t ns); + /** + * Read multiple sectors with callback as each sector's data + * + * \param[in] sector Logical sector to be read. + * \param[in] ns Number of sectors to be read. + * \param[out] dst Pointer to the location that will receive the data. + * \param[in] callback Function to be called with each sector's data + * \param[in] context Pointer to be passed to the callback function + * \return true for success or false for failure. + */ + bool readSectorsCallback(uint32_t sector, uint8_t* dst, size_t ns, + void (*callback)(uint32_t sector, uint8_t *buf, void *context), void *context); + /** Set SPI sharing state + * \param[in] value desired state. + * \return true for success else false; + */ + bool setDedicatedSpi(bool value); + /** + * Write a 512 byte sector to an SD card. + * + * \param[in] sector Logical sector to be written. + * \param[in] src Pointer to the location of the data to be written. + * \return true for success or false for failure. + */ + bool writeSector(uint32_t sector, const uint8_t* src); + /** + * Write multiple 512 byte sectors to an SD card. + * + * \param[in] sector Logical sector to be written. + * \param[in] ns Number of sectors to be written. + * \param[in] src Pointer to the location of the data to be written. + * \return true for success or false for failure. + */ + bool writeSectors(uint32_t sector, const uint8_t* src, size_t ns); + /** + * Write multiple sectors to SD card with callback to prep data. + * + * \param[in] sector Logical sector to be written. + * \param[in] ns Number of sectors to be written. + * \param[in] callback Function to be called for each sector's data + * \param[in] context to pass to callback function + * \return true for success or false for failure. + */ + bool writeSectorsCallback(uint32_t sector, size_t ns, + const uint8_t * (*callback)(uint32_t sector, void *context), void *context); + + private: + uint32_t m_curSector; + bool m_dedicatedSpi = false; +}; +//============================================================================== +#if ENABLE_DEDICATED_SPI +/** typedef for dedicated SPI. */ +typedef DedicatedSpiCard SdSpiCard; +#else +/** typedef for shared SPI. */ +typedef SharedSpiCard SdSpiCard; +#endif #endif // SdSpiCard_h diff --git a/firmware/3.0/lib/SdFat/src/SdCard/SdioCard.h b/firmware/3.0/lib/SdFat/src/SdCard/SdioCard.h old mode 100644 new mode 100755 index 447248d..cfbe4cd --- a/firmware/3.0/lib/SdFat/src/SdCard/SdioCard.h +++ b/firmware/3.0/lib/SdFat/src/SdCard/SdioCard.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -61,13 +61,12 @@ class SdioCard : public SdCardInterface { */ bool begin(SdioConfig sdioConfig); /** Disable an SDIO card. - * \return false - not implemented. + * not implemented. */ - bool end() {return false;} + void end() {} #ifndef DOXYGEN_SHOULD_SKIP_THIS - // Use sectorCount(). cardSize() will be removed in the future. - uint32_t cardSize() __attribute__ ((deprecated)) {return sectorCount();} + uint32_t __attribute__((error("use sectorCount()"))) cardSize(); #endif // DOXYGEN_SHOULD_SKIP_THIS /** Erase a range of sectors. * diff --git a/firmware/3.0/lib/SdFat/src/SdCard/SdioTeensy.cpp b/firmware/3.0/lib/SdFat/src/SdCard/SdioTeensy.cpp old mode 100644 new mode 100755 index 1f4cdf6..e2d461b --- a/firmware/3.0/lib/SdFat/src/SdCard/SdioTeensy.cpp +++ b/firmware/3.0/lib/SdFat/src/SdCard/SdioTeensy.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -198,9 +198,7 @@ static bool (*m_busyFcn)() = 0; static bool m_initDone = false; static bool m_version2; static bool m_highCapacity; -#if ENABLE_TEENSY_SDIO_MOD static bool m_transferActive = false; -#endif // ENABLE_TEENSY_SDIO_MOD static uint8_t m_errorCode = SD_CARD_ERROR_INIT_NOT_CALLED; static uint32_t m_errorLine = 0; static uint32_t m_rca; @@ -331,7 +329,7 @@ static void gpioMux(uint8_t mode) { // add speed strength args? static void enableGPIO(bool enable) { const uint32_t CLOCK_MASK = IOMUXC_SW_PAD_CTL_PAD_PKE | -#if defined(ARDUINO_TEENSY41) +#if defined(__IMXRT1062__) IOMUXC_SW_PAD_CTL_PAD_DSE(7) | #else // defined(ARDUINO_TEENSY41) IOMUXC_SW_PAD_CTL_PAD_DSE(4) | ///// WHG @@ -574,7 +572,6 @@ static bool transferStop() { if (!cardCommand(CMD12_XFERTYP, 0)) { return sdError(SD_CARD_ERROR_CMD12); } -// if (yieldTimeout(isBusyCMD13)) { if (yieldTimeout(isBusyDat)) { return sdError(SD_CARD_ERROR_CMD13); } @@ -601,7 +598,7 @@ static bool yieldTimeout(bool (*fcn)()) { m_busyFcn = 0; return true; } - SysCall::yield(); + yield(); } m_busyFcn = 0; return false; // Caller will set errorCode. @@ -624,7 +621,6 @@ static bool waitTimeout(bool (*fcn)()) { } return false; // Caller will set errorCode. } -#if ENABLE_TEENSY_SDIO_MOD //------------------------------------------------------------------------------ static bool waitTransferComplete() { if (!m_transferActive) { @@ -639,7 +635,6 @@ static bool waitTransferComplete() { } return true; } -#endif // ENABLE_TEENSY_SDIO_MOD //============================================================================== // Start of SdioCard member functions. //============================================================================== @@ -776,7 +771,6 @@ uint32_t SdioCard::errorLine() const { } //------------------------------------------------------------------------------ bool SdioCard::isBusy() { -#if ENABLE_TEENSY_SDIO_MOD if (m_sdioConfig.useDma()) { return m_busyFcn ? m_busyFcn() : m_initDone && isBusyCMD13(); } else { @@ -798,9 +792,6 @@ bool SdioCard::isBusy() { // Use DAT0 low as busy. return SDHC_PRSSTAT & (1 << 24) ? false : true; } -#else // ENABLE_TEENSY_SDIO_MOD - return m_busyFcn ? m_busyFcn() : m_initDone && isBusyCMD13(); -#endif // ENABLE_TEENSY_SDIO_MOD } //------------------------------------------------------------------------------ uint32_t SdioCard::kHzSdClk() { @@ -865,11 +856,9 @@ bool SdioCard::readSector(uint32_t sector, uint8_t* dst) { memcpy(dst, aligned, 512); } } else { -#if ENABLE_TEENSY_SDIO_MOD if (!waitTransferComplete()) { return false; } -#endif // ENABLE_TEENSY_SDIO_MOD if (m_curState != READ_STATE || sector != m_curSector) { if (!syncDevice()) { return false; @@ -967,26 +956,12 @@ bool SdioCard::stopTransmission(bool blocking) { } //------------------------------------------------------------------------------ bool SdioCard::syncDevice() { -#if ENABLE_TEENSY_SDIO_MOD if (!waitTransferComplete()) { return false; } if (m_curState != IDLE_STATE) { return stopTransmission(true); } -#else // ENABLE_TEENSY_SDIO_MOD - if (m_curState == READ_STATE) { - m_curState = IDLE_STATE; - if (!readStop()) { - return false; - } - } else if (m_curState == WRITE_STATE) { - m_curState = IDLE_STATE; - if (!writeStop()) { - return false; - } - } -#endif // ENABLE_TEENSY_SDIO_MOD return true; } //------------------------------------------------------------------------------ @@ -997,11 +972,9 @@ uint8_t SdioCard::type() const { //------------------------------------------------------------------------------ bool SdioCard::writeData(const uint8_t* src) { DBG_IRQSTAT(); -#if ENABLE_TEENSY_SDIO_MOD if (!waitTransferComplete()) { return false; } -#endif // ENABLE_TEENSY_SDIO_MOD const uint32_t* p32 = reinterpret_cast(src); if (!(SDHC_PRSSTAT & SDHC_PRSSTAT_WTA)) { SDHC_PROCTL &= ~SDHC_PROCTL_SABGREQ; @@ -1019,17 +992,8 @@ bool SdioCard::writeData(const uint8_t* src) { } p32 += FIFO_WML; } -#if ENABLE_TEENSY_SDIO_MOD m_transferActive = true; return true; -#else // ENABLE_TEENSY_SDIO_MOD - if (waitTimeout(isBusyTransferComplete)) { - return sdError(SD_CARD_ERROR_WRITE_TIMEOUT); - } - m_irqstat = SDHC_IRQSTAT; - SDHC_IRQSTAT = m_irqstat; - return (m_irqstat & SDHC_IRQSTAT_TC) && !(m_irqstat & SDHC_IRQSTAT_ERROR); -#endif // ENABLE_TEENSY_SDIO_MOD } //------------------------------------------------------------------------------ bool SdioCard::writeSector(uint32_t sector, const uint8_t* src) { @@ -1046,7 +1010,6 @@ bool SdioCard::writeSector(uint32_t sector, const uint8_t* src) { return sdError(SD_CARD_ERROR_CMD24); } } else { -#if ENABLE_TEENSY_SDIO_MOD if (!waitTransferComplete()) { return false; } @@ -1058,7 +1021,6 @@ bool SdioCard::writeSector(uint32_t sector, const uint8_t* src) { } } #endif // defined(__MK64FX512__) || defined(__MK66FX1M0__) -#endif // ENABLE_TEENSY_SDIO_MOD if (m_curState != WRITE_STATE || m_curSector != sector) { if (!syncDevice()) { return false; @@ -1073,16 +1035,6 @@ bool SdioCard::writeSector(uint32_t sector, const uint8_t* src) { return false; } m_curSector++; -#if !ENABLE_TEENSY_SDIO_MOD -#if defined(__MK64FX512__) || defined(__MK66FX1M0__) - // End transfer with CMD12 if required. - if ((SDHC_BLKATTR & 0XFFFF0000) == 0) { - if (!syncDevice()) { - return false; - } - } -#endif // defined(__MK64FX512__) || defined(__MK66FX1M0__) -#endif // !ENABLE_TEENSY_SDIO_MOD } return true; } diff --git a/firmware/3.0/lib/SdFat/src/SdFat.h b/firmware/3.0/lib/SdFat/src/SdFat.h old mode 100644 new mode 100755 index 28d9563..ad71eb0 --- a/firmware/3.0/lib/SdFat/src/SdFat.h +++ b/firmware/3.0/lib/SdFat/src/SdFat.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -24,6 +24,8 @@ */ #ifndef SdFat_h #define SdFat_h +/** This copy of SdFat has special modifications for Teensy. */ +#define SD_FAT_TEENSY_MODIFIED 1 /** * \file * \brief main SdFs include file. @@ -37,16 +39,16 @@ #include "sdios.h" #endif // INCLUDE_SDIOS //------------------------------------------------------------------------------ -/** SdFat version for cpp use. */ -#define SD_FAT_VERSION 20005 +/** SdFat version for cpp use. */ +#define SD_FAT_VERSION 20102 /** SdFat version as string. */ -#define SD_FAT_VERSION_STR "2.0.5-beta.1" +#define SD_FAT_VERSION_STR "2.1.2" //============================================================================== /** * \class SdBase * \brief base SD file system template class. */ -template +template class SdBase : public Vol { public: //---------------------------------------------------------------------------- @@ -80,6 +82,10 @@ class SdBase : public Vol { * \return true for success or false for failure. */ bool begin(SdSpiConfig spiConfig) { + spiConfigBackupPin = spiConfig.csPin; + spiConfigBackupOptions = spiConfig.options; + spiConfigBackupClock = spiConfig.maxSck; + spiConfigBackupPort = spiConfig.spiPort; return cardBegin(spiConfig) && Vol::begin(m_card); } //--------------------------------------------------------------------------- @@ -89,9 +95,22 @@ class SdBase : public Vol { * \return true for success or false for failure. */ bool begin(SdioConfig sdioConfig) { + spiConfigBackupPin = 255; + sdioConfigBackup = sdioConfig; return cardBegin(sdioConfig) && Vol::begin(m_card); } //---------------------------------------------------------------------------- + /** Restart library with same config, used after media removed and replaced */ + bool restart() { + if (spiConfigBackupPin == 255) { + return begin(sdioConfigBackup); + } else { + SdSpiConfig spiConfig(spiConfigBackupPin, spiConfigBackupOptions, + spiConfigBackupClock, spiConfigBackupPort); + return begin(spiConfig); + } + } + //---------------------------------------------------------------------------- /** \return Pointer to SD card object. */ SdCard* card() {return m_card;} //---------------------------------------------------------------------------- @@ -115,6 +134,14 @@ class SdBase : public Vol { return m_card && !m_card->errorCode(); } //---------------------------------------------------------------------------- + /** End use of card. */ + void end() { + Vol::end(); + if (m_card) { + m_card->end(); + } + } + //---------------------------------------------------------------------------- /** %Print error info and halt. * * \param[in] pr Print destination. @@ -128,7 +155,7 @@ class SdBase : public Vol { } else if (!Vol::fatType()) { pr->println(F("Check SD format.")); } - SysCall::halt(); + while (true) {} } //---------------------------------------------------------------------------- /** %Print error info and halt. @@ -153,13 +180,51 @@ class SdBase : public Vol { errorHalt(pr); } //---------------------------------------------------------------------------- + /** Format SD card + * + * \param[in] pr Print destination. + * \return true for success else false. + */ + bool format(print_t* pr = nullptr) { + Fmt fmt; + uint8_t* mem = Vol::end(); + if (!mem) { + return false; + } + bool switchSpi = hasDedicatedSpi() && !isDedicatedSpi(); + if (switchSpi && !setDedicatedSpi(true)) { + return 0; + } + bool rtn = fmt.format(card(), mem, pr); + if (switchSpi && !setDedicatedSpi(false)) { + return 0; + } + return rtn; + } + //---------------------------------------------------------------------------- + /** \return the free cluster count. */ + uint32_t freeClusterCount() { + bool switchSpi = hasDedicatedSpi() && !isDedicatedSpi(); + if (switchSpi && !setDedicatedSpi(true)) { + return 0; + } + uint32_t rtn = Vol::freeClusterCount(); + if (switchSpi && !setDedicatedSpi(false)) { + return 0; + } + return rtn; + } + //---------------------------------------------------------------------------- + /** \return true if can be in dedicated SPI state */ + bool hasDedicatedSpi() {return m_card ? m_card->hasDedicatedSpi() : false;} + //---------------------------------------------------------------------------- /** %Print error info and halt. * * \param[in] pr Print destination. */ void initErrorHalt(print_t* pr) { initErrorPrint(pr); - SysCall::halt(); + while (true) {} } //---------------------------------------------------------------------------- /** %Print error info and halt. @@ -177,7 +242,7 @@ class SdBase : public Vol { * \param[in] pr Print destination. * \param[in] msg Message to print. */ - void initErrorHalt(Print* pr, const __FlashStringHelper* msg) { + void initErrorHalt(print_t* pr, const __FlashStringHelper* msg) { pr->println(msg); initErrorHalt(pr); } @@ -186,7 +251,7 @@ class SdBase : public Vol { * * \param[in] pr Print destination. */ - void initErrorPrint(Print* pr) { + void initErrorPrint(print_t* pr) { pr->println(F("begin() failed")); if (sdErrorCode()) { pr->println(F("Do not reformat the SD.")); @@ -197,6 +262,9 @@ class SdBase : public Vol { errorPrint(pr); } //---------------------------------------------------------------------------- + /** \return true if in dedicated SPI state. */ + bool isDedicatedSpi() {return m_card ? m_card->isDedicatedSpi() : false;} + //---------------------------------------------------------------------------- /** %Print volume FAT/exFAT type. * * \param[in] pr Print destination. @@ -241,7 +309,7 @@ class SdBase : public Vol { * \param[in] pr Print destination. * \param[in] msg Message to print. */ - void errorPrint(Print* pr, const __FlashStringHelper* msg) { + void errorPrint(print_t* pr, const __FlashStringHelper* msg) { pr->print(F("error: ")); pr->println(msg); errorPrint(pr); @@ -278,6 +346,17 @@ class SdBase : public Vol { /** \return SD card error data. */ uint8_t sdErrorData() {return m_card ? m_card->errorData() : 0;} //---------------------------------------------------------------------------- + /** Set SPI sharing state + * \param[in] value desired state. + * \return true for success else false; + */ + bool setDedicatedSpi(bool value) { + if (m_card) { + return m_card->setDedicatedSpi(value); + } + return false; + } + //---------------------------------------------------------------------------- /** \return pointer to base volume */ Vol* vol() {return reinterpret_cast(this);} //---------------------------------------------------------------------------- @@ -341,104 +420,74 @@ class SdBase : public Vol { #endif // ENABLE_ARDUINO_SERIAL //---------------------------------------------------------------------------- private: - SdCard* m_card; + SdCard* m_card = nullptr; SdCardFactory m_cardFactory; + SdCsPin_t spiConfigBackupPin; + uint8_t spiConfigBackupOptions; + uint32_t spiConfigBackupClock; + SpiPort_t* spiConfigBackupPort; + SdioConfig sdioConfigBackup; }; //------------------------------------------------------------------------------ /** * \class SdFat32 * \brief SD file system class for FAT volumes. */ -class SdFat32 : public SdBase { +class SdFat32 : public SdBase { public: - /** Format a SD card FAT32/FAT16. - * - * \param[in] pr Optional Print information. - * \return true for success or false for failure. - */ - bool format(print_t* pr = nullptr) { - FatFormatter fmt; - uint8_t* cache = cacheClear(); - if (!cache) { - return false; - } - return fmt.format(card(), cache, pr); - } }; //------------------------------------------------------------------------------ /** * \class SdExFat * \brief SD file system class for exFAT volumes. */ -class SdExFat : public SdBase { +class SdExFat : public SdBase { public: - /** Format a SD card exFAT. - * - * \param[in] pr Optional Print information. - * \return true for success or false for failure. - */ - bool format(print_t* pr = nullptr) { - ExFatFormatter fmt; - uint8_t* cache = cacheClear(); - if (!cache) { - return false; - } - return fmt.format(card(), cache, pr); - } }; //------------------------------------------------------------------------------ /** * \class SdFs * \brief SD file system class for FAT16, FAT32, and exFAT volumes. */ -class SdFs : public SdBase { +class SdFs : public SdBase { public: - /** Format a SD card FAT or exFAT. - * - * \param[in] pr Optional Print information. - * \return true for success or false for failure. - */ - bool format(print_t* pr = nullptr) { - static_assert(sizeof(m_volMem) >= 512, "m_volMem too small"); - uint32_t sectorCount = card()->sectorCount(); - if (sectorCount == 0) { - return false; - } - end(); - if (sectorCount > 67108864) { - ExFatFormatter fmt; - return fmt.format(card(), reinterpret_cast(m_volMem), pr); - } else { - FatFormatter fmt; - return fmt.format(card(), reinterpret_cast(m_volMem), pr); - } - } }; //------------------------------------------------------------------------------ -#if SDFAT_FILE_TYPE == 1 +#if SDFAT_FILE_TYPE == 1 || defined(DOXYGEN) /** Select type for SdFat. */ typedef SdFat32 SdFat; -/** Select type for File. */ -#if !defined(__has_include) || !__has_include() -typedef File32 File; -#endif /** Select type for SdBaseFile. */ typedef FatFile SdBaseFile; #elif SDFAT_FILE_TYPE == 2 typedef SdExFat SdFat; -#if !defined(__has_include) || !__has_include() -typedef ExFile File; -#endif typedef ExFatFile SdBaseFile; #elif SDFAT_FILE_TYPE == 3 typedef SdFs SdFat; -#if !defined(__has_include) || !__has_include() -typedef FsFile File; -#endif typedef FsBaseFile SdBaseFile; #else // SDFAT_FILE_TYPE #error Invalid SDFAT_FILE_TYPE #endif // SDFAT_FILE_TYPE +// +// Only define File if FS.h is not included. +// Line with test for __has_include must not have operators or parentheses. +#if defined __has_include +#if __has_include() +#define HAS_INCLUDE_FS_H +#ifndef TEENSYDUINO +#warning File not defined because __has_include(FS.h) +#endif +#endif // __has_include() +#endif // defined __has_include +#ifndef HAS_INCLUDE_FS_H +#if SDFAT_FILE_TYPE == 1 || defined(DOXYGEN) +/** Select type for File. */ +typedef File32 File; +#elif SDFAT_FILE_TYPE == 2 +typedef ExFile File; +#elif SDFAT_FILE_TYPE == 3 +typedef FsFile File; +#endif // SDFAT_FILE_TYPE +#endif // HAS_INCLUDE_FS_H /** * \class SdFile * \brief FAT16/FAT32 file with Print. diff --git a/firmware/3.0/lib/SdFat/src/SdFatConfig.h b/firmware/3.0/lib/SdFat/src/SdFatConfig.h old mode 100644 new mode 100755 index 9c14d07..102dfae --- a/firmware/3.0/lib/SdFat/src/SdFatConfig.h +++ b/firmware/3.0/lib/SdFat/src/SdFatConfig.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -32,6 +32,19 @@ #ifdef __AVR__ #include #endif // __AVR__ +// +// To try UTF-8 encoded filenames. +// #define USE_UTF8_LONG_NAMES 1 +// +// For minimum flash size use these settings: +// #define USE_FAT_FILE_FLAG_CONTIGUOUS 0 +// #define ENABLE_DEDICATED_SPI 0 +// #define USE_LONG_FILE_NAMES 0 +// #define SDFAT_FILE_TYPE 1 +// +// Options can be set in a makefile or an IDE like platformIO +// if they are in a #ifndef/#endif block below. +//------------------------------------------------------------------------------ /** For Debug - must be one */ #define ENABLE_ARDUINO_FEATURES 1 /** For Debug - must be one */ @@ -39,12 +52,6 @@ /** For Debug - must be one */ #define ENABLE_ARDUINO_STRING 1 //------------------------------------------------------------------------------ -/** Set zero to disable mod for non-blocking write. */ -#define ENABLE_TEENSY_SDIO_MOD 1 -//------------------------------------------------------------------------------ -/** Set USE_BLOCK_DEVICE_INTERFACE nonzero to use generic block device */ -#define USE_BLOCK_DEVICE_INTERFACE 0 -//------------------------------------------------------------------------------ #if ENABLE_ARDUINO_FEATURES #include "Arduino.h" #ifdef PLATFORM_ID @@ -53,18 +60,6 @@ #endif // PLATFORM_ID #endif // ENABLE_ARDUINO_FEATURES //------------------------------------------------------------------------------ -/** - * Set INCLUDE_SDIOS nonzero to include sdios.h in SdFat.h. - * sdios.h provides C++ style IO Streams. - */ -#define INCLUDE_SDIOS 0 -//------------------------------------------------------------------------------ -/** - * Set USE_FAT_FILE_FLAG_CONTIGUOUS nonzero to optimize access to - * contiguous files. - */ -#define USE_FAT_FILE_FLAG_CONTIGUOUS 1 -//------------------------------------------------------------------------------ /** * File types for SdFat, File, SdFile, SdBaseFile, fstream, * ifstream, and ofstream. @@ -73,16 +68,27 @@ * * 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT. */ +#ifndef SDFAT_FILE_TYPE #if defined(__AVR__) && FLASHEND < 0X8000 // 32K AVR boards. #define SDFAT_FILE_TYPE 1 #elif defined(__arm__) // ARM boards usually have plenty of memory #define SDFAT_FILE_TYPE 3 +#define USE_UTF8_LONG_NAMES 1 #else // defined(__AVR__) && FLASHEND < 0X8000 // All other boards. -#define SDFAT_FILE_TYPE 1 +#define SDFAT_FILE_TYPE 3 #endif // defined(__AVR__) && FLASHEND < 0X8000 +#endif // SDFAT_FILE_TYPE +//------------------------------------------------------------------------------ +/** + * Set USE_FAT_FILE_FLAG_CONTIGUOUS nonzero to optimize access to + * contiguous files. A small amount of flash is flash is used. + */ +#ifndef USE_FAT_FILE_FLAG_CONTIGUOUS +#define USE_FAT_FILE_FLAG_CONTIGUOUS 1 +#endif // USE_FAT_FILE_FLAG_CONTIGUOUS //------------------------------------------------------------------------------ /** * Set ENABLE_DEDICATED_SPI non-zero to enable dedicated use of the SPI bus. @@ -90,8 +96,9 @@ * performance by using very large multi-block transfers to and * from the SD card. * - * Enabling dedicated SPI will cost some extra flash and RAM. + * Enabling dedicated SPI will cost extra flash and RAM. */ +#ifndef ENABLE_DEDICATED_SPI #if defined(__AVR__) && FLASHEND < 0X8000 // 32K AVR boards. #define ENABLE_DEDICATED_SPI 1 @@ -99,7 +106,9 @@ // All other boards. #define ENABLE_DEDICATED_SPI 1 #endif // defined(__AVR__) && FLASHEND < 0X8000 +#endif // ENABLE_DEDICATED_SPI //------------------------------------------------------------------------------ +// Driver options /** * If the symbol SPI_DRIVER_SELECT is: * @@ -112,9 +121,50 @@ * * 3 - An external SPI driver derived from SdSpiBaseClass is always used. */ +#ifndef SPI_DRIVER_SELECT #define SPI_DRIVER_SELECT 0 -//------------------------------------------------------------------------------ +#endif // SPI_DRIVER_SELECT /** + * If USE_SPI_ARRAY_TRANSFER is non-zero and the standard SPI library is + * use, the array transfer function, transfer(buf, size), will be used. + * This option will allocate up to a 512 byte temporary buffer for send. + * This may be faster for some boards. Do not use this with AVR boards. + */ +#ifndef USE_SPI_ARRAY_TRANSFER +#define USE_SPI_ARRAY_TRANSFER 0 +#endif // USE_SPI_ARRAY_TRANSFER +/** + * SD maximum initialization clock rate. + */ +#ifndef SD_MAX_INIT_RATE_KHZ +#define SD_MAX_INIT_RATE_KHZ 400 +#endif // SD_MAX_INIT_RATE_KHZ +/** + * Set USE_BLOCK_DEVICE_INTERFACE nonzero to use a generic block device. + * This allow use of an external FsBlockDevice driver that is derived from + * the FsBlockDeviceInterface like this: + * + * class UsbMscDriver : public FsBlockDeviceInterface { + * ... code for USB mass storage class driver. + * }; + * + * UsbMscDriver usbMsc; + * FsVolume key; + * ... + * + * // Init USB MSC driver. + * if (!usbMsc.begin()) { + * ... handle driver init failure. + * } + * // Init FAT/exFAT volume. + * if (!key.begin(&usbMsc)) { + * ... handle FAT/exFAT failure. + * } + */ +#ifndef USE_BLOCK_DEVICE_INTERFACE +#define USE_BLOCK_DEVICE_INTERFACE 1 +#endif // USE_BLOCK_DEVICE_INTERFACE + /** * SD_CHIP_SELECT_MODE defines how the functions * void sdCsInit(SdCsPin_t pin) {pinMode(pin, OUTPUT);} * and @@ -127,15 +177,12 @@ * * 2 - No internal definition and must be defined in the application. */ +#ifndef SD_CHIP_SELECT_MODE #define SD_CHIP_SELECT_MODE 0 +#endif // SD_CHIP_SELECT_MODE /** Type for card chip select pin. */ typedef uint8_t SdCsPin_t; //------------------------------------------------------------------------------ -/** - * SD maximum initialization clock rate. - */ -#define SD_MAX_INIT_RATE_KHZ 400 -//------------------------------------------------------------------------------ /** * Set USE_LONG_FILE_NAMES nonzero to use long file names (LFN) in FAT16/FAT32. * exFAT always uses long file names. @@ -156,7 +203,41 @@ typedef uint8_t SdCsPin_t; * * (asterisk) * */ +#ifndef USE_LONG_FILE_NAMES #define USE_LONG_FILE_NAMES 1 +#endif // USE_LONG_FILE_NAMES +/** + * Set USE_UTF8_LONG_NAMES nonzero to use UTF-8 file names. Use of UTF-8 names + * will require significantly more flash memory and a small amount of extra + * RAM. + * + * UTF-8 filenames allow encoding of 1,112,064 code points in Unicode using + * one to four one-byte (8-bit) code units. + * + * As of Version 13.0, the Unicode Standard defines 143,859 characters. + * + * getName() will return UTF-8 strings and printName() will write UTF-8 strings. + */ +#ifndef USE_UTF8_LONG_NAMES +#define USE_UTF8_LONG_NAMES 0 +#endif // USE_UTF8_LONG_NAMES + +#if USE_UTF8_LONG_NAMES && !USE_LONG_FILE_NAMES +#error "USE_UTF8_LONG_NAMES requires USE_LONG_FILE_NAMES to be non-zero." +#endif // USE_UTF8_LONG_NAMES && !USE_LONG_FILE_NAMES +//------------------------------------------------------------------------------ +/** + * Set MAINTAIN_FREE_CLUSTER_COUNT nonzero to keep the count of free clusters + * updated. This will increase the speed of the freeClusterCount() call + * after the first call. Extra flash will be required. + */ +#ifndef MAINTAIN_FREE_CLUSTER_COUNT +#if defined(__arm__) +#define MAINTAIN_FREE_CLUSTER_COUNT 1 +#else +#define MAINTAIN_FREE_CLUSTER_COUNT 0 +#endif +#endif // MAINTAIN_FREE_CLUSTER_COUNT //------------------------------------------------------------------------------ /** * Set the default file time stamp when a RTC callback is not used. @@ -184,14 +265,9 @@ typedef uint8_t SdCsPin_t; * Some cards will not sleep in low power mode unless CHECK_FLASH_PROGRAMMING * is non-zero. */ +#ifndef CHECK_FLASH_PROGRAMMING #define CHECK_FLASH_PROGRAMMING 0 -//------------------------------------------------------------------------------ -/** - * Set MAINTAIN_FREE_CLUSTER_COUNT nonzero to keep the count of free clusters - * updated. This will increase the speed of the freeClusterCount() call - * after the first call. Extra flash will be required. - */ -#define MAINTAIN_FREE_CLUSTER_COUNT 0 +#endif // CHECK_FLASH_PROGRAMMING //------------------------------------------------------------------------------ /** * To enable SD card CRC checking for SPI, set USE_SD_CRC nonzero. @@ -202,12 +278,15 @@ typedef uint8_t SdCsPin_t; * Set USE_SD_CRC to 2 to used a larger table driven CRC-CCITT function. This * function is faster for AVR but may be slower for ARM and other processors. */ -#define USE_SD_CRC 1 +#ifndef USE_SD_CRC +#define USE_SD_CRC 0 +#endif // USE_SD_CRC //------------------------------------------------------------------------------ /** If the symbol USE_FCNTL_H is nonzero, open flags for access modes O_RDONLY, * O_WRONLY, O_RDWR and the open modifiers O_APPEND, O_CREAT, O_EXCL, O_SYNC * will be defined by including the system file fcntl.h. */ +#ifndef USE_FCNTL_H #if defined(__AVR__) // AVR fcntl.h does not define open flags. #define USE_FCNTL_H 0 @@ -222,32 +301,37 @@ typedef uint8_t SdCsPin_t; #else // defined(__AVR__) #define USE_FCNTL_H 0 #endif // defined(__AVR__) +#endif // USE_FCNTL_H //------------------------------------------------------------------------------ /** - * Handle Watchdog Timer for WiFi modules. - * - * Yield will be called before accessing the SPI bus if it has been more - * than WDT_YIELD_TIME_MILLIS milliseconds since the last yield call by SdFat. + * Set INCLUDE_SDIOS nonzero to include sdios.h in SdFat.h. + * sdios.h provides C++ style IO Streams. */ -#if defined(PLATFORM_ID) || defined(ESP8266) -// If Particle device or ESP8266 call yield. -#define WDT_YIELD_TIME_MILLIS 100 -#else // defined(PLATFORM_ID) || defined(ESP8266) -#define WDT_YIELD_TIME_MILLIS 0 -#endif // defined(PLATFORM_ID) || defined(ESP8266) +#ifndef INCLUDE_SDIOS +#define INCLUDE_SDIOS 0 +#endif // INCLUDE_SDIOS //------------------------------------------------------------------------------ /** * Set FAT12_SUPPORT nonzero to enable use if FAT12 volumes. * FAT12 has not been well tested and requires additional flash. */ +#ifndef FAT12_SUPPORT +#if defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__) +// mainly defined for support of USBHost builds... But included T3.5... +#define FAT12_SUPPORT 1 +#else #define FAT12_SUPPORT 0 +#endif +#endif // FAT12_SUPPORT //------------------------------------------------------------------------------ /** * Set DESTRUCTOR_CLOSES_FILE nonzero to close a file in its destructor. * * Causes use of lots of heap in ARM. */ +#ifndef DESTRUCTOR_CLOSES_FILE #define DESTRUCTOR_CLOSES_FILE 0 +#endif // DESTRUCTOR_CLOSES_FILE //------------------------------------------------------------------------------ /** * Call flush for endl if ENDL_CALLS_FLUSH is nonzero @@ -266,14 +350,16 @@ typedef uint8_t SdCsPin_t; * If ENDL_CALLS_FLUSH is zero, you must call flush and/or close to force * all data to be written to the SD. */ +#ifndef ENDL_CALLS_FLUSH #define ENDL_CALLS_FLUSH 0 +#endif // ENDL_CALLS_FLUSH //------------------------------------------------------------------------------ /** * Set USE_SIMPLE_LITTLE_ENDIAN nonzero for little endian processors * with no memory alignment restrictions. */ -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && !defined(__SAMD21G18A__)\ - && !defined(__MKL26Z64__) && !defined(ESP8266) +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\ + && (defined(__AVR__) || defined(__ARM_FEATURE_UNALIGNED) || defined(__ARM_ARCH_7EM__)) #define USE_SIMPLE_LITTLE_ENDIAN 1 #else // __BYTE_ORDER_ #define USE_SIMPLE_LITTLE_ENDIAN 0 @@ -300,6 +386,7 @@ typedef uint8_t SdCsPin_t; #else // __arm__ #define USE_EXFAT_BITMAP_CACHE 0 #endif // __arm__ + //------------------------------------------------------------------------------ /** * Set USE_MULTI_SECTOR_IO nonzero to use multi-sector SD read/write. @@ -319,13 +406,13 @@ typedef uint8_t SdCsPin_t; #define BUILTIN_SDCARD 254 #endif // BUILTIN_SDCARD // SPI for built-in card. -#ifndef SDCARD_SPI -#define SDCARD_SPI SPI1 -#define SDCARD_MISO_PIN 59 -#define SDCARD_MOSI_PIN 61 -#define SDCARD_SCK_PIN 60 -#define SDCARD_SS_PIN 62 -#endif // SDCARD_SPI +#ifndef SDFAT_SDCARD_SPI +#define SDFAT_SDCARD_SPI SPI1 +#define SDFAT_SDCARD_MISO_PIN 59 +#define SDFAT_SDCARD_MOSI_PIN 61 +#define SDFAT_SDCARD_SCK_PIN 60 +#define SDFAT_SDCARD_SS_PIN 62 +#endif // SDFAT_SDCARD_SPI #define HAS_SDIO_CLASS 1 #endif // defined(__MK64FX512__) || defined(__MK66FX1M0__) #if defined(__IMXRT1062__) @@ -336,10 +423,12 @@ typedef uint8_t SdCsPin_t; * Determine the default SPI configuration. */ #if defined(ARDUINO_ARCH_APOLLO3)\ - || defined(__AVR__)\ + || (defined(__AVR__) && defined(SPDR) && defined(SPSR) && defined(SPIF))\ + || (defined(__AVR__) && defined(SPI0) && defined(SPI_RXCIF_bm))\ || defined(ESP8266) || defined(ESP32)\ || defined(PLATFORM_ID)\ || defined(ARDUINO_SAM_DUE)\ + || defined(STM32_CORE_VERSION)\ || defined(__STM32F1__) || defined(__STM32F4__)\ || (defined(CORE_TEENSY) && defined(__arm__)) #define SD_HAS_CUSTOM_SPI 1 @@ -352,4 +441,5 @@ typedef uint8_t SdCsPin_t; /** Default is no SDIO. */ #define HAS_SDIO_CLASS 0 #endif // HAS_SDIO_CLASS + #endif // SdFatConfig_h diff --git a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiArduinoDriver.h b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiArduinoDriver.h old mode 100644 new mode 100755 index 0fe088f..00bdb9f --- a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiArduinoDriver.h +++ b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiArduinoDriver.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License diff --git a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiArtemis.cpp b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiArtemis.cpp old mode 100644 new mode 100755 index 954db6c..a7a064f --- a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiArtemis.cpp +++ b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiArtemis.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -42,12 +42,17 @@ void SdSpiArduinoDriver::deactivate() { m_spi->endTransaction(); } //------------------------------------------------------------------------------ +void SdSpiArduinoDriver::end() { + m_spi->end(); +} +//------------------------------------------------------------------------------ uint8_t SdSpiArduinoDriver::receive() { return m_spi->transfer(0XFF); } //------------------------------------------------------------------------------ uint8_t SdSpiArduinoDriver::receive(uint8_t* buf, size_t count) { - m_spi->transferIn(buf, count); + memset(buf, 0XFF, count); + m_spi->transfer(buf, count); return 0; } //------------------------------------------------------------------------------ diff --git a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiAvr.h b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiAvr.h old mode 100644 new mode 100755 index eefd3e1..c3df3fe --- a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiAvr.h +++ b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiAvr.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -27,19 +27,23 @@ // Use of in-line for AVR to save flash. #define nop asm volatile ("nop\n\t") //------------------------------------------------------------------------------ +inline void SdSpiArduinoDriver::activate() { + SPI.beginTransaction(m_spiSettings); +} +//------------------------------------------------------------------------------ inline void SdSpiArduinoDriver::begin(SdSpiConfig spiConfig) { (void)spiConfig; SPI.begin(); } //------------------------------------------------------------------------------ -inline void SdSpiArduinoDriver::activate() { - SPI.beginTransaction(m_spiSettings); -} -//------------------------------------------------------------------------------ inline void SdSpiArduinoDriver::deactivate() { SPI.endTransaction(); } //------------------------------------------------------------------------------ +inline void SdSpiArduinoDriver::end() { + SPI.end(); +} +//------------------------------------------------------------------------------ inline uint8_t SdSpiArduinoDriver::receive() { return SPI.transfer(0XFF); } @@ -48,19 +52,37 @@ inline uint8_t SdSpiArduinoDriver::receive(uint8_t* buf, size_t count) { if (count == 0) { return 0; } - uint8_t* pr = buf; +#ifdef SPSR SPDR = 0XFF; - while (--count > 0) { + while (--count) { + // nops optimize loop for 16MHz CPU 8 MHz SPI + nop; + nop; while (!(SPSR & _BV(SPIF))) {} uint8_t in = SPDR; SPDR = 0XFF; - *pr++ = in; - // nops to optimize loop for 16MHz CPU 8 MHz SPI + *buf++ = in; + } + while (!(SPSR & _BV(SPIF))) {} + *buf = SPDR; +#elif defined(SPI_RXCIF_bm) + SPI0.DATA = 0XFF; + while (--count) { + // nops optimize loop for ATmega4809 16MHz CPU 8 MHz SPI + nop; nop; nop; + nop; + while (!(SPI0.INTFLAGS & SPI_RXCIF_bm)) {} + uint8_t in = SPI0.DATA; + SPI0.DATA = 0XFF; + *buf++ = in; } - while (!(SPSR & _BV(SPIF))) {} - *pr = SPDR; + while (!(SPI0.INTFLAGS & SPI_RXCIF_bm)) {} + *buf = SPI0.DATA; +#else // SPSR +#error Unsupported AVR CPU - edit SdFatConfig.h to use standard SPI library. +#endif // SPSR return 0; } //------------------------------------------------------------------------------ @@ -72,15 +94,31 @@ inline void SdSpiArduinoDriver::send(const uint8_t* buf , size_t count) { if (count == 0) { return; } +#ifdef SPSR SPDR = *buf++; - while (--count > 0) { + while (--count) { uint8_t b = *buf++; + // nops optimize loop for 16MHz CPU 8 MHz SPI + nop; + nop; while (!(SPSR & (1 << SPIF))) {} SPDR = b; - // nops to optimize loop for 16MHz CPU 8 MHz SPI + } + while (!(SPSR & (1 << SPIF))) {} +#elif defined(SPI_RXCIF_bm) + SPI0.DATA = *buf++; + while (--count) { + uint8_t b = *buf++; + // nops optimize loop for ATmega4809 16MHz CPU 8 MHz SPI + nop; nop; nop; + while (!(SPI0.INTFLAGS & SPI_RXCIF_bm)) {} + SPI0.DATA = b; } - while (!(SPSR & (1 << SPIF))) {} + while (!(SPI0.INTFLAGS & SPI_RXCIF_bm)) {} +#else // SPSR +#error Unsupported AVR CPU - edit SdFatConfig.h to use standard SPI library. +#endif // SPSR } #endif // SdSpiAvr_h diff --git a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiBareUnoDriver.h b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiBareUnoDriver.h old mode 100644 new mode 100755 index 99ba6be..c0c8bbd --- a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiBareUnoDriver.h +++ b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiBareUnoDriver.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -92,10 +92,6 @@ class SdSpiDriverBareUno { public: /** Activate SPI hardware. */ void activate() {} - /** deactivate SPI driver. */ - void end() {} - /** Deactivate SPI hardware. */ - void deactivate() {} /** Initialize the SPI bus. * * \param[in] spiConfig SD card configuration. @@ -112,6 +108,10 @@ class SdSpiDriverBareUno { unoPinMode(UNO_SCK, OUTPUT); unoPinMode(UNO_MOSI, OUTPUT); } + /** Deactivate SPI hardware. */ + void deactivate() {} + /** deactivate SPI driver. */ + void end() {} /** Receive a byte. * * \return The byte. diff --git a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiBaseClass.h b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiBaseClass.h old mode 100644 new mode 100755 index 1957327..cd61fef --- a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiBaseClass.h +++ b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiBaseClass.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -43,6 +43,8 @@ class SdSpiBaseClass { virtual void begin(SdSpiConfig config) = 0; /** Deactivate SPI hardware. */ virtual void deactivate() {} + /** deactivate SPI driver. */ + virtual void end() {} /** Receive a byte. * * \return The byte. diff --git a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiChipSelect.cpp b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiChipSelect.cpp old mode 100644 new mode 100755 index 5b52632..cec052a --- a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiChipSelect.cpp +++ b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiChipSelect.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License diff --git a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiDriver.h b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiDriver.h old mode 100644 new mode 100755 index 95b5bf9..dfbad17 --- a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiDriver.h +++ b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiDriver.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -50,15 +50,15 @@ const uint8_t SHARED_SPI = 0; const uint8_t DEDICATED_SPI = 1; /** * \param[in] opt option field of SdSpiConfig. - * \return true for shared SPI. + * \return true for dedicated SPI. */ -inline bool spiOptionShared(uint8_t opt) {return !(opt & DEDICATED_SPI);} +inline bool spiOptionDedicated(uint8_t opt) {return opt & DEDICATED_SPI;} #else // ENABLE_DEDICATED_SPI /** * \param[in] opt option field of SdSpiConfig. - * \return true for shared SPI. + * \return true for dedicated SPI. */ -inline bool spiOptionShared(uint8_t opt) {(void)opt; return true;} +inline bool spiOptionDedicated(uint8_t opt) {(void)opt; return false;} #endif // ENABLE_DEDICATED_SPI //------------------------------------------------------------------------------ /** SPISettings for SCK frequency in Hz. */ @@ -92,7 +92,7 @@ typedef SdSpiSoftDriver SpiPort_t; #elif SPI_DRIVER_SELECT == 3 class SdSpiBaseClass; /** Port type for extrernal SPI driver. */ -typedef SdSpiBaseClass SpiPort_t; +typedef SdSpiBaseClass SpiPort_t; #else // SPI_DRIVER_SELECT typedef void* SpiPort_t; #endif // SPI_DRIVER_SELECT @@ -136,7 +136,7 @@ class SdSpiConfig { /** Chip select pin. */ const SdCsPin_t csPin; /** Options */ - const uint8_t options = 0; + const uint8_t options = SHARED_SPI; /** Max SCK frequency */ const uint32_t maxSck = SD_SCK_MHZ(50); /** SPI port */ diff --git a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiDue.cpp b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiDue.cpp old mode 100644 new mode 100755 index fa5e71c..f9260b1 --- a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiDue.cpp +++ b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiDue.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -33,13 +33,13 @@ /* chip select register number */ #define SPI_CHIP_SEL 3 /* DMAC receive channel */ -#define SPI_DMAC_RX_CH 1 +#define SPI_DMAC_RX_CH 1 /* DMAC transmit channel */ -#define SPI_DMAC_TX_CH 0 +#define SPI_DMAC_TX_CH 0 /* DMAC Channel HW Interface Number for SPI TX. */ -#define SPI_TX_IDX 1 +#define SPI_TX_IDX 1 /* DMAC Channel HW Interface Number for SPI RX. */ -#define SPI_RX_IDX 2 +#define SPI_RX_IDX 2 //------------------------------------------------------------------------------ /* Disable DMA Controller. */ static void dmac_disable() { @@ -62,25 +62,6 @@ static bool dmac_channel_transfer_done(uint32_t ul_num) { return (DMAC->DMAC_CHSR & (DMAC_CHSR_ENA0 << ul_num)) ? false : true; } //------------------------------------------------------------------------------ -void SdSpiArduinoDriver::begin(SdSpiConfig spiConfig) { - (void)spiConfig; - SPI.begin(); -#if USE_SAM3X_DMAC - pmc_enable_periph_clk(ID_DMAC); - dmac_disable(); - DMAC->DMAC_GCFG = DMAC_GCFG_ARB_CFG_FIXED; - dmac_enable(); -#if USE_SAM3X_BUS_MATRIX_FIX - MATRIX->MATRIX_WPMR = 0x4d415400; - MATRIX->MATRIX_MCFG[1] = 1; - MATRIX->MATRIX_MCFG[2] = 1; - MATRIX->MATRIX_SCFG[0] = 0x01000010; - MATRIX->MATRIX_SCFG[1] = 0x01000010; - MATRIX->MATRIX_SCFG[7] = 0x01000010; -#endif // USE_SAM3X_BUS_MATRIX_FIX -#endif // USE_SAM3X_DMAC -} -//------------------------------------------------------------------------------ // start RX DMA static void spiDmaRX(uint8_t* dst, uint16_t count) { dmac_channel_disable(SPI_DMAC_RX_CH); @@ -141,10 +122,33 @@ void SdSpiArduinoDriver::activate() { pSpi->SPI_CR |= SPI_CR_SPIEN; } //------------------------------------------------------------------------------ +void SdSpiArduinoDriver::begin(SdSpiConfig spiConfig) { + (void)spiConfig; + SPI.begin(); +#if USE_SAM3X_DMAC + pmc_enable_periph_clk(ID_DMAC); + dmac_disable(); + DMAC->DMAC_GCFG = DMAC_GCFG_ARB_CFG_FIXED; + dmac_enable(); +#if USE_SAM3X_BUS_MATRIX_FIX + MATRIX->MATRIX_WPMR = 0x4d415400; + MATRIX->MATRIX_MCFG[1] = 1; + MATRIX->MATRIX_MCFG[2] = 1; + MATRIX->MATRIX_SCFG[0] = 0x01000010; + MATRIX->MATRIX_SCFG[1] = 0x01000010; + MATRIX->MATRIX_SCFG[7] = 0x01000010; +#endif // USE_SAM3X_BUS_MATRIX_FIX +#endif // USE_SAM3X_DMAC +} +//------------------------------------------------------------------------------ void SdSpiArduinoDriver::deactivate() { SPI.endTransaction(); } //------------------------------------------------------------------------------ +void SdSpiArduinoDriver::end() { + SPI.end(); +} +//------------------------------------------------------------------------------ static inline uint8_t spiTransfer(uint8_t b) { Spi* pSpi = SPI0; diff --git a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiESP.cpp b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiESP.cpp old mode 100644 new mode 100755 index 73bc24e..40d2523 --- a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiESP.cpp +++ b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiESP.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -34,10 +34,10 @@ void SdSpiArduinoDriver::activate() { void SdSpiArduinoDriver::begin(SdSpiConfig spiConfig) { if (spiConfig.spiPort) { m_spi = spiConfig.spiPort; -#if defined(SDCARD_SPI) && defined(SDCARD_SS_PIN) - } else if (spiConfig.csPin == SDCARD_SS_PIN) { - m_spi = &SDCARD_SPI; -#endif // defined(SDCARD_SPI) && defined(SDCARD_SS_PIN) +#if defined(SDFAT_SDCARD_SPI) && defined(SDFAT_SDCARD_SS_PIN) + } else if (spiConfig.csPin == SDFAT_SDCARD_SS_PIN) { + m_spi = &SDFAT_SDCARD_SPI; +#endif // defined(SDFAT_SDCARD_SPI) && defined(SDFAT_SDCARD_SS_PIN) } else { m_spi = &SPI; } @@ -48,6 +48,10 @@ void SdSpiArduinoDriver::deactivate() { m_spi->endTransaction(); } //------------------------------------------------------------------------------ +void SdSpiArduinoDriver::end() { + m_spi->end(); +} +//------------------------------------------------------------------------------ uint8_t SdSpiArduinoDriver::receive() { return m_spi->transfer(0XFF); } diff --git a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiLibDriver.h b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiLibDriver.h old mode 100644 new mode 100755 index 8bf09d2..da402ec --- a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiLibDriver.h +++ b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiLibDriver.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -36,16 +36,20 @@ inline void SdSpiArduinoDriver::activate() { inline void SdSpiArduinoDriver::begin(SdSpiConfig spiConfig) { if (spiConfig.spiPort) { m_spi = spiConfig.spiPort; -#if defined(SDCARD_SPI) && defined(SDCARD_SS_PIN) - } else if (spiConfig.csPin == SDCARD_SS_PIN) { - m_spi = &SDCARD_SPI; -#endif // defined(SDCARD_SPI) && defined(SDCARD_SS_PIN) +#if defined(SDFAT_SDCARD_SPI) && defined(SDFAT_SDCARD_SS_PIN) + } else if (spiConfig.csPin == SDFAT_SDCARD_SS_PIN) { + m_spi = &SDFAT_SDCARD_SPI; +#endif // defined(SDFAT_SDCARD_SPI) && defined(SDFAT_SDCARD_SS_PIN) } else { m_spi = &SPI; } m_spi->begin(); } //------------------------------------------------------------------------------ +inline void SdSpiArduinoDriver::end() { + m_spi->end(); +} +//------------------------------------------------------------------------------ inline void SdSpiArduinoDriver::deactivate() { m_spi->endTransaction(); } @@ -55,9 +59,14 @@ inline uint8_t SdSpiArduinoDriver::receive() { } //------------------------------------------------------------------------------ inline uint8_t SdSpiArduinoDriver::receive(uint8_t* buf, size_t count) { +#if USE_SPI_ARRAY_TRANSFER + memset(buf, 0XFF, count); + m_spi->transfer(buf, count); +#else // USE_SPI_ARRAY_TRANSFER for (size_t i = 0; i < count; i++) { buf[i] = m_spi->transfer(0XFF); } +#endif // USE_SPI_ARRAY_TRANSFER return 0; } //------------------------------------------------------------------------------ @@ -66,8 +75,16 @@ inline void SdSpiArduinoDriver::send(uint8_t data) { } //------------------------------------------------------------------------------ inline void SdSpiArduinoDriver::send(const uint8_t* buf, size_t count) { +#if USE_SPI_ARRAY_TRANSFER + if (count <= 512) { + uint8_t tmp[512]; + memcpy(tmp, buf, count); + m_spi->transfer(tmp, count); + } +#else // USE_SPI_ARRAY_TRANSFER for (size_t i = 0; i < count; i++) { m_spi->transfer(buf[i]); } +#endif // USE_SPI_ARRAY_TRANSFER } #endif // SdSpiLibDriver_h diff --git a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiParticle.cpp b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiParticle.cpp old mode 100644 new mode 100755 index c76253d..e691820 --- a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiParticle.cpp +++ b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiParticle.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -47,6 +47,10 @@ void SdSpiArduinoDriver::deactivate() { m_spi->endTransaction(); } //------------------------------------------------------------------------------ +void SdSpiArduinoDriver::end() { + m_spi->end(); +} +//------------------------------------------------------------------------------ uint8_t SdSpiArduinoDriver::receive() { return m_spi->transfer(0XFF); } diff --git a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiSTM32.cpp b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiSTM32.cpp old mode 100644 new mode 100755 index 737bdd2..1e2369a --- a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiSTM32.cpp +++ b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiSTM32.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -22,6 +22,7 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ +// Driver for: https://github.com/rogerclarkmelbourne/Arduino_STM32 #include "SdSpiDriver.h" #if defined(SD_USE_CUSTOM_SPI)\ && (defined(__STM32F1__) || defined(__STM32F4__)) @@ -50,6 +51,10 @@ void SdSpiArduinoDriver::deactivate() { m_spi->endTransaction(); } //------------------------------------------------------------------------------ +void SdSpiArduinoDriver::end() { + m_spi->end(); +} +//------------------------------------------------------------------------------ uint8_t SdSpiArduinoDriver::receive() { return m_spi->transfer(0XFF); } diff --git a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiSTM32Core.cpp b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiSTM32Core.cpp new file mode 100755 index 0000000..86b2a7a --- /dev/null +++ b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiSTM32Core.cpp @@ -0,0 +1,75 @@ +/** + * Copyright (c) 2011-2021 Bill Greiman + * This file is part of the SdFat library for SD memory cards. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +// Driver for: https://github.com/stm32duino/Arduino_Core_STM32 +#include "SdSpiDriver.h" +#if defined(SD_USE_CUSTOM_SPI) && defined(STM32_CORE_VERSION) +//------------------------------------------------------------------------------ +void SdSpiArduinoDriver::activate() { + m_spi->beginTransaction(m_spiSettings); +} +//------------------------------------------------------------------------------ +void SdSpiArduinoDriver::begin(SdSpiConfig spiConfig) { + if (spiConfig.spiPort) { + m_spi = spiConfig.spiPort; + } else { + m_spi = &SPI; + } + m_spi->begin(); +} +//------------------------------------------------------------------------------ +void SdSpiArduinoDriver::deactivate() { + m_spi->endTransaction(); +} +//------------------------------------------------------------------------------ +void SdSpiArduinoDriver::end() { + m_spi->end(); +} +//------------------------------------------------------------------------------ +uint8_t SdSpiArduinoDriver::receive() { + return m_spi->transfer(0XFF); +} +//------------------------------------------------------------------------------ +uint8_t SdSpiArduinoDriver::receive(uint8_t* buf, size_t count) { + // Must send 0XFF - SD looks at send data for command. + memset(buf, 0XFF, count); + m_spi->transfer(buf, count); + return 0; +} +//------------------------------------------------------------------------------ +void SdSpiArduinoDriver::send(uint8_t data) { + m_spi->transfer(data); +} +//------------------------------------------------------------------------------ +void SdSpiArduinoDriver::send(const uint8_t* buf, size_t count) { + // Avoid stack overflow if bad count. This should cause a write error. + if (count > 512) { + return; + } + // Not easy to avoid receive so use tmp RX buffer. + uint8_t rxBuf[512]; + // Discard const - STM32 not const correct. + m_spi->transfer(const_cast(buf), rxBuf, count); +} +#endif // defined(SD_USE_CUSTOM_SPI) && defined(STM32_CORE_VERSION) diff --git a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiSoftDriver.h b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiSoftDriver.h old mode 100644 new mode 100755 index f283e2f..b49221e --- a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiSoftDriver.h +++ b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiSoftDriver.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -49,6 +49,8 @@ class SdSpiSoftDriver { } /** Deactivate SPI hardware. */ void deactivate() {} + /** deactivate SPI driver. */ + void end() {} /** Receive a byte. * * \return The byte. diff --git a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiTeensy3.cpp b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiTeensy3.cpp old mode 100644 new mode 100755 index 247c08f..57237ff --- a/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiTeensy3.cpp +++ b/firmware/3.0/lib/SdFat/src/SpiDriver/SdSpiTeensy3.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -33,13 +33,13 @@ void SdSpiArduinoDriver::activate() { void SdSpiArduinoDriver::begin(SdSpiConfig spiConfig) { if (spiConfig.spiPort) { m_spi = spiConfig.spiPort; -#if defined(SDCARD_SPI) && defined(SDCARD_SS_PIN) - } else if (spiConfig.csPin == SDCARD_SS_PIN) { - m_spi = &SDCARD_SPI; - m_spi->setMISO(SDCARD_MISO_PIN); - m_spi->setMOSI(SDCARD_MOSI_PIN); - m_spi->setSCK(SDCARD_SCK_PIN); -#endif // defined(SDCARD_SPI) && defined(SDCARD_SS_PIN) +#if defined(SDFAT_SDCARD_SPI) && defined(SDFAT_SDCARD_SS_PIN) + } else if (spiConfig.csPin == SDFAT_SDCARD_SS_PIN) { + m_spi = &SDFAT_SDCARD_SPI; + m_spi->setMISO(SDFAT_SDCARD_MISO_PIN); + m_spi->setMOSI(SDFAT_SDCARD_MOSI_PIN); + m_spi->setSCK(SDFAT_SDCARD_SCK_PIN); +#endif // defined(SDFAT_SDCARD_SPI) && defined(SDFAT_SDCARD_SS_PIN) } else { m_spi = &SPI; } @@ -50,6 +50,10 @@ void SdSpiArduinoDriver::deactivate() { m_spi->endTransaction(); } //------------------------------------------------------------------------------ +void SdSpiArduinoDriver::end() { + m_spi->end(); +} +//------------------------------------------------------------------------------ uint8_t SdSpiArduinoDriver::receive() { return m_spi->transfer(0XFF); } diff --git a/firmware/3.0/lib/SdFat/src/common/ArduinoFiles.h b/firmware/3.0/lib/SdFat/src/common/ArduinoFiles.h old mode 100644 new mode 100755 index 3e08de9..748125d --- a/firmware/3.0/lib/SdFat/src/common/ArduinoFiles.h +++ b/firmware/3.0/lib/SdFat/src/common/ArduinoFiles.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -24,7 +24,7 @@ */ #ifndef ArduinoFiles_h #define ArduinoFiles_h -#include "../SdFatConfig.h" +#include "SysCall.h" //------------------------------------------------------------------------------ /** Arduino SD.h style flag for open for read. */ #ifndef FILE_READ @@ -90,7 +90,9 @@ class StreamFile : public stream_t, public BaseFile { * Use getName(char* name, size_t size). * \return a pointer to replacement suggestion. */ - const char* name() const {return "use getName()";} +#ifndef DOXYGEN_SHOULD_SKIP_THIS + char* __attribute__((error("use getName(name, size)"))) name(); +#endif // DOXYGEN_SHOULD_SKIP_THIS /** Return the next available byte without consuming it. * * \return The byte if no error and not at eof else -1; diff --git a/firmware/3.0/lib/SdFat/src/common/CompileDateTime.h b/firmware/3.0/lib/SdFat/src/common/CompileDateTime.h old mode 100644 new mode 100755 index 829dd22..4f57aa6 --- a/firmware/3.0/lib/SdFat/src/common/CompileDateTime.h +++ b/firmware/3.0/lib/SdFat/src/common/CompileDateTime.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License diff --git a/firmware/3.0/lib/SdFat/src/common/DebugMacros.h b/firmware/3.0/lib/SdFat/src/common/DebugMacros.h old mode 100644 new mode 100755 index e01f609..7d0af92 --- a/firmware/3.0/lib/SdFat/src/common/DebugMacros.h +++ b/firmware/3.0/lib/SdFat/src/common/DebugMacros.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -24,7 +24,9 @@ */ #ifndef DebugMacros_h #define DebugMacros_h -#include "../SdFatConfig.h" +#include "SysCall.h" + +// 0 - disable, 1 - fail, halt 2 - fail, halt, warn #define USE_DBG_MACROS 0 #if USE_DBG_MACROS @@ -32,22 +34,41 @@ #ifndef DBG_FILE #error DBG_FILE not defined #endif // DBG_FILE -static void dbgPrint(uint16_t line) { + +__attribute__((unused)) static void dbgFail(uint16_t line) { Serial.print(F("DBG_FAIL: ")); Serial.print(F(DBG_FILE)); Serial.write('.'); Serial.println(line); } +__attribute__((unused)) static void dbgHalt(uint16_t line) { + Serial.print(F("DBG_HALT: ")); + Serial.print(F(DBG_FILE)); + Serial.write('.'); + Serial.println(line); + while (true) {} +} +#define DBG_FAIL_MACRO dbgFail(__LINE__) +#define DBG_HALT_MACRO dbgHalt(__LINE__) +#define DBG_HALT_IF(b) if (b) {dbgHalt(__LINE__);} -#define DBG_PRINT_IF(b) if (b) {Serial.print(F(__FILE__));\ - Serial.println(__LINE__);} -#define DBG_HALT_IF(b) if (b) {Serial.print(F("DBG_HALT "));\ - Serial.print(F(__FILE__)); Serial.println(__LINE__);\ - while (true) {}} -#define DBG_FAIL_MACRO dbgPrint(__LINE__); #else // USE_DBG_MACROS #define DBG_FAIL_MACRO -#define DBG_PRINT_IF(b) +#define DBG_HALT_MACRO #define DBG_HALT_IF(b) #endif // USE_DBG_MACROS + +#if USE_DBG_MACROS > 1 +__attribute__((unused)) static void dbgWarn(uint16_t line) { + Serial.print(F("DBG_WARN: ")); + Serial.print(F(DBG_FILE)); + Serial.write('.'); + Serial.println(line); +} +#define DBG_WARN_MACRO dbgWarn(__LINE__) +#define DBG_WARN_IF(b) if (b) {dbgWarn(__LINE__);} +#else // USE_DBG_MACROS > 1 +#define DBG_WARN_MACRO +#define DBG_WARN_IF(b) +#endif // USE_DBG_MACROS > 1 #endif // DebugMacros_h diff --git a/firmware/3.0/lib/SdFat/src/common/FmtNumber.cpp b/firmware/3.0/lib/SdFat/src/common/FmtNumber.cpp old mode 100644 new mode 100755 index fcc9e54..d9eb37e --- a/firmware/3.0/lib/SdFat/src/common/FmtNumber.cpp +++ b/firmware/3.0/lib/SdFat/src/common/FmtNumber.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -134,13 +134,12 @@ void divmod10(uint32_t in, uint32_t &div, uint32_t &mod) q = q >> 3; // determine error - uint32_t r = in - ((q << 3) + (q << 1)); // r = in - q*10; + uint32_t r = in - ((q << 3) + (q << 1)); // r = in - q*10; div = q + (r > 9); if (r > 9) mod = r - 10; else mod = r; } -// Hackers delight function is here: -// http://www.hackersdelight.org/hdcodetxt/divuc.c.txt +// See: https://github.com/hcs0/Hackers-Delight // Code below uses 8/10 = 0.1100 1100 1100 1100 1100 1100 1100 1100. // 15 ops including the multiply, or 17 elementary ops. unsigned divu10(unsigned n) { diff --git a/firmware/3.0/lib/SdFat/src/common/FmtNumber.h b/firmware/3.0/lib/SdFat/src/common/FmtNumber.h old mode 100644 new mode 100755 index 73e6ad1..6d25ed8 --- a/firmware/3.0/lib/SdFat/src/common/FmtNumber.h +++ b/firmware/3.0/lib/SdFat/src/common/FmtNumber.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License diff --git a/firmware/3.0/lib/SdFat/src/common/FsApiConstants.h b/firmware/3.0/lib/SdFat/src/common/FsApiConstants.h old mode 100644 new mode 100755 index fadc45f..3905e14 --- a/firmware/3.0/lib/SdFat/src/common/FsApiConstants.h +++ b/firmware/3.0/lib/SdFat/src/common/FsApiConstants.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -24,8 +24,7 @@ */ #ifndef FsApiConstants_h #define FsApiConstants_h -#include "../SdFatConfig.h" - +#include "SysCall.h" #if USE_FCNTL_H #include /* values for GNU Arm Embedded Toolchain. diff --git a/firmware/3.0/lib/SdFat/src/common/BlockDevice.h b/firmware/3.0/lib/SdFat/src/common/FsBlockDevice.h old mode 100644 new mode 100755 similarity index 86% rename from firmware/3.0/lib/SdFat/src/common/BlockDevice.h rename to firmware/3.0/lib/SdFat/src/common/FsBlockDevice.h index aebfeef..c0cabaf --- a/firmware/3.0/lib/SdFat/src/common/BlockDevice.h +++ b/firmware/3.0/lib/SdFat/src/common/FsBlockDevice.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -22,12 +22,12 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -#ifndef BlockDevice_h -#define BlockDevice_h +#ifndef FsBlockDevice_h +#define FsBlockDevice_h #include "SdCard/SdCard.h" #if HAS_SDIO_CLASS || USE_BLOCK_DEVICE_INTERFACE -typedef BlockDeviceInterface BlockDevice; +typedef FsBlockDeviceInterface FsBlockDevice; #else -typedef SdCard BlockDevice; +typedef SdCard FsBlockDevice; #endif -#endif // BlockDevice_h +#endif // FsBlockDevice_h diff --git a/firmware/3.0/lib/SdFat/src/common/BlockDeviceInterface.h b/firmware/3.0/lib/SdFat/src/common/FsBlockDeviceInterface.h old mode 100644 new mode 100755 similarity index 60% rename from firmware/3.0/lib/SdFat/src/common/BlockDeviceInterface.h rename to firmware/3.0/lib/SdFat/src/common/FsBlockDeviceInterface.h index 748059f..df2fde6 --- a/firmware/3.0/lib/SdFat/src/common/BlockDeviceInterface.h +++ b/firmware/3.0/lib/SdFat/src/common/FsBlockDeviceInterface.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -24,22 +24,24 @@ */ /** * \file - * \brief BlockDeviceInterface include file. + * \brief FsBlockDeviceInterface include file. */ -#ifndef BlockDeviceInterface_h -#define BlockDeviceInterface_h +#ifndef FsBlockDeviceInterface_h +#define FsBlockDeviceInterface_h #include #include -#include "../SdFatConfig.h" /** - * \class BlockDeviceInterface - * \brief BlockDeviceInterface class. + * \class FsBlockDeviceInterface + * \brief FsBlockDeviceInterface class. */ -class BlockDeviceInterface { +class FsBlockDeviceInterface { public: - virtual ~BlockDeviceInterface() {} + virtual ~FsBlockDeviceInterface() {} + + /** end use of device */ + virtual void end() {} /** - * Check for BlockDevice busy. + * Check for FsBlockDevice busy. * * \return true if busy else false. */ @@ -63,6 +65,25 @@ class BlockDeviceInterface { */ virtual bool readSectors(uint32_t sector, uint8_t* dst, size_t ns) = 0; + /** + * Read multiple sectors with callback as each sector's data + * + * \param[in] sector Logical sector to be read. + * \param[in] ns Number of sectors to be read. + * \param[out] dst Pointer to the location that will receive the data. + * \param[in] callback Function to be called with each sector's data + * \param[in] context Pointer to be passed to the callback function + * \return true for success or false for failure. + */ + virtual bool readSectorsCallback(uint32_t sector, uint8_t* dst, size_t ns, + void (*callback)(uint32_t sector, uint8_t *buf, void *context), void *context) { + for (size_t i = 0; i < ns; i++) { + if (!readSector(sector + i, dst)) return false; + callback(sector + i, dst, context); + } + return true; + } + /** \return device size in sectors. */ virtual uint32_t sectorCount() = 0; @@ -89,5 +110,22 @@ class BlockDeviceInterface { * \return true for success or false for failure. */ virtual bool writeSectors(uint32_t sector, const uint8_t* src, size_t ns) = 0; + + /** + * Write multiple sectors with callback for each sector's data + * + * \param[in] sector Logical sector to be written. + * \param[in] ns Number of sectors to be written. + * \param[in] callback Function to be called for each sector's data + * \param[in] context Context to pass to callback function + * \return true for success or false for failure. + */ + virtual bool writeSectorsCallback(uint32_t sector, size_t ns, + const uint8_t * (*callback)(uint32_t sector, void *context), void *context) { + for (size_t i = 0; i < ns; i++) { + if (!writeSector(sector + i, callback(sector + i, context))) return false; + } + return true; + } }; -#endif // BlockDeviceInterface_h +#endif // FsBlockDeviceInterface_h diff --git a/firmware/3.0/lib/SdFat/src/common/FsCache.cpp b/firmware/3.0/lib/SdFat/src/common/FsCache.cpp old mode 100644 new mode 100755 index e19357e..227a82f --- a/firmware/3.0/lib/SdFat/src/common/FsCache.cpp +++ b/firmware/3.0/lib/SdFat/src/common/FsCache.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -22,10 +22,11 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ +#define DBG_FILE "FsCache.cpp" #include "DebugMacros.h" #include "FsCache.h" //------------------------------------------------------------------------------ -uint8_t* FsCache::get(uint32_t sector, uint8_t option) { +uint8_t* FsCache::prepare(uint32_t sector, uint8_t option) { if (!m_blockDev) { DBG_FAIL_MACRO; goto fail; diff --git a/firmware/3.0/lib/SdFat/src/common/FsCache.h b/firmware/3.0/lib/SdFat/src/common/FsCache.h old mode 100644 new mode 100755 index 76b2438..f5d8ae8 --- a/firmware/3.0/lib/SdFat/src/common/FsCache.h +++ b/firmware/3.0/lib/SdFat/src/common/FsCache.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -29,8 +29,7 @@ * \brief Common cache code for exFAT and FAT. */ #include "SysCall.h" -#include "BlockDevice.h" -#include "DebugMacros.h" +#include "FsBlockDevice.h" /** * \class FsCache * \brief Sector cache. @@ -128,7 +127,7 @@ class FsCache { /** Initialize the cache. * \param[in] blockDev Block device for this cache. */ - void init(BlockDevice* blockDev) { + void init(FsBlockDevice* blockDev) { m_blockDev = blockDev; invalidate(); } @@ -154,6 +153,12 @@ class FsCache { bool isDirty() { return m_status & CACHE_STATUS_DIRTY; } + /** Prepare cache to access sector. + * \param[in] sector Sector to read. + * \param[in] option mode for cached sector. + * \return Address of cached sector. + */ + uint8_t* prepare(uint32_t sector, uint8_t option); /** \return Logical sector number for cached sector. */ uint32_t sector() { return m_sector; @@ -164,11 +169,6 @@ class FsCache { void setMirrorOffset(uint32_t offset) { m_mirrorOffset = offset; } - /** Fill cache with sector data. - * \param[in] sector Sector to read. - * \param[in] option mode for cached sector. - * \return Address of cached sector. */ - uint8_t* get(uint32_t sector, uint8_t option); /** Write current sector if dirty. * \return true for success or false for failure. */ @@ -176,7 +176,7 @@ class FsCache { private: uint8_t m_status; - BlockDevice* m_blockDev; + FsBlockDevice* m_blockDev; uint32_t m_mirrorOffset; uint32_t m_sector; uint8_t m_buffer[512]; diff --git a/firmware/3.0/lib/SdFat/src/common/FsDateTime.cpp b/firmware/3.0/lib/SdFat/src/common/FsDateTime.cpp old mode 100644 new mode 100755 index 50e792a..31f5f58 --- a/firmware/3.0/lib/SdFat/src/common/FsDateTime.cpp +++ b/firmware/3.0/lib/SdFat/src/common/FsDateTime.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License diff --git a/firmware/3.0/lib/SdFat/src/common/FsDateTime.h b/firmware/3.0/lib/SdFat/src/common/FsDateTime.h old mode 100644 new mode 100755 index b614eac..cd8b2c7 --- a/firmware/3.0/lib/SdFat/src/common/FsDateTime.h +++ b/firmware/3.0/lib/SdFat/src/common/FsDateTime.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License diff --git a/firmware/3.0/lib/SdFat/src/FatLib/FatLibConfig.h b/firmware/3.0/lib/SdFat/src/common/FsName.cpp old mode 100644 new mode 100755 similarity index 67% rename from firmware/3.0/lib/SdFat/src/FatLib/FatLibConfig.h rename to firmware/3.0/lib/SdFat/src/common/FsName.cpp index 08f7966..f2a98e8 --- a/firmware/3.0/lib/SdFat/src/FatLib/FatLibConfig.h +++ b/firmware/3.0/lib/SdFat/src/common/FsName.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -22,11 +22,33 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -/** - * \file - * \brief configuration definitions - */ -#ifndef FatLibConfig_h -#define FatLibConfig_h -#include "SdFatConfig.h" -#endif // FatLibConfig_h +#include "FsName.h" +#include "FsUtf.h" +#if USE_UTF8_LONG_NAMES +uint16_t FsName::get16() { + uint16_t rtn; + if (ls) { + rtn = ls; + ls = 0; + } else if (next >= end) { + rtn = 0; + } else { + uint32_t cp; + const char* ptr = FsUtf::mbToCp(next, end, &cp); + if (!ptr) { + goto fail; + } + next = ptr; + if (cp <= 0XFFFF) { + rtn = cp; + } else { + ls = FsUtf::lowSurrogate(cp); + rtn = FsUtf::highSurrogate(cp); + } + } + return rtn; + + fail: + return 0XFFFF; +} +#endif // USE_UTF8_LONG_NAMES diff --git a/firmware/3.0/lib/SdFat/src/common/SysCallBareUno.cpp b/firmware/3.0/lib/SdFat/src/common/FsName.h old mode 100644 new mode 100755 similarity index 55% rename from firmware/3.0/lib/SdFat/src/common/SysCallBareUno.cpp rename to firmware/3.0/lib/SdFat/src/common/FsName.h index 4df383b..d7cc425 --- a/firmware/3.0/lib/SdFat/src/common/SysCallBareUno.cpp +++ b/firmware/3.0/lib/SdFat/src/common/FsName.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -22,34 +22,45 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ +#ifndef FsName_h +#define FsName_h #include "SysCall.h" -#if 0 // defined(__AVR_ATmega328P__) && !ENABLE_ARDUINO_FEATURES -#include - -// ISR for timer 2 Compare A interrupt -volatile uint16_t timer2 = 0; -ISR(TIMER2_COMPA_vect) { - timer2++; -} -SdMillis_t SysCall::curTimeMS() { - if (TIMSK2 != (1 << OCIE2A)) { - // use system clock (clkI/O). - ASSR &= ~(1 << AS2); - // Clear Timer on Compare Match (CTC) mode - TCCR2A = (1 << WGM21); - // Only need 64x prescale bits in TCCR2B - TCCR2B = (1 << CS22); - // set TOP so timer period is 1 ms. - #if F_CPU/64000 > 250 - #error F_CPU too large. - #endif // F_CPU/64000 > 250 - OCR2A = F_CPU/64000UL - 1; - // Enable interrupt. - TIMSK2 = (1 << OCIE2A); +#include +/** + * \file + * \brief FsName class. + */ +/** + * \class FsName + * \brief Handle UTF-8 file names. + */ +class FsName { + public: + /** Beginning of LFN. */ + const char* begin; + /** Next LFN character of end. */ + const char* next; + /** Position one beyond last LFN character. */ + const char* end; +#if !USE_UTF8_LONG_NAMES + /** \return true if at end. */ + bool atEnd() {return next == end;} + /** Reset to start of LFN. */ + void reset() {next = begin;} + /** \return next char of LFN. */ + char getch() {return atEnd() ? 0 : *next++;} + /** \return next UTF-16 unit of LFN. */ + uint16_t get16() {return atEnd() ? 0 : *next++;} +#else // !USE_UTF8_LONG_NAMES + uint16_t ls = 0; + bool atEnd() { + return !ls && next == end; + } + void reset() { + next = begin; + ls = 0; // lowSurrogate } - cli(); - uint16_t rtn = timer2; - sei(); - return rtn; -} -#endif // defined(__AVR_ATmega328P__) && !ENABLE_ARDUINO_FEATURES + uint16_t get16(); +#endif // !USE_UTF8_LONG_NAMES +}; +#endif // FsName_h diff --git a/firmware/3.0/lib/SdFat/src/common/FsStructs.cpp b/firmware/3.0/lib/SdFat/src/common/FsStructs.cpp old mode 100644 new mode 100755 index 5d434ee..14f3a7d --- a/firmware/3.0/lib/SdFat/src/common/FsStructs.cpp +++ b/firmware/3.0/lib/SdFat/src/common/FsStructs.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License diff --git a/firmware/3.0/lib/SdFat/src/common/FsStructs.h b/firmware/3.0/lib/SdFat/src/common/FsStructs.h old mode 100644 new mode 100755 index 0a65bff..3a3be74 --- a/firmware/3.0/lib/SdFat/src/common/FsStructs.h +++ b/firmware/3.0/lib/SdFat/src/common/FsStructs.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -24,7 +24,9 @@ */ #ifndef FsStructs_h #define FsStructs_h +#include #include +#include "SdFatConfig.h" //----------------------------------------------------------------------------- void lbaToMbrChs(uint8_t* chs, uint32_t capacityMB, uint32_t lba); //----------------------------------------------------------------------------- @@ -42,7 +44,6 @@ inline uint64_t getLe64(const uint8_t* src) { inline void setLe16(uint8_t* dst, uint16_t src) { *reinterpret_cast(dst) = src; } - inline void setLe32(uint8_t* dst, uint32_t src) { *reinterpret_cast(dst) = src; } @@ -91,7 +92,29 @@ inline void setLe64(uint8_t* dst, uint64_t src) { dst[7] = src >> 56; } #endif // USE_SIMPLE_LITTLE_ENDIAN -//----------------------------------------------------------------------------- +//------------------------------------------------------------------------------ +// Size of FAT and exFAT directory structures. +const size_t FS_DIR_SIZE = 32; +//------------------------------------------------------------------------------ +// Reserved characters for exFAT names and FAT LFN. +inline bool lfnReservedChar(uint8_t c) { + return c < 0X20 || c == '"' || c == '*' || c == '/' || c == ':' + || c == '<' || c == '>' || c == '?' || c == '\\'|| c == '|'; +} +//------------------------------------------------------------------------------ +// Reserved characters for FAT short 8.3 names. +inline bool sfnReservedChar(uint8_t c) { + if (c == '"' || c == '|' || c == '[' || c == '\\' || c == ']') { + return true; + } + // *+,./ or :;<=>? + if ((0X2A <= c && c <= 0X2F && c != 0X2D) || (0X3A <= c && c <= 0X3F)) { + return true; + } + // Reserved if not in range (0X20, 0X7F). + return !(0X20 < c && c < 0X7F); +} +//------------------------------------------------------------------------------ const uint16_t MBR_SIGNATURE = 0xAA55; const uint16_t PBR_SIGNATURE = 0xAA55; @@ -103,13 +126,13 @@ typedef struct mbrPartition { uint8_t relativeSectors[4]; uint8_t totalSectors[4]; } MbrPart_t; -//----------------------------------------------------------------------------- +//------------------------------------------------------------------------------ typedef struct masterBootRecordSector { uint8_t bootCode[446]; MbrPart_t part[4]; uint8_t signature[2]; } MbrSector_t; -//----------------------------------------------------------------------------- +//------------------------------------------------------------------------------ typedef struct partitionBootSector { uint8_t jmpInstruction[3]; char oemName[8]; @@ -117,12 +140,12 @@ typedef struct partitionBootSector { uint8_t bootCode[390]; uint8_t signature[2]; } pbs_t; -//----------------------------------------------------------------------------- +//------------------------------------------------------------------------------ typedef struct { uint8_t type; uint8_t data[31]; } DirGeneric_t; -//============================================================================= +//============================================================================== typedef struct { uint64_t position; uint32_t cluster; @@ -257,7 +280,9 @@ static inline bool isSubdir(const DirFat_t* dir) { * begin with an entry having this mask. */ const uint8_t FAT_ORDER_LAST_LONG_ENTRY = 0X40; +/** Max long file name length */ +const uint8_t FAT_MAX_LFN_LENGTH = 255; typedef struct { uint8_t order; uint8_t unicode1[10]; @@ -381,4 +406,43 @@ typedef struct { uint8_t mustBeZero; uint8_t unicode[30]; } DirName_t; + +//----------------------------------------------------------------------------- +// WIP GPT support for now just assume 16 bytes... +typedef struct { + uint8_t data[16]; +} Guid_t; + +typedef struct { + uint8_t signature[8]; + uint8_t revision[4]; + uint8_t headerSize[4]; + uint8_t crc32[4]; + uint8_t reserved[4]; + uint8_t currentLBA[8]; + uint8_t backupLBA[8]; + uint8_t firstLBA[8]; + uint8_t lastLBA[8]; + uint8_t diskGUID[16]; + uint8_t startLBAArray[8]; + uint8_t numberPartitions[4]; + uint8_t sizePartitionEntry[4]; + uint8_t crc32PartitionEntries[4]; + uint8_t unused[420]; // should be 0; +} GPTPartitionHeader_t; + +typedef struct { + uint8_t partitionTypeGUID[16]; + uint8_t uniqueGUID[16]; + uint8_t firstLBA[8]; + uint8_t lastLBA[8]; + uint8_t attributeFlags[8]; + uint16_t name[36]; +} GPTPartitionEntryItem_t; + +typedef struct { + GPTPartitionEntryItem_t items[4]; +} GPTPartitionEntrySector_t; + + #endif // FsStructs_h diff --git a/firmware/3.0/lib/SdFat/src/common/FsUtf.cpp b/firmware/3.0/lib/SdFat/src/common/FsUtf.cpp new file mode 100755 index 0000000..ea69494 --- /dev/null +++ b/firmware/3.0/lib/SdFat/src/common/FsUtf.cpp @@ -0,0 +1,115 @@ +/** + * Copyright (c) 2011-2021 Bill Greiman + * This file is part of the SdFat library for SD memory cards. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include "FsUtf.h" +namespace FsUtf { + //---------------------------------------------------------------------------- + char* cpToMb(uint32_t cp, char* str, char* end) { + size_t n = end - str; + if (cp < 0X80) { + if (n < 1) goto fail; + *(str++) = static_cast(cp); + } else if (cp < 0X800) { + if (n < 2) goto fail; + *(str++) = static_cast((cp >> 6) | 0XC0); + *(str++) = static_cast((cp & 0X3F) | 0X80); + } else if (cp < 0X10000) { + if (n < 3) goto fail; + *(str++) = static_cast((cp >> 12) | 0XE0); + *(str++) = static_cast(((cp >> 6) & 0X3F) | 0X80); + *(str++) = static_cast((cp & 0X3F) | 0X80); + } else { + if (n < 4) goto fail; + *(str++) = static_cast((cp >> 18) | 0XF0); + *(str++) = static_cast(((cp >> 12) & 0X3F)| 0X80); + *(str++) = static_cast(((cp >> 6) & 0X3F) | 0X80); + *(str++) = static_cast((cp & 0X3F) | 0X80); + } + return str; + + fail: + return nullptr; + } + //---------------------------------------------------------------------------- + // to do? improve error check + const char* mbToCp(const char* str, const char* end, uint32_t* rtn) { + size_t n; + uint32_t cp; + if (str >= end) { + return nullptr; + } + uint8_t ch = str[0]; + if ((ch & 0X80) == 0) { + *rtn = ch; + return str + 1; + } + if ((ch & 0XE0) == 0XC0) { + cp = ch & 0X1F; + n = 2; + } else if ((ch & 0XF0) == 0XE0) { + cp = ch & 0X0F; + n = 3; + } else if ((ch & 0XF8) == 0XF0) { + cp = ch & 0X07; + n = 4; + } else { + return nullptr; + } + if ((str + n) > end) { + return nullptr; + } + for (size_t i = 1; i < n; i++) { + ch = str[i]; + if ((ch & 0XC0) != 0X80) { + return nullptr; + } + cp <<= 6; + cp |= ch & 0X3F; + } + // Don't allow over long as ASCII. + if (cp < 0X80 || !isValidCp(cp)) { + return nullptr; + } + *rtn = cp; + return str + n; + } + //---------------------------------------------------------------------------- + const char* mbToU16(const char* str, + const char* end, uint16_t* hs, uint16_t* ls) { + uint32_t cp; + const char* ptr = mbToCp(str, end, &cp); + if (!ptr) { + return nullptr; + } + if (cp <= 0XFFFF) { + *hs = cp; + *ls = 0; + } else { + *hs = highSurrogate(cp); + *ls = lowSurrogate(cp); + } + return ptr; + } +} // namespace FsUtf + diff --git a/firmware/3.0/lib/SdFat/src/common/FsUtf.h b/firmware/3.0/lib/SdFat/src/common/FsUtf.h new file mode 100755 index 0000000..ae72f0d --- /dev/null +++ b/firmware/3.0/lib/SdFat/src/common/FsUtf.h @@ -0,0 +1,109 @@ +/** + * Copyright (c) 2011-2021 Bill Greiman + * This file is part of the SdFat library for SD memory cards. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#ifndef FsUtf_h +#define FsUtf_h +/** +* \file +* \brief Unicode Transformation Format functions. +*/ +#include +#include +namespace FsUtf { + /** High surrogate for a code point. + * \param{in} cp code point. + * \return high surrogate. + */ + inline uint16_t highSurrogate(uint32_t cp) { + return (cp >> 10) + (0XD800 - (0X10000 >> 10)); + } + /** Low surrogate for a code point. + * \param{in} cp code point. + * \return low surrogate. + */ + inline uint16_t lowSurrogate(uint32_t cp) { + return (cp & 0X3FF) + 0XDC00; + } + /** Check for a valid code point. + * \param[in] cp code point. + * \return true if valid else false. + */ + inline bool isValidCp(uint32_t cp) { + return cp <= 0x10FFFF && (cp < 0XD800 || cp > 0XDFFF); + } + /** Check for UTF-16 surrogate. + * \param[in] c UTF-16 unit. + * \return true if c is a surrogate else false. + */ + inline bool isSurrogate(uint16_t c) { + return 0XD800 <= c && c <= 0XDFFF; + } + /** Check for UTF-16 high surrogate. + * \param[in] c UTF-16 unit.. + * \return true if c is a high surrogate else false. + */ + inline bool isHighSurrogate(uint16_t c) { + return 0XD800 <= c && c <= 0XDBFF; + } + /** Check for UTF-16 low surrogate. + * \param[in] c UTF-16 unit.. + * \return true if c is a low surrogate else false. + */ + inline bool isLowSurrogate(uint16_t c) { + return 0XDC00 <= c && c <= 0XDFFF; + } + /** Convert UFT-16 surrogate pair to code point. + * \param[in] hs high surrogate. + * \param[in] ls low surrogate. + * \return code point. + */ + inline uint32_t u16ToCp(uint16_t hs, uint16_t ls) { + return 0X10000 + (((hs & 0X3FF) << 10) | (ls & 0X3FF)); + } + /** Encodes a 32 bit code point as a UTF-8 sequence. + * \param[in] cp code point to encode. + * \param[out] str location for UTF-8 sequence. + * \param[in] end location following last character of str. + * \return location one beyond last encoded character. + */ + char* cpToMb(uint32_t cp, char* str, char* end); + /** Get next code point from a UTF-8 sequence. + * \param[in] str location for UTF-8 sequence. + * \param[in] end location following last character of str. + * May be nullptr if str is zero terminated. + * \param[out] rtn location for the code point. + * \return location of next UTF-8 character in str of nullptr for error. + */ + const char* mbToCp(const char* str, const char* end, uint32_t* rtn); + /** Get next code point from a UTF-8 sequence as UTF-16. + * \param[in] str location for UTF-8 sequence. + * \param[in] end location following last character of str. + * \param[out] hs location for the code point or high surrogate. + * \param[out] ls location for zero or high surrogate. + * \return location of next UTF-8 character in str of nullptr for error. + */ + const char* mbToU16(const char* str, + const char* end, uint16_t* hs, uint16_t* ls); +} // namespace FsUtf +#endif // FsUtf_h diff --git a/firmware/3.0/lib/SdFat/src/common/PrintBasic.cpp b/firmware/3.0/lib/SdFat/src/common/PrintBasic.cpp old mode 100644 new mode 100755 index 7ba957e..c0c6d58 --- a/firmware/3.0/lib/SdFat/src/common/PrintBasic.cpp +++ b/firmware/3.0/lib/SdFat/src/common/PrintBasic.cpp @@ -23,6 +23,7 @@ * DEALINGS IN THE SOFTWARE. */ #include "PrintBasic.h" +#if ENABLE_ARDUINO_FEATURES == 0 #include size_t PrintBasic::print(long n, uint8_t base) { @@ -87,3 +88,4 @@ size_t PrintBasic::printDouble(double n, uint8_t prec) { } return rtn; } +#endif // ENABLE_ARDUINO_FEATURES == 0 diff --git a/firmware/3.0/lib/SdFat/src/common/PrintBasic.h b/firmware/3.0/lib/SdFat/src/common/PrintBasic.h old mode 100644 new mode 100755 index 42e8292..f174371 --- a/firmware/3.0/lib/SdFat/src/common/PrintBasic.h +++ b/firmware/3.0/lib/SdFat/src/common/PrintBasic.h @@ -31,16 +31,16 @@ #include #include #include +#include "../SdFatConfig.h" -class __FlashStringHelper; - -#ifdef F -#warning F() macro defined for non Arduino System -#elif defined(__AVR__) +#ifndef F +#if defined(__AVR__) #include -#define F(str) (reinterpret_cast(PSTR(str))) -#else // F +class __FlashStringHelper; +#define F(string_literal) (reinterpret_cast(PSTR(string_literal))) +#else // defined(__AVR__) #define F(str) (str) +#endif // defined(__AVR__) #endif // F #ifdef BIN diff --git a/firmware/3.0/lib/SdFat/src/common/PrintTemplates.h b/firmware/3.0/lib/SdFat/src/common/PrintTemplates.h deleted file mode 100644 index 7cff151..0000000 --- a/firmware/3.0/lib/SdFat/src/common/PrintTemplates.h +++ /dev/null @@ -1,500 +0,0 @@ -/** - * Copyright (c) 2011-2020 Bill Greiman - * This file is part of the SdFat library for SD memory cards. - * - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ -#ifndef PrintTemplates_h -#define PrintTemplates_h -/** - * \file - * \brief templates for printf - */ -#include -#include "FmtNumber.h" -/** test for digit */ -#define isDigit(d) ('0' <= (d) && (d) <= '9') -/** control for supported floating formats */ -#define PRINTF_USE_FLOAT 2 -//----------------------------------------------------------------------------- -/** Formatted print. - * - * \param[in] file destination file or device. - * \param[in] fmt format string. - * \param[in] ap argument list. - * - * \return number of character printed for success else a negative value. - */ -template -int vfprintf(F* file, const char *fmt, va_list ap) { -#if PRINTF_USE_FLOAT - char buf[30]; - double f; -#else // PRINTF_USE_FLOAT - char buf[15]; -#endif // PRINTF_USE_FLOAT - char prefix[3]; - unsigned base; - int n; - int nc = 0; - int nf; - int nz; - int prec; - int width; - size_t np; - size_t ns; - size_t nw; - long ln; - char c; - char plusSign; - char* ptr; // end of string - char* str; // start of string - bool altForm; - bool leftAdjust; - bool isLong; - bool zeroPad; - - while (true) { - const char* bgn = fmt; - while ((c = *fmt++) && c!= '%') {} - nw = fmt - bgn - 1; - if (nw) { - nc += nw; - if (nw != file->write(bgn, nw)) { - goto fail; - } - } - if (!c) break; - altForm = false; - leftAdjust = false; - np = 0; - nz = 0; - zeroPad = false; - plusSign = 0; - c = *fmt++; - - while (true) { - if (c == '-') { - leftAdjust = true; - } else if (c == '+') { - plusSign = '+'; - } else if (c == ' ') { - if (plusSign == 0) { - plusSign = ' '; - } - } else if (c == '0') { - zeroPad = true; - } else if (c == '#') { - altForm = true; - } else { - break; - } - c = *fmt++; - } - - width = 0; - if (isDigit(c)) { - while(isDigit(c)) { - width = 10 * width + c - '0'; - c = *fmt++; - } - } else if (c == '*') { - width = va_arg(ap, int); - c = *fmt++; - if (width < 0) { - leftAdjust = true; - width = -width; - } - } - if (leftAdjust) { - zeroPad = false; - } - - prec = -1; - if (c == '.') { - zeroPad = false; - prec = 0; - c = *fmt++; - if (isDigit(c)) { - while(isDigit(c)) { - prec = 10 * prec + c - '0'; - c = *fmt++; - } - } else if (c == '*') { - prec = va_arg(ap, int); - c = *fmt++; - } - } - - isLong = false; - if (c == 'l' || c =='L') { - isLong = true; - c = *fmt++; - } - - if (!c) break; - - str = buf + sizeof(buf); - ptr = str; - switch(c) { - case 'c': - *--str = va_arg(ap, int); - break; - - case 's': - str = va_arg(ap, char *); - if (!str) { - str = (char*)"(null)"; - } - ns = strlen(str); - ptr = str + (prec >= 0 && (size_t)prec < ns ? prec : ns); - break; - - case 'd': - case 'i': - ln = isLong ? va_arg(ap, long) : va_arg(ap, int); - if (prec || ln) { - if (ln < 0) { - prefix[np++] = '-'; - ln = -ln; - } else if (plusSign) { - prefix[np++] = plusSign; - } - str = fmtUnsigned(str, ln, 10, true); - nz = prec + str - ptr; - } - break; - -#if PRINTF_USE_FLOAT > 1 - case 'e': - case 'E': - case 'f': - case 'F': - f = va_arg(ap, double); - if (f < 0) { - f = -f; - prefix[np++] = '-'; - } else if (plusSign) { - prefix[np++] = plusSign; - } - str = fmtDouble(str, f, prec < 0 ? 6 : prec, altForm, c); - break; -#elif PRINTF_USE_FLOAT > 0 - case 'f': - case 'F': - f = va_arg(ap, double); - if (f < 0) { - f = -f; - prefix[np++] = '-'; - } else if (plusSign) { - prefix[np++] = plusSign; - } - str = fmtDouble(str, f, prec < 0 ? 6 : prec, altForm); - break; -#endif // PRINTF_USE_FLOAT - - case 'o': - base = 8; - goto printUnsigned; - - case 'u': - base = 10; - altForm = false; - goto printUnsigned; - - case 'x': - case 'X': - base = 16; - goto printUnsigned; - - printUnsigned: - ln = isLong ? va_arg(ap, long) : va_arg(ap, int); - if (prec || ln) { - str = fmtUnsigned(str, ln, base, c == 'X'); - nz = prec + str - ptr; - } - if (altForm && ln) { - if (c == 'o') { - *--str = '0'; - } else { - prefix[np++] = '0'; - prefix[np++] = c; - } - } - break; - - default: - *--str = c; - break; - } - ns = (ptr - str); - if (nz < 0) nz = 0; - n = ns + np + nz; - if (width < n) { - nc += n; - nf = 0; - } else { - nc += width; - if (zeroPad) { - nz += width - n; - nf = 0; - } else { - nf = width - n; - } - } - // Do right blank padding. - if (!leftAdjust) { - for (; nf > 0; nf--) { - if (1 != file->write(' ')) { - goto fail; - } - } - } - // Don't call write if no prefix. - if (np && np != file->write(prefix, np)) { - goto fail; - } - // Do zero padding. - for (; nz > 0; nz--) { - if (1 != file->write('0')) { - goto fail; - } - } - // Main item. - if (ns != file->write(str, ns)) { - goto fail; - } - // Right blank padding. - for (; nf > 0; nf--) { - if (1 != file->write(' ')) { - goto fail; - } - } - } - return nc; - fail: - return -1; -} -//----------------------------------------------------------------------------- -/** Formatted print. - * - * \param[in] file destination file or device. - * \param[in] fmt format string. - * - * \return number of character printed for success else a negative value. - */ -template -int fprintf(T *file, const char* fmt, ...) { - va_list ap; - va_start(ap, fmt); - int rtn = vfprintf(file, fmt, ap); - va_end(ap); - return rtn; -} -//----------------------------------------------------------------------------- -/** Minimal formatted print. - * - * \param[in] file destination file or device. - * \param[in] fmt format string. - * \param[in] ap argument list. - * - * \return number of character printed for success else a negative value. - */ -template -int vmprintf(F* file, const char *fmt, va_list ap) { - char buf[15]; - char* ptr; - char* str; - bool isLong; - char c; - int nc = 0; - size_t ns; - long n; - - while (true) { - const char* bgn = fmt; - while ((c = *fmt++) && c!= '%') {} - ns = fmt - bgn - 1; - if (ns) { - nc += file->write(bgn, ns); - } - if (!c) { - break; - } - c = *fmt++; - if (c == 'l') { - isLong = true; - c = *fmt++; - } else { - isLong = false; - } - if (!c) { - break; - } - ptr = str = buf + sizeof(buf); - switch (c) { - case 'c': - *--str = va_arg(ap, int); - break; - - case 's': - str = va_arg(ap, char*); - ptr = str ? str + strlen(str) : nullptr; - break; - - case 'd': - n = isLong ? va_arg(ap, long) : va_arg(ap, int); - str = fmtSigned(str, n, 10, true); - break; - - case 'u': - n = isLong ? va_arg(ap, long) : va_arg(ap, int); - str = fmtUnsigned(str, n, 10, true); - break; - - case 'x': - case 'X': - n = isLong ? va_arg(ap, long) : va_arg(ap, int); - str = fmtUnsigned(str, n, 16, c == 'X'); - break; - - default: - *--str = c;; - break; - } - ns = ptr - str; - nc += file->write(str, ns); - } - return nc; -} -//----------------------------------------------------------------------------- -/** Minimal formatted print. - * - * \param[in] file destination file or device. - * \param[in] fmt format string. - * - * \return number of character printed for success else a negative value. - */ -template -int mprintf(T *file, const char* fmt, ...) { - va_list ap; - va_start(ap, fmt); - int rtn = vmprintf(file, fmt, ap); - va_end(ap); - return rtn; -} -//------------------------------------------------------------------------------ -#ifdef __AVR__ -/** Minimal formatted print. - * - * \param[in] file destination file or device. - * \param[in] ifsh format string using F() macro. - * \param[in] ap argument list. - * - * \return number of character printed for success else a negative value. - */ -template -int vmprintf(F file, const __FlashStringHelper *ifsh, va_list ap) { - bool isLong; - char buf[15]; - char c; - char* ptr; - char* str; - size_t ns; - int nc = 0; - long n; - - PGM_P fmt = reinterpret_cast(ifsh); - while (true) { - while ((c = pgm_read_byte(fmt++)) && c != '%') { - nc += file->write(c); - } - if (!c) { - break; - } - c = pgm_read_byte(fmt++); - if (c == 'l') { - isLong = true; - c = pgm_read_byte(fmt++); - } else { - isLong = false; - } - if (!c) { - break; - } - ptr = str = buf + sizeof(buf); - switch (c) { - case 'c': - *--str = va_arg(ap, int); - break; - - case 's': - str = va_arg(ap, char*); - ptr = str ? str + strlen(str) : nullptr; - break; - - case 'd': - n = isLong ? va_arg(ap, long) : va_arg(ap, int); - str = fmtSigned(str, n, 10, true); - break; - - case 'u': - n = isLong ? va_arg(ap, long) : va_arg(ap, int); - str = fmtUnsigned(str, n, 10, true); - break; - - case 'x': - case 'X': - n = isLong ? va_arg(ap, long) : va_arg(ap, int); - str = fmtUnsigned(str, n, 16, c == 'X'); - break; - - default: - *--str = c;; - break; - } - ns = ptr - str; - nc += file->write(str, ns); - } - return nc; -} -#endif // __AVR__ -//----------------------------------------------------------------------------- -/** Minimal formatted print. - * - * \param[in] file destination file or device. - * \param[in] ifsh format string using F() macro. - * - * \return number of character printed for success else a negative value. - */ -template -int mprintf(F* file, const __FlashStringHelper *ifsh, ...) { - va_list ap; - va_start(ap, ifsh); -#ifdef __AVR__ - int rtn = vmprintf(file, ifsh, ap); -#else // __AVR__ - int rtn = vmprintf(file, (const char*)ifsh, ap); -#endif // __AVR__ - va_end(ap); - return rtn; -} -#endif // PrintTemplates_h diff --git a/firmware/3.0/lib/SdFat/src/common/SysCall.h b/firmware/3.0/lib/SdFat/src/common/SysCall.h old mode 100644 new mode 100755 index bad8404..c7be07e --- a/firmware/3.0/lib/SdFat/src/common/SysCall.h +++ b/firmware/3.0/lib/SdFat/src/common/SysCall.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -37,26 +37,6 @@ #define nullptr NULL #endif // __cplusplus < 201103 //------------------------------------------------------------------------------ -/** Type for millis. */ -typedef uint16_t SdMillis_t; -//------------------------------------------------------------------------------ -/** - * \class SysCall - * \brief SysCall - Class to wrap system calls. - */ -class SysCall { - public: - /** \return the time in milliseconds. */ - static SdMillis_t curTimeMS(); - /** Halt execution of this thread. */ - static void halt() { - while (1) { - yield(); - } - } - /** Yield to other threads. */ - static void yield(); -}; #if ENABLE_ARDUINO_FEATURES #if defined(ARDUINO) /** Use Arduino Print. */ @@ -72,33 +52,11 @@ typedef Stream stream_t; #define F(str) (str) #endif // F //------------------------------------------------------------------------------ -/** \return the time in milliseconds. */ -inline SdMillis_t SysCall::curTimeMS() { - return millis(); -} -//------------------------------------------------------------------------------ -#if defined(PLATFORM_ID) // Only defined if a Particle device -inline void SysCall::yield() { - // Recommended to only call Particle.process() if system threading is disabled - if (system_thread_get_state(NULL) == spark::feature::DISABLED) { - Particle.process(); - } -} -#elif defined(ARDUINO) -inline void SysCall::yield() { - // Use the external Arduino yield() function. - ::yield(); -} -#else // defined(PLATFORM_ID) -inline void SysCall::yield() {} -#endif // defined(PLATFORM_ID) -//------------------------------------------------------------------------------ #else // ENABLE_ARDUINO_FEATURES #include "PrintBasic.h" /** If not Arduino */ typedef PrintBasic print_t; /** If not Arduino */ typedef PrintBasic stream_t; -inline void SysCall::yield() {} #endif // ENABLE_ARDUINO_FEATURES #endif // SysCall_h diff --git a/firmware/3.0/lib/SdFat/src/common/upcase.cpp b/firmware/3.0/lib/SdFat/src/common/upcase.cpp new file mode 100755 index 0000000..af23181 --- /dev/null +++ b/firmware/3.0/lib/SdFat/src/common/upcase.cpp @@ -0,0 +1,228 @@ +/** + * Copyright (c) 2011-2021 Bill Greiman + * This file is part of the SdFat library for SD memory cards. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include +#include "upcase.h" +#ifdef __AVR__ +#include +#define TABLE_MEM PROGMEM +#define readTable8(sym) pgm_read_byte(&sym) +#define readTable16(sym) pgm_read_word(&sym) +#else // __AVR__ +#define TABLE_MEM +#define readTable8(sym) (sym) +#define readTable16(sym) (sym) +#endif // __AVR__ + +struct map16 { + uint16_t base; + int8_t off; + uint8_t count; +}; +typedef struct map16 map16_t; + +struct pair16 { + uint16_t key; + uint16_t val; +}; +typedef struct pair16 pair16_t; +//------------------------------------------------------------------------------ +static const map16_t mapTable[] TABLE_MEM = { + {0X0061, -32, 26}, + {0X00E0, -32, 23}, + {0X00F8, -32, 7 }, + {0X0100, 1, 48}, + {0X0132, 1, 6}, + {0X0139, 1, 16}, + {0X014A, 1, 46}, + {0X0179, 1, 6}, + {0X0182, 1, 4}, + {0X01A0, 1, 6}, + {0X01B3, 1, 4}, + {0X01CD, 1, 16}, + {0X01DE, 1, 18}, + {0X01F8, 1, 40}, + {0X0222, 1, 18}, + {0X0246, 1, 10}, + {0X03AD, -37, 3}, + {0X03B1, -32, 17}, + {0X03C3, -32, 9}, + {0X03D8, 1, 24}, + {0X0430, -32, 32}, + {0X0450, -80, 16}, + {0X0460, 1, 34}, + {0X048A, 1, 54}, + {0X04C1, 1, 14}, + {0X04D0, 1, 68}, + {0X0561, -48, 38}, + {0X1E00, 1, 150}, + {0X1EA0, 1, 90}, + {0X1F00, 8, 8}, + {0X1F10, 8, 6}, + {0X1F20, 8, 8}, + {0X1F30, 8, 8}, + {0X1F40, 8, 6}, + {0X1F60, 8, 8}, + {0X1F70, 74, 2}, + {0X1F72, 86, 4}, + {0X1F76, 100, 2}, + {0X1F7A, 112, 2}, + {0X1F7C, 126, 2}, + {0X1F80, 8, 8}, + {0X1F90, 8, 8}, + {0X1FA0, 8, 8}, + {0X1FB0, 8, 2}, + {0X1FD0, 8, 2}, + {0X1FE0, 8, 2}, + {0X2170, -16, 16}, + {0X24D0, -26, 26}, + {0X2C30, -48, 47}, + {0X2C67, 1, 6}, + {0X2C80, 1, 100}, + {0X2D00, 0, 38}, + {0XFF41, -32, 26}, +}; +const size_t MAP_DIM = sizeof(mapTable)/sizeof(map16_t); +//------------------------------------------------------------------------------ +static const pair16_t lookupTable[] TABLE_MEM = { + {0X00FF, 0X0178}, + {0X0180, 0X0243}, + {0X0188, 0X0187}, + {0X018C, 0X018B}, + {0X0192, 0X0191}, + {0X0195, 0X01F6}, + {0X0199, 0X0198}, + {0X019A, 0X023D}, + {0X019E, 0X0220}, + {0X01A8, 0X01A7}, + {0X01AD, 0X01AC}, + {0X01B0, 0X01AF}, + {0X01B9, 0X01B8}, + {0X01BD, 0X01BC}, + {0X01BF, 0X01F7}, + {0X01C6, 0X01C4}, + {0X01C9, 0X01C7}, + {0X01CC, 0X01CA}, + {0X01DD, 0X018E}, + {0X01F3, 0X01F1}, + {0X01F5, 0X01F4}, + {0X023A, 0X2C65}, + {0X023C, 0X023B}, + {0X023E, 0X2C66}, + {0X0242, 0X0241}, + {0X0253, 0X0181}, + {0X0254, 0X0186}, + {0X0256, 0X0189}, + {0X0257, 0X018A}, + {0X0259, 0X018F}, + {0X025B, 0X0190}, + {0X0260, 0X0193}, + {0X0263, 0X0194}, + {0X0268, 0X0197}, + {0X0269, 0X0196}, + {0X026B, 0X2C62}, + {0X026F, 0X019C}, + {0X0272, 0X019D}, + {0X0275, 0X019F}, + {0X027D, 0X2C64}, + {0X0280, 0X01A6}, + {0X0283, 0X01A9}, + {0X0288, 0X01AE}, + {0X0289, 0X0244}, + {0X028A, 0X01B1}, + {0X028B, 0X01B2}, + {0X028C, 0X0245}, + {0X0292, 0X01B7}, + {0X037B, 0X03FD}, + {0X037C, 0X03FE}, + {0X037D, 0X03FF}, + {0X03AC, 0X0386}, + {0X03C2, 0X03A3}, + {0X03CC, 0X038C}, + {0X03CD, 0X038E}, + {0X03CE, 0X038F}, + {0X03F2, 0X03F9}, + {0X03F8, 0X03F7}, + {0X03FB, 0X03FA}, + {0X04CF, 0X04C0}, + {0X1D7D, 0X2C63}, + {0X1F51, 0X1F59}, + {0X1F53, 0X1F5B}, + {0X1F55, 0X1F5D}, + {0X1F57, 0X1F5F}, + {0X1F78, 0X1FF8}, + {0X1F79, 0X1FF9}, + {0X1FB3, 0X1FBC}, + {0X1FCC, 0X1FC3}, + {0X1FE5, 0X1FEC}, + {0X1FFC, 0X1FF3}, + {0X214E, 0X2132}, + {0X2184, 0X2183}, + {0X2C61, 0X2C60}, + {0X2C76, 0X2C75}, +}; +const size_t LOOKUP_DIM = sizeof(lookupTable)/sizeof(pair16_t); +//------------------------------------------------------------------------------ +static size_t searchPair16(const pair16_t* table, size_t size, uint16_t key) { + size_t left = 0; + size_t right = size; + size_t mid; + while (right - left > 1) { + mid = left + (right - left)/2; + if (readTable16(table[mid].key) <= key) { + left = mid; + } else { + right = mid; + } + } + return left; +} +//------------------------------------------------------------------------------ +uint16_t toUpcase(uint16_t chr) { + uint16_t i, first; + // Optimize for simple ASCII. + if (chr < 127) { + return chr - ('a' <= chr && chr <= 'z' ? 'a' - 'A' : 0); + } + i = searchPair16(reinterpret_cast(mapTable), MAP_DIM, chr); + first = readTable16(mapTable[i].base); + if (first <= chr && (chr - first) < readTable8(mapTable[i].count)) { + int8_t off = readTable8(mapTable[i].off); + if (off == 1) { + return chr - ((chr - first) & 1); + } + return chr + (off ? off : -0x1C60); + } + i = searchPair16(lookupTable, LOOKUP_DIM, chr); + if (readTable16(lookupTable[i].key) == chr) { + return readTable16(lookupTable[i].val); + } + return chr; +} +//------------------------------------------------------------------------------ +uint32_t upcaseChecksum(uint16_t uc, uint32_t sum) { + sum = (sum << 31) + (sum >> 1) + (uc & 0XFF); + sum = (sum << 31) + (sum >> 1) + (uc >> 8); + return sum; +} diff --git a/firmware/3.0/lib/SdFat/src/ExFatLib/upcase.h b/firmware/3.0/lib/SdFat/src/common/upcase.h old mode 100644 new mode 100755 similarity index 75% rename from firmware/3.0/lib/SdFat/src/ExFatLib/upcase.h rename to firmware/3.0/lib/SdFat/src/common/upcase.h index 214855b..979986e --- a/firmware/3.0/lib/SdFat/src/ExFatLib/upcase.h +++ b/firmware/3.0/lib/SdFat/src/common/upcase.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -24,13 +24,7 @@ */ #ifndef upcase_h #define upcase_h -#include "ExFatFile.h" -bool exFatCmpName(const DirName_t* unicode, - const char* name, size_t offset, size_t n); -bool exFatCmpName(const DirName_t* unicode, - const ExChar16_t* name, size_t offset, size_t n); -uint16_t exFatHashName(const char* name, size_t n, uint16_t hash); -uint16_t exFatHashName(const ExChar16_t* name, size_t n, uint16_t hash); +#include uint16_t toUpcase(uint16_t chr); uint32_t upcaseChecksum(uint16_t unicode, uint32_t checksum); #endif // upcase_h diff --git a/firmware/3.0/lib/SdFat/src/iostream/ArduinoStream.h b/firmware/3.0/lib/SdFat/src/iostream/ArduinoStream.h old mode 100644 new mode 100755 index 4e1ccac..1fbce34 --- a/firmware/3.0/lib/SdFat/src/iostream/ArduinoStream.h +++ b/firmware/3.0/lib/SdFat/src/iostream/ArduinoStream.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -28,7 +28,6 @@ * \file * \brief ArduinoInStream and ArduinoOutStream classes */ -#include "SdFatConfig.h" #include "bufstream.h" //============================================================================== /** @@ -54,7 +53,7 @@ class ArduinoInStream : public ibufstream { uint32_t t; m_line[0] = '\0'; while (!m_hw->available()) { - SysCall::yield(); + yield(); } while (1) { @@ -111,7 +110,7 @@ class ArduinoOutStream : public ostream { * * \param[in] pr Print object for this ArduinoOutStream. */ - explicit ArduinoOutStream(Print& pr) : m_pr(&pr) {} + explicit ArduinoOutStream(print_t& pr) : m_pr(&pr) {} protected: /// @cond SHOW_PROTECTED @@ -146,6 +145,6 @@ class ArduinoOutStream : public ostream { /// @endcond private: ArduinoOutStream() {} - Print* m_pr; + print_t* m_pr; }; #endif // ArduinoStream_h diff --git a/firmware/3.0/lib/SdFat/src/iostream/StdioStream.cpp b/firmware/3.0/lib/SdFat/src/iostream/StdioStream.cpp old mode 100644 new mode 100755 index cc36cb6..3505b14 --- a/firmware/3.0/lib/SdFat/src/iostream/StdioStream.cpp +++ b/firmware/3.0/lib/SdFat/src/iostream/StdioStream.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License diff --git a/firmware/3.0/lib/SdFat/src/iostream/StdioStream.h b/firmware/3.0/lib/SdFat/src/iostream/StdioStream.h old mode 100644 new mode 100755 index e43fe04..76998d7 --- a/firmware/3.0/lib/SdFat/src/iostream/StdioStream.h +++ b/firmware/3.0/lib/SdFat/src/iostream/StdioStream.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -95,7 +95,7 @@ const uint8_t UNGETC_BUF_SIZE = 2; /** Seek relative to current position. */ #define SEEK_CUR 1 #endif // SEEK_CUR -#ifndef SEEK_END +#ifndef SEEK_END /** Seek relative to end-of-file. */ #define SEEK_END 2 #endif // SEEK_END @@ -440,7 +440,7 @@ class StdioStream : private StreamBaseFile { return n > 0 ? n : 0; } //---------------------------------------------------------------------------- - /** Print a number. + /** Print a number. * * \param[in] val the number to be printed. * diff --git a/firmware/3.0/lib/SdFat/src/iostream/StreamBaseClass.cpp b/firmware/3.0/lib/SdFat/src/iostream/StreamBaseClass.cpp old mode 100644 new mode 100755 index 67cf6bc..0d867d7 --- a/firmware/3.0/lib/SdFat/src/iostream/StreamBaseClass.cpp +++ b/firmware/3.0/lib/SdFat/src/iostream/StreamBaseClass.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License diff --git a/firmware/3.0/lib/SdFat/src/iostream/bufstream.h b/firmware/3.0/lib/SdFat/src/iostream/bufstream.h old mode 100644 new mode 100755 index 3291a0d..1b91f04 --- a/firmware/3.0/lib/SdFat/src/iostream/bufstream.h +++ b/firmware/3.0/lib/SdFat/src/iostream/bufstream.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License diff --git a/firmware/3.0/lib/SdFat/src/iostream/fstream.h b/firmware/3.0/lib/SdFat/src/iostream/fstream.h old mode 100644 new mode 100755 index 9686d45..b176a52 --- a/firmware/3.0/lib/SdFat/src/iostream/fstream.h +++ b/firmware/3.0/lib/SdFat/src/iostream/fstream.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License diff --git a/firmware/3.0/lib/SdFat/src/iostream/ios.h b/firmware/3.0/lib/SdFat/src/iostream/ios.h old mode 100644 new mode 100755 index cac0bdb..cb22a58 --- a/firmware/3.0/lib/SdFat/src/iostream/ios.h +++ b/firmware/3.0/lib/SdFat/src/iostream/ios.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -33,7 +33,7 @@ /** For internal use in c++ streams */ typedef fspos_t pos_t; //============================================================================== -#if SDFAT_FILE_TYPE == 1 +#if SDFAT_FILE_TYPE == 1 || defined(DOXYGEN) /** Set File type for iostreams. */ typedef FatFile StreamBaseFile; #elif SDFAT_FILE_TYPE == 2 diff --git a/firmware/3.0/lib/SdFat/src/iostream/iostream.h b/firmware/3.0/lib/SdFat/src/iostream/iostream.h old mode 100644 new mode 100755 index a41eafd..8ced149 --- a/firmware/3.0/lib/SdFat/src/iostream/iostream.h +++ b/firmware/3.0/lib/SdFat/src/iostream/iostream.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License diff --git a/firmware/3.0/lib/SdFat/src/iostream/istream.cpp b/firmware/3.0/lib/SdFat/src/iostream/istream.cpp old mode 100644 new mode 100755 index 8c7c5cc..87fe004 --- a/firmware/3.0/lib/SdFat/src/iostream/istream.cpp +++ b/firmware/3.0/lib/SdFat/src/iostream/istream.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -197,13 +197,13 @@ bool istream::getDouble(double* value) { if (exp & 1) { if (expNeg) { // check for underflow - if (v < FLT_MIN * pow10 && frac != 0) { + if (v < DBL_MIN * pow10 && frac != 0) { goto fail; } v /= pow10; } else { // check for overflow - if (v > FLT_MAX / pow10) { + if (v > DBL_MAX / pow10) { goto fail; } v *= pow10; diff --git a/firmware/3.0/lib/SdFat/src/iostream/istream.h b/firmware/3.0/lib/SdFat/src/iostream/istream.h old mode 100644 new mode 100755 index 5ad2fea..5642f3c --- a/firmware/3.0/lib/SdFat/src/iostream/istream.h +++ b/firmware/3.0/lib/SdFat/src/iostream/istream.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License @@ -285,8 +285,8 @@ class istream : public virtual ios { * */ int peek(); -// istream& read(char *str, streamsize count); -// streamsize readsome(char *str, streamsize count); + // istream& read(char *str, streamsize count); + // streamsize readsome(char *str, streamsize count); /** * \return the stream position */ diff --git a/firmware/3.0/lib/SdFat/src/iostream/ostream.cpp b/firmware/3.0/lib/SdFat/src/iostream/ostream.cpp old mode 100644 new mode 100755 index d7ac154..c82c5a6 --- a/firmware/3.0/lib/SdFat/src/iostream/ostream.cpp +++ b/firmware/3.0/lib/SdFat/src/iostream/ostream.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License diff --git a/firmware/3.0/lib/SdFat/src/iostream/ostream.h b/firmware/3.0/lib/SdFat/src/iostream/ostream.h old mode 100644 new mode 100755 index 09f501c..e57ff79 --- a/firmware/3.0/lib/SdFat/src/iostream/ostream.h +++ b/firmware/3.0/lib/SdFat/src/iostream/ostream.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License diff --git a/firmware/3.0/lib/SdFat/src/sdios.h b/firmware/3.0/lib/SdFat/src/sdios.h old mode 100644 new mode 100755 index 2801704..64c197e --- a/firmware/3.0/lib/SdFat/src/sdios.h +++ b/firmware/3.0/lib/SdFat/src/sdios.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011-2020 Bill Greiman + * Copyright (c) 2011-2021 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License diff --git a/firmware/3.0/lib/Time/library.properties b/firmware/3.0/lib/Time/library.properties old mode 100644 new mode 100755 index 2c5d58c..4aa6ad8 --- a/firmware/3.0/lib/Time/library.properties +++ b/firmware/3.0/lib/Time/library.properties @@ -1,5 +1,5 @@ name=Time -version=1.6 +version=1.6.1 author=Michael Margolis maintainer=Paul Stoffregen sentence=Timekeeping functionality for Arduino diff --git a/firmware/3.0/lib/Wire/Wire.cpp b/firmware/3.0/lib/Wire/Wire.cpp old mode 100644 new mode 100755 index d62393e..e06631b --- a/firmware/3.0/lib/Wire/Wire.cpp +++ b/firmware/3.0/lib/Wire/Wire.cpp @@ -75,11 +75,6 @@ void TwoWire::begin(uint8_t address) begin(); } -void TwoWire::begin(int address) -{ - begin((uint8_t)address); -} - void TwoWire::end() { TWCR &= ~(_BV(TWEN) | _BV(TWIE) | _BV(TWEA)); @@ -115,21 +110,6 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop return read; } -uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity) -{ - return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true); -} - -uint8_t TwoWire::requestFrom(int address, int quantity) -{ - return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true); -} - -uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop) -{ - return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)sendStop); -} - uint8_t TwoWire::requestFrom(uint8_t addr, uint8_t qty, uint32_t iaddr, uint8_t n, uint8_t stop) { if (n > 0) { @@ -158,11 +138,6 @@ void TwoWire::beginTransmission(uint8_t address) txBufferLength = 0; } -void TwoWire::beginTransmission(int address) -{ - beginTransmission((uint8_t)address); -} - // // Originally, 'endTransmission' was an f(void) function. // It has been modified to take one parameter indicating @@ -188,14 +163,6 @@ uint8_t TwoWire::endTransmission(uint8_t sendStop) return ret; } -// This provides backwards compatibility with the original -// definition, and expected behaviour, of endTransmission -// -uint8_t TwoWire::endTransmission(void) -{ - return endTransmission(true); -} - // must be called in: // slave tx event callback // or after beginTransmission(address) diff --git a/firmware/3.0/lib/Wire/Wire.h b/firmware/3.0/lib/Wire/Wire.h old mode 100644 new mode 100755 index cffb667..c67ba65 --- a/firmware/3.0/lib/Wire/Wire.h +++ b/firmware/3.0/lib/Wire/Wire.h @@ -57,21 +57,37 @@ class TwoWire : public Stream public: TwoWire(); void begin(); - void begin(uint8_t); - void begin(int); + void begin(uint8_t address); + void begin(int address) { + begin((uint8_t)address); + } void end(); - void setClock(uint32_t); - void setSDA(uint8_t); - void setSCL(uint8_t); - void beginTransmission(uint8_t); - void beginTransmission(int); - uint8_t endTransmission(void); - uint8_t endTransmission(uint8_t); - uint8_t requestFrom(uint8_t, uint8_t); - uint8_t requestFrom(uint8_t, uint8_t, uint8_t); - uint8_t requestFrom(int, int); - uint8_t requestFrom(int, int, int); - uint8_t requestFrom(uint8_t, uint8_t, uint32_t, uint8_t, uint8_t); + void setClock(uint32_t frequency); + void setSDA(uint8_t pin); + void setSCL(uint8_t pin); + void beginTransmission(uint8_t address); + void beginTransmission(int address) { + beginTransmission((uint8_t)address); + } + uint8_t endTransmission(uint8_t sendStop); + uint8_t endTransmission(void) { + return endTransmission(1); + } + uint8_t requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop); + uint8_t requestFrom(uint8_t address, uint8_t quantity, bool sendStop) { + return requestFrom(address, quantity, (uint8_t)(sendStop ? 1 : 0)); + } + uint8_t requestFrom(uint8_t address, uint8_t quantity) { + return requestFrom(address, quantity, (uint8_t)1); + } + uint8_t requestFrom(int address, int quantity, int sendStop) { + return requestFrom((uint8_t)address, (uint8_t)quantity, + (uint8_t)(sendStop ? 1 : 0)); + } + uint8_t requestFrom(int address, int quantity) { + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)1); + } + uint8_t requestFrom(uint8_t addr, uint8_t qty, uint32_t iaddr, uint8_t n, uint8_t stop); virtual size_t write(uint8_t); virtual size_t write(const uint8_t *, size_t); virtual int available(void); diff --git a/firmware/3.0/lib/Wire/WireIMXRT.cpp b/firmware/3.0/lib/Wire/WireIMXRT.cpp old mode 100644 new mode 100755 index dc7f5d6..24f8034 --- a/firmware/3.0/lib/Wire/WireIMXRT.cpp +++ b/firmware/3.0/lib/Wire/WireIMXRT.cpp @@ -6,7 +6,12 @@ //#include "debug/printf.h" -#define PINCONFIG (IOMUXC_PAD_ODE | IOMUXC_PAD_SRE | IOMUXC_PAD_DSE(4) | IOMUXC_PAD_SPEED(1) | IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3)) +#define PINCONFIG (IOMUXC_PAD_ODE | IOMUXC_PAD_SRE | IOMUXC_PAD_DSE(4) | IOMUXC_PAD_SPEED(1) | IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3) | IOMUXC_PAD_HYS) + + +//*************************************************** +// Master Mode +//*************************************************** FLASHMEM void TwoWire::begin(void) { @@ -15,107 +20,15 @@ FLASHMEM void TwoWire::begin(void) hardware.clock_gate_register |= hardware.clock_gate_mask; port->MCR = LPI2C_MCR_RST; setClock(100000); - - // Setup SDA register - *(portControlRegister(hardware.sda_pins[sda_pin_index_].pin)) = PINCONFIG; - *(portConfigRegister(hardware.sda_pins[sda_pin_index_].pin)) = hardware.sda_pins[sda_pin_index_].mux_val; - if (hardware.sda_pins[sda_pin_index_].select_input_register) { - *(hardware.sda_pins[sda_pin_index_].select_input_register) = hardware.sda_pins[sda_pin_index_].select_val; - } - - // setup SCL register - *(portControlRegister(hardware.scl_pins[scl_pin_index_].pin)) = PINCONFIG; - *(portConfigRegister(hardware.scl_pins[scl_pin_index_].pin)) = hardware.scl_pins[scl_pin_index_].mux_val; - if (hardware.scl_pins[scl_pin_index_].select_input_register) { - *(hardware.scl_pins[scl_pin_index_].select_input_register) = hardware.scl_pins[scl_pin_index_].select_val; - } -} - -void TwoWire::begin(uint8_t address) -{ - // TODO: slave mode + // setSDA() & setSCL() may be called before or after begin() + configSDApin(sda_pin_index_); // Setup SDA register + configSCLpin(scl_pin_index_); // setup SCL register } void TwoWire::end() { } -void TwoWire::setSDA(uint8_t pin) { - if (pin == hardware.sda_pins[sda_pin_index_].pin) return; - uint32_t newindex=0; - while (1) { - uint32_t sda_pin = hardware.sda_pins[newindex].pin; - if (sda_pin == 255) return; - if (sda_pin == pin) break; - if (++newindex >= sizeof(hardware.sda_pins)) return; - } - if ((hardware.clock_gate_register & hardware.clock_gate_mask)) { - *(portConfigRegister(hardware.sda_pins[sda_pin_index_].pin)) = 5; // hard to know what to go back to? - - // setup new one... - *(portControlRegister(hardware.sda_pins[newindex].pin)) |= IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3); - *(portConfigRegister(hardware.sda_pins[newindex].pin)) = hardware.sda_pins[newindex].mux_val; - if (hardware.sda_pins[newindex].select_input_register) { - *(hardware.sda_pins[newindex].select_input_register) = hardware.sda_pins[newindex].select_val; - } - } - sda_pin_index_ = newindex; -} - -void TwoWire::setSCL(uint8_t pin) { - if (pin == hardware.scl_pins[scl_pin_index_].pin) return; - uint32_t newindex=0; - while (1) { - uint32_t scl_pin = hardware.scl_pins[newindex].pin; - if (scl_pin == 255) return; - if (scl_pin == pin) break; - if (++newindex >= sizeof(hardware.scl_pins)) return; - } - if ((hardware.clock_gate_register & hardware.clock_gate_mask)) { - *(portConfigRegister(hardware.scl_pins[scl_pin_index_].pin)) = 5; // hard to know what to go back to? - - // setup new one... - *(portControlRegister(hardware.scl_pins[newindex].pin)) |= IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3); - *(portConfigRegister(hardware.scl_pins[newindex].pin)) = hardware.scl_pins[newindex].mux_val; - if (hardware.scl_pins[newindex].select_input_register) { - *(hardware.scl_pins[newindex].select_input_register) = hardware.scl_pins[newindex].select_val; - } - } - scl_pin_index_ = newindex; -} - -bool TwoWire::force_clock() -{ - bool ret = false; - uint32_t sda_pin = hardware.sda_pins[sda_pin_index_].pin; - uint32_t scl_pin = hardware.scl_pins[scl_pin_index_].pin; - uint32_t sda_mask = digitalPinToBitMask(sda_pin); - uint32_t scl_mask = digitalPinToBitMask(scl_pin); - // take control of pins with GPIO - *portConfigRegister(sda_pin) = 5 | 0x10; - *portSetRegister(sda_pin) = sda_mask; - *portModeRegister(sda_pin) |= sda_mask; - *portConfigRegister(scl_pin) = 5 | 0x10; - *portSetRegister(scl_pin) = scl_mask; - *portModeRegister(scl_pin) |= scl_mask; - delayMicroseconds(10); - for (int i=0; i < 9; i++) { - if ((*portInputRegister(sda_pin) & sda_mask) - && (*portInputRegister(scl_pin) & scl_mask)) { - // success, both pins are high - ret = true; - break; - } - *portClearRegister(scl_pin) = scl_mask; - delayMicroseconds(5); - *portSetRegister(scl_pin) = scl_mask; - delayMicroseconds(5); - } - // return control of pins to I2C - *(portConfigRegister(sda_pin)) = hardware.sda_pins[sda_pin_index_].mux_val; - *(portConfigRegister(scl_pin)) = hardware.scl_pins[scl_pin_index_].mux_val; - return ret; -} size_t TwoWire::write(uint8_t data) { @@ -145,9 +58,6 @@ size_t TwoWire::write(const uint8_t *data, size_t quantity) return 0; } - - - // 2 BBF = Bus Busy Flag // 1 MBF = Master Busy Flag // 40 DMF = Data Match Flag @@ -307,14 +217,200 @@ uint8_t TwoWire::requestFrom(uint8_t addr, uint8_t qty, uint32_t iaddr, uint8_t return requestFrom(addr, qty, stop); } +bool TwoWire::force_clock() +{ + bool ret = false; + uint32_t sda_pin = hardware.sda_pins[sda_pin_index_].pin; + uint32_t scl_pin = hardware.scl_pins[scl_pin_index_].pin; + uint32_t sda_mask = digitalPinToBitMask(sda_pin); + uint32_t scl_mask = digitalPinToBitMask(scl_pin); + // take control of pins with GPIO + *portConfigRegister(sda_pin) = 5 | 0x10; + *portSetRegister(sda_pin) = sda_mask; + *portModeRegister(sda_pin) |= sda_mask; + *portConfigRegister(scl_pin) = 5 | 0x10; + *portSetRegister(scl_pin) = scl_mask; + *portModeRegister(scl_pin) |= scl_mask; + delayMicroseconds(10); + for (int i=0; i < 9; i++) { + if ((*portInputRegister(sda_pin) & sda_mask) + && (*portInputRegister(scl_pin) & scl_mask)) { + // success, both pins are high + ret = true; + break; + } + *portClearRegister(scl_pin) = scl_mask; + delayMicroseconds(5); + *portSetRegister(scl_pin) = scl_mask; + delayMicroseconds(5); + } + // return control of pins to I2C + *(portConfigRegister(sda_pin)) = hardware.sda_pins[sda_pin_index_].mux_val; + *(portConfigRegister(scl_pin)) = hardware.scl_pins[scl_pin_index_].mux_val; + return ret; +} + + + +//*************************************************** +// Slave Mode +//*************************************************** + +// registers start on page 2835 + +void TwoWire::begin(uint8_t address) +{ + CCM_CSCDR2 = (CCM_CSCDR2 & ~CCM_CSCDR2_LPI2C_CLK_PODF(63)) | CCM_CSCDR2_LPI2C_CLK_SEL; + hardware.clock_gate_register |= hardware.clock_gate_mask; + // setSDA() & setSCL() may be called before or after begin() + configSDApin(sda_pin_index_); // Setup SDA register + configSCLpin(scl_pin_index_); // setup SCL register + port->SCR = LPI2C_SCR_RST; + port->SCR = 0; + port->SCFGR1 = LPI2C_SCFGR1_TXDSTALL | LPI2C_SCFGR1_RXSTALL; // page 2841 + port->SCFGR2 = 0; // page 2843; + port->SAMR = LPI2C_SAMR_ADDR0(address); + attachInterruptVector(hardware.irq_number, hardware.irq_function); + NVIC_SET_PRIORITY(hardware.irq_number, 144); + NVIC_ENABLE_IRQ(hardware.irq_number); + port->SIER = LPI2C_SIER_TDIE | LPI2C_SIER_RDIE | LPI2C_SIER_SDIE; + transmitting = 0; + slave_mode = 1; + port->SCR = LPI2C_SCR_SEN; +} + + +void TwoWire::isr(void) +{ + uint32_t status = port->SSR; + uint32_t w1c_bits = status & 0xF00; + if (w1c_bits) port->SSR = w1c_bits; + + //Serial.print("isr "); + //Serial.println(status, HEX); + + if (status & LPI2C_SSR_RDF) { // Receive Data Flag + int rx = port->SRDR; + if (rx & 0x8000) { + rxBufferIndex = 0; + rxBufferLength = 0; + } + if (rxBufferLength < BUFFER_LENGTH) { + rxBuffer[rxBufferLength++] = rx & 255; + } + //Serial.print("rx = "); + //Serial.println(rx, HEX); + } + if (status & LPI2C_SSR_TDF) { // Transmit Data Flag + if (!transmitting) { + if (user_onRequest != nullptr) { + (*user_onRequest)(); + } + txBufferIndex = 0; + transmitting = 1; + } + if (txBufferIndex < txBufferLength) { + port->STDR = txBuffer[txBufferIndex++]; + } else { + port->STDR = 0; + } + //Serial.println("tx"); + } + + if (status & LPI2C_SSR_SDF) { // Stop + //Serial.println("Stop"); + if (rxBufferLength > 0 && user_onReceive != nullptr) { + (*user_onReceive)(rxBufferLength); + } + rxBufferIndex = 0; + rxBufferLength = 0; + txBufferIndex = 0; + txBufferLength = 0; + transmitting = 0; + } +} + + + +//*************************************************** +// Pins Configuration +//*************************************************** + + +FLASHMEM void TwoWire::setSDA(uint8_t pin) { + if (pin == hardware.sda_pins[sda_pin_index_].pin) return; + uint32_t newindex=0; + while (1) { + uint32_t sda_pin = hardware.sda_pins[newindex].pin; + if (sda_pin == 255) return; + if (sda_pin == pin) break; + if (++newindex >= sizeof(hardware.sda_pins)) return; + } + if ((hardware.clock_gate_register & hardware.clock_gate_mask)) { + // disable old pin, hard to know what to go back to? + *(portConfigRegister(hardware.sda_pins[sda_pin_index_].pin)) = 5; + // setup new one... + configSDApin(newindex); + } + sda_pin_index_ = newindex; +} + +FLASHMEM void TwoWire::configSDApin(uint8_t i) +{ + *(portControlRegister(hardware.sda_pins[i].pin)) = PINCONFIG; + *(portConfigRegister(hardware.sda_pins[i].pin)) = hardware.sda_pins[i].mux_val; + if (hardware.sda_pins[i].select_input_register) { + *(hardware.sda_pins[i].select_input_register) = hardware.sda_pins[i].select_val; + } +} + +FLASHMEM void TwoWire::setSCL(uint8_t pin) { + if (pin == hardware.scl_pins[scl_pin_index_].pin) return; + uint32_t newindex=0; + while (1) { + uint32_t scl_pin = hardware.scl_pins[newindex].pin; + if (scl_pin == 255) return; + if (scl_pin == pin) break; + if (++newindex >= sizeof(hardware.scl_pins)) return; + } + if ((hardware.clock_gate_register & hardware.clock_gate_mask)) { + // disable old pin, hard to know what to go back to? + *(portConfigRegister(hardware.scl_pins[scl_pin_index_].pin)) = 5; + // setup new one... + configSCLpin(newindex); + } + scl_pin_index_ = newindex; +} + +FLASHMEM void TwoWire::configSCLpin(uint8_t i) +{ + *(portControlRegister(hardware.scl_pins[i].pin)) = PINCONFIG; + *(portConfigRegister(hardware.scl_pins[i].pin)) = hardware.scl_pins[i].mux_val; + if (hardware.scl_pins[i].select_input_register) { + *(hardware.scl_pins[i].select_input_register) = hardware.scl_pins[i].select_val; + } +} + + + +#if defined(ARDUINO_TEENSY_MICROMOD) +void lpi2c1_isr(void) { Wire.isr(); } +void lpi2c3_isr(void) { Wire2.isr(); } +void lpi2c4_isr(void) { Wire1.isr(); } +void lpi2c2_isr(void) { Wire3.isr(); } +#else +void lpi2c1_isr(void) { Wire.isr(); } +void lpi2c3_isr(void) { Wire1.isr(); } +void lpi2c4_isr(void) { Wire2.isr(); } +#endif PROGMEM constexpr TwoWire::I2C_Hardware_t TwoWire::i2c1_hardware = { CCM_CCGR2, CCM_CCGR2_LPI2C1(CCM_CCGR_ON), {{18, 3 | 0x10, &IOMUXC_LPI2C1_SDA_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}}, {{19, 3 | 0x10, &IOMUXC_LPI2C1_SCL_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}}, - IRQ_LPI2C1 + IRQ_LPI2C1, &lpi2c1_isr }; TwoWire Wire(&IMXRT_LPI2C1, TwoWire::i2c1_hardware); @@ -328,7 +424,7 @@ constexpr TwoWire::I2C_Hardware_t TwoWire::i2c3_hardware = { {{17, 1 | 0x10, &IOMUXC_LPI2C3_SDA_SELECT_INPUT, 2}, {36, 2 | 0x10, &IOMUXC_LPI2C3_SDA_SELECT_INPUT, 1}}, {{16, 1 | 0x10, &IOMUXC_LPI2C3_SCL_SELECT_INPUT, 2}, {37, 2 | 0x10, &IOMUXC_LPI2C3_SCL_SELECT_INPUT, 1}}, #endif - IRQ_LPI2C3 + IRQ_LPI2C3, &lpi2c3_isr }; //TwoWire Wire1(&IMXRT_LPI2C3, TwoWire::i2c3_hardware); @@ -337,7 +433,7 @@ constexpr TwoWire::I2C_Hardware_t TwoWire::i2c4_hardware = { CCM_CCGR6, CCM_CCGR6_LPI2C4_SERIAL(CCM_CCGR_ON), {{25, 0 | 0x10, &IOMUXC_LPI2C4_SDA_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}}, {{24, 0 | 0x10, &IOMUXC_LPI2C4_SCL_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}}, - IRQ_LPI2C4 + IRQ_LPI2C4, &lpi2c4_isr }; //TwoWire Wire2(&IMXRT_LPI2C4, TwoWire::i2c4_hardware); @@ -356,13 +452,15 @@ constexpr TwoWire::I2C_Hardware_t TwoWire::i2c2_hardware = { CCM_CCGR2, CCM_CCGR2_LPI2C2(CCM_CCGR_ON), {{41, 2 | 0x10, &IOMUXC_LPI2C2_SDA_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}}, {{40, 2 | 0x10, &IOMUXC_LPI2C2_SCL_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}}, - IRQ_LPI2C4 + IRQ_LPI2C2, &lpi2c2_isr }; TwoWire Wire3(&IMXRT_LPI2C2, TwoWire::i2c2_hardware); #endif + + // Timeout if a device stretches SCL this long, in microseconds #define CLOCK_STRETCH_TIMEOUT 15000 diff --git a/firmware/3.0/lib/Wire/WireIMXRT.h b/firmware/3.0/lib/Wire/WireIMXRT.h old mode 100644 new mode 100755 index e930488..73d7b9e --- a/firmware/3.0/lib/Wire/WireIMXRT.h +++ b/firmware/3.0/lib/Wire/WireIMXRT.h @@ -32,7 +32,7 @@ #include #include -#define BUFFER_LENGTH 32 +#define BUFFER_LENGTH 136 //#define WIRE_HAS_END 1 #define WIRE_IMPLEMENT_WIRE #define WIRE_IMPLEMENT_WIRE1 @@ -56,7 +56,8 @@ class TwoWire : public Stream uint32_t clock_gate_mask; pin_info_t sda_pins[cnt_sda_pins]; pin_info_t scl_pins[cnt_scl_pins]; - IRQ_NUMBER_t irq; + IRQ_NUMBER_t irq_number; + void (*irq_function)(void); } I2C_Hardware_t; static const I2C_Hardware_t i2c1_hardware; static const I2C_Hardware_t i2c2_hardware; @@ -88,6 +89,9 @@ class TwoWire : public Stream return endTransmission(1); } uint8_t requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop); + uint8_t requestFrom(uint8_t address, uint8_t quantity, bool sendStop) { + return requestFrom(address, quantity, (uint8_t)(sendStop ? 1 : 0)); + } uint8_t requestFrom(uint8_t address, uint8_t quantity) { return requestFrom(address, quantity, (uint8_t)1); } @@ -152,8 +156,10 @@ class TwoWire : public Stream } using Print::write; private: - //void isr(void); + void isr(void); //bool wait_idle(void); + void configSDApin(uint8_t index); + void configSCLpin(uint8_t index); bool wait_idle(); bool force_clock(); IMXRT_LPI2C_t * const port; @@ -177,10 +183,10 @@ class TwoWire : public Stream void (*user_onRequest)(void) = nullptr; void (*user_onReceive)(int) = nullptr; void sda_rising_isr(void); - friend void i2c0_isr(void); - friend void i2c1_isr(void); - friend void i2c2_isr(void); - friend void i2c3_isr(void); + friend void lpi2c1_isr(void); + friend void lpi2c2_isr(void); + friend void lpi2c3_isr(void); + friend void lpi2c4_isr(void); friend void sda_rising_isr0(void); friend void sda_rising_isr1(void); }; diff --git a/firmware/3.0/lib/Wire/WireKinetis.cpp b/firmware/3.0/lib/Wire/WireKinetis.cpp old mode 100644 new mode 100755 index dcc12c4..29ea0a1 --- a/firmware/3.0/lib/Wire/WireKinetis.cpp +++ b/firmware/3.0/lib/Wire/WireKinetis.cpp @@ -51,6 +51,8 @@ void sda_rising_isr0(void); void sda_rising_isr1(void); +#define CLOCK_GATE_REG(addr) (*(volatile uint32_t *)(addr)) + void TwoWire::begin(void) { //serial_begin(BAUD2DIV(115200)); @@ -64,7 +66,7 @@ void TwoWire::begin(void) user_onRequest = NULL; user_onReceive = NULL; slave_mode = 0; - hardware.clock_gate_register |= hardware.clock_gate_mask; + CLOCK_GATE_REG(hardware.clock_gate_register) |= hardware.clock_gate_mask; port().C1 = 0; // On Teensy 3.0 external pullup resistors *MUST* be used // the PORT_PCR_PE bit is ignored when in I2C mode @@ -90,7 +92,7 @@ void TwoWire::begin(void) void TwoWire::setClock(uint32_t frequency) { - if (!(hardware.clock_gate_register & hardware.clock_gate_mask)) return; + if (!(CLOCK_GATE_REG(hardware.clock_gate_register) & hardware.clock_gate_mask)) return; #if F_BUS == 128000000 if (frequency < 400000) { @@ -268,7 +270,7 @@ void TwoWire::setSDA(uint8_t pin) if (sda_pin == pin) break; if (++newindex >= sizeof(hardware.sda_pin)) return; } - if ((hardware.clock_gate_register & hardware.clock_gate_mask)) { + if ((CLOCK_GATE_REG(hardware.clock_gate_register) & hardware.clock_gate_mask)) { volatile uint32_t *reg; reg = portConfigRegister(hardware.sda_pin[sda_pin_index]); *reg = 0; @@ -289,7 +291,7 @@ void TwoWire::setSCL(uint8_t pin) if (scl_pin == pin) break; if (++newindex >= sizeof(hardware.scl_pin)) return; } - if ((hardware.clock_gate_register & hardware.clock_gate_mask)) { + if ((CLOCK_GATE_REG(hardware.clock_gate_register) & hardware.clock_gate_mask)) { volatile uint32_t *reg; reg = portConfigRegister(hardware.scl_pin[scl_pin_index]); *reg = 0; @@ -311,7 +313,7 @@ void TwoWire::begin(uint8_t address) void TwoWire::end() { - if (!(hardware.clock_gate_register & hardware.clock_gate_mask)) return; + if (!(CLOCK_GATE_REG(hardware.clock_gate_register) & hardware.clock_gate_mask)) return; NVIC_DISABLE_IRQ(hardware.irq); // TODO: should this try to create a stop condition?? port().C1 = 0; @@ -320,7 +322,7 @@ void TwoWire::end() *reg = 0; reg = portConfigRegister(hardware.sda_pin[sda_pin_index]); *reg = 0; - hardware.clock_gate_register &= ~hardware.clock_gate_mask; + CLOCK_GATE_REG(hardware.clock_gate_register) &= ~hardware.clock_gate_mask; } @@ -837,7 +839,7 @@ uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait } constexpr TwoWire::I2C_Hardware_t TwoWire::i2c0_hardware = { - SIM_SCGC4, SIM_SCGC4_I2C0, + SIM_SCGC4_ADDRESS, SIM_SCGC4_I2C0, #if defined(__MKL26Z64__) || defined(__MK20DX128__) || defined(__MK20DX256__) 18, 17, 255, 255, 255, 2, 2, 0, 0, 0, @@ -854,7 +856,7 @@ constexpr TwoWire::I2C_Hardware_t TwoWire::i2c0_hardware = { #if defined(__MKL26Z64__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) constexpr TwoWire::I2C_Hardware_t TwoWire::i2c1_hardware = { - SIM_SCGC4, SIM_SCGC4_I2C1, + SIM_SCGC4_ADDRESS, SIM_SCGC4_I2C1, #if defined(__MKL26Z64__) 23, 255, 255, 255, 255, 2, 0, 0, 0, 0, @@ -877,7 +879,7 @@ constexpr TwoWire::I2C_Hardware_t TwoWire::i2c1_hardware = { #if defined(__MK64FX512__) || defined(__MK66FX1M0__) constexpr TwoWire::I2C_Hardware_t TwoWire::i2c2_hardware = { - SIM_SCGC1, SIM_SCGC1_I2C2, + SIM_SCGC1_ADDRESS, SIM_SCGC1_I2C2, #if defined(__MK64FX512__) || defined(__MK66FX1M0__) 4, 255, 255, 255, 255, 5, 0, 0, 0, 0, @@ -890,7 +892,7 @@ constexpr TwoWire::I2C_Hardware_t TwoWire::i2c2_hardware = { #if defined(__MK66FX1M0__) constexpr TwoWire::I2C_Hardware_t TwoWire::i2c3_hardware = { - SIM_SCGC1, SIM_SCGC1_I2C3, + SIM_SCGC1_ADDRESS, SIM_SCGC1_I2C3, #if defined(__MK66FX1M0__) 56, 255, 255, 255, 255, 2, 0, 0, 0, 0, @@ -907,22 +909,22 @@ constexpr TwoWire::I2C_Hardware_t TwoWire::i2c3_hardware = { #define MAKE_CONST(x) (__builtin_constant_p(x) ? (x) : (x)) #ifdef WIRE_IMPLEMENT_WIRE -constexpr uintptr_t i2c0_addr = uintptr_t(MAKE_CONST(&KINETIS_I2C0)); +constexpr uintptr_t i2c0_addr = KINETIS_I2C0_ADDRESS; TwoWire Wire(i2c0_addr, TwoWire::i2c0_hardware); void i2c0_isr(void) { Wire.isr(); } #endif #ifdef WIRE_IMPLEMENT_WIRE1 -constexpr uintptr_t i2c1_addr = uintptr_t(MAKE_CONST(&KINETIS_I2C1)); +constexpr uintptr_t i2c1_addr = KINETIS_I2C1_ADDRESS; TwoWire Wire1(i2c1_addr, TwoWire::i2c1_hardware); void i2c1_isr(void) { Wire1.isr(); } #endif #ifdef WIRE_IMPLEMENT_WIRE2 -constexpr uintptr_t i2c2_addr = uintptr_t(MAKE_CONST(&KINETIS_I2C2)); +constexpr uintptr_t i2c2_addr = KINETIS_I2C2_ADDRESS; TwoWire Wire2(i2c2_addr, TwoWire::i2c2_hardware); void i2c2_isr(void) { Wire2.isr(); } #endif #ifdef WIRE_IMPLEMENT_WIRE3 -constexpr uintptr_t i2c3_addr = uintptr_t(MAKE_CONST(&KINETIS_I2C3)); +constexpr uintptr_t i2c3_addr = KINETIS_I2C3_ADDRESS; TwoWire Wire3(i2c3_addr, TwoWire::i2c3_hardware); void i2c3_isr(void) { Wire3.isr(); } #endif diff --git a/firmware/3.0/lib/Wire/WireKinetis.h b/firmware/3.0/lib/Wire/WireKinetis.h old mode 100644 new mode 100755 index e7781ac..4cc0c5b --- a/firmware/3.0/lib/Wire/WireKinetis.h +++ b/firmware/3.0/lib/Wire/WireKinetis.h @@ -32,7 +32,14 @@ #include #include -#define BUFFER_LENGTH 32 +#if defined(__MKL26Z64__) || defined(__MK20DX128__) +#define BUFFER_LENGTH 40 +#elif defined(__MK20DX256__) +#define BUFFER_LENGTH 72 +#else +#define BUFFER_LENGTH 136 +#endif + #define WIRE_HAS_END 1 @@ -78,7 +85,7 @@ class TwoWire : public Stream public: // Hardware description struct typedef struct { - volatile uint32_t &clock_gate_register; + uintptr_t clock_gate_register; uint32_t clock_gate_mask; uint8_t sda_pin[5]; uint8_t sda_mux[5]; @@ -116,6 +123,9 @@ class TwoWire : public Stream return endTransmission(1); } uint8_t requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop); + uint8_t requestFrom(uint8_t address, uint8_t quantity, bool sendStop) { + return requestFrom(address, quantity, (uint8_t)(sendStop ? 1 : 0)); + } uint8_t requestFrom(uint8_t address, uint8_t quantity) { return requestFrom(address, quantity, (uint8_t)1); } diff --git a/firmware/3.0/other/platformio_teensy4.zip b/firmware/3.0/other/platformio_teensy4.zip deleted file mode 100644 index 1238370..0000000 Binary files a/firmware/3.0/other/platformio_teensy4.zip and /dev/null differ diff --git a/firmware/3.0/src/general/globalvariables.cpp b/firmware/3.0/src/general/globalvariables.cpp old mode 100644 new mode 100755 index ba9d12d..942ef6b --- a/firmware/3.0/src/general/globalvariables.cpp +++ b/firmware/3.0/src/general/globalvariables.cpp @@ -26,8 +26,8 @@ /*############################# PUBLIC VARIABLES ##############################*/ //Current firmware version -char versionString[] = "Firmware 3.02 from 05.07.2021"; -uint16_t fwVersion = 302; +char versionString[] = "Firmware 3.0.3 from 07.05.2023"; +uint16_t fwVersion = 303; //320x240 buffer unsigned short* bigBuffer; diff --git a/firmware/README.MD b/firmware/README.MD index 3121c98..2b659d9 100644 --- a/firmware/README.MD +++ b/firmware/README.MD @@ -1,20 +1,13 @@ # DIY-Thermocam - Firmware -## THIS GUIDE IS ONLY REQUIRED, IF YOU WANT TO MAKE CHANGES TO THE FIRMWARE ON YOUR OWN +### THIS GUIDE IS ONLY REQUIRED, IF YOU WANT TO MAKE CHANGES TO THE FIRMWARE ON YOUR OWN -This guide should work on **all common operating systems** (**Windows, Linux & macOS**). - -**Download** and **install** the following programs: - -1. [VS Code](https://code.visualstudio.com/) -2. [PlatformIO Core](https://docs.platformio.org/en/latest//core/installation.html) -3. [PlatformIO for VS Code](https://platformio.org/install/ide?install=vscode) +In case you want to flash the newest version of the firmware to your device without modification, **go to the release section of this repo**. -The **Teensyduino** version that comes pre-installed with PlatformIO does not support Mass Storage Mode (MTP), so we **need to update it**. Extract the content of [platformio_teensy4.zip](3.0/other/platformio_teensy4.zip) to: `C:\Users\\.platformio` (filepath on Windows or macOS is different, I am using Windows) and overwrite any existing files. +This guide should work on **all common operating systems** (**Windows, Linux & macOS**). -Now **start VS Code** and open the folder that you have just cloned with **File -> Open Folder**. +You need to have [VS Code](https://code.visualstudio.com/) installed and download the zip archive of this repository. Then **unpack the 3.0 folder inside the firmware subfolder**, **start VS Code** and open this folder with **File -> Open Folder**. -**PlatformIO should initialize itself automatically** and you see the buttons to **Build, Upload and Clean** the project in the blue bar **at the bottom**. +**PlatformIO should initialize itself automatically** and you see the buttons to **Build, Upload and Clean** the project in the blue bar **at the bottom**. If this is not the case, **set it up manually using the instructions provided [here](https://platformio.org/install/ide?install=vscode)**. **Before you click "Upload"**, make sure the Thermocam is **connected to the PC** via a micro USB cable and **turned on**. The **Teensy CLI** should then automatically detect it and **flash the .hex file to the board**. After a restart the changes should be present on the device. -