Merge pull request #70 from Mimoja/SDCard

Add Support for an SDCard and SoftSPI
This commit is contained in:
Jelmer
2023-06-24 23:29:24 +02:00
committed by GitHub
16 changed files with 376 additions and 88 deletions

View File

@@ -160,7 +160,7 @@ Latency will be around 40 seconds.">
<div><span id="runstate"></div>
<div><span id="apstatecolor">&#11044;</span> <span id="apstate">loading</span></div>
<div><span id="apconfigbutton">AP config</span></div>
<div><a href="/edit" target="littlefs" class="filebutton">edit littleFS</a></div>
<div><a href="/edit" target="littlefs" class="filebutton">edit contentFS</a></div>
</div>
</div>

View File

@@ -0,0 +1,7 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x150000,
app1, app, ota_1, 0x160000,0x150000,
spiffs, data, spiffs, 0x2B0000,0x140000,
coredump, data, coredump,0x3F0000,0x10000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x5000
3 otadata data ota 0xe000 0x2000
4 app0 app ota_0 0x10000 0x150000
5 app1 app ota_1 0x160000 0x150000
6 spiffs data spiffs 0x2B0000 0x140000
7 coredump data coredump 0x3F0000 0x10000

View File

@@ -0,0 +1,39 @@
#ifndef _DYN_STORAGE_H_
#define _DYN_STORAGE_H_
#include "FS.h"
#ifdef HAS_SDCARD
#ifndef SD_CARD_SS
#error SD_CARD_SS UNDEFINED
#endif
#ifndef SD_CARD_CLK
#define SD_CARD_CLK 18
#endif
#ifndef SD_CARD_MISO
#define SD_CARD_MISO 19
#endif
#ifndef SD_CARD_MOSI
#define SD_CARD_MOSI 23
#endif
#endif
class DynStorage {
public:
DynStorage();
void begin();
void end();
void listFiles();
size_t freeSpace();
private:
bool isInited;
};
extern DynStorage Storage;
extern fs::FS *contentFS;
#endif

View File

@@ -21,6 +21,7 @@ lib_deps =
https://github.com/Bodmer/U8g2_for_TFT_eSPI
https://github.com/ricmoo/qrcode
fastled/FastLED
https://github.com/MajenkoLibraries/SoftSPI
platform_packages =
board_build.filesystem = littlefs
@@ -319,4 +320,4 @@ build_flags =
-D LOAD_FONT2
build_src_filter =
+<*>-<usbflasher.cpp>-<serialconsole.cpp>

View File

@@ -13,7 +13,7 @@
#ifdef CONTENT_RSS
#include <rssClass.h>
#endif
#include <LittleFS.h>
#include "storage.h"
#include <time.h>
#include <map>
@@ -143,7 +143,7 @@ void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) {
if (imageParams.hasRed) imageParams.dataType = DATATYPE_IMG_RAW_2BPP;
if (prepareDataAvail(&filename, imageParams.dataType, mac, cfgobj["timetolive"].as<int>())) {
cfgobj["#fetched"] = true;
if (cfgobj["delete"].as<String>() == "1") LittleFS.remove("/" + cfgobj["filename"].as<String>());
if (cfgobj["delete"].as<String>() == "1") contentFS->remove("/" + cfgobj["filename"].as<String>());
} else {
wsErr("Error accessing " + filename);
}
@@ -323,7 +323,7 @@ void drawString(TFT_eSprite &spr, String content, uint16_t posx, uint16_t posy,
spr.setTextColor(PAL_BLACK, PAL_WHITE);
spr.drawString(content, posx, posy);
} else {
if (font != "") spr.loadFont(font, LittleFS);
if (font != "") spr.loadFont(font, *contentFS);
spr.setTextColor(color, PAL_WHITE);
spr.drawString(content, posx, posy);
if (font != "") spr.unloadFont();
@@ -420,7 +420,7 @@ void drawNumber(String &filename, int32_t count, int32_t thresholdred, tagRecord
if (count > 99) font = loc["fonts"][1].as<String>();
if (count > 999) font = loc["fonts"][2].as<String>();
if (count > 9999) font = loc["fonts"][3].as<String>();
spr.loadFont(font, LittleFS);
spr.loadFont(font, *contentFS);
spr.drawString(String(count), loc["xy"][0].as<uint16_t>(), loc["xy"][1].as<uint16_t>());
spr.unloadFont();
@@ -505,7 +505,7 @@ void drawWeather(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, imgP
dtostrf(temperature, 2, 1, tmpOutput);
drawString(spr, String(tmpOutput), loc["temp"][0], loc["temp"][1], loc["temp"][2], TL_DATUM, (temperature < 0 ? PAL_RED : PAL_BLACK));
spr.loadFont(loc["icon"][2], LittleFS);
spr.loadFont(loc["icon"][2], *contentFS);
if (weathercode == 55 || weathercode == 65 || weathercode == 75 || weathercode == 82 || weathercode == 86 || weathercode == 95 || weathercode == 99) {
spr.setTextColor(PAL_RED, PAL_WHITE);
} else {
@@ -515,7 +515,7 @@ void drawWeather(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, imgP
spr.printToSprite(weatherIcons[weathercode]);
spr.unloadFont();
spr.loadFont(loc["dir"][2], LittleFS);
spr.loadFont(loc["dir"][2], *contentFS);
spr.setTextColor(PAL_BLACK, PAL_WHITE);
spr.setCursor(loc["dir"][0], loc["dir"][1]);
spr.printToSprite(windDirectionIcon(winddirection));
@@ -578,7 +578,7 @@ void drawForecast(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, img
uint8_t weathercode = doc["daily"]["weathercode"][dag].as<int>();
if (weathercode > 40) weathercode -= 40;
spr.loadFont(loc["icon"][2], LittleFS);
spr.loadFont(loc["icon"][2], *contentFS);
if (weathercode == 55 || weathercode == 65 || weathercode == 75 || weathercode == 82 || weathercode == 86 || weathercode == 95 || weathercode == 99) {
spr.setTextColor(PAL_RED, PAL_WHITE);
} else {
@@ -597,7 +597,7 @@ void drawForecast(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, img
int8_t tmax = round(doc["daily"]["temperature_2m_max"][dag].as<double>());
uint8_t wind = windSpeedToBeaufort(doc["daily"]["windspeed_10m_max"][dag].as<double>());
spr.loadFont(loc["day"][2], LittleFS);
spr.loadFont(loc["day"][2], *contentFS);
if (loc["rain"]) {
int8_t rain = round(doc["daily"]["precipitation_sum"][dag].as<double>());
@@ -624,7 +624,7 @@ void drawForecast(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, img
int getImgURL(String &filename, String URL, time_t fetched, imgParam &imageParams, String MAC) {
// https://images.klari.net/kat-bw29.jpg
LittleFS.begin();
Storage.begin();
Serial.println("get external " + URL);
HTTPClient http;
@@ -634,7 +634,7 @@ int getImgURL(String &filename, String URL, time_t fetched, imgParam &imageParam
http.setTimeout(5000); // timeout in ms
int httpCode = http.GET();
if (httpCode == 200) {
File f = LittleFS.open("/temp/temp.jpg", "w");
File f = contentFS->open("/temp/temp.jpg", "w");
if (f) {
http.writeToStream(&f);
f.close();
@@ -796,7 +796,7 @@ void drawQR(String &filename, String qrcontent, String title, tagRecord *&taginf
#ifdef CONTENT_QR
TFT_eSPI tft = TFT_eSPI();
TFT_eSprite spr = TFT_eSprite(&tft);
LittleFS.begin();
Storage.begin();
const char *text = qrcontent.c_str();
QRCode qrcode;
@@ -1031,7 +1031,7 @@ void prepareConfigFile(uint8_t *dst, JsonObject config) {
}
void getTemplate(JsonDocument &json, const char *filePath, uint8_t id, uint8_t hwtype) {
File jsonFile = LittleFS.open(filePath, "r");
File jsonFile = contentFS->open(filePath, "r");
if (!jsonFile) {
Serial.println("Failed to open content template file " + String(filePath));
return;

View File

@@ -2,7 +2,8 @@
#include <Arduino.h>
#include <ArduinoJson.h>
#include <LittleFS.h>
#include "storage.h"
#include "LittleFS.h"
#include <MD5Builder.h>
// #include <FS.h>
@@ -109,24 +110,29 @@ class flasher {
flasher::flasher() {
zbs = new ZBS_interface;
Storage.end();
}
flasher::~flasher() {
delete zbs;
Storage.begin();
}
#ifndef FLASHER_AP_SPEED
#define FLASHER_AP_SPEED 4000000
#endif
bool flasher::connectTag(uint8_t port) {
bool result;
switch (port) {
case 0:
result = zbs->begin(FLASHER_AP_SS, FLASHER_AP_CLK, FLASHER_AP_MOSI, FLASHER_AP_MISO, FLASHER_AP_RESET, (uint8_t *)powerPinsAP, sizeof(powerPinsAP), 8000000);
result = zbs->begin(FLASHER_AP_SS, FLASHER_AP_CLK, FLASHER_AP_MOSI, FLASHER_AP_MISO, FLASHER_AP_RESET, (uint8_t *)powerPinsAP, sizeof(powerPinsAP), FLASHER_AP_SPEED);
break;
#ifdef OPENEPAPERLINK_PCB
case 1:
result = zbs->begin(FLASHER_EXT_SS, FLASHER_EXT_CLK, FLASHER_EXT_MOSI, FLASHER_EXT_MISO, FLASHER_EXT_RESET, (uint8_t *)powerPinsExt, sizeof(powerPinsExt), 8000000);
result = zbs->begin(FLASHER_EXT_SS, FLASHER_EXT_CLK, FLASHER_EXT_MOSI, FLASHER_EXT_MISO, FLASHER_EXT_RESET, (uint8_t *)powerPinsExt, sizeof(powerPinsExt), FLASHER_AP_SPEED);
break;
case 2:
result = zbs->begin(FLASHER_ALT_SS, FLASHER_ALT_CLK, FLASHER_ALT_MOSI, FLASHER_ALT_MISO, FLASHER_ALT_RESET, (uint8_t *)powerPinsAlt, sizeof(powerPinsAlt), 8000000);
result = zbs->begin(FLASHER_ALT_SS, FLASHER_ALT_CLK, FLASHER_ALT_MOSI, FLASHER_ALT_MISO, FLASHER_ALT_RESET, (uint8_t *)powerPinsAlt, sizeof(powerPinsAlt), FLASHER_AP_SPEED);
break;
#endif
default:
@@ -206,7 +212,7 @@ bool flasher::getInfoBlockType() {
bool flasher::findTagByMD5() {
StaticJsonDocument<3000> doc;
DynamicJsonDocument APconfig(600);
fs::File readfile = LittleFS.open("/tag_md5_db.json", "r");
fs::File readfile = contentFS->open("/tag_md5_db.json", "r");
DeserializationError err = deserializeJson(doc, readfile);
if (!err) {
for (JsonObject elem : doc.as<JsonArray>()) {
@@ -236,7 +242,7 @@ bool flasher::findTagByMD5() {
bool flasher::findTagByType(uint8_t type) {
StaticJsonDocument<3000> doc;
DynamicJsonDocument APconfig(600);
fs::File readfile = LittleFS.open("/tag_md5_db.json", "r");
fs::File readfile = contentFS->open("/tag_md5_db.json", "r");
DeserializationError err = deserializeJson(doc, readfile);
if (!err) {
for (JsonObject elem : doc.as<JsonArray>()) {
@@ -300,7 +306,7 @@ bool flasher::backupFlash() {
getFirmwareMD5();
if (!zbs->select_flash(0)) return false;
md5char[16] = 0x00;
fs::File backup = LittleFS.open("/" + (String)md5char + "_backup.bin", "w", true);
fs::File backup = contentFS->open("/" + (String)md5char + "_backup.bin", "w", true);
for (uint32_t c = 0; c < 65535; c++) {
backup.write(zbs->read_flash(c));
}
@@ -474,7 +480,7 @@ bool flasher::writeFlashFromPackOffset(fs::File *file, uint16_t length) {
bool flasher::writeFlashFromPack(String filename, uint8_t type) {
StaticJsonDocument<512> doc;
DynamicJsonDocument APconfig(512);
fs::File readfile = LittleFS.open(filename, "r");
fs::File readfile = contentFS->open(filename, "r");
DeserializationError err = deserializeJson(doc, readfile);
if (!err) {
for (JsonObject elem : doc.as<JsonArray>()) {
@@ -505,7 +511,7 @@ bool flasher::writeFlashFromPack(String filename, uint8_t type) {
uint16_t getAPUpdateVersion(uint8_t type) {
StaticJsonDocument<512> doc;
DynamicJsonDocument APconfig(512);
fs::File readfile = LittleFS.open("/AP_FW_Pack.bin", "r");
fs::File readfile = contentFS->open("/AP_FW_Pack.bin", "r");
DeserializationError err = deserializeJson(doc, readfile);
if (!err) {
for (JsonObject elem : doc.as<JsonArray>()) {
@@ -529,7 +535,7 @@ uint16_t getAPUpdateVersion(uint8_t type) {
}
bool checkForcedAPFlash() {
return LittleFS.exists("/AP_force_flash.bin");
return contentFS->exists("/AP_force_flash.bin");
}
bool doForcedAPFlash() {
@@ -547,14 +553,14 @@ bool doForcedAPFlash() {
f->writeInfoBlock();
}
fs::File readfile = LittleFS.open("/AP_force_flash.bin", "r");
fs::File readfile = contentFS->open("/AP_force_flash.bin", "r");
bool res = f->writeFlashFromPackOffset(&readfile, readfile.size());
#ifdef HAS_RGB_LED
if (res) addFadeColor(CRGB::Green);
if (!res) addFadeColor(CRGB::Red);
#endif
readfile.close();
if (res) LittleFS.remove("/AP_force_flash.bin");
if (res) contentFS->remove("/AP_force_flash.bin");
f->zbs->reset();
delete f;
return res;

View File

@@ -1,8 +1,10 @@
#include <Arduino.h>
#include <WiFi.h>
#include <WiFiManager.h>
#include <time.h>
#include "storage.h"
#include "contentmanager.h"
#include "flasher.h"
#include "makeimage.h"
@@ -84,6 +86,8 @@ void setup() {
heap_caps_malloc_extmem_enable(64);
#endif
Storage.begin();
/*
Serial.println("\n\n##################################");
Serial.printf("Internal Total heap %d, internal Free Heap %d\n", ESP.getHeapSize(), ESP.getFreeHeap());

View File

@@ -1,6 +1,6 @@
#include <Arduino.h>
#include <FS.h>
#include <LittleFS.h>
#include "storage.h"
#include <TFT_eSPI.h>
#include <TJpg_Decoder.h>
#include <makeimage.h>
@@ -15,7 +15,7 @@ bool spr_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap)
}
void jpg2buffer(String filein, String fileout, imgParam &imageParams) {
LittleFS.begin();
Storage.begin();
TJpgDec.setSwapBytes(true);
TJpgDec.setJpgScale(1);
TJpgDec.setCallback(spr_output);
@@ -23,7 +23,7 @@ void jpg2buffer(String filein, String fileout, imgParam &imageParams) {
if (filein.c_str()[0] != '/') {
filein = "/" + filein;
}
TJpgDec.getFsJpgSize(&w, &h, filein, LittleFS);
TJpgDec.getFsJpgSize(&w, &h, filein, *contentFS);
if (w==0 && h==0) {
wsErr("invalid jpg");
return;
@@ -47,7 +47,7 @@ void jpg2buffer(String filein, String fileout, imgParam &imageParams) {
wsErr("Failed to create sprite in jpg2buffer");
} else {
spr.fillSprite(TFT_WHITE);
TJpgDec.drawFsJpg(0, 0, filein, LittleFS);
TJpgDec.drawFsJpg(0, 0, filein, *contentFS);
spr2buffer(spr, fileout, imageParams);
spr.deleteSprite();
@@ -76,9 +76,9 @@ uint32_t colorDistance(const Color &c1, const Color &c2, const Error &e1) {
void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) {
long t = millis();
LittleFS.begin();
Storage.begin();
fs::File f_out = LittleFS.open(fileout, "w");
fs::File f_out = contentFS->open(fileout, "w");
bool dither = true;
uint8_t rotate = imageParams.rotate;

View File

@@ -3,12 +3,12 @@
#include <Arduino.h>
#include <FS.h>
#include <HTTPClient.h>
#include <LittleFS.h>
#include "storage.h"
#include <MD5Builder.h>
#include <makeimage.h>
#include <time.h>
#include "LittleFS.h"
#include "storage.h"
#include "commstructs.h"
#include "serialap.h"
#include "settings.h"
@@ -130,14 +130,14 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t
}
*filename = "/" + *filename;
LittleFS.begin();
Storage.begin();
if (!LittleFS.exists(*filename)) {
if (!contentFS->exists(*filename)) {
wsErr("File not found. " + *filename);
return false;
}
fs::File file = LittleFS.open(*filename);
fs::File file = contentFS->open(*filename);
uint32_t filesize = file.size();
if (filesize == 0) {
file.close();
@@ -161,8 +161,8 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t
if (memcmp(md5bytes, taginfo->md5pending, 16) == 0) {
wsLog("new image is the same as current or already pending image. not updating tag.");
wsSendTaginfo(dst, SYNC_TAGSTATUS);
if (LittleFS.exists(*filename)) {
LittleFS.remove(*filename);
if (contentFS->exists(*filename)) {
contentFS->remove(*filename);
}
return true;
}
@@ -182,10 +182,10 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t
if (dataType != DATATYPE_FW_UPDATE) {
char dst_path[64];
sprintf(dst_path, "/current/%02X%02X%02X%02X%02X%02X%02X%02X.pending\0", dst[7], dst[6], dst[5], dst[4], dst[3], dst[2], dst[1], dst[0]);
if (LittleFS.exists(dst_path)) {
LittleFS.remove(dst_path);
if (contentFS->exists(dst_path)) {
contentFS->remove(dst_path);
}
LittleFS.rename(*filename, dst_path);
contentFS->rename(*filename, dst_path);
*filename = String(dst_path);
wsLog("new image: " + String(dst_path));
@@ -241,7 +241,7 @@ void prepareExternalDataAvail(struct pendingData* pending, IPAddress remoteIP) {
case DATATYPE_IMG_RAW_1BPP:
case DATATYPE_IMG_RAW_2BPP:
case DATATYPE_IMG_RAW_1BPP_DIRECT: {
LittleFS.begin();
Storage.begin();
char hexmac[17];
mac2hex(pending->targetMac, hexmac);
@@ -252,13 +252,13 @@ void prepareExternalDataAvail(struct pendingData* pending, IPAddress remoteIP) {
http.begin(imageUrl);
int httpCode = http.GET();
if (httpCode == 200) {
File file = LittleFS.open(filename, "w");
File file = contentFS->open(filename, "w");
http.writeToStream(&file);
file.close();
}
http.end();
fs::File file = LittleFS.open(filename);
fs::File file = contentFS->open(filename);
uint32_t filesize = file.size();
if (filesize == 0) {
file.close();
@@ -338,7 +338,7 @@ void processBlockRequest(struct espBlockRequest* br) {
if (taginfo->data == nullptr) {
// not cached. open file, cache the data
fs::File file = LittleFS.open(taginfo->filename);
fs::File file = contentFS->open(taginfo->filename);
if (!file) {
Serial.print("No current file. Canceling request\n");
prepareCancelPending(br->src);
@@ -380,11 +380,15 @@ void processXferComplete(struct espXferComplete* xfc, bool local) {
char dst_path[64];
sprintf(src_path, "/current/%02X%02X%02X%02X%02X%02X%02X%02X.pending\0", xfc->src[7], xfc->src[6], xfc->src[5], xfc->src[4], xfc->src[3], xfc->src[2], xfc->src[1], xfc->src[0]);
sprintf(dst_path, "/current/%02X%02X%02X%02X%02X%02X%02X%02X.raw\0", xfc->src[7], xfc->src[6], xfc->src[5], xfc->src[4], xfc->src[3], xfc->src[2], xfc->src[1], xfc->src[0]);
if (LittleFS.exists(dst_path) && LittleFS.exists(src_path)) {
LittleFS.remove(dst_path);
if (contentFS->exists(dst_path) && contentFS->exists(src_path)) {
contentFS->remove(dst_path);
}
if (LittleFS.exists(src_path)) {
LittleFS.rename(src_path, dst_path);
if (contentFS->exists(src_path)) {
#ifndef REMOVE_RAW
contentFS->rename(src_path, dst_path);
#else
contentFS->remove(src_path);
#endif
}
time_t now;
@@ -396,8 +400,8 @@ void processXferComplete(struct espXferComplete* xfc, bool local) {
clearPending(taginfo);
taginfo->wakeupReason = 0;
if (taginfo->contentMode == 12 && local == false) {
if (LittleFS.exists(dst_path)) {
LittleFS.remove(dst_path);
if (contentFS->exists(dst_path)) {
contentFS->remove(dst_path);
}
}
}

View File

@@ -4,7 +4,7 @@
#include <ArduinoJson.h>
#include <FS.h>
#include <HTTPClient.h>
#include <LittleFS.h>
#include "storage.h"
#include <MD5Builder.h>
#include <Update.h>
@@ -51,7 +51,7 @@ void handleCheckFile(AsyncWebServerRequest* request) {
}
String filePath = request->getParam("path")->value();
File file = LittleFS.open(filePath, "r");
File file = contentFS->open(filePath, "r");
if (!file) {
StaticJsonDocument<64> doc;
doc["filesize"] = 0;
@@ -121,7 +121,7 @@ void handleLittleFSUpload(AsyncWebServerRequest* request, String filename, size_
} else {
path = request->getParam("path", true)->value();
Serial.println("update " + path);
request->_tempFile = LittleFS.open(path, "w", true);
request->_tempFile = contentFS->open(path, "w", true);
}
}
if (len) {
@@ -268,7 +268,7 @@ void handleRollback(AsyncWebServerRequest* request) {
void handleUpdateActions(AsyncWebServerRequest* request) {
wsSerial("Performing cleanup");
File file = LittleFS.open("/update_actions.json", "r");
File file = contentFS->open("/update_actions.json", "r");
if (!file) {
wsSerial("No update_actions.json present");
request->send(200, "No update actions needed");
@@ -278,12 +278,12 @@ void handleUpdateActions(AsyncWebServerRequest* request) {
DeserializationError error = deserializeJson(doc, file);
JsonArray deleteFiles = doc["deletefile"].as<JsonArray>();
for (const auto& filePath : deleteFiles) {
if (LittleFS.remove(filePath.as<const char*>())) {
if (contentFS->remove(filePath.as<const char*>())) {
wsSerial("deleted file: " + filePath.as<String>());
}
}
file.close();
wsSerial("Cleanup finished");
request->send(200, "Clean up finished");
LittleFS.remove("/update_actions.json");
contentFS->remove("/update_actions.json");
}

View File

@@ -2,7 +2,6 @@
#include <Arduino.h>
#include <HardwareSerial.h>
#include <LittleFS.h>
#include "commstructs.h"
#include "flasher.h"
@@ -10,6 +9,7 @@
#include "newproto.h"
#include "powermgt.h"
#include "settings.h"
#include "storage.h"
#include "web.h"
#include "zbs_interface.h"
@@ -205,6 +205,7 @@ bool sendDataAvail(struct pendingData* pending) {
}
if (waitCmdReply()) goto sdasend;
Serial.printf("SDA send failed in try %d\n", attempt);
delay(200);
}
Serial.print("SDA failed to send...\n");
txEnd();
@@ -747,6 +748,15 @@ void APTask(void* parameter) {
#endif
Serial.println("Please verify your wiring and try again!");
}
#ifdef HAS_SDCARD
if (SD_CARD_CLK == FLASHER_AP_CLK ||
SD_CARD_MISO == FLASHER_AP_MISO ||
SD_CARD_MOSI == FLASHER_AP_MOSI) {
Serial.println("Reseting in 30 seconds to restore SPI state!\n");
flashCountDown(30);
ESP.restart();
}
#endif
}
uint8_t attempts = 0;

View File

@@ -0,0 +1,215 @@
#include "storage.h"
#ifdef HAS_SDCARD
#include "FS.h"
#include "SD.h"
#include "SPI.h"
#endif
#include "LittleFS.h"
DynStorage::DynStorage() : isInited(0) {}
static void initLittleFS() {
LittleFS.begin();
contentFS = &LittleFS;
}
#ifdef HAS_SDCARD
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
size_t DynStorage::freeSpace(){
this->begin();
#ifdef HAS_SDCARD
return SD.totalBytes() - SD.usedBytes();
#endif
return LittleFS.totalBytes() - LittleFS.usedBytes();
}
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);
}
}
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 {
File target = contentFS->open(file.path(), "w");
if (target) {
copyFile(file, target);
target.close();
file.close();
} else {
Serial.print("Couldn't create high target file");
Serial.println(file.path());
return;
}
}
file = root.openNextFile();
}
} else {
File target = contentFS->open(root.path(), "w");
if (target) {
copyFile(root, target);
} else {
Serial.print("Couldn't create target file ");
Serial.println(root.path());
return;
}
}
}
#ifdef HAS_SDCARD
void copyIfNeeded(const char* path) {
if (!contentFS->exists(path) && LittleFS.exists(path)) {
Serial.printf("SDCard does not contain %s, littleFS does, copying\n", path);
copyBetweenFS(LittleFS, path, *contentFS);
}
}
#endif
void DynStorage::begin() {
initLittleFS();
#ifdef HAS_SDCARD
initSDCard();
copyIfNeeded("/index.html");
copyIfNeeded("/fonts");
copyIfNeeded("/www");
copyIfNeeded("/AP_FW_Pack.bin");
copyIfNeeded("/tag_md5_db.json");
copyIfNeeded("/update_actions.json");
copyIfNeeded("/content_template.json");
#endif
if (!contentFS->exists("/current")) {
contentFS->mkdir("/current");
}
if (!contentFS->exists("/temp")) {
contentFS->mkdir("/temp");
}
}
void DynStorage::end() {
#ifdef HAS_SDCARD
initLittleFS();
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
}
void listDir(fs::FS& fs, const char* dirname, uint8_t levels) {
Storage.begin();
// Print blank line on screen
Serial.printf(" \n ");
Serial.printf("Listing directory: %s\n", dirname);
File root = fs.open(dirname);
if (!root) {
Serial.println("Failed to open directory");
return;
}
if (!root.isDirectory()) {
Serial.println("Not a directory");
return;
}
File file = root.openNextFile();
while (file) {
if (!strcmp("System Volume Information", file.name())) {
file = root.openNextFile();
continue;
}
if (file.isDirectory()) {
Serial.print(" DIR : ");
Serial.println(file.name());
if (levels) {
listDir(fs, file.path(), levels - 1);
}
Serial.println();
} else {
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print(" SIZE: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}
void DynStorage::listFiles() {
listDir(LittleFS, "/", 1);
#ifdef HAS_SDCARD
listDir(*contentFS, "/", 1);
#endif
}
fs::FS* contentFS;
DynStorage Storage;

View File

@@ -3,7 +3,7 @@
#include <Arduino.h>
#include <FS.h>
#include "LittleFS.h"
#include "storage.h"
void init_time() {
struct tm timeinfo;
@@ -28,7 +28,7 @@ void logLine(String text) {
char timeStr[24];
strftime(timeStr, sizeof(timeStr), "%Y-%m-%d %H:%M:%S ", localtime(&now));
File logFile = LittleFS.open("/log.txt", "a");
File logFile = contentFS->open("/log.txt", "a");
if (logFile) {
logFile.print(timeStr);
logFile.println(text);

View File

@@ -5,7 +5,7 @@
#include <FS.h>
#include <vector>
#include "LittleFS.h"
#include "storage.h"
#include "language.h"
std::vector<tagRecord*> tagDB;
@@ -126,8 +126,8 @@ void saveDB(String filename) {
long t = millis();
LittleFS.begin();
fs::File file = LittleFS.open(filename, "w");
Storage.begin();
fs::File file = contentFS->open(filename, "w");
if (!file) {
Serial.println("saveDB: Failed to open file");
return;
@@ -161,8 +161,8 @@ void loadDB(String filename) {
Serial.println("reading DB from file");
long t = millis();
LittleFS.begin();
fs::File readfile = LittleFS.open(filename, "r");
Storage.begin();
fs::File readfile = contentFS->open(filename, "r");
if (!readfile) {
Serial.println("loadDB: Failed to open file");
return;
@@ -264,9 +264,9 @@ void clearPending(tagRecord* taginfo) {
}
void initAPconfig() {
LittleFS.begin(true);
Storage.begin();
DynamicJsonDocument APconfig(500);
File configFile = LittleFS.open("/current/apconfig.json", "r");
File configFile = contentFS->open("/current/apconfig.json", "r");
if (configFile) {
DeserializationError error = deserializeJson(APconfig, configFile);
if (error) {
@@ -285,7 +285,7 @@ void initAPconfig() {
}
void saveAPconfig() {
fs::File configFile = LittleFS.open("/current/apconfig.json", "w");
fs::File configFile = contentFS->open("/current/apconfig.json", "w");
DynamicJsonDocument APconfig(500);
APconfig["channel"] = config.channel;
APconfig["alias"] = config.alias;

View File

@@ -6,7 +6,8 @@
#include <ESPAsyncWebServer.h>
#include <ESPmDNS.h>
#include <FS.h>
#include <LittleFS.h>
#include "storage.h"
#include "LittleFS.h"
#include <SPIFFSEditor.h>
#include <WiFi.h>
#include <WiFiManager.h> // https://github.com/tzapu/WiFiManager/tree/feature_asyncwebserver
@@ -135,7 +136,7 @@ void wsSendSysteminfo() {
sys["heap"] = ESP.getFreeHeap();
sys["recordcount"] = tagDB.size();
sys["dbsize"] = tagDB.size() * sizeof(tagRecord);
sys["littlefsfree"] = LittleFS.totalBytes() - LittleFS.usedBytes();
sys["littlefsfree"] = Storage.freeSpace();
sys["apstate"] = apInfo.state;
sys["runstate"] = config.runStatus;
@@ -215,15 +216,7 @@ uint8_t wsClientCount() {
}
void init_web() {
LittleFS.begin(true);
if (!LittleFS.exists("/current")) {
LittleFS.mkdir("/current");
}
if (!LittleFS.exists("/temp")) {
LittleFS.mkdir("/temp");
}
Storage.begin();
WiFi.mode(WIFI_STA);
WiFiManager wm;
@@ -243,8 +236,8 @@ void init_web() {
Serial.print("Connected! IP address: ");
Serial.println(WiFi.localIP());
// server.addHandler(new SPIFFSEditor(LittleFS, http_username, http_password));
server.addHandler(new SPIFFSEditor(LittleFS));
// server.addHandler(new SPIFFSEditor(*contentFS, http_username, http_password));
server.addHandler(new SPIFFSEditor(*contentFS));
ws.onEvent(onEvent);
server.addHandler(&ws);
@@ -260,8 +253,8 @@ void init_web() {
ESP.restart();
});
server.serveStatic("/current", LittleFS, "/current/");
server.serveStatic("/", LittleFS, "/www/").setDefaultFile("index.html");
server.serveStatic("/current", *contentFS, "/current/");
server.serveStatic("/", *contentFS, "/www/").setDefaultFile("index.html");
server.on(
"/imgupload", HTTP_POST, [](AsyncWebServerRequest *request) {
@@ -371,7 +364,7 @@ void init_web() {
server.on("/get_ap_config", HTTP_GET, [](AsyncWebServerRequest *request) {
UDPcomm udpsync;
udpsync.getAPList();
File configFile = LittleFS.open("/current/apconfig.json", "r");
File configFile = contentFS->open("/current/apconfig.json", "r");
if (!configFile) {
request->send(500, "text/plain", "Error opening apconfig.json file");
return;
@@ -411,7 +404,7 @@ void init_web() {
server.on("/backup_db", HTTP_GET, [](AsyncWebServerRequest *request) {
saveDB("/current/tagDB.json");
File file = LittleFS.open("/current/tagDB.json", "r");
File file = contentFS->open("/current/tagDB.json", "r");
AsyncWebServerResponse *response = request->beginResponse(file, "tagDB.json", String(), true);
request->send(response);
file.close();
@@ -449,7 +442,7 @@ void doImageUpload(AsyncWebServerRequest *request, String filename, size_t index
} else {
filename = "unknown.jpg";
}
request->_tempFile = LittleFS.open("/" + filename, "w");
request->_tempFile = contentFS->open("/" + filename, "w");
}
if (len) {
// stream the incoming chunk to the opened file

View File

@@ -7,6 +7,10 @@
#include <stdint.h>
#include <stdio.h>
#ifdef USE_SOFTSPI
#include <SoftSPI.h>
#endif
#include "powermgt.h"
uint8_t ZBS_interface::begin(uint8_t SS, uint8_t CLK, uint8_t MOSI, uint8_t MISO, uint8_t RESET, uint8_t* POWER, uint8_t powerPins, uint32_t spi_speed) {
@@ -27,7 +31,12 @@ uint8_t ZBS_interface::begin(uint8_t SS, uint8_t CLK, uint8_t MOSI, uint8_t MISO
digitalWrite(_CLK_PIN, LOW);
digitalWrite(_MOSI_PIN, HIGH);
#ifdef USE_SOFTSPI
if (!spi) spi = new SoftSPI(_MOSI_PIN, _MISO_PIN, _CLK_PIN);
#else
if (!spi) spi = new SPIClass(HSPI);
#endif
spiSettings = SPISettings(spi_speed, MSBFIRST, SPI_MODE0);
spi_ready = 0;