diff --git a/data-src/index.js b/data-src/index.js index 6dd60fd..2055e5e 100644 --- a/data-src/index.js +++ b/data-src/index.js @@ -4849,7 +4849,7 @@ class Firmware { let div = this.createFileUploader('/updateApplication'); general.reloadApp = true; let inst = div.querySelector('div[id=divInstText]'); - inst.innerHTML = '
Select a binary file [SomfyController.littlefs.bin] containing the littlefs data for the application then press the Upload File button.
'; + inst.innerHTML = '
Select a binary file [SomfyController.littlefs.<chip>.bin, e.g. SomfyController.littlefs.esp32.bin] containing the littlefs data for the application then press the Upload File button.
'; if (this.isMobile()) { inst.innerHTML += `
WARNING
`; inst.innerHTML += '
This browser does not support automatic backups. It is highly recommended that you back up your configuration using the backup button before proceeding.
'; diff --git a/src/GitOTA.cpp b/src/GitOTA.cpp index 9b13d9c..9391624 100644 --- a/src/GitOTA.cpp +++ b/src/GitOTA.cpp @@ -43,7 +43,7 @@ void GitRelease::setReleaseProperty(const char *key, const char *val) { void GitRelease::setAssetProperty(const char *key, const char *val) { if(strcmp(key, "name") == 0) { //Serial.println(val); - if(strstr(val, "littlefs.bin")) this->hasFS = true; + if(isFsAsset(val)) this->hasFS = true; else if(strstr(val, "ino.esp32.bin")) { if(strlen(this->hwVersions)) strcat(this->hwVersions, ","); strcat(this->hwVersions, "32"); @@ -353,22 +353,16 @@ void GitUpdater::emitDownloadProgress(uint8_t num, size_t total, size_t loaded, sockEmit.loop(); webServer.loop(); } -void GitUpdater::setFirmwareFile() { +// The chip part of this board's release asset names. +static const char *chipName() { esp_chip_info_t ci; esp_chip_info(&ci); switch(ci.model) { - case esp_chip_model_t::CHIP_ESP32S3: - strcpy(this->currentFile, "SomfyController.ino.esp32s3.bin"); - break; - case esp_chip_model_t::CHIP_ESP32S2: - strcpy(this->currentFile, "SomfyController.ino.esp32s2.bin"); - break; - case esp_chip_model_t::CHIP_ESP32C3: - strcpy(this->currentFile, "SomfyController.ino.esp32c3.bin"); - break; - default: - strcpy(this->currentFile, "SomfyController.ino.esp32.bin"); - break; + case esp_chip_model_t::CHIP_ESP32S3: return "esp32s3"; + case esp_chip_model_t::CHIP_ESP32S2: return "esp32s2"; + case esp_chip_model_t::CHIP_ESP32C3: return "esp32c3"; + case esp_chip_model_t::CHIP_ESP32C6: return "esp32c6"; + default: return "esp32"; } } @@ -379,14 +373,14 @@ bool GitUpdater::beginUpdate(const char *version) { strcpy(this->targetRelease, version); this->emitUpdateCheck(); - this->setFirmwareFile(); + releaseAssetName(this->currentFile, sizeof(this->currentFile), "ino", chipName()); this->partition = U_FLASH; this->lockFS = this->cancelled = false; this->error = 0; this->error = this->downloadFile(); if(this->error == 0 && !this->cancelled) { somfy.commit(); - strcpy(this->currentFile, "SomfyController.littlefs.bin"); + releaseAssetName(this->currentFile, sizeof(this->currentFile), "littlefs", chipName()); this->partition = U_SPIFFS; this->lockFS = true; this->error = this->downloadFile(); @@ -405,8 +399,8 @@ bool GitUpdater::beginUpdate(const char *version) { return true; } bool GitUpdater::recoverFilesystem() { - sprintf(this->baseUrl, "https://github.com/rstrouse/ESPSomfy-RTS/releases/download/%s/", settings.fwVersion.name); - strcpy(this->currentFile, "SomfyController.littlefs.bin"); + sprintf(this->baseUrl, "https://github.com/cjkas/ESPSomfy-RTS/releases/download/%s/", settings.fwVersion.name); + releaseAssetName(this->currentFile, sizeof(this->currentFile), "littlefs", chipName()); this->status = GIT_UPDATING; this->partition = U_SPIFFS; this->lockFS = true; diff --git a/src/GitOTA.h b/src/GitOTA.h index 6996f83..7a02112 100644 --- a/src/GitOTA.h +++ b/src/GitOTA.h @@ -55,7 +55,6 @@ class GitUpdater { bool beginUpdate(const char *release); bool endUpdate(); int8_t downloadFile(); - void setFirmwareFile(); void setCurrentRelease(GitRepo &repo); void loop(); diff --git a/src/Utils.cpp b/src/Utils.cpp index 75c77f0..2651f2a 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -150,6 +150,14 @@ bool worthRoaming(bool connected, int currentRssi, int apRssi, int minGain) { bool otaProven(bool networkUp, unsigned long uptimeMs, unsigned long minUptimeMs) { return networkUp && uptimeMs >= minUptimeMs; } +bool releaseAssetName(char *buf, size_t size, const char *kind, const char *chip) { + int n = snprintf(buf, size, "SomfyController.%s.%s.bin", kind, chip); + return n >= 0 && (size_t)n < size; +} +bool isFsAsset(const char *name) { + size_t len = strlen(name); + return strstr(name, ".littlefs.") && len >= 4 && strcmp(name + len - 4, ".bin") == 0; +} const char *wifiAuthModeName(uint8_t authMode) { switch(authMode) { case 0: return "OPEN"; diff --git a/src/Utils.h b/src/Utils.h index 27c9ba9..723d9d5 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -86,6 +86,12 @@ heap_emit_t heapEmitTarget(uint8_t num, uint32_t sinceLastMs, uint32_t intervalM // update has proven itself: it has run for minUptimeMs and the network is // up. Until then a reset rolls back to the previous firmware. bool otaProven(bool networkUp, unsigned long uptimeMs, unsigned long minUptimeMs); +// A release asset's name: "SomfyController...bin", kind "ino" for +// the firmware or "littlefs" for the web UI image, chip e.g. "esp32s3". False +// when it doesn't fit in size. +bool releaseAssetName(char *buf, size_t size, const char *kind, const char *chip); +// Whether a release asset is a LittleFS image, for any chip. +bool isFsAsset(const char *name); // How well loop() keeps up: the passes it made per second and its longest // pass, over the window since the last memStatus broadcast. Only the loop // task calls record(), rate(), maxUs() and publish(). publish() closes the diff --git a/test/test_utils/test_utils.cpp b/test/test_utils/test_utils.cpp index b17d0e0..2e5db6e 100644 --- a/test/test_utils/test_utils.cpp +++ b/test/test_utils/test_utils.cpp @@ -272,6 +272,34 @@ static void test_otaProven_not_without_network() { TEST_ASSERT_FALSE(otaProven(false, 3600000, 60000)); } +/********************************************************************* + * releaseAssetName / isFsAsset + ********************************************************************/ +static void test_releaseAssetName_matches_the_release_workflow() { + // .github/workflows/build.yaml fwname and fsname. + char buf[64]; + TEST_ASSERT_TRUE(releaseAssetName(buf, sizeof(buf), "ino", "esp32")); + TEST_ASSERT_EQUAL_STRING("SomfyController.ino.esp32.bin", buf); + TEST_ASSERT_TRUE(releaseAssetName(buf, sizeof(buf), "littlefs", "esp32s3")); + TEST_ASSERT_EQUAL_STRING("SomfyController.littlefs.esp32s3.bin", buf); +} +static void test_releaseAssetName_too_small_buffer() { + char buf[16]; + TEST_ASSERT_FALSE(releaseAssetName(buf, sizeof(buf), "littlefs", "esp32c6")); + TEST_ASSERT_EQUAL(sizeof(buf) - 1, strlen(buf)); +} +static void test_isFsAsset_per_chip_images() { + TEST_ASSERT_TRUE(isFsAsset("SomfyController.littlefs.esp32.bin")); + TEST_ASSERT_TRUE(isFsAsset("SomfyController.littlefs.esp32c6.bin")); + TEST_ASSERT_TRUE(isFsAsset("SomfyController.littlefs.bin")); +} +static void test_isFsAsset_not_the_other_assets() { + TEST_ASSERT_FALSE(isFsAsset("SomfyController.ino.esp32.bin")); + TEST_ASSERT_FALSE(isFsAsset("SomfyController.onboard.esp32.bin.zip")); + TEST_ASSERT_FALSE(isFsAsset("SomfyController.littlefs.bin.sha256")); + TEST_ASSERT_FALSE(isFsAsset("")); +} + /********************************************************************* * wifiAuthModeName ********************************************************************/ @@ -402,6 +430,10 @@ int main(int argc, char **argv) { RUN_TEST(test_otaProven_after_the_minimum_uptime_with_network); RUN_TEST(test_otaProven_not_before_the_minimum_uptime); RUN_TEST(test_otaProven_not_without_network); + RUN_TEST(test_releaseAssetName_matches_the_release_workflow); + RUN_TEST(test_releaseAssetName_too_small_buffer); + RUN_TEST(test_isFsAsset_per_chip_images); + RUN_TEST(test_isFsAsset_not_the_other_assets); RUN_TEST(test_wifiAuthModeName_matches_the_idf_enum); RUN_TEST(test_wifiAuthModeName_unknown_past_the_shared_values); RUN_TEST(test_heapEmitTarget_one_client_always_gets_it);