Better auto-flashing, support for firmware-packs

This commit is contained in:
Jelmer
2023-05-06 18:41:22 +02:00
parent 25cfe44784
commit 117120c0df
5 changed files with 659 additions and 217 deletions

View File

@@ -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"
}
]

View File

@@ -1,7 +1,14 @@
#include <Arduino.h>
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);
#define FLASHER_AP_PORT 0
#ifdef OPENEPAPERLINK_PCB
#define FLASHER_EXT_PORT 1
#define FLASHER_ALTRADIO_PORT 2
#endif

View File

@@ -1,8 +1,10 @@
#include "flasher.h"
#include <Arduino.h>
#include <ArduinoJson.h>
#include <LittleFS.h>
#include <MD5Builder.h>
// #include <FS.h>
#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<JsonArray>()) {
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<JsonArray>()) {
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<JsonArray>()) {
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<JsonArray>()) {
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;
}

View File

@@ -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);
}
}

View File

@@ -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();