From 117120c0dfe1891908baa4ba74345ffe74d30e26 Mon Sep 17 00:00:00 2001 From: Jelmer Date: Sat, 6 May 2023 18:41:22 +0200 Subject: [PATCH] Better auto-flashing, support for firmware-packs --- ESP32_AP-Flasher/data/tag_md5_db.json | 74 +++ ESP32_AP-Flasher/include/flasher.h | 15 +- ESP32_AP-Flasher/src/flasher.cpp | 753 +++++++++++++++++++------- ESP32_AP-Flasher/src/main.cpp | 10 +- ESP32_AP-Flasher/src/serialap.cpp | 24 +- 5 files changed, 659 insertions(+), 217 deletions(-) create mode 100644 ESP32_AP-Flasher/data/tag_md5_db.json diff --git a/ESP32_AP-Flasher/data/tag_md5_db.json b/ESP32_AP-Flasher/data/tag_md5_db.json new file mode 100644 index 00000000..d2449e4c --- /dev/null +++ b/ESP32_AP-Flasher/data/tag_md5_db.json @@ -0,0 +1,74 @@ +[ + { + "name":"1.54 White", + "mac_offset":64518, + "mac_format":1, + "mac_suffix":"3410", + "MD5":"EC4CF26432B8E250BD3C56EFA0B6E852", + "type":0, + "note":"White 1.54 033" + }, + { + "name":"1.54 Black NFC", + "mac_offset":64518, + "mac_format":1, + "mac_suffix":"3430", + "MD5":"F77F2BDA76EC584CFF143DFD74654354", + "type":0, + "note":"Black 1.54 032 w/NFC" + }, + { + "name":"Segmented UK", + "mac_offset":30722, + "mac_format":2, + "mac_suffix":"0131", + "MD5":"A27D978C48888FA045E8D3F90DC27029", + "type":240, + "note":"Segmented, UK, TSC0 Ebie" + }, + { + "name":"4.2 Black + NFC", + "mac_offset":64518, + "mac_format":1, + "mac_suffix":"4830", + "MD5":"A7E30D170AC8F2569F4D7E815594FB9F", + "type":2, + "note":"4.2 v033 FW" + }, + { + "name":"2.9 White", + "mac_offset":64518, + "mac_format":1, + "mac_suffix":"3B10", + "MD5":"A41315C16017BA64CF5BE12DFCA0F781", + "type":1, + "note":"2.9 v033 FW" + }, + { + "name":"2.9 White + NFC UC8151", + "mac_offset":64518, + "mac_format":1, + "mac_suffix":"3B30", + "MD5":"F707C29A240D7DD237C3C1265FAF4B68", + "type":17, + "note":"2.9 White + NFC UC8151 V032 FW" + }, + { + "name":"2.9 White + NFC UC8151", + "mac_offset":64518, + "mac_format":1, + "mac_suffix":"3B30", + "MD5":"D7E45FEECA144BB4ED750BEADE2CAD0A", + "type":17, + "note":"2.9 White + NFC UC8151 V033 FW" + }, + { + "name":"2.9 White + NFC UC8151", + "mac_offset":64518, + "mac_format":1, + "mac_suffix":"3B30", + "MD5":"4643F4F74321FC9B4F9F0ECBD93B74AB", + "type":17, + "note":"2.9 White + NFC UC8151 V025 FW" + } + ] \ No newline at end of file diff --git a/ESP32_AP-Flasher/include/flasher.h b/ESP32_AP-Flasher/include/flasher.h index d7b2088e..57f46a18 100644 --- a/ESP32_AP-Flasher/include/flasher.h +++ b/ESP32_AP-Flasher/include/flasher.h @@ -1,7 +1,14 @@ #include -String lookupFirmwareFile(uint16_t &version); -bool performDeviceFlash(); +uint16_t getAPUpdateVersion(uint8_t type); +bool checkForcedAPFlash(); +bool doForcedAPFlash(); +bool doAPFlash(); +bool doAPUpdate(uint8_t type); +bool doTagFlash(); -void getFirmwareMD5(class ZBS_interface* zbs, uint8_t* md5p); -void getInfoPageMac(class ZBS_interface* zbs, uint8_t* mac); \ No newline at end of file +#define FLASHER_AP_PORT 0 +#ifdef OPENEPAPERLINK_PCB +#define FLASHER_EXT_PORT 1 +#define FLASHER_ALTRADIO_PORT 2 +#endif \ No newline at end of file diff --git a/ESP32_AP-Flasher/src/flasher.cpp b/ESP32_AP-Flasher/src/flasher.cpp index cf78d737..34f8d76b 100644 --- a/ESP32_AP-Flasher/src/flasher.cpp +++ b/ESP32_AP-Flasher/src/flasher.cpp @@ -1,8 +1,10 @@ #include "flasher.h" #include +#include #include #include +// #include #include "settings.h" #include "time.h" @@ -10,58 +12,6 @@ #define FINGERPRINT_FLASH_SIZE 10240 -uint8_t *infoblock = nullptr; -uint8_t *flashbuffer = nullptr; - -static class ZBS_interface *zbs; - -void getFirmwareMD5(class ZBS_interface* zbs, uint8_t* md5p) { - uint8_t *buffer = (uint8_t *)malloc(FINGERPRINT_FLASH_SIZE); - - /* - zbs = new ZBS_interface; - bool interfaceWorking = zbs->begin(FLASHER_EXT_SS, FLASHER_EXT_CLK, FLASHER_EXT_MOSI, FLASHER_EXT_MISO, FLASHER_EXT_RESET, FLASHER_EXT_POWER, 8000000); - if (!interfaceWorking) { - Serial.print("I wasn't able to connect to a ZBS tag, please check wiring and definitions in the settings.h file.\n"); - delete zbs; - return; - } - */ - - zbs->select_flash(0); - for (uint16_t c = 0; c < FINGERPRINT_FLASH_SIZE; c++) { - buffer[c] = zbs->read_flash(c); - } - - { - MD5Builder md5; - md5.begin(); - md5.add(buffer, FINGERPRINT_FLASH_SIZE); - md5.calculate(); - md5.getBytes(md5p); - } - - Serial.printf("MD5="); - for (uint8_t c = 0; c < 16; c++) { - Serial.printf("%02X", md5p[c]); - } - Serial.printf("\n"); - free(buffer); -} - -void getInfoPageMac(class ZBS_interface* zbs, uint8_t* mac){ - zbs->select_flash(1); - for (uint16_t c = 0; c < 8; c++) { - mac[c] = zbs->read_flash(c+0x10); - } - Serial.printf("Infopage mac="); - for (uint8_t c = 0; c < 8; c++) { - Serial.printf("%02X", mac[c]); - } - Serial.printf("\n"); -} - - #ifdef OPENEPAPERLINK_PCB bool extTagConnected() { // checks if the TEST (P1.0) pin on the ZBS243 will come up high. If it doesn't, there's probably a tag connected. @@ -73,65 +23,276 @@ bool extTagConnected() { } #endif -// look for the latest version of the firmware file... It's supposed to be something like zigbeebase0003.bin -String lookupFirmwareFile(uint16_t &version) { - String filename; - File root = LittleFS.open("/"); - File file = root.openNextFile(); - while (file) { - if (strncmp(file.name(), "zigbeebase", 10) == 0) { - filename = "/" + ((String)file.name()); +void dump(uint8_t *a, uint16_t l) { + if (a == nullptr) { + Serial.print("Tried to dump the contents of a nullptr, this is probably not what you want.\n"); + } + Serial.printf(" "); +#define ROWS 16 + for (uint8_t c = 0; c < ROWS; c++) { + Serial.printf(" %02X", c); + } + Serial.printf("\n--------"); + for (uint8_t c = 0; c < ROWS; c++) { + Serial.printf("---"); + } + for (uint16_t c = 0; c < l; c++) { + if ((c % ROWS) == 0) { + Serial.printf("\n0x%04X | ", c); } - file.close(); - file = root.openNextFile(); + Serial.printf("%02X ", a[c]); } - if (filename.length()) { - char buffer[16]; - memset(buffer, 0, 16); - strncpy(buffer, filename.c_str() + 11, 4); - version = strtoul(buffer, NULL, 16); - root.close(); - return filename; - } else { - version = 0; - root.close(); - return ""; + Serial.printf("\n--------"); + for (uint8_t c = 0; c < ROWS; c++) { + Serial.printf("---"); } + Serial.printf("\n"); } +class flasher { + public: + class ZBS_interface *zbs = nullptr; + uint8_t md5[16] = {0}; + char md5char[34]; + uint8_t tagtype; + uint8_t *infoblock = nullptr; + // Infoblock structure: + // 0x00-0x0F - Calibration data + // 0x10-0x17 - MAC + // 0x19 - OpenEPaperLink Type + // 0x30 - Original firmware MD5 -// guess device type based on flash memory contents -uint16_t getDeviceType() { - uint8_t type29[8] = {0x7d, 0x22, 0xff, 0x02, 0xa4, 0x58, 0xf0, 0x90}; - uint8_t type154[8] = {0xa1, 0x23, 0x22, 0x02, 0xa4, 0xc3, 0xe4, 0xf0}; - uint8_t buffer[8] = {0}; - zbs->select_flash(0); - for (uint8_t c = 0; c < 8; c++) { - buffer[c] = zbs->read_flash(0x08 + c); - } - if (memcmp(buffer, type29, 8) == 0) { - return 0x3B10; - } - if (memcmp(buffer, type154, 8) == 0) { - return 0x3410; - } - return 0xFFF0; -} - -// extract original mac from firmware and make it 2 bytes longer based on info in settings.h -uint64_t getOriginalTagMac() { - zbs->select_flash(0); uint8_t mac[8] = {0}; + uint8_t mac_format = 0; + uint16_t mac_suffix = 0; + uint16_t mac_offset = 0; + + flasher(); + ~flasher(); + bool connectTag(uint8_t port); + void getFirmwareMD5(); + bool getFirmwareMac(); + bool findTagByMD5(); + bool findTagByType(uint8_t type); + bool getInfoBlockMD5(); + bool getInfoBlockMac(); + bool getInfoBlockType(); + void getMacFromWiFi(); + bool prepareInfoBlock(); + + bool writeFlash(uint8_t *flashbuffer, uint16_t size); + bool writeFlashFromPack(String filename, uint8_t type); + bool writeFlashFromPackOffset(fs::File *file, uint16_t length); + + bool readInfoBlock(); + bool writeInfoBlock(); + + protected: + bool writeBlock256(uint16_t offset, uint8_t *flashbuffer); + void get_mac_format1(); + void get_mac_format2(); +}; + +flasher::flasher() { + zbs = new ZBS_interface; +} +flasher::~flasher() { + delete zbs; +} + +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, FLASHER_AP_POWER, 8000000); + break; +#ifdef OPENEPAPERLINK_PCB + case 1: + result = zbs->begin(FLASHER_EXT_SS, FLASHER_EXT_CLK, FLASHER_EXT_MOSI, FLASHER_EXT_MISO, FLASHER_EXT_RESET, FLASHER_EXT_POWER, 8000000); + break; + case 2: + result = zbs->begin(FLASHER_ALT_SS, FLASHER_ALT_CLK, FLASHER_ALT_MOSI, FLASHER_ALT_MISO, FLASHER_ALT_RESET, 255, 8000000); + break; +#endif + default: + Serial.printf("Tried to connect to port %d, but this port isn't available. Some dev borked it up, probably Jelmer.\n", port); + return false; + } + if (!result) Serial.printf("I tried connecting to port, but I couldn't establish a link to the tag. That's all I know.\n"); + return result; +} + +void flasher::getFirmwareMD5() { + uint8_t *buffer = (uint8_t *)malloc(FINGERPRINT_FLASH_SIZE); + if (buffer == nullptr) { + Serial.print("couldn't malloc bytes for firmware MD5\n"); + return; + } + + zbs->select_flash(0); + for (uint16_t c = 0; c < FINGERPRINT_FLASH_SIZE; c++) { + buffer[c] = zbs->read_flash(c); + } + + { + MD5Builder md5calc; + md5calc.begin(); + md5calc.add(buffer, FINGERPRINT_FLASH_SIZE); + md5calc.calculate(); + md5calc.getBytes(md5); + } + + for (uint8_t c = 0; c < 16; c++) { + sprintf(md5char + (2 * c), "%02X", md5[c]); + } + Serial.printf("MD5=%s\n", md5char); + free(buffer); +} + +bool flasher::getInfoBlockMac() { + if (!zbs->select_flash(1)) return false; + for (uint16_t c = 7; c < 8; c--) { + mac[7 - c] = zbs->read_flash(c + 0x10); + } + Serial.printf("Infopage mac="); + uint16_t macsum = 0; + for (uint8_t c = 0; c < 8; c++) { + macsum += mac[c]; + Serial.printf("%02X", mac[c]); + } + Serial.printf("\n"); + if (macsum == 0) return false; + if (macsum > 0x5F9) return false; + return true; +} + +bool flasher::getInfoBlockMD5() { + if (!zbs->select_flash(1)) return false; + for (uint16_t c = 0; c < 16; c++) { + md5[c] = zbs->read_flash(c + 0x30); + } + uint16_t macsum = 0; + for (uint8_t c = 0; c < 16; c++) { + macsum += md5[c]; + sprintf(md5char + (2 * c), "%02X", md5[c]); + } + Serial.printf("Infoblock MD5=%s\n", md5char); + if (macsum == 0) return false; // invalid mac + if (macsum > 0xF00) return false; // *probably* an invalid mac + return true; +} + +bool flasher::getInfoBlockType() { + if (!zbs->select_flash(1)) return false; + tagtype = zbs->read_flash(0x19); + return true; +} + +bool flasher::findTagByMD5() { + StaticJsonDocument<3000> doc; + DynamicJsonDocument APconfig(600); + fs::File readfile = LittleFS.open("/tag_md5_db.json", "r"); + DeserializationError err = deserializeJson(doc, readfile); + if (!err) { + for (JsonObject elem : doc.as()) { + const char *jsonmd5 = elem["MD5"]; + if (jsonmd5 != nullptr) { + if (strncmp(md5char, jsonmd5, 32) == 0) { + Serial.print("MD5 Matches > "); + const char *name = elem["name"]; + Serial.println(name); + mac_suffix = strtoul(elem["mac_suffix"], 0, 16); + mac_format = elem["mac_format"]; + mac_offset = elem["mac_offset"]; + tagtype = elem["type"]; + readfile.close(); + return true; + } + } + } + Serial.print("Failed to find this tag's current firmware MD5 in the json database. If this tag is already OpenEpaperLink, this is to be expected.\n"); + } else { + Serial.print("Failed to read json file\n"); + } + readfile.close(); + return false; +} + +bool flasher::findTagByType(uint8_t type) { + StaticJsonDocument<3000> doc; + DynamicJsonDocument APconfig(600); + fs::File readfile = LittleFS.open("/tag_md5_db.json", "r"); + DeserializationError err = deserializeJson(doc, readfile); + if (!err) { + for (JsonObject elem : doc.as()) { + if (elem["type"] != nullptr) { + uint8_t jtype = elem["type"]; + if (jtype == type) { + Serial.print("Type Matches > "); + const char *name = elem["name"]; + Serial.println(name); + const char *jsonmd5 = elem["MD5"]; + + for (uint8_t c = 0; c < 16; c++) { + uint32_t n = 0; + sscanf(jsonmd5 + (2 * c), "%02X", &n); + md5[c] = (uint8_t)n; + } + + for (uint8_t c = 0; c < 16; c++) { + sprintf(md5char + (2 * c), "%02X", md5[c]); + } + + mac_suffix = strtoul(elem["mac_suffix"], 0, 16); + mac_format = elem["mac_format"]; + mac_offset = elem["mac_offset"]; + tagtype = elem["type"]; + readfile.close(); + return true; + } + } + } + Serial.print("Failed to find this tag's type in the json database.\n"); + } else { + Serial.print("Failed to read json file\n"); + } + readfile.close(); + return false; +} + +bool flasher::getFirmwareMac() { + if (!mac_offset) return false; + switch (mac_format) { + case 1: + get_mac_format1(); + break; + case 2: + get_mac_format2(); + break; + default: + return false; + } + return true; +} + +void flasher::getMacFromWiFi() { + mac[0] = 0x00; + mac[1] = 0x00; + esp_read_mac(mac + 2, ESP_MAC_WIFI_SOFTAP); +} + +// extract original mac from firmware (1.54" and 2.9") and make it 2 bytes longer based on info in settings.h +void flasher::get_mac_format1() { + zbs->select_flash(0); for (uint8_t c = 0; c < 6; c++) { - mac[c + 2] = zbs->read_flash(0xFC06 + c); + mac[c + 2] = zbs->read_flash(mac_offset + c); // 0xFC06 } mac[0] = (uint8_t)(CUSTOM_MAC_HDR >> 8); mac[1] = (uint8_t)CUSTOM_MAC_HDR; - uint16_t type = getDeviceType(); - mac[6] = (uint8_t)(type >> 8); - mac[7] = (uint8_t)(type & 0xFF); + mac[6] = (uint8_t)(mac_suffix >> 8); + mac[7] = (uint8_t)(mac_suffix & 0xFF); uint8_t xorchk = 0; for (uint8_t c = 2; c < 8; c++) { @@ -139,136 +300,328 @@ uint64_t getOriginalTagMac() { xorchk ^= (mac[c] >> 4); } mac[7] |= xorchk; - return *((uint64_t *)(mac)); } -// extract custom firmware mac from Infoblock -uint64_t getInfoBlockMac() { - zbs->select_flash(1); - uint8_t mac[8] = {0}; - for (uint8_t c = 0; c < 8; c++) { - mac[c] = zbs->read_flash(0x10 + c); - } - return *((uint64_t *)(mac)); -} +// extract original mac from segmented tag +void flasher::get_mac_format2() { + zbs->select_flash(0); -// get info from infoblock (eeprom flash, kinda) -void readInfoBlock() { - if (infoblock == nullptr) { - // allocate room for infopage - infoblock = (uint8_t *)calloc(1024, 1); + for (uint8_t c = 0; c < 3; c++) { + mac[c] = zbs->read_flash(mac_offset + c); // 0x7802 } - zbs->select_flash(1); // select info page - for (uint16_t c = 0; c < 1024; c++) { - infoblock[c] = zbs->read_flash(c); + for (uint8_t c = 3; c < 6; c++) { + mac[c] = zbs->read_flash(mac_offset + 2 + c); } -} -// write info to infoblock -void writeInfoBlock() { - if (infoblock == nullptr) { - return; - } - zbs->select_flash(1); - zbs->erase_infoblock(); - zbs->select_flash(1); // select info page - for (uint16_t c = 0; c < 1024; c++) { - for (uint8_t i = 0; i < MAX_WRITE_ATTEMPTS; i++) { - zbs->write_flash(c, infoblock[c]); - if (zbs->read_flash(c) == infoblock[c]) { - break; - } - } - } + uint16_t type = mac_suffix; + mac[6] = (uint8_t)(type >> 8); + mac[7] = (uint8_t)(type & 0xFF); } // erase flash and program from flash buffer -void writeFlashBlock(uint16_t size) { - if (flashbuffer == nullptr) { - return; - } - zbs->select_flash(0); +bool flasher::writeFlash(uint8_t *flashbuffer, uint16_t size) { + if (!zbs->select_flash(0)) return false; zbs->erase_flash(); - zbs->select_flash(0); + if (!zbs->select_flash(0)) return false; Serial.printf("Starting flash, size=%d\n", size); - uint8_t i = 0; for (uint16_t c = 0; c < size; c++) { - for (i = 0; i < MAX_WRITE_ATTEMPTS; i++) { + if (flashbuffer[c] == 0xFF) goto flashWriteSuccess; + for (uint8_t i = 0; i < MAX_WRITE_ATTEMPTS; i++) { zbs->write_flash(c, flashbuffer[c]); if (zbs->read_flash(c) == flashbuffer[c]) { - break; + goto flashWriteSuccess; } } - if (i == MAX_WRITE_ATTEMPTS) { - Serial.printf("x"); - } else { - Serial.printf("."); - } + return false; + flashWriteSuccess: if (c % 256 == 0) { Serial.printf("\rNow flashing, %d/%d ", c, size); vTaskDelay(1 / portTICK_PERIOD_MS); } } + return true; +} + +bool flasher::writeBlock256(uint16_t offset, uint8_t *flashbuffer) { + for (uint16_t c = 0; c < 256; c++) { + if (flashbuffer[c] == 0xFF) goto flashWriteSuccess; + for (uint8_t i = 0; i < MAX_WRITE_ATTEMPTS; i++) { + zbs->write_flash(offset + c, flashbuffer[c]); + if (zbs->read_flash(offset + c) == flashbuffer[c]) { + goto flashWriteSuccess; + } + } + return false; + flashWriteSuccess: + continue; + } + return true; +} + +// get info from infoblock (eeprom flash, kinda) +bool flasher::readInfoBlock() { + if (!zbs->select_flash(1)) return false; + if (infoblock == nullptr) { + infoblock = (uint8_t *)malloc(1024); + if (infoblock == nullptr) return false; + } + for (uint16_t c = 0; c < 1024; c++) { + infoblock[c] = zbs->read_flash(c); + } + return true; +} + +// write info to infoblock +bool flasher::writeInfoBlock() { + if (infoblock == nullptr) return false; + if (!zbs->select_flash(1)) return false; + zbs->erase_infoblock(); + if (!zbs->select_flash(1)) return false; + // select info page + + for (uint16_t c = 0; c < 1024; c++) { + if (infoblock[c] == 0xFF) goto ifBlockWriteSuccess; + for (uint8_t i = 0; i < MAX_WRITE_ATTEMPTS; i++) { + zbs->write_flash(c, infoblock[c]); + if (zbs->read_flash(c) == infoblock[c]) { + goto ifBlockWriteSuccess; + } + } + return false; + ifBlockWriteSuccess: + continue; + } + return true; +} + +bool flasher::prepareInfoBlock() { + if (infoblock == nullptr) return false; + for (uint8_t c = 7; c < 8; c--) { + infoblock[0x10 + (7 - c)] = mac[c]; + } + infoblock[0x19] = tagtype; + for (uint8_t c = 0; c < 16; c++) { + infoblock[0x30 + c] = md5[c]; + } + return true; +} + +bool flasher::writeFlashFromPackOffset(fs::File *file, uint16_t length) { + if (!zbs->select_flash(0)) return false; + zbs->erase_flash(); + if (!zbs->select_flash(0)) return false; + Serial.printf("Starting flash, size=%d\n", length); + + uint8_t *buf = (uint8_t *)malloc(256); + uint16_t offset = 0; + while (length) { + if (length > 256) { + file->read(buf, 256); + length -= 256; + } else { + file->read(buf, length); + length = 0; + } + Serial.printf("\rFlashing, %d bytes left ", length); + bool res = writeBlock256(offset, buf); + offset += 256; + if (!res) { + Serial.printf("Failed writing block to tag, probably a hardware failure\n"); + return false; + } + vTaskDelay(1 / portTICK_PERIOD_MS); + } + Serial.printf("\nFlashing done\n"); + return true; +} + +bool flasher::writeFlashFromPack(String filename, uint8_t type) { + StaticJsonDocument<512> doc; + DynamicJsonDocument APconfig(512); + fs::File readfile = LittleFS.open(filename, "r"); + DeserializationError err = deserializeJson(doc, readfile); + if (!err) { + for (JsonObject elem : doc.as()) { + if (elem["type"] != nullptr) { + uint8_t jtype = elem["type"]; + if (jtype == type) { + const char *name = elem["name"]; + Serial.print("Flashing from FW pack: "); + Serial.println(name); + + uint32_t offset = elem["offset"]; + uint16_t length = elem["length"]; + readfile.seek(offset); + bool result = writeFlashFromPackOffset(&readfile, length); + readfile.close(); + return result; + } + } + } + Serial.print("Failed to find this tag's type in the FW pack database.\n"); + } else { + Serial.print("Failed to read json header from FW pack\n"); + } + readfile.close(); + return false; +} + +uint16_t getAPUpdateVersion(uint8_t type) { + StaticJsonDocument<512> doc; + DynamicJsonDocument APconfig(512); + fs::File readfile = LittleFS.open("/AP_FW_Pack.bin", "r"); + DeserializationError err = deserializeJson(doc, readfile); + if (!err) { + for (JsonObject elem : doc.as()) { + if (elem["type"] != nullptr) { + uint8_t jtype = elem["type"]; + if (jtype == type) { + const char *name = elem["name"]; + uint32_t version = elem["version"]; + Serial.printf("AP FW version %04X - %s found in FW pack\n", version, name); + readfile.close(); + return version; + } + } + } + Serial.print("Failed to find this tag's type in the AP FW pack database.\n"); + } else { + Serial.print("Failed to read json header from FW pack\n"); + } + readfile.close(); + return 0; +} + +bool checkForcedAPFlash() { + return LittleFS.exists("/AP_force_flash.bin"); +} + +bool doForcedAPFlash() { + Serial.printf("Doing a forced AP Flash!\n"); + class flasher *f = new flasher(); + if (!f->connectTag(0)) { + Serial.printf("Sorry, failed to connect to this tag...\n"); + delete f; + return false; + } + + // we're going to overwrite the contents of the tag, so if we haven't set the mac already, we can forget about it. We'll set the mac to the wifi mac + if(!f->getInfoBlockMac()){ + f->readInfoBlock(); + f->getMacFromWiFi(); + f->prepareInfoBlock(); + f->writeInfoBlock(); + } + + fs::File readfile = LittleFS.open("/AP_force_flash.bin", "r"); + bool res = f->writeFlashFromPackOffset(&readfile, readfile.size()); + readfile.close(); + if(res) LittleFS.remove("/AP_force_flash.bin"); + f->zbs->reset(); + delete f; + return res; +} + +bool doAPFlash() { + // This function expects a tag in stock configuration, to be used as an AP. It can also work with 'dead' AP's. + class flasher *f = new flasher(); + if (!f->connectTag(0)) { + Serial.printf("Sorry, failed to connect to this tag...\n"); + delete f; + return false; + } + + f->getFirmwareMD5(); + + if (f->findTagByMD5()) { + // fresh tag for AP + Serial.printf("Found an original fw tag, flashing it for use with OpenEPaperLink\n"); + f->readInfoBlock(); + f->getFirmwareMac(); + f->prepareInfoBlock(); + f->writeInfoBlock(); + } else if (f->getInfoBlockMD5() && f->findTagByMD5()) { + // used tag, but recognized + } else { + // unknown tag, bailing out. + Serial.printf("Found a tag, but don't know what to do with it. Consider flashing using a file called \"AP_force_flash.bin\"\n"); + delete f; + return false; + } + bool res = f->writeFlashFromPack("/AP_FW_Pack.bin", f->tagtype); + f->zbs->reset(); + delete f; + return res; +} + +bool doAPUpdate(uint8_t type) { + // this function expects the tag to be already flashed with some version of the OpenEpaperLink Firmware, and that it correctly reported its type + class flasher *f = new flasher(); + if (!f->connectTag(0)) { + Serial.printf("Sorry, failed to connect to this tag...\n"); + delete f; + return false; + } + + f->readInfoBlock(); + if (f->getInfoBlockMD5() && f->findTagByMD5()) { + // header (MD5) was correctly set. We'll use the type set there, instead of the provided 'type' in the argument + type = f->tagtype; + } else { + f->readInfoBlock(); + // Couldn't recognize the firmware, maybe it was already used for OpenEPaperLink? + if (!f->getInfoBlockMac()) { + // infoblock mac was incorrectly configured, we skipped it in an earlier version. We'll consider it lost, and overwrite it with the wifi mac. + f->getMacFromWiFi(); + } + // we'll try to update the MD5, searching for it by type. + f->findTagByType(type); + f->writeInfoBlock(); + } + // TODO: DO THE ACTUAL FLASHING! + bool res = f->writeFlashFromPack("/AP_FW_Pack.bin", f->tagtype); + if(res)f->zbs->reset(); + delete f; + return res; } // perform device flash, save mac, everything -bool performDeviceFlash() { - uint8_t interfaceWorking = 0; - zbs = new ZBS_interface; - interfaceWorking = zbs->begin(FLASHER_AP_SS, FLASHER_AP_CLK, FLASHER_AP_MOSI, FLASHER_AP_MISO, FLASHER_AP_RESET, FLASHER_AP_POWER, 8000000); - if (!interfaceWorking) { - Serial.print("I wasn't able to connect to a ZBS tag, please check wiring and definitions in the settings.h file.\n"); - delete zbs; +bool doTagFlash() { + class flasher *f = new flasher(); + if (!f->connectTag(1)) { + Serial.printf("Sorry, failed to connect to this tag...\n"); return false; } - readInfoBlock(); - uint8_t mac[8] = {0}; - *((uint64_t *)(mac)) = getInfoBlockMac(); - // check if the mac has been set at all, 0xFF- is not allowed - if (*((uint64_t *)(mac)) == 0xFFFFFFFFFFFFFFFF) { - // mac not set in infopage, get it from the original firmware - *((uint64_t *)(mac)) = getOriginalTagMac(); - zbs->select_flash(1); - for (uint8_t c = 0; c < 8; c++) { - infoblock[0x17 - c] = mac[c]; - // write mac directly to infoblock without erasing; the bytes should all be 0xFF anyway - zbs->write_flash(0x17 - c, mac[c]); + f->getFirmwareMD5(); + + if (f->findTagByMD5()) { + // this tag currently contains original firmware, found its fingerprint + Serial.printf("Found original firmware tag, recognized its fingerprint (%s)\n", f->md5char); + f->readInfoBlock(); + f->getFirmwareMac(); + f->prepareInfoBlock(); + f->writeInfoBlock(); + f->writeFlashFromPack("/Tag_FW_Pack.bin", f->tagtype); + } else if (f->getInfoBlockMD5()) { + // did find an infoblock MD5 that looks valid + if (f->findTagByMD5()) { + // did find the md5 in the database + Serial.printf("Found an already-flashed tag, recognized its fingerprint (%s)\n", f->md5char); + f->getInfoBlockMac(); + f->getInfoBlockType(); + f->readInfoBlock(); + f->writeFlashFromPack("/Tag_FW_Pack.bin", f->tagtype); + } else { + // couldn't find the md5 from the infoblock + Serial.printf("Found an already-flashed tag, but we couldn't find its fingerprint (%s) in the database\n", f->md5char); + return false; } - } - - uint16_t version = 0; - File file = LittleFS.open(lookupFirmwareFile(version)); - if (!file) { - // couldn't find a valid firmware version - delete zbs; - return false; } else { - Serial.printf("Preparing to flash version %04X (%d bytes) to the tag\n", version, file.size()); + // We couldn't recognize the tag from it's fingerprint... + Serial.printf("Found a tag but didn't recognize its fingerprint\n", f->md5char); } - // load buffer with zbs firmware - uint16_t flashbuffersize = file.size(); - flashbuffer = (uint8_t *)calloc(flashbuffersize, 1); - uint32_t index = 0; - while (file.available()) { - flashbuffer[index] = file.read(); - index++; - portYIELD(); - } - - // write firmware from buffer and finish by rewriting the info block again - writeFlashBlock(flashbuffersize); - writeInfoBlock(); - Serial.print("All done with flashing\n"); - - file.close(); - free(infoblock); - infoblock = nullptr; - free(flashbuffer); - flashbuffer = nullptr; - //zbs->reset(); - vTaskDelay(100/portTICK_PERIOD_MS); - delete zbs; - return true; -} + delete f; + return false; +} \ No newline at end of file diff --git a/ESP32_AP-Flasher/src/main.cpp b/ESP32_AP-Flasher/src/main.cpp index cfc0fc4c..85aa2270 100644 --- a/ESP32_AP-Flasher/src/main.cpp +++ b/ESP32_AP-Flasher/src/main.cpp @@ -27,7 +27,9 @@ void timeTask(void* parameter) { if (!getLocalTime(&tm)) { Serial.println("Waiting for valid time from NTP-server"); } else { - if (now % 5 == 0) wsSendSysteminfo(); + if (now % 5 == 0) { + wsSendSysteminfo(); + } if (now % 300 == 6) saveDB("/current/tagDB.json"); contentRunner(); @@ -89,5 +91,9 @@ void setup() { } void loop() { - vTaskDelay(30000 / portTICK_PERIOD_MS); + vTaskDelay(10000 / portTICK_PERIOD_MS); + //performDeviceFlash(); + while (1) { + vTaskDelay(10000 / portTICK_PERIOD_MS); + } } \ No newline at end of file diff --git a/ESP32_AP-Flasher/src/serialap.cpp b/ESP32_AP-Flasher/src/serialap.cpp index e6d61f47..cb641f09 100644 --- a/ESP32_AP-Flasher/src/serialap.cpp +++ b/ESP32_AP-Flasher/src/serialap.cpp @@ -9,7 +9,6 @@ #include "newproto.h" #include "powermgt.h" #include "settings.h" - #include "web.h" #include "zbs_interface.h" @@ -537,43 +536,46 @@ void APTask(void* parameter) { AP_SERIAL_PORT.begin(115200, SERIAL_8N1, FLASHER_AP_RXD, FLASHER_AP_TXD); + vTaskDelay(3000 / portTICK_PERIOD_MS); + + if(checkForcedAPFlash())doForcedAPFlash(); + if (bringAPOnline()) { // AP works - ShowAPInfo(); uint16_t fsversion; - lookupFirmwareFile(fsversion); + fsversion = getAPUpdateVersion(apInfo.type); if ((fsversion) && (apInfo.version != fsversion)) { Serial.printf("Firmware version on LittleFS: %04X\n", fsversion); - Serial.printf("Performing flash update in about 30 seconds"); + Serial.printf("Performing flash update in about 30 seconds\n"); vTaskDelay(30000 / portTICK_PERIOD_MS); apInfo.isOnline = false; apInfo.state = AP_STATE_FLASHING; - if (performDeviceFlash()) { - Serial.printf("Flash completed, let's try to boot the AP!"); + if (doAPUpdate(apInfo.type)) { + Serial.printf("Flash completed, let's try to boot the AP!\n"); if (bringAPOnline()) { // AP works ShowAPInfo(); setAPchannel(); } else { - Serial.printf("Failed to bring up the AP after flashing... That's not supposed to happen!"); + Serial.printf("Failed to bring up the AP after flashing... That's not supposed to happen!\n"); apInfo.isOnline = false; apInfo.state = AP_STATE_FAILED; } } else { apInfo.isOnline = false; apInfo.state = AP_STATE_FAILED; - Serial.println("Failed to update version on the AP :("); + Serial.println("Failed to update version on the AP :(\n"); } } } else { // AP unavailable, maybe time to flash? apInfo.isOnline = false; apInfo.state = AP_STATE_OFFLINE; - Serial.println("I wasn't able to connect to a ZBS tag. This could be the first time this AP is booted and the AP-tag may be unflashed. We'll try to flash it!"); - Serial.println("Performing firmware flash in about 10 seconds"); + Serial.println("I wasn't able to connect to a ZBS tag. This could be the first time this AP is booted and the AP-tag may be unflashed. We'll try to flash it!\n"); + Serial.println("Performing firmware flash in about 10 seconds\n"); vTaskDelay(10000 / portTICK_PERIOD_MS); - if (performDeviceFlash()) { + if (doAPFlash()) { if (bringAPOnline()) { // AP works ShowAPInfo();