mirror of
https://github.com/OpenEPaperLink/OpenEPaperLink.git
synced 2026-03-21 01:04:30 +01:00
Coprocessor OTA changes (#425)
OTA changes to support C6/H2 OTA updates from configured repo.
This commit is contained in:
62
.github/workflows/release.yml
vendored
62
.github/workflows/release.yml
vendored
@@ -5,6 +5,12 @@ on:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
env:
|
||||
INCLUDE_C6_H2: true
|
||||
INCLUDE_MINI_AP: false
|
||||
INCLUDE_Nano_AP: false
|
||||
INCLUDE_S2_Tag_Flasher: false
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-22.04
|
||||
@@ -41,30 +47,37 @@ jobs:
|
||||
run: |
|
||||
mkdir espbinaries
|
||||
|
||||
#- name: esp-idf build
|
||||
# uses: espressif/esp-idf-ci-action@v1
|
||||
# with:
|
||||
# esp_idf_version: latest
|
||||
# target: esp32c6
|
||||
# path: 'ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/'
|
||||
- name: build ESP32-C6 firmware
|
||||
if: ${{ env.INCLUDE_C6_H2 == 'true' }}
|
||||
uses: espressif/esp-idf-ci-action@v1
|
||||
with:
|
||||
esp_idf_version: latest
|
||||
target: esp32c6
|
||||
path: 'ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/'
|
||||
|
||||
# - name: esp-idf build
|
||||
# uses: espressif/esp-idf-ci-action@v1
|
||||
# with:
|
||||
# esp_idf_version: latest
|
||||
# target: esp32h2
|
||||
# path: 'ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/'
|
||||
- name: Add C6 files to release
|
||||
if: ${{ env.INCLUDE_C6_H2 == 'true' }}
|
||||
run: |
|
||||
cp /home/runner/work/OpenEPaperLink/OpenEPaperLink/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/build/OpenEPaperLink_esp32_C6.bin espbinaries/OpenEPaperLink_esp32_C6.bin
|
||||
cp /home/runner/work/OpenEPaperLink/OpenEPaperLink/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/build/bootloader/bootloader.bin espbinaries/bootloader_C6.bin
|
||||
cp /home/runner/work/OpenEPaperLink/OpenEPaperLink/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/build/partition_table/partition-table.bin espbinaries/partition-table_C6.bin
|
||||
cp /home/runner/work/OpenEPaperLink/OpenEPaperLink//binaries/ESP32-C6/firmware_C6.json espbinaries
|
||||
|
||||
#- name: Add C6 files to release
|
||||
# run: |
|
||||
# cp /home/runner/work/OpenEPaperLink/OpenEPaperLink/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/build/OpenEPaperLink_esp32_C6.bin espbinaries/OpenEPaperLink_esp32_C6.bin
|
||||
- name: build ESP32-H2 firmware
|
||||
if: ${{ env.INCLUDE_C6_H2 == 'true' }}
|
||||
uses: espressif/esp-idf-ci-action@v1
|
||||
with:
|
||||
esp_idf_version: latest
|
||||
target: esp32h2
|
||||
path: 'ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/'
|
||||
|
||||
#- name: Add H2 files to release
|
||||
# run: |
|
||||
# cd ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/
|
||||
# dir build
|
||||
# esptool.py --chip esp32h2 merge_bin -o merged-firmware.bin --flash_mode dio --flash_size 4MB --flash_freq 48m 0x0 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/OpenEPaperLink_esp32_H2.bin
|
||||
# cp merged-firmware.bin ../../espbinaries/OpenEPaperLink_esp32_H2.bin
|
||||
- name: Add H2 files to release
|
||||
if: ${{ env.INCLUDE_C6_H2 == 'true' }}
|
||||
run: |
|
||||
cp /home/runner/work/OpenEPaperLink/OpenEPaperLink/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/build/OpenEPaperLink_esp32_H2.bin espbinaries/OpenEPaperLink_esp32_H2.bin
|
||||
cp /home/runner/work/OpenEPaperLink/OpenEPaperLink/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/build/bootloader/bootloader.bin espbinaries/bootloader_H2.bin
|
||||
cp /home/runner/work/OpenEPaperLink/OpenEPaperLink/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/build/partition_table/partition-table.bin espbinaries/partition-table_H2.bin
|
||||
cp /home/runner/work/OpenEPaperLink/OpenEPaperLink//binaries/ESP32-H2/firmware_H2.json espbinaries
|
||||
|
||||
# - name: Zip web files
|
||||
# run: |
|
||||
@@ -72,6 +85,7 @@ jobs:
|
||||
# python gzip_wwwfiles.py
|
||||
|
||||
- name: Build firmware for OpenEPaperLink_Mini_AP
|
||||
if: ${{ env.INCLUDE_MINI_AP == 'true' }}
|
||||
run: |
|
||||
cd ESP32_AP-Flasher
|
||||
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=${{ github.ref_name }} -D SHA=$GITHUB_SHA"
|
||||
@@ -90,6 +104,7 @@ jobs:
|
||||
cp OpenEPaperLink_Mini_AP/merged-firmware.bin espbinaries/OpenEPaperLink_Mini_AP_full.bin
|
||||
|
||||
- name: Build firmware for OpenEPaperLink_Nano_AP
|
||||
if: ${{ env.INCLUDE_Nano_AP == 'true' }}
|
||||
run: |
|
||||
cd ESP32_AP-Flasher
|
||||
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=${{ github.ref_name }} -D SHA=$GITHUB_SHA"
|
||||
@@ -106,7 +121,6 @@ jobs:
|
||||
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink
|
||||
cp OpenEPaperLink_Nano_AP/firmware.bin espbinaries/OpenEPaperLink_Nano_AP.bin
|
||||
cp OpenEPaperLink_Nano_AP/merged-firmware.bin espbinaries/OpenEPaperLink_Nano_AP_full.bin
|
||||
|
||||
# - name: move files for big APs
|
||||
# run: |
|
||||
# cp -a binaries/ESP32-C6/. ESP32_AP-Flasher/data/
|
||||
@@ -128,7 +142,6 @@ jobs:
|
||||
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink
|
||||
cp OpenEPaperLink_AP_and_Flasher/firmware.bin espbinaries/OpenEPaperLink_AP_and_Flasher.bin
|
||||
cp OpenEPaperLink_AP_and_Flasher/merged-firmware.bin espbinaries/OpenEPaperLink_AP_and_Flasher_full.bin
|
||||
|
||||
- name: Build firmware for ESP32_S3_16_8_YELLOW_AP
|
||||
run: |
|
||||
cd ESP32_AP-Flasher
|
||||
@@ -254,7 +267,6 @@ jobs:
|
||||
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink
|
||||
cp BLE_ONLY_AP/firmware.bin espbinaries/BLE_ONLY_AP.bin
|
||||
cp BLE_ONLY_AP/merged-firmware.bin espbinaries/BLE_ONLY_AP_full.bin
|
||||
|
||||
- name: generate release json file
|
||||
run: |
|
||||
mkdir jsonfiles
|
||||
@@ -272,6 +284,7 @@ jobs:
|
||||
# this is down here intentionally to be able to modify the binary folder before adding it to the Tag_Flasher later (ota binaries can be removed)
|
||||
|
||||
- name: Build firmware for Tag_Flasher
|
||||
if: ${{ env.INCLUDE_S2_Tag_Flasher == 'true' }}
|
||||
run: |
|
||||
cd Tag_Flasher/ESP32_Flasher
|
||||
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=${{ github.ref_name }} -D SHA=$GITHUB_SHA"
|
||||
@@ -288,7 +301,6 @@ jobs:
|
||||
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink
|
||||
cp S2_Tag_Flasher/firmware.bin espbinaries/S2_Tag_Flasher.bin
|
||||
cp S2_Tag_Flasher/merged-firmware.bin espbinaries/S2_Tag_Flasher_full.bin
|
||||
|
||||
- name: Add esp bins to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,4 +1,16 @@
|
||||
#include <Arduino.h>
|
||||
#include <LittleFS.h>
|
||||
|
||||
bool doC6flash(uint8_t doDownload);
|
||||
#if defined HAS_H2
|
||||
#define SHORT_CHIP_NAME "H2"
|
||||
#define OTA_BIN_DIR "ESP32-H2"
|
||||
#define ESP_CHIP_TYPE ESP32H2_CHIP
|
||||
#elif defined HAS_TSLR
|
||||
#define SHORT_CHIP_NAME "TSLR"
|
||||
#elif defined C6_OTA_FLASHING
|
||||
#define SHORT_CHIP_NAME "C6"
|
||||
#define OTA_BIN_DIR "ESP32-C6"
|
||||
#define ESP_CHIP_TYPE ESP32C6_CHIP
|
||||
#endif
|
||||
|
||||
bool FlashC6_H2(const char *Url);
|
||||
|
||||
@@ -180,24 +180,29 @@ build_flags =
|
||||
-D HAS_TFT
|
||||
-D HAS_LILYGO_TPANEL
|
||||
-D CORE_DEBUG_LEVEL=1
|
||||
-D ARDUINO_USB_CDC_ON_BOOT=1
|
||||
-D ARDUINO_USB_CDC_ON_BOOT=1
|
||||
-D CONFIG_ESP32S3_SPIRAM_SUPPORT=1
|
||||
-D CONFIG_SPIRAM_USE_MALLOC=1
|
||||
-D POWER_NO_SOFT_POWER
|
||||
-D BOARD_HAS_PSRAM
|
||||
-D CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
|
||||
-D HAS_BLE_WRITER
|
||||
-D FLASHER_AP_SS=-1
|
||||
-D FLASHER_AP_SS=-1
|
||||
-D FLASHER_AP_CLK=-1
|
||||
-D FLASHER_AP_MOSI=-1
|
||||
-D FLASHER_AP_MISO=-1
|
||||
-D FLASHER_AP_RESET=34
|
||||
-D FLASHER_AP_POWER={-1}
|
||||
-D FLASHER_AP_TEST=-1
|
||||
; NB: FLASHER_DEBUG_TXD and FLASHER_DEBUG_RXD use the same pins as
|
||||
; FLASHER_AP_TXD and FLASHER_AP_RXD but the naming convention is different
|
||||
-D FLASHER_DEBUG_SHARED
|
||||
-D FLASHER_DEBUG_PORT=1
|
||||
-D FLASHER_AP_TXD=48
|
||||
-D FLASHER_DEBUG_RXD=48
|
||||
-D FLASHER_AP_RXD=47
|
||||
-D FLASHER_DEBUG_TXD=43
|
||||
-D FLASHER_DEBUG_RXD=44
|
||||
-D FLASHER_DEBUG_TXD=47
|
||||
;
|
||||
-D FLASHER_DEBUG_PROG=33
|
||||
-D FLASHER_LED=-1
|
||||
-D TFT_HEIGHT=480
|
||||
@@ -207,6 +212,8 @@ build_flags =
|
||||
-D SERIAL_FLASHER_INTERFACE_UART=1
|
||||
-D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=200
|
||||
-D SERIAL_FLASHER_RESET_HOLD_TIME_MS=200
|
||||
-D HAS_H2
|
||||
-D C6_OTA_FLASHING
|
||||
-D HAS_SUBGHZ
|
||||
build_src_filter =
|
||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>
|
||||
|
||||
@@ -9,6 +9,14 @@
|
||||
#include "storage.h"
|
||||
#include "tag_db.h"
|
||||
#include "web.h"
|
||||
#include "espflasher.h"
|
||||
#include "util.h"
|
||||
|
||||
#define LOG(format, ... ) Serial.printf(format,## __VA_ARGS__)
|
||||
|
||||
#ifndef FLASHER_DEBUG_PORT
|
||||
#define FLASHER_DEBUG_PORT 2
|
||||
#endif
|
||||
|
||||
esp_loader_error_t connect_to_target(uint32_t higher_transmission_rate) {
|
||||
esp_loader_connect_args_t connect_config = ESP_LOADER_CONNECT_DEFAULT();
|
||||
@@ -120,150 +128,197 @@ esp_loader_error_t flash_binary(String &file_path, size_t address) {
|
||||
|
||||
bool downloadAndWriteBinary(String &filename, const char *url) {
|
||||
HTTPClient binaryHttp;
|
||||
Serial.println(url);
|
||||
bool Ret = false;
|
||||
bool bHaveFsMutex = false;
|
||||
|
||||
LOG("downloadAndWriteBinary: url %s\n",url);
|
||||
binaryHttp.begin(url);
|
||||
binaryHttp.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS);
|
||||
int binaryResponseCode = binaryHttp.GET();
|
||||
Serial.println(binaryResponseCode);
|
||||
if (binaryResponseCode == HTTP_CODE_OK) {
|
||||
do {
|
||||
int binaryResponseCode = binaryHttp.GET();
|
||||
if(binaryResponseCode != HTTP_CODE_OK) {
|
||||
wsSerial("http error " + String(binaryResponseCode) + " fetching " + String(url));
|
||||
break;
|
||||
}
|
||||
int contentLength = binaryHttp.getSize();
|
||||
Serial.println(contentLength);
|
||||
LOG("contentLength %d\r\n",contentLength);
|
||||
if(contentLength < 0) {
|
||||
wsSerial("Couldn't get contentLength");
|
||||
break;
|
||||
}
|
||||
xSemaphoreTake(fsMutex, portMAX_DELAY);
|
||||
bHaveFsMutex = true;
|
||||
File file = contentFS->open(filename, "wb");
|
||||
if (file) {
|
||||
wsSerial("downloading " + String(filename));
|
||||
WiFiClient *stream = binaryHttp.getStreamPtr();
|
||||
uint8_t buffer[1024];
|
||||
size_t totalBytesRead = 0;
|
||||
time_t timeOut = millis() + 5000;
|
||||
// while (stream->available()) {
|
||||
while (millis() < timeOut) {
|
||||
size_t bytesRead = stream->readBytes(buffer, sizeof(buffer));
|
||||
if(!file) {
|
||||
wsSerial("file open error " + String(filename));
|
||||
break;
|
||||
}
|
||||
wsSerial("downloading " + String(filename));
|
||||
WiFiClient *stream = binaryHttp.getStreamPtr();
|
||||
uint8_t buffer[1024];
|
||||
size_t totalBytesRead = 0;
|
||||
// timeout if we don't average at least 1k bytes/second
|
||||
unsigned long timeOut = millis() + contentLength;
|
||||
while(stream->connected() && totalBytesRead < contentLength) {
|
||||
size_t bytesRead;
|
||||
size_t bytesToRead;
|
||||
if(stream->available()) {
|
||||
bytesToRead = min(sizeof(buffer), (size_t) stream->available());
|
||||
bytesRead = stream->readBytes(buffer, bytesToRead);
|
||||
if(bytesRead == 0 || millis() > timeOut) {
|
||||
wsSerial("Download time out");
|
||||
break;
|
||||
}
|
||||
file.write(buffer, bytesRead);
|
||||
totalBytesRead += bytesRead;
|
||||
if (totalBytesRead == contentLength) break;
|
||||
vTaskDelay(1 / portTICK_PERIOD_MS);
|
||||
} else {
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
}
|
||||
file.close();
|
||||
xSemaphoreGive(fsMutex);
|
||||
binaryHttp.end();
|
||||
|
||||
file = contentFS->open(filename, "r");
|
||||
if (file) {
|
||||
if (totalBytesRead == contentLength || (contentLength == 0 && file.size() > 0)) {
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
wsSerial("Download failed, " + String(file.size()) + " bytes");
|
||||
file.close();
|
||||
}
|
||||
} else {
|
||||
xSemaphoreGive(fsMutex);
|
||||
wsSerial("file open error " + String(filename));
|
||||
}
|
||||
} else {
|
||||
wsSerial("http error " + String(binaryResponseCode) + " fetching " + String(url));
|
||||
}
|
||||
file.close();
|
||||
|
||||
if(!stream->connected()) {
|
||||
wsSerial("Connection dropped during transfer");
|
||||
break;
|
||||
}
|
||||
file = contentFS->open(filename, "r");
|
||||
if(!file) {
|
||||
wsSerial("file open error " + String(filename));
|
||||
break;
|
||||
}
|
||||
if(file.size() == contentLength) {
|
||||
Ret = true;
|
||||
} else {
|
||||
wsSerial("Download failed, " + String(file.size()) + " bytes");
|
||||
}
|
||||
file.close();
|
||||
} while(false);
|
||||
binaryHttp.setReuse(false);
|
||||
binaryHttp.end();
|
||||
return false;
|
||||
if(bHaveFsMutex) {
|
||||
xSemaphoreGive(fsMutex);
|
||||
}
|
||||
|
||||
return Ret;
|
||||
}
|
||||
|
||||
bool doC6flash(uint8_t doDownload) {
|
||||
String filenameFirmwareLocal = "/firmware.json";
|
||||
bool FlashC6_H2(const char *RepoUrl) {
|
||||
String JsonFilename = "/firmware_" SHORT_CHIP_NAME ".json" ;
|
||||
bool Ret = false;
|
||||
bool bLoaderInit = false;
|
||||
bool bDownload = strlen(RepoUrl) > 0;
|
||||
int retry;
|
||||
DynamicJsonDocument jsonDoc(1024);
|
||||
if (doDownload) {
|
||||
const String githubUrl = "https://raw.githubusercontent.com/" + config.repo + "/master/binaries/ESP32-C6/firmware.json";
|
||||
if (downloadAndWriteBinary(filenameFirmwareLocal, githubUrl.c_str())) {
|
||||
File readfile = contentFS->open(filenameFirmwareLocal, "r");
|
||||
if (!readfile) {
|
||||
Serial.println("load firmware.json: Failed to open file");
|
||||
return false;
|
||||
}
|
||||
DeserializationError jsonError = deserializeJson(jsonDoc, readfile);
|
||||
|
||||
if (!jsonError) {
|
||||
JsonArray jsonArray = jsonDoc.as<JsonArray>();
|
||||
for (JsonObject obj : jsonArray) {
|
||||
String filename = "/" + obj["filename"].as<String>();
|
||||
// String binaryUrl = "https://raw.githubusercontent.com/" + config.repo + "/master/binaries/ESP32-C6" + String(filename);
|
||||
String binaryUrl = "http://www.openepaperlink.eu/binaries/ESP32-C6" + String(filename);
|
||||
for (int retry = 0; retry < 10; retry++) {
|
||||
if (downloadAndWriteBinary(filename, binaryUrl.c_str())) {
|
||||
break;
|
||||
}
|
||||
wsSerial("Retry " + String(retry));
|
||||
if (retry < 9) {
|
||||
delay(1000);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
wsSerial("json error fetching " + String(githubUrl));
|
||||
return false;
|
||||
LOG("%s#%d: ",__FUNCTION__,__LINE__); util::printHeap();
|
||||
|
||||
do {
|
||||
if(bDownload) {
|
||||
String FileUrl = RepoUrl + JsonFilename;
|
||||
if(!downloadAndWriteBinary(JsonFilename, FileUrl.c_str())) {
|
||||
LOG("%s#%d: ",__FUNCTION__,__LINE__); util::printHeap();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
File readfile = contentFS->open(filenameFirmwareLocal, "r");
|
||||
if (!readfile) {
|
||||
Serial.println("load local firmware.json: Failed to open file");
|
||||
return false;
|
||||
|
||||
File readfile = contentFS->open(JsonFilename, "r");
|
||||
if(!readfile) {
|
||||
Serial.println("load " + JsonFilename + ": Failed to open file");
|
||||
break;
|
||||
}
|
||||
DeserializationError jsonError = deserializeJson(jsonDoc, readfile);
|
||||
}
|
||||
|
||||
const loader_esp32_config_t config = {
|
||||
.baud_rate = 115200,
|
||||
.uart_port = 2,
|
||||
.uart_rx_pin = FLASHER_DEBUG_TXD,
|
||||
.uart_tx_pin = FLASHER_DEBUG_RXD,
|
||||
.reset_trigger_pin = FLASHER_AP_RESET,
|
||||
.gpio0_trigger_pin = FLASHER_DEBUG_PROG,
|
||||
};
|
||||
if(jsonError) {
|
||||
wsSerial(String("json error parsing") + JsonFilename);
|
||||
break;
|
||||
}
|
||||
|
||||
if (loader_port_esp32_init(&config) != ESP_LOADER_SUCCESS) {
|
||||
wsSerial("Serial initialization failed");
|
||||
loader_port_esp32_deinit();
|
||||
return false;
|
||||
}
|
||||
if(!bDownload) {
|
||||
Ret = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (connect_to_target(115200) == ESP_LOADER_SUCCESS) {
|
||||
if (esp_loader_get_target() == ESP32C6_CHIP) {
|
||||
wsSerial("Connected to ESP32-C6");
|
||||
int maxRetries = 5;
|
||||
esp_loader_error_t err;
|
||||
JsonArray jsonArray = jsonDoc.as<JsonArray>();
|
||||
for(JsonObject obj : jsonArray) {
|
||||
String filename = "/" + obj["filename"].as<String>();
|
||||
String binaryUrl = RepoUrl + filename;
|
||||
|
||||
JsonArray jsonArray = jsonDoc.as<JsonArray>();
|
||||
for (JsonObject obj : jsonArray) {
|
||||
String filename = "/" + obj["filename"].as<String>();
|
||||
const char *addressStr = obj["address"];
|
||||
uint32_t address = strtoul(addressStr, NULL, 16);
|
||||
|
||||
for (int retry = 0; retry < maxRetries; retry++) {
|
||||
err = flash_binary(filename, address);
|
||||
if (err == ESP_LOADER_SUCCESS) break;
|
||||
Serial.printf("Flash failed with error %d. Retrying...\n", err);
|
||||
for(retry = 0; retry < 10; retry++) {
|
||||
if(downloadAndWriteBinary(filename, binaryUrl.c_str())) {
|
||||
break;
|
||||
}
|
||||
wsSerial("Retry " + String(retry));
|
||||
if(retry < 9) {
|
||||
delay(1000);
|
||||
}
|
||||
if (err != ESP_LOADER_SUCCESS) {
|
||||
loader_port_esp32_deinit();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Serial.println("Done!");
|
||||
} else {
|
||||
wsSerial("Connected to wrong ESP32 type");
|
||||
loader_port_esp32_deinit();
|
||||
return false;
|
||||
if(retry == 10) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
wsSerial("Connection to the C6 failed");
|
||||
if(retry < 10) {
|
||||
Ret = true;
|
||||
}
|
||||
} while(false);
|
||||
|
||||
if(Ret == true) do {
|
||||
Ret = false;
|
||||
const loader_esp32_config_t config = {
|
||||
.baud_rate = 115200,
|
||||
.uart_port = FLASHER_DEBUG_PORT,
|
||||
.uart_rx_pin = FLASHER_DEBUG_TXD,
|
||||
.uart_tx_pin = FLASHER_DEBUG_RXD,
|
||||
.reset_trigger_pin = FLASHER_AP_RESET,
|
||||
.gpio0_trigger_pin = FLASHER_DEBUG_PROG,
|
||||
};
|
||||
|
||||
bLoaderInit = true;
|
||||
if(loader_port_esp32_init(&config) != ESP_LOADER_SUCCESS) {
|
||||
wsSerial("Serial initialization failed");
|
||||
break;
|
||||
}
|
||||
|
||||
if(connect_to_target(115200) != ESP_LOADER_SUCCESS) {
|
||||
wsSerial("Connection to the " SHORT_CHIP_NAME " failed");
|
||||
break;
|
||||
}
|
||||
|
||||
if(esp_loader_get_target() != ESP_CHIP_TYPE) {
|
||||
wsSerial("Connected to wrong ESP32 type");
|
||||
break;
|
||||
}
|
||||
wsSerial("Connected to ESP32-" SHORT_CHIP_NAME);
|
||||
int maxRetries = 5;
|
||||
esp_loader_error_t err;
|
||||
|
||||
JsonArray jsonArray = jsonDoc.as<JsonArray>();
|
||||
for(JsonObject obj : jsonArray) {
|
||||
String filename = "/" + obj["filename"].as<String>();
|
||||
const char *addressStr = obj["address"];
|
||||
uint32_t address = strtoul(addressStr, NULL, 16);
|
||||
|
||||
for(int retry = 0; retry < maxRetries; retry++) {
|
||||
err = flash_binary(filename, address);
|
||||
if(err == ESP_LOADER_SUCCESS) {
|
||||
Ret = true;
|
||||
break;
|
||||
}
|
||||
Serial.printf("Flash failed with error %d. Retrying...\n", err);
|
||||
delay(1000);
|
||||
}
|
||||
if(err != ESP_LOADER_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Serial.println("Done!");
|
||||
} while(false);
|
||||
|
||||
if(bLoaderInit) {
|
||||
loader_port_esp32_deinit();
|
||||
return false;
|
||||
}
|
||||
loader_port_esp32_deinit();
|
||||
return true;
|
||||
|
||||
LOG("%s#%d: ",__FUNCTION__,__LINE__); util::printHeap();
|
||||
return Ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <MD5Builder.h>
|
||||
#include <Update.h>
|
||||
|
||||
#include "flasher.h"
|
||||
#include "espflasher.h"
|
||||
#include "leds.h"
|
||||
#include "serialap.h"
|
||||
@@ -15,6 +16,7 @@
|
||||
#include "util.h"
|
||||
#include "web.h"
|
||||
|
||||
|
||||
#ifndef BUILD_ENV_NAME
|
||||
#define BUILD_ENV_NAME unknown
|
||||
#endif
|
||||
@@ -30,6 +32,8 @@
|
||||
|
||||
#define STR_IMPL(x) #x
|
||||
#define STR(x) STR_IMPL(x)
|
||||
#define LOG(format, ... ) Serial.printf(format,## __VA_ARGS__)
|
||||
|
||||
|
||||
void handleSysinfoRequest(AsyncWebServerRequest* request) {
|
||||
StaticJsonDocument<250> doc;
|
||||
@@ -41,12 +45,20 @@ void handleSysinfoRequest(AsyncWebServerRequest* request) {
|
||||
doc["psramsize"] = ESP.getPsramSize();
|
||||
doc["flashsize"] = ESP.getFlashChipSize();
|
||||
doc["rollback"] = Update.canRollBack();
|
||||
#if defined C6_OTA_FLASHING
|
||||
doc["hasC6"] = 1;
|
||||
doc["C6version"] = apInfo.version;
|
||||
#else
|
||||
doc["ap_version"] = apInfo.version;
|
||||
|
||||
doc["hasC6"] = 0;
|
||||
doc["hasH2"] = 0;
|
||||
doc["hasTslr"] = 0;
|
||||
|
||||
#if defined HAS_H2
|
||||
doc["hasH2"] = 1;
|
||||
#elif defined HAS_TSLR
|
||||
doc["hasTslr"] = 1;
|
||||
#elif defined C6_OTA_FLASHING
|
||||
doc["hasC6"] = 1;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_EXT_FLASHER
|
||||
doc["hasFlasher"] = 1;
|
||||
#else
|
||||
@@ -290,22 +302,26 @@ void handleRollback(AsyncWebServerRequest* request) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef C6_OTA_FLASHING
|
||||
void C6firmwareUpdateTask(void* parameter) {
|
||||
uint8_t doDownload = *((uint8_t*)parameter);
|
||||
String *Url = reinterpret_cast<String *>(parameter);
|
||||
LOG("C6firmwareUpdateTask: url '%s'\n",Url->c_str());
|
||||
wsSerial("Stopping AP service");
|
||||
|
||||
setAPstate(false, AP_STATE_FLASHING);
|
||||
config.runStatus = RUNSTATUS_STOP;
|
||||
#ifndef FLASHER_DEBUG_SHARED
|
||||
extern bool rxSerialStopTask2;
|
||||
rxSerialStopTask2 = true;
|
||||
#endif
|
||||
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||
Serial1.end();
|
||||
|
||||
wsSerial("C6 flash starting");
|
||||
wsSerial(SHORT_CHIP_NAME " flash starting");
|
||||
|
||||
bool result = doC6flash(doDownload);
|
||||
bool result = FlashC6_H2(Url->c_str());
|
||||
|
||||
wsSerial("C6 flash end");
|
||||
wsSerial(SHORT_CHIP_NAME " flash end");
|
||||
|
||||
if (result) {
|
||||
setAPstate(false, AP_STATE_OFFLINE);
|
||||
@@ -315,12 +331,13 @@ void C6firmwareUpdateTask(void* parameter) {
|
||||
|
||||
wsSerial("starting monitor");
|
||||
Serial1.begin(115200, SERIAL_8N1, FLASHER_AP_RXD, FLASHER_AP_TXD);
|
||||
#ifndef FLASHER_DEBUG_SHARED
|
||||
rxSerialStopTask2 = false;
|
||||
#ifdef FLASHER_DEBUG_RXD
|
||||
xTaskCreate(rxSerialTask2, "rxSerialTask2", 1750, NULL, 2, NULL);
|
||||
#endif
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
|
||||
apInfo.version = 0;
|
||||
wsSerial("resetting AP");
|
||||
APTagReset();
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
@@ -328,23 +345,47 @@ void C6firmwareUpdateTask(void* parameter) {
|
||||
wsSerial("bringing AP online");
|
||||
if (bringAPOnline()) config.runStatus = RUNSTATUS_RUN;
|
||||
|
||||
wsSerial("Finished!");
|
||||
} else {
|
||||
wsSerial("Flashing failed. :-(");
|
||||
// Wait for version info to arrive
|
||||
vTaskDelay(50 / portTICK_PERIOD_MS);
|
||||
if(apInfo.version == 0) {
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (result) {
|
||||
wsSerial("Finished!");
|
||||
char buffer[50];
|
||||
snprintf(buffer,sizeof(buffer),
|
||||
"ESP32-" SHORT_CHIP_NAME " version is now %04x",apInfo.version);
|
||||
wsSerial(String(buffer));
|
||||
}
|
||||
else if(apInfo.version == 0) {
|
||||
wsSerial("AP failed failed to come online. :-(");
|
||||
}
|
||||
else {
|
||||
wsSerial("Flashing failed. :-(");
|
||||
}
|
||||
delete Url;
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void handleUpdateC6(AsyncWebServerRequest* request) {
|
||||
#if defined C6_OTA_FLASHING
|
||||
uint8_t doDownload = 1;
|
||||
if (request->hasParam("download", true)) {
|
||||
doDownload = atoi(request->getParam("download", true)->value().c_str());
|
||||
if (request->hasParam("url",true)) {
|
||||
String *Url = new String(request->getParam("url",true)->value());
|
||||
xTaskCreate(C6firmwareUpdateTask, "OTAUpdateTask", 6400, Url, 10, NULL);
|
||||
request->send(200, "Ok");
|
||||
}
|
||||
xTaskCreate(C6firmwareUpdateTask, "OTAUpdateTask", 6144, &doDownload, 10, NULL);
|
||||
request->send(200, "Ok");
|
||||
else {
|
||||
LOG("Sending bad request");
|
||||
request->send(400, "Bad request");
|
||||
}
|
||||
#elif defined(SHORT_CHIP_NAME)
|
||||
request->send(400, SHORT_CHIP_NAME " flashing not implemented");
|
||||
#else
|
||||
request->send(400, "C6 flashing not implemented");
|
||||
request->send(400, "C6/H2 flashing not implemented");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#include "web.h"
|
||||
#include "zbs_interface.h"
|
||||
|
||||
#define LOG(format, ... ) printf(format,## __VA_ARGS__)
|
||||
|
||||
QueueHandle_t rxCmdQueue;
|
||||
SemaphoreHandle_t txActive;
|
||||
|
||||
@@ -25,7 +27,9 @@ SemaphoreHandle_t txActive;
|
||||
volatile uint8_t cmdReplyValue = CMD_REPLY_WAIT;
|
||||
|
||||
#define AP_SERIAL_PORT Serial1
|
||||
#ifndef FLASHER_DEBUG_SHARED
|
||||
volatile bool rxSerialStopTask2 = false;
|
||||
#endif
|
||||
|
||||
uint8_t channelList[6];
|
||||
struct espSetChannelPower curChannel = {0, 11, 10};
|
||||
@@ -42,6 +46,17 @@ struct espSetChannelPower curChannel = {0, 11, 10};
|
||||
volatile uint32_t lastAPActivity = 0;
|
||||
struct APInfoS apInfo;
|
||||
|
||||
enum ApSerialState {
|
||||
SERIAL_STATE_NONE,
|
||||
SERIAL_STATE_INITIALIZED,
|
||||
SERIAL_STATE_STARTING,
|
||||
SERIAL_STATE_RUNNING,
|
||||
SERIAL_STATE_STOP,
|
||||
SERIAL_STATE_STOPPED
|
||||
};
|
||||
|
||||
volatile ApSerialState gSerialTaskState;
|
||||
|
||||
struct rxCmd {
|
||||
uint8_t* data;
|
||||
uint8_t len;
|
||||
@@ -156,6 +171,21 @@ void setAPstate(bool isOnline, uint8_t state) {
|
||||
rgbIdlePeriod = (isOnline ? 767 : 255);
|
||||
if (isOnline) rgbIdle();
|
||||
#endif
|
||||
#ifdef FLASHER_DEBUG_SHARED
|
||||
// Flasher shares port with AP comms
|
||||
if(state == AP_STATE_FLASHING) {
|
||||
LOG("Shared COM port, gSerialTaskState %d\n",gSerialTaskState);
|
||||
gSerialTaskState = SERIAL_STATE_STOP;
|
||||
for(int i = 0; i < 100; i++) {
|
||||
vTaskDelay(1 / portTICK_RATE_MS);
|
||||
if(gSerialTaskState == SERIAL_STATE_STOPPED) {
|
||||
gSerialTaskState = SERIAL_STATE_NONE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
LOG("gSerialTaskState %d\n",gSerialTaskState);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Reset the tag
|
||||
@@ -435,7 +465,9 @@ void rxSerialTask(void* parameter) {
|
||||
static char lastchar = 0;
|
||||
static uint8_t charindex = 0;
|
||||
|
||||
while (1) {
|
||||
gSerialTaskState = SERIAL_STATE_RUNNING;
|
||||
LOG("rxSerialTask starting\n");
|
||||
while (gSerialTaskState == SERIAL_STATE_RUNNING) {
|
||||
while (AP_SERIAL_PORT.available()) {
|
||||
lastchar = AP_SERIAL_PORT.read();
|
||||
switch (RXState) {
|
||||
@@ -666,9 +698,14 @@ void rxSerialTask(void* parameter) {
|
||||
}
|
||||
vTaskDelay(1 / portTICK_PERIOD_MS);
|
||||
} // end of while(1)
|
||||
|
||||
AP_SERIAL_PORT.end(false);
|
||||
gSerialTaskState = SERIAL_STATE_STOPPED;
|
||||
LOG("rxSerialTask stopped\n");
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
#ifdef FLASHER_DEBUG_RXD
|
||||
#if defined(FLASHER_DEBUG_RXD) && !defined(FLASHER_DEBUG_SHARED)
|
||||
void rxSerialTask2(void* parameter) {
|
||||
char lastchar = 0;
|
||||
time_t startTime = millis();
|
||||
@@ -747,11 +784,29 @@ void segmentedShowIp() {
|
||||
}
|
||||
|
||||
bool bringAPOnline() {
|
||||
#ifdef BLE_ONLY
|
||||
#ifdef BLE_ONLY
|
||||
apInfo.state = AP_STATE_NORADIO;
|
||||
#endif
|
||||
#endif
|
||||
if (apInfo.state == AP_STATE_NORADIO) return true;
|
||||
if (apInfo.state == AP_STATE_FLASHING) return false;
|
||||
|
||||
if(gSerialTaskState != SERIAL_STATE_INITIALIZED) {
|
||||
#if (AP_PROCESS_PORT == FLASHER_AP_PORT)
|
||||
AP_SERIAL_PORT.begin(115200, SERIAL_8N1, FLASHER_AP_RXD, FLASHER_AP_TXD);
|
||||
#elif defined(HAS_EXT_FLASHER)
|
||||
#if (AP_PROCESS_PORT == FLASHER_EXT_PORT)
|
||||
AP_SERIAL_PORT.begin(115200, SERIAL_8N1, FLASHER_EXT_RXD, FLASHER_EXT_TXD);
|
||||
#elif (AP_PROCESS_PORT == FLASHER_ALTRADIO_PORT)
|
||||
AP_SERIAL_PORT.begin(115200, SERIAL_8N1, FLASHER_AP_RXD, FLASHER_AP_TXD);
|
||||
#endif
|
||||
#endif
|
||||
gSerialTaskState = SERIAL_STATE_INITIALIZED;
|
||||
}
|
||||
if(gSerialTaskState != SERIAL_STATE_RUNNING) {
|
||||
gSerialTaskState = SERIAL_STATE_STARTING;
|
||||
xTaskCreate(rxSerialTask, "rxSerialTask", 1750, NULL, 11, NULL);
|
||||
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||
}
|
||||
setAPstate(false, AP_STATE_OFFLINE);
|
||||
// try without rebooting
|
||||
AP_SERIAL_PORT.updateBaudRate(115200);
|
||||
@@ -823,25 +878,12 @@ void APTask(void* parameter) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if (AP_PROCESS_PORT == FLASHER_AP_PORT)
|
||||
AP_SERIAL_PORT.begin(115200, SERIAL_8N1, FLASHER_AP_RXD, FLASHER_AP_TXD);
|
||||
#endif
|
||||
#ifdef HAS_EXT_FLASHER
|
||||
#if (AP_PROCESS_PORT == FLASHER_EXT_PORT)
|
||||
AP_SERIAL_PORT.begin(115200, SERIAL_8N1, FLASHER_EXT_RXD, FLASHER_EXT_TXD);
|
||||
#endif
|
||||
#if (AP_PROCESS_PORT == FLASHER_ALTRADIO_PORT)
|
||||
AP_SERIAL_PORT.begin(115200, SERIAL_8N1, FLASHER_AP_RXD, FLASHER_AP_TXD);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
xTaskCreate(rxCmdProcessor, "rxCmdProcessor", 6000, NULL, 15, NULL);
|
||||
xTaskCreate(rxSerialTask, "rxSerialTask", 1750, NULL, 11, NULL);
|
||||
#ifdef FLASHER_DEBUG_RXD
|
||||
#if defined(FLASHER_DEBUG_RXD) && !defined(FLASHER_DEBUG_SHARED)
|
||||
xTaskCreate(rxSerialTask2, "rxSerialTask2", 1750, NULL, 2, NULL);
|
||||
#endif
|
||||
|
||||
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||
#endif
|
||||
bringAPOnline();
|
||||
|
||||
#ifndef C6_OTA_FLASHING
|
||||
|
||||
@@ -514,13 +514,21 @@ void init_web() {
|
||||
UDPcomm udpsync;
|
||||
udpsync.getAPList();
|
||||
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
||||
String HasC6 = "0";
|
||||
String HasH2 = "0";
|
||||
String HasTSLR = "0";
|
||||
|
||||
response->print("{");
|
||||
#ifdef C6_OTA_FLASHING
|
||||
response->print("\"C6\": \"1\", ");
|
||||
#else
|
||||
response->print("\"C6\": \"0\", ");
|
||||
#ifdef HAS_H2
|
||||
HasH2 = "1";
|
||||
#elif defined(HAS_TSLR)
|
||||
HasTSLR = "1";
|
||||
#elif defined(C6_OTA_FLASHING)
|
||||
HasC6 = "1";
|
||||
#endif
|
||||
response->print("\"C6\": \"" + HasC6 + "\", ");
|
||||
response->print("\"H2\": \"" + HasH2 + "\", ");
|
||||
response->print("\"TLSR\": \"" + HasTSLR + "\", ");
|
||||
#ifdef SAVE_SPACE
|
||||
response->print("\"savespace\": \"1\", ");
|
||||
#else
|
||||
|
||||
@@ -522,7 +522,10 @@ options:
|
||||
<button id="confirmSelectRepo">Confirm</button><button id="cancelSelectRepo">Cancel</button>
|
||||
</div>
|
||||
<h4>Releases</h4>
|
||||
<div id="releasetable"></div>
|
||||
<div id="releasetable" class="releasetable"></div>
|
||||
<h4 id="radio_release_title"></h4>
|
||||
<div id="radio_releasetable" class="releasetable"></div>
|
||||
<div id="radio_releasetable1" class="releasetable"></div>
|
||||
<h4>Other actions</h4>
|
||||
<div>
|
||||
<p id="rollbackOption" style="display:none">
|
||||
|
||||
@@ -825,37 +825,37 @@ h4 {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#releasetable {
|
||||
.releasetable {
|
||||
margin: 10px 0px;
|
||||
}
|
||||
|
||||
#releasetable table {
|
||||
.releasetable table {
|
||||
border-spacing: 1px;
|
||||
}
|
||||
|
||||
#releasetable th {
|
||||
.releasetable th {
|
||||
text-align: left;
|
||||
background-color: #ffffff;
|
||||
padding: 1px 5px;
|
||||
}
|
||||
|
||||
#releasetable td {
|
||||
.releasetable td {
|
||||
background-color: #ffffff;
|
||||
padding: 1px 5px;
|
||||
min-width: 70px;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
#releasetable td:nth-child(2) {
|
||||
.releasetable td:nth-child(2) {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#releasetable button {
|
||||
.releasetable button {
|
||||
padding: 3px 10px;
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
|
||||
#releasetable button:hover {
|
||||
.releasetable button:hover {
|
||||
background-color: #a0a0a0;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,10 +54,9 @@ window.addEventListener("loadConfig", function () {
|
||||
$(".logo").innerHTML = data.alias;
|
||||
this.document.title = data.alias;
|
||||
}
|
||||
if (data.C6 == 1) {
|
||||
if (data.C6 == 1 || (data.H2 && data.H2 == 1)) {
|
||||
var optionToRemove = $("#apcfgchid").querySelector('option[value="27"]');
|
||||
if (optionToRemove) $("#apcfgchid").removeChild(optionToRemove);
|
||||
$('#updateC6Option').style.display = 'block';
|
||||
}
|
||||
if (data.hasFlasher == 1) {
|
||||
$('[data-target="flashtab"]').style.display = 'block';
|
||||
|
||||
@@ -7,8 +7,27 @@ let running = false;
|
||||
let errors = 0;
|
||||
let env = '', currentVer = '', currentBuildtime = 0;
|
||||
let buttonState = false;
|
||||
let gIsC6 = false;
|
||||
let gIsH2 = false;
|
||||
let gModuleType = '';
|
||||
let gShortName = '';
|
||||
let gCurrentRfVer = 0;
|
||||
|
||||
export async function initUpdate() {
|
||||
if (apConfig.C6 == 1) {
|
||||
gIsC6 = true;
|
||||
gModuleType = "ESP32-C6";
|
||||
gShortName = "C6";
|
||||
}
|
||||
else if(apConfig?.H2 && apConfig.H2 == 1) {
|
||||
gIsH2 = true;
|
||||
gModuleType = "ESP32-H2";
|
||||
gShortName = "H2";
|
||||
}
|
||||
else {
|
||||
gModuleType = "Unknown"
|
||||
}
|
||||
$('#radio_release_title').innerHTML = gModuleType + " Firmware";
|
||||
|
||||
const response = await fetch("version.txt");
|
||||
let filesystemversion = await response.text();
|
||||
@@ -30,7 +49,7 @@ export async function initUpdate() {
|
||||
$('#selectRepo').style.display = 'inline-block';
|
||||
$('#repoWarning').style.display = 'none';
|
||||
|
||||
const sysinfoPromise = fetch("sysinfo")
|
||||
const sdata = await fetch("sysinfo")
|
||||
.then(response => {
|
||||
if (response.status != 200) {
|
||||
print("Error fetching sysinfo: " + response.status, "red");
|
||||
@@ -48,98 +67,170 @@ export async function initUpdate() {
|
||||
print('Error fetching sysinfo: ' + error, "red");
|
||||
});
|
||||
|
||||
const repoPromise = fetch(repoUrl)
|
||||
.then(response => response.json())
|
||||
if (sdata.env) {
|
||||
print(`current env: ${sdata.env}`);
|
||||
print(`build date: ${formatEpoch(sdata.buildtime)}`);
|
||||
print(`esp32 version: ${sdata.buildversion}`);
|
||||
if(gModuleType != '') {
|
||||
var hex_ver = '0000' + sdata.ap_version.toString(16);
|
||||
print(`${gModuleType} version: ${hex_ver.slice(-4)}`);
|
||||
}
|
||||
print(`filesystem version: ${filesystemversion}`);
|
||||
print(`psram size: ${sdata.psramsize}`);
|
||||
print(`flash size: ${sdata.flashsize}`);
|
||||
print("--------------------------", "gray");
|
||||
env = apConfig.env || sdata.env;
|
||||
if (sdata.env != env) {
|
||||
print(`Warning: you selected a build environment ${env} which is\ndifferent than the currently used ${sdata.env}.\nOnly update the firmware with a mismatched build environment if\nyou know what you're doing.`, "yellow");
|
||||
}
|
||||
currentVer = sdata.buildversion;
|
||||
currentBuildtime = sdata.buildtime;
|
||||
gCurrentRfVer = sdata.ap_version;
|
||||
if (sdata.rollback) $("#rollbackOption").style.display = 'block';
|
||||
$('#environment').value = env;
|
||||
}
|
||||
|
||||
|
||||
Promise.all([sysinfoPromise, repoPromise])
|
||||
.then(([sdata, rdata]) => {
|
||||
|
||||
if (sdata.env) {
|
||||
print(`current env: ${sdata.env}`);
|
||||
print(`build date: ${formatEpoch(sdata.buildtime)}`);
|
||||
print(`esp32 version: ${sdata.buildversion}`);
|
||||
print(`filesystem version: ${filesystemversion}`);
|
||||
print(`psram size: ${sdata.psramsize}`);
|
||||
print(`flash size: ${sdata.flashsize}`);
|
||||
if (sdata.hasC6) {
|
||||
print(`ESP-C6/H2 version: 0x${parseInt(sdata.C6version).toString(16).toUpperCase()}`);
|
||||
}
|
||||
print("--------------------------", "gray");
|
||||
env = apConfig.env || sdata.env;
|
||||
if (sdata.env != env) {
|
||||
print(`Warning: you selected a build environment ${env} which is\ndifferent than the currently used ${sdata.env}.\nOnly update the firmware with a mismatched build environment if\nyou know what you're doing.`, "yellow");
|
||||
}
|
||||
currentVer = sdata.buildversion;
|
||||
currentBuildtime = sdata.buildtime;
|
||||
if (sdata.rollback) $("#rollbackOption").style.display = 'block';
|
||||
$('#environment').value = env;
|
||||
const rdata = await fetch(repoUrl).then(response => response.json())
|
||||
const JsonName = 'firmware_' + gShortName + '.json';
|
||||
const releaseDetails = rdata.map(release => {
|
||||
const assets = release.assets;
|
||||
const filesJsonAsset = assets.find(asset => asset.name === 'filesystem.json');
|
||||
const binariesJsonAsset = assets.find(asset => asset.name === 'binaries.json');
|
||||
const containsEnv = assets.find(asset => asset.name === env + '.bin');
|
||||
const firmwareAsset = assets.find(asset => asset.name === JsonName);
|
||||
if (filesJsonAsset && binariesJsonAsset && containsEnv) {
|
||||
return {
|
||||
html_url: release.html_url,
|
||||
tag_name: release.tag_name,
|
||||
name: release.name,
|
||||
date: formatDateTime(release.published_at),
|
||||
author: release.author.login,
|
||||
file_url: filesJsonAsset.browser_download_url,
|
||||
bin_url: binariesJsonAsset.browser_download_url,
|
||||
firmware_url: firmwareAsset?.browser_download_url,
|
||||
}
|
||||
};
|
||||
})
|
||||
|
||||
const releaseDetails = rdata.map(release => {
|
||||
const assets = release.assets;
|
||||
const filesJsonAsset = assets.find(asset => asset.name === 'filesystem.json');
|
||||
const binariesJsonAsset = assets.find(asset => asset.name === 'binaries.json');
|
||||
const containsEnv = assets.find(asset => asset.name === env + '.bin');
|
||||
if (filesJsonAsset && binariesJsonAsset && containsEnv) {
|
||||
return {
|
||||
html_url: release.html_url,
|
||||
tag_name: release.tag_name,
|
||||
name: release.name,
|
||||
date: formatDateTime(release.published_at),
|
||||
author: release.author.login,
|
||||
file_url: filesJsonAsset.browser_download_url,
|
||||
bin_url: binariesJsonAsset.browser_download_url
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const easyupdate = $('#easyupdate');
|
||||
if (releaseDetails.length === 0) {
|
||||
easyupdate.innerHTML = ("No releases found.");
|
||||
if (releaseDetails.length === 0) {
|
||||
easyupdate.innerHTML = ("No releases found.");
|
||||
} else {
|
||||
const release = releaseDetails[0];
|
||||
if (release?.tag_name) {
|
||||
if (release.tag_name == currentVer) {
|
||||
easyupdate.innerHTML = `Version ${currentVer}. You are up to date`;
|
||||
} else if (release.date < formatEpoch(currentBuildtime - 30 * 60)) {
|
||||
easyupdate.innerHTML = `Your version is newer than the latest release date.<br>Are you the developer? :-)`;
|
||||
} else {
|
||||
const release = releaseDetails[0];
|
||||
if (release?.tag_name) {
|
||||
if (normalizeVersion(release.tag_name) === normalizeVersion(currentVer)) {
|
||||
easyupdate.innerHTML = `Version ${currentVer}. You are up to date`;
|
||||
} else if (release.date < formatEpoch(currentBuildtime - 30 * 60)) {
|
||||
easyupdate.innerHTML = `Your version is newer than the latest release date.<br>Are you the developer? :-)`;
|
||||
} else {
|
||||
easyupdate.innerHTML = `An update from version ${currentVer} to version ${release.tag_name} is available.<button onclick="otamodule.updateAll('${release.bin_url}','${release.file_url}','${release.tag_name}')">Update now!</button>`;
|
||||
}
|
||||
}
|
||||
easyupdate.innerHTML = `An update from version ${currentVer} to version ${release.tag_name} is available.<button onclick="otamodule.updateAll('${release.bin_url}','${release.file_url}','${release.tag_name}')">Update now!</button>`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const table = document.createElement('table');
|
||||
const tableHeader = document.createElement('tr');
|
||||
tableHeader.innerHTML = '<th>Release</th><th>Date</th><th>Name</th><th colspan="2">Update:</th><th>Remark</th>';
|
||||
table.appendChild(tableHeader);
|
||||
const table = document.createElement('table');
|
||||
const tableHeader = document.createElement('tr');
|
||||
tableHeader.innerHTML = '<th>Release</th><th>Date</th><th>Name</th><th colspan="2"><center>Update</center></th><th>Remark</th>';
|
||||
table.appendChild(tableHeader);
|
||||
|
||||
let rowCounter = 0;
|
||||
releaseDetails.forEach(release => {
|
||||
if (rowCounter < 4 && release?.html_url) {
|
||||
const tableRow = document.createElement('tr');
|
||||
let tablerow = `<td><a href="${release.html_url}" target="_new">${release.tag_name}</a></td><td>${release.date}</td><td>${release.name}</td><td><button type="button" onclick="otamodule.updateWebpage('${release.file_url}','${release.tag_name}', true)">Filesystem</button></td><td><button type="button" onclick="otamodule.updateESP('${release.bin_url}', true)">ESP32</button></td>`;
|
||||
if (release.tag_name == currentVer) {
|
||||
tablerow += "<td>current version</td>";
|
||||
} else if (release.date < formatEpoch(currentBuildtime)) {
|
||||
tablerow += "<td>older</td>";
|
||||
} else {
|
||||
tablerow += "<td>newer</td>";
|
||||
}
|
||||
tableRow.innerHTML = tablerow;
|
||||
table.appendChild(tableRow);
|
||||
rowCounter++;
|
||||
}
|
||||
});
|
||||
let rowCounter = 0;
|
||||
let radioFwCounter = 0;
|
||||
releaseDetails.forEach(release => {
|
||||
if (rowCounter < 4 && release?.html_url) {
|
||||
const tableRow = document.createElement('tr');
|
||||
let tablerow = `<td><a href="${release.html_url}" target="_new">${release.tag_name}</a></td><td>${release.date}</td><td>${release.name}</td><td><button type="button" onclick="otamodule.updateWebpage('${release.file_url}','${release.tag_name}', true)">Filesystem</button></td><td><button type="button" onclick="otamodule.updateESP('${release.bin_url}', true)">ESP32</button></td>`;
|
||||
if (release.tag_name == currentVer) {
|
||||
tablerow += "<td>current version</td>";
|
||||
} else if (release.date < formatEpoch(currentBuildtime)) {
|
||||
tablerow += "<td>older</td>";
|
||||
} else {
|
||||
tablerow += "<td>newer</td>";
|
||||
}
|
||||
tableRow.innerHTML = tablerow;
|
||||
table.appendChild(tableRow);
|
||||
rowCounter++;
|
||||
}
|
||||
if (release?.firmware_url) {
|
||||
radioFwCounter++;
|
||||
}
|
||||
});
|
||||
$('#releasetable').innerHTML = "";
|
||||
$('#releasetable').appendChild(table);
|
||||
|
||||
$('#releasetable').innerHTML = "";
|
||||
$('#releasetable').appendChild(table);
|
||||
disableButtons(buttonState);
|
||||
})
|
||||
.catch(error => {
|
||||
print('Error fetching releases:' + error, "red");
|
||||
});
|
||||
if(radioFwCounter > 0) {
|
||||
const table1 = document.createElement('table');
|
||||
const tableHeader1 = document.createElement('tr');
|
||||
|
||||
tableHeader1.innerHTML = '<th>Release</th><th>Date</th><th>Name</th><th><center>Update</center></th><th>Version</th><th>Remark</th>';
|
||||
table1.appendChild(tableHeader1);
|
||||
|
||||
rowCounter = 0;
|
||||
for (const release of releaseDetails) {
|
||||
if (rowCounter < 4 && release?.firmware_url) {
|
||||
const tableRow = document.createElement('tr');
|
||||
var tablerow;
|
||||
var firmwareVer = "unknown";
|
||||
var release_url = release.firmware_url;
|
||||
|
||||
tablerow = `<td><a href="${release.html_url}" target="_new">${release.tag_name}</a></td><td>${release.date}</td><td>${release.name}</td>`;
|
||||
tablerow += `<td><button type="button" onclick="otamodule.updateC6H2('${release_url}')">${gModuleType}</button></td>`;
|
||||
const firmwareUrl = 'http://proxy.openepaperlink.org/proxy.php?url=' + release.firmware_url;
|
||||
firmwareVer = await fetch(firmwareUrl, { method: 'GET'})
|
||||
.then(function (response) { return response.json(); })
|
||||
.then(function (response) {
|
||||
return response[2]['version']; })
|
||||
.catch(error => {
|
||||
print('Error fetching releases:' + error, "red");
|
||||
});
|
||||
tablerow += '<td>' + firmwareVer + '</td><td>';
|
||||
if(firmwareVer != 'unknown') {
|
||||
let Ver = Number('0x' + firmwareVer);
|
||||
if(Ver > gCurrentRfVer) {
|
||||
tablerow += 'Newer';
|
||||
}
|
||||
else if (Ver < gCurrentRfVer) {
|
||||
tablerow += 'Older';
|
||||
}
|
||||
else if(!Number.isNaN(Ver)){
|
||||
tablerow += 'Same';
|
||||
}
|
||||
}
|
||||
tablerow += '</td>';
|
||||
tableRow.innerHTML = tablerow;
|
||||
table1.appendChild(tableRow);
|
||||
rowCounter++;
|
||||
}
|
||||
};
|
||||
|
||||
$('#radio_releasetable').innerHTML = "";
|
||||
$('#radio_releasetable').appendChild(table1);
|
||||
}
|
||||
|
||||
const table2 = document.createElement('table');
|
||||
{
|
||||
const tableHeader2 = document.createElement('tr');
|
||||
tableHeader2.innerHTML = '<th>Firmware</th><th><center>Update</center></th>';
|
||||
table2.appendChild(tableHeader2);
|
||||
const tableRow = document.createElement('tr');
|
||||
tablerow = '<td>Last uploaded version</td>';
|
||||
tablerow += `<td><button type="button" onclick="otamodule.updateC6H2('')">${gModuleType}</button></td>`;
|
||||
tableRow.innerHTML = tablerow;
|
||||
table2.appendChild(tableRow);
|
||||
}
|
||||
{
|
||||
const tableRow = document.createElement('tr');
|
||||
const Url = "https://raw.githubusercontent.com/" + repo +
|
||||
"/master/binaries/ESP32-" + gShortName +
|
||||
"/firmware_" + gShortName + ".json";
|
||||
|
||||
tablerow = `<td><a href="https://github.com/${repo}" target="_new">Latest version from repo</a></td>`;
|
||||
tablerow += `<td><button type="button" onclick="otamodule.updateC6H2('${Url}')">${gModuleType}</button></td>`;
|
||||
tableRow.innerHTML = tablerow;
|
||||
table2.appendChild(tableRow);
|
||||
}
|
||||
$('#radio_releasetable1').innerHTML = "";
|
||||
$('#radio_releasetable1').appendChild(table2);
|
||||
|
||||
disableButtons(buttonState);
|
||||
}
|
||||
|
||||
export function updateAll(binUrl, fileUrl, tagname) {
|
||||
@@ -358,19 +449,18 @@ $('#rollbackBtn').onclick = function () {
|
||||
disableButtons(false);
|
||||
}
|
||||
|
||||
$('#updateC6Btn').onclick = function () {
|
||||
export async function updateC6H2(Url) {
|
||||
if (running) return;
|
||||
disableButtons(true);
|
||||
running = true;
|
||||
errors = 0;
|
||||
const ReleaseUrl = Url.substring(0,Url.lastIndexOf('/'));
|
||||
const consoleDiv = document.getElementById('updateconsole');
|
||||
consoleDiv.scrollTop = consoleDiv.scrollHeight;
|
||||
|
||||
print("Flashing ESP32-C6...");
|
||||
|
||||
const isChecked = $('#c6download').checked;
|
||||
const formData = new FormData();
|
||||
formData.append('download', isChecked ? '1' : '0');
|
||||
|
||||
print("Flashing " + gModuleType + " ...");
|
||||
formData.append('url', ReleaseUrl);
|
||||
|
||||
fetch("update_c6", {
|
||||
method: "POST",
|
||||
@@ -418,7 +508,7 @@ $('#selectRepo').onclick = function (event) {
|
||||
if (!responseBody.trim().startsWith("[")) {
|
||||
throw new Error("Failed to fetch the release info file");
|
||||
}
|
||||
const updateData = JSON.parse(responseBody).filter(item => !item.name.endsWith('_full.bin'));
|
||||
const updateData = JSON.parse(responseBody).filter(item => !item.name.endsWith('_full.bin') && !item.name.includes('_H2.') && !item.name.includes('_C6.'));
|
||||
|
||||
const inputParent = $('#environment').parentNode;
|
||||
const selectElement = document.createElement('select');
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
[{
|
||||
"filename": "bootloader.bin",
|
||||
"filename": "bootloader_C6.bin",
|
||||
"address": "0x0",
|
||||
"version": "0001"
|
||||
},
|
||||
{
|
||||
"filename": "partition-table.bin",
|
||||
"filename": "partition-table_C6.bin",
|
||||
"address": "0x8000",
|
||||
"version": "0001"
|
||||
},
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
[{
|
||||
"filename": "bootloader.bin",
|
||||
"filename": "bootloader_H2.bin",
|
||||
"address": "0x0",
|
||||
"version": "0001"
|
||||
},
|
||||
{
|
||||
"filename": "partition-table.bin",
|
||||
"filename": "partition-table_H2.bin",
|
||||
"address": "0x8000",
|
||||
"version": "0001"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user