diff --git a/firmware/.vscode/extensions.json b/firmware/.vscode/extensions.json index e80666b..0f0d740 100644 --- a/firmware/.vscode/extensions.json +++ b/firmware/.vscode/extensions.json @@ -1,7 +1,7 @@ -{ - // See http://go.microsoft.com/fwlink/?LinkId=827846 - // for the documentation about the extensions.json format - "recommendations": [ - "platformio.platformio-ide" - ] -} +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ] +} diff --git a/firmware/deploy.py b/firmware/deploy.py new file mode 100644 index 0000000..8643342 --- /dev/null +++ b/firmware/deploy.py @@ -0,0 +1,121 @@ +import struct +import locale +from collections import namedtuple +from datetime import datetime +import subprocess +from distutils.version import StrictVersion + +locale.setlocale(locale.LC_ALL, 'en_US') + +# sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) +APP_DESC_OFFSET = 32 + +# sizeof(esp_app_desc_t) +APP_DESC_SIZE = 256 + +APP_DESC_STRUCT = " 0 + + if int(commits_since_tag) == 0: + version_string = latest_release + else: + next_version = increment_version(latest_release) + version_string = version_format.format( + version=next_version, commits=commits_since_tag, sha=sha) + + if is_dirty: + version_string += ".dirty" + return version_string + + +def read_app_description(file_name): + def process_bytes(b): + if not isinstance(b, bytes): + return b + s = b.decode() + return s[:s.find("\x00")] + + with open(file_name, 'rb') as f: + f.seek(APP_DESC_OFFSET, 0) + raw_app_desc = f.read(APP_DESC_SIZE) + unpacked = struct.unpack(APP_DESC_STRUCT, raw_app_desc) + unpacked = tuple(process_bytes(e) for e in unpacked) + magic_word, secure_version, _, _, version, project_name, time, date, idf_ver, app_elf_sha256, *_ = unpacked + assert magic_word == 0xABCD5432 + return AppDesc(secure_version, version, project_name, time, date, idf_ver, app_elf_sha256) + + +def patch_app_description(file_name, version, project_name, time, date): + assert len(version) < 32 + assert len(project_name) < 32 + assert len(time) < 16 + assert len(date) < 16 + + def fill_zeros(s, total_length): + s += "\x00" * (total_length - len(s)) + s = s.encode() + assert len(s) == total_length + return s + + with open(file_name, 'r+b') as f: + f.seek(APP_DESC_OFFSET, 0) + raw_app_desc = f.read(APP_DESC_SIZE) + unpacked = list(struct.unpack(APP_DESC_STRUCT, raw_app_desc)) + unpacked[4] = fill_zeros(version, 32) + unpacked[5] = fill_zeros(project_name, 32) + unpacked[6] = fill_zeros(time, 16) + unpacked[7] = fill_zeros(date, 16) + packed = struct.pack(APP_DESC_STRUCT, *unpacked) + f.seek(APP_DESC_OFFSET, 0) + f.write(packed) + + +def add_info_to_firmware(firmware_file, version): + now = datetime.now() + date = now.strftime("%b %d %Y") + time = now.strftime("%H:%M:%S") + patch_app_description(firmware_file, version=version, + project_name="swimtracker.bauer.tech", time=time, date=date) + + +if __name__ == "__main__": + fimware_file = ".pio/build/esp32/firmware.bin" + print(read_app_description(fimware_file)) + + patch_app_description(fimware_file, version="myversion", + project_name="swimtracker.bauer.tech", time="22:16:12", date="Feb 20 2020") + print(read_app_description(fimware_file)) diff --git a/firmware/src/firmware_main.cpp b/firmware/src/firmware_main.cpp index 9ed1a78..eabe6ea 100644 --- a/firmware/src/firmware_main.cpp +++ b/firmware/src/firmware_main.cpp @@ -72,7 +72,7 @@ void httpSetup(SessionManager *sessionManager) Serial.println("Tare"); sessionManager->tare(); }; - auto cbFirmwareUpdate = [](httpd_req_t * req) { + auto cbFirmwareUpdate = [](httpd_req_t *req) { httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); httpd_resp_send(req, "OK", -1); firmwareUpdate(); @@ -116,7 +116,22 @@ void httpSetup(SessionManager *sessionManager) { const String freeBytes(ESP.getFreePsram()); const String usedBytes(ESP.getPsramSize() - ESP.getFreePsram()); - result += "\"psram\": { \"used\": " + usedBytes + ", \"free\":" + freeBytes + "}\n"; + result += "\"psram\": { \"used\": " + usedBytes + ", \"free\":" + freeBytes + "},\n"; + } + // firmware + { + auto descr = esp_ota_get_app_description(); + const String projectName(descr->project_name); + const String versionStr(descr->version); + const String idfVersion(descr->idf_ver); + const String compileDate(descr->date); + const String compileTime(descr->time); + result += "\"firmware\": { \"name\" : \"" + + projectName + "\", \"version\": \"" + + versionStr + "\", \"idfVersion\": \"" + + idfVersion + "\", \"compile_date\": \"" + + compileDate + +"\", \"compile_time\": \"" + + compileTime + "\" }\n"; } result += "}"; httpd_resp_send(req, result.c_str(), result.length()); @@ -178,11 +193,8 @@ void checkWifi() while (WiFi.status() != WL_CONNECTED) { Serial.println("WiFi disconnected. Try to reconnect"); - WiFi.disconnect(); - WiFi.mode(WIFI_OFF); - WiFi.mode(WIFI_STA); - WiFi.begin(CONFIG_WIFI_SSID, CONFIG_WIFI_PASSWORD); - delay(200); + WiFi.reconnect(); + delay(2000); } } @@ -202,7 +214,7 @@ void setup() while (!Serial) { } - Serial.println("Starting SwimTracker Firmware"); + Serial.printf("Starting SwimTracker Firmware - connecting to %s\n", CONFIG_WIFI_SSID); // File system bool spiffsResult = SPIFFS.begin(true); @@ -212,6 +224,7 @@ void setup() ESP_ERROR_CHECK(esp_event_loop_create_default()); // WiFi + WiFi.disconnect(); WiFi.mode(WIFI_STA); WiFi.begin(CONFIG_WIFI_SSID, CONFIG_WIFI_PASSWORD); String fullHostname = String(CONFIG_HOSTNAME) + getIdSuffix(); @@ -230,14 +243,18 @@ void setup() } Serial.print("Connected to WiFi. IP:"); Serial.println(WiFi.localIP()); - - Serial.println("Running version 1"); // todo + + Serial.println("Running version new24!"); // todo // Session sessionManager.begin(); // HTTP & Websocket server httpSetup(&sessionManager); + Serial.printf("Offset %d\n", sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t)); + Serial.printf("Size %d\n", sizeof(esp_app_desc_t)); + + webSocketServer.begin(); }