mirror of
https://github.com/OpenEPaperLink/OpenEPaperLink.git
synced 2026-03-21 07:06:36 +01:00
* Fix filesystem mutex handling This fixes the re-initialization of the filesystem mutex when the dyn storage module is reinitialized. Using xSemaphoreCreateMutex would cause a memory leak when the begin function is called multiple times and a semaphore leakage could be caused by the re-initialization of the global fsMutex variable while the semaphore is taken. The fsMutex should not be taken while the logLine function is called as this would cause a nested take of the fsMutex, which causes a deadlock. Signed-off-by: Frank Kunz <mailinglists@kunz-im-inter.net> * Fix hard coded littlefs in json upload Signed-off-by: Frank Kunz <mailinglists@kunz-im-inter.net> * Add new AP hardware support OpenEPaperLink_ESP32-PoE-ISO_AP This is based on Olimex ESP32-PoE-ISO https://www.olimex.com/Products/IoT/ESP32/ESP32-POE-ISO/open-source-hardware It has a SD Card slot that is used to store all filesystem data on SD. Use the prepare_sdcard.sh script to copy all needed data to an empty SD card that is formatted with FAT filesystem. The AP firmware will format the SD if an unformatted or from formatted card is used. This can be used to intially prepare an empty SD card for usage. For tag communication a ESP32-C6-WROOM-1(U) is used with the following connection scheme: ESP32-PoE-ISO | ESP32-C6-WROOM-1 ---------------+------------------ GPIO5 | EN GPIO13 | GPIO9 GPIO36 | GPIO3 GPIO4 | GPIO2 GPIO33 | GPIO24 GPIO32 | GPIO25 | GPIO8 pullup 5.1k Signed-off-by: Frank Kunz <mailinglists@kunz-im-inter.net> * Avoid error message log print when parsers.json is missing Signed-off-by: Frank Kunz <mailinglists@kunz-im-inter.net> * Workaround for IEEE802.15.4 modem stuck issue The ESP32-C6 esp-idf based modem firmware can run into a case where it does not receive data anymore from the tags. This can be detected when it starts to print "receive buffer full, drop the current frame" and does not recover from that. In such a case a modem reset is triggered. Signed-off-by: Frank Kunz <mailinglists@kunz-im-inter.net> * Add OpenEPaperLink_ESP32-PoE-ISO_AP to release build Signed-off-by: Frank Kunz <mailinglists@kunz-im-inter.net> * Add OpenEPaperLink_ESP32-PoE-ISO_AP to condidional build Signed-off-by: Frank Kunz <mailinglists@kunz-im-inter.net> * Add Ethernet support The ethernet support allows to make the network/internet connection via LAN cable instead of WiFi. LAN is preferred, if a LAN cable is connected and a valid IP configuration via DHCP can be obtained, WiFi is switched off. If the LAN cable is disconnected, a fall back to WiFi is done. Use those defines in platform.ini for PHY settings: ETHERNET_PHY_POWER: IO pin where the PHY can be switched of/on, can be -1 if not used. ETHERNET_CLK_MODE: PHY clock mode, see eth_clock_mode_t in ETH.h ETHERNET_PHY_MDC: PHY MDC pin ETHERNET_PHY_MDIO: PHY MDIO pin ETHERNET_PHY_TYPE: PHY type, see eth_phy_type_t in ETH.h Limitations: - only DHCP is supported, no static IP configuration for LAN so far. - If GPIO0 is used for one of the ETHERNET_CLK_MODE modes, then GPIO0 cannot be used to clear the WiFi configuration. Signed-off-by: Frank Kunz <mailinglists@kunz-im-inter.net> --------- Signed-off-by: Frank Kunz <mailinglists@kunz-im-inter.net> Co-authored-by: Frank Kunz <mailinglists@kunz-im-inter.net>
248 lines
6.0 KiB
C++
248 lines
6.0 KiB
C++
#include "storage.h"
|
|
|
|
#ifdef HAS_SDCARD
|
|
#include "FS.h"
|
|
#ifdef SD_CARD_SDMMC
|
|
#include "SD_MMC.h"
|
|
#define SDCARD SD_MMC
|
|
#else
|
|
#include "SD.h"
|
|
#include "SPI.h"
|
|
#define SDCARD SD
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef SD_CARD_ONLY
|
|
#include "LittleFS.h"
|
|
#endif
|
|
|
|
DynStorage::DynStorage() : isInited(0) {}
|
|
|
|
SemaphoreHandle_t fsMutex = NULL;
|
|
|
|
#ifndef SD_CARD_ONLY
|
|
static void initLittleFS() {
|
|
LittleFS.begin();
|
|
contentFS = &LittleFS;
|
|
}
|
|
#endif
|
|
|
|
#ifdef HAS_SDCARD
|
|
static bool sd_init_done = false;
|
|
#ifdef SD_CARD_SDMMC
|
|
static void initSDCard() {
|
|
if(!SD_MMC.begin("/sdcard", true, true, BOARD_MAX_SDMMC_FREQ, 5)){
|
|
Serial.println("Card Mount Failed");
|
|
return;
|
|
}
|
|
uint8_t cardType = SD_MMC.cardType();
|
|
|
|
if(cardType == CARD_NONE){
|
|
Serial.println("No SD_MMC card attached");
|
|
return;
|
|
}
|
|
|
|
Serial.print("SD_MMC Card Type: ");
|
|
if(cardType == CARD_MMC){
|
|
Serial.println("MMC");
|
|
} else if(cardType == CARD_SD){
|
|
Serial.println("SDSC");
|
|
} else if(cardType == CARD_SDHC){
|
|
Serial.println("SDHC");
|
|
} else {
|
|
Serial.println("UNKNOWN");
|
|
}
|
|
|
|
uint64_t cardSize = SD_MMC.cardSize() / (1024 * 1024);
|
|
Serial.printf("SD_MMC Card Size: %lluMB\n", cardSize);
|
|
|
|
contentFS = &SD_MMC;
|
|
}
|
|
#else
|
|
static SPIClass* spi;
|
|
|
|
static void initSDCard() {
|
|
uint8_t spi_bus = VSPI;
|
|
|
|
// SD.begin and spi.begin are allocating memory so we dont want to do that
|
|
if(!spi) {
|
|
spi = new SPIClass(spi_bus);
|
|
spi->begin(SD_CARD_CLK, SD_CARD_MISO, SD_CARD_MOSI, SD_CARD_SS);
|
|
|
|
bool res = SD.begin(SD_CARD_SS, *spi, 40000000);
|
|
if (!res) {
|
|
Serial.println("Card Mount Failed");
|
|
return;
|
|
}
|
|
}
|
|
|
|
uint8_t cardType = SD.cardType();
|
|
|
|
if (cardType == CARD_NONE) {
|
|
Serial.println("No SD card attached");
|
|
return;
|
|
}
|
|
|
|
contentFS = &SD;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
uint64_t DynStorage::freeSpace(){
|
|
this->begin();
|
|
#ifdef HAS_SDCARD
|
|
return SDCARD.totalBytes() - SDCARD.usedBytes();
|
|
#endif
|
|
#ifndef SD_CARD_ONLY
|
|
return LittleFS.totalBytes() - LittleFS.usedBytes();
|
|
#endif
|
|
}
|
|
|
|
#ifndef SD_CARD_ONLY
|
|
void copyFile(File in, File out) {
|
|
Serial.print("Copying ");
|
|
Serial.print(in.path());
|
|
Serial.print(" to ");
|
|
Serial.println(out.path());
|
|
|
|
size_t n;
|
|
uint8_t buf[64];
|
|
while ((n = in.read(buf, sizeof(buf))) > 0) {
|
|
out.write(buf, n);
|
|
}
|
|
}
|
|
|
|
#ifdef HAS_SDCARD
|
|
|
|
void copyBetweenFS(FS& sourceFS, const char* source_path, FS& targetFS) {
|
|
File root = sourceFS.open(source_path);
|
|
char next_path[128];
|
|
|
|
if (root.isDirectory()) {
|
|
if (!contentFS->exists(root.path())) {
|
|
if (!contentFS->mkdir(root.path())) {
|
|
Serial.print("Failed to create directory ");
|
|
Serial.println(root.path());
|
|
return;
|
|
}
|
|
}
|
|
File file = root.openNextFile();
|
|
while (file) {
|
|
if (file.isDirectory()) {
|
|
sprintf(next_path, "%s/%s\0", root.path(), file.path());
|
|
|
|
copyBetweenFS(sourceFS, file.path(), targetFS);
|
|
} else {
|
|
xSemaphoreTake(fsMutex, portMAX_DELAY);
|
|
File target = contentFS->open(file.path(), "w");
|
|
if (target) {
|
|
copyFile(file, target);
|
|
target.close();
|
|
file.close();
|
|
xSemaphoreGive(fsMutex);
|
|
} else {
|
|
xSemaphoreGive(fsMutex);
|
|
Serial.print("Couldn't create high target file");
|
|
Serial.println(file.path());
|
|
return;
|
|
}
|
|
}
|
|
file = root.openNextFile();
|
|
}
|
|
} else {
|
|
xSemaphoreTake(fsMutex, portMAX_DELAY);
|
|
File target = contentFS->open(root.path(), "w");
|
|
if (target) {
|
|
copyFile(root, target);
|
|
target.close();
|
|
xSemaphoreGive(fsMutex);
|
|
} else {
|
|
xSemaphoreGive(fsMutex);
|
|
Serial.print("Couldn't create target file ");
|
|
Serial.println(root.path());
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void copyIfNeeded(const char* path) {
|
|
if (!contentFS->exists(path) && LittleFS.exists(path)) {
|
|
Serial.printf("SDCard does not contain %s, littleFS does, copying\r\n", path);
|
|
copyBetweenFS(LittleFS, path, *contentFS);
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
void DynStorage::begin() {
|
|
if(fsMutex == NULL) {
|
|
fsMutex = xSemaphoreCreateMutex();
|
|
}
|
|
|
|
#ifndef SD_CARD_ONLY
|
|
initLittleFS();
|
|
#endif
|
|
|
|
#ifdef HAS_SDCARD
|
|
if(!sd_init_done) {
|
|
xSemaphoreTake(fsMutex, portMAX_DELAY);
|
|
initSDCard();
|
|
xSemaphoreGive(fsMutex);
|
|
sd_init_done = true;
|
|
}
|
|
#ifndef SD_CARD_ONLY
|
|
copyIfNeeded("/index.html");
|
|
copyIfNeeded("/fonts");
|
|
copyIfNeeded("/www");
|
|
copyIfNeeded("/tagtypes");
|
|
copyIfNeeded("/AP_FW_Pack.bin");
|
|
copyIfNeeded("/tag_md5_db.json");
|
|
copyIfNeeded("/update_actions.json");
|
|
copyIfNeeded("/content_template.json");
|
|
#endif
|
|
#endif
|
|
|
|
if (!contentFS->exists("/current")) {
|
|
contentFS->mkdir("/current");
|
|
}
|
|
if (!contentFS->exists("/temp")) {
|
|
contentFS->mkdir("/temp");
|
|
}
|
|
}
|
|
|
|
void DynStorage::end() {
|
|
#ifdef HAS_SDCARD
|
|
#ifndef SD_CARD_ONLY
|
|
initLittleFS();
|
|
#endif
|
|
#ifdef SD_CARD_SDMMC
|
|
#ifndef SD_CARD_ONLY
|
|
contentFS = &LittleFS;
|
|
#endif
|
|
SD_MMC.end();
|
|
sd_init_done = false;
|
|
#else
|
|
#ifndef SD_CARD_ONLY
|
|
if (SD_CARD_CLK == FLASHER_AP_CLK ||
|
|
SD_CARD_MISO == FLASHER_AP_MISO ||
|
|
SD_CARD_MOSI == FLASHER_AP_MOSI) {
|
|
Serial.println("Tearing down SD card connection");
|
|
|
|
copyBetweenFS(*contentFS, "/tag_md5_db.json", LittleFS);
|
|
copyBetweenFS(*contentFS, "/AP_FW_Pack.bin", LittleFS);
|
|
if (contentFS->exists("/AP_force_flash.bin")) {
|
|
copyBetweenFS(*contentFS, "/AP_force_flash.bin", LittleFS);
|
|
contentFS->remove("/AP_force_flash.bin");
|
|
}
|
|
Serial.println("Swapping to LittleFS");
|
|
|
|
contentFS = &LittleFS;
|
|
}
|
|
#endif
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
fs::FS* contentFS;
|
|
DynStorage Storage;
|