Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
07e931b46This file is pinned to the selected release. Download the original to open it in your design tool.
// ═══════════════════════════════════════════════════════════
// PatternFlow - which image is running, as eight hex digits
//
// The version string names a release, and two different images can carry
// the same one: a local build, an edition, a fix flashed before the bump.
// The console needs to tell images apart exactly, because its page URLs
// carry ?v=<build> and a URL naming the running build is served immutable
// (core_send.h). A browser then keeps each page until the firmware changes,
// and not a moment longer.
//
// The source is the ELF's SHA-256, which esptool writes into the app
// descriptor at build time (elf2image --elf-sha256-offset 0xb0; the
// PlatformIO and Arduino IDE builds both pass it). The first four bytes are
// plenty to tell a handful of images apart. An image built without that
// step reads all zeros, and then a hash of the compile time and the version
// stands in: still different for every build, just not for every byte.
//
// License: MIT
// ═══════════════════════════════════════════════════════════
#pragma once
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <esp_ota_ops.h> // esp_ota_get_app_elf_sha256 (IDF 4.4)
#include "../net_config.h" // PF_IMPROV_FW_VERSION
namespace PFBuild {
// FNV-1a, 32-bit: the fallback's hash.
inline uint32_t fnv1a32(const char* s) {
uint32_t h = 2166136261u;
while (*s) {
h ^= (uint8_t)*s++;
h *= 16777619u;
}
return h;
}
// Fills out[9] with eight lowercase hex digits and a NUL.
inline void compute(char* out) {
out[0] = '\0';
esp_ota_get_app_elf_sha256(out, 9);
bool stamped = strlen(out) == 8;
if (stamped) {
stamped = false;
for (int i = 0; i < 8; ++i) {
if (out[i] != '0') stamped = true;
}
}
if (!stamped) {
snprintf(out, 9, "%08x",
(unsigned)fnv1a32(__DATE__ " " __TIME__ " " PF_IMPROV_FW_VERSION));
}
}
// Computed once, on first use. A function-local static because the first
// callers race: /api/status and a page send can both be first, and the
// guarded initialisation makes the loser wait instead of reading half a
// string.
inline const char* id() {
static char buf[9];
static const bool ready = (compute(buf), true);
(void)ready;
return buf;
}
} // namespace PFBuild