Merge remote-tracking branch 'origin/keymindCascade' into keymindCascade
This commit is contained in:
commit
41405ee01b
54 files changed
+3962
-477
No files matched your search
@@ -76,7 +76,26 @@ void formatStorageLayout(MainBoard& board, char* reply, size_t reply_size) {
|
||||
(unsigned long)internal_fs_start,
|
||||
(unsigned long)(internal_fs_size / 1024UL));
|
||||
|
||||
#if defined(ENABLE_OTA) && defined(OTA_RAK_AUTO_STORE)
|
||||
#if defined(ENABLE_OTA) && defined(OTA_RAK15002_SD_STORE)
|
||||
(void)board;
|
||||
// Optional SD discovery can be slow and takes ownership of the IO-slot
|
||||
// bus. A layout/status query must not mount it or allocate an OTA context.
|
||||
const auto* context = mesh::ota::ota_context_if_active();
|
||||
if (!context) {
|
||||
appendStorageLayout(reply, reply_size, "; ext:sd=optional ota=not-prepared");
|
||||
} else {
|
||||
#if defined(OTA_SEEDER_ONLY)
|
||||
appendStorageLayout(reply, reply_size, "; ext:sd=optional owner=ota-archive source-only");
|
||||
#else
|
||||
const auto& store = context->fetch_store;
|
||||
appendStorageLayout(reply, reply_size, "; ota=%s medium=%s staged=%lu",
|
||||
store.selectionReason(),
|
||||
store.usesSd() ? "sd" : store.usesQspi() ? "qspi" :
|
||||
store.usesInternal() ? "internal" : "not-prepared",
|
||||
(unsigned long)store.staged_size());
|
||||
#endif
|
||||
}
|
||||
#elif defined(ENABLE_OTA) && defined(OTA_RAK_AUTO_STORE)
|
||||
(void)board;
|
||||
mesh::ota::OtaStoreAdaptiveNrf52& store = mesh::ota::ota_ctx().fetch_store;
|
||||
if (store.usesExternal()) {
|
||||
|
||||
@@ -21,6 +21,13 @@
|
||||
namespace UserGpioPinPolicy {
|
||||
|
||||
inline bool isFirmwareReserved(uint8_t pin) {
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
// The exact RAK15002 recipe claims these WisBlock nets even when no card
|
||||
// is fitted: user GPIO must not defeat card detection or a later SD/NOR/
|
||||
// Ethernet handoff. WB_IO6 is Arduino pin 10, not GPIO number 6.
|
||||
if (pin == PIN_SPI_SCK || pin == WB_IO6 || pin == 26
|
||||
|| pin == PIN_SPI_MISO || pin == PIN_SPI_MOSI) return true;
|
||||
#endif
|
||||
#if defined(STATION_G3_ESP32)
|
||||
// A module may be present in the inactive slot too. Never offer its pins
|
||||
// for user GPIO, even when the current boot selected the other slot.
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
#include "../../nrf52/EthernetCliTransmit.h"
|
||||
#include <SPI.h>
|
||||
#include <EthernetUdp.h>
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
#include "../../ota/OtaSdSpiBusNrf52.h"
|
||||
#endif
|
||||
|
||||
#define PIN_SPI1_MISO (29) // (0 + 29)
|
||||
#define PIN_SPI1_MOSI (30) // (0 + 30)
|
||||
@@ -16,6 +19,64 @@ SPIClass ETHERNET_SPI_PORT(NRF_SPIM1, PIN_SPI1_MISO, PIN_SPI1_SCK, PIN_SPI1_MOSI
|
||||
#define PIN_ETHERNET_SS 26
|
||||
|
||||
bool RAK13800EthernetInterface::begin() {
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
// Rare shared-CS Ethernet is explicitly enabled after the SD/NOR context
|
||||
// has supplied its pin/transfer ownership hooks. Boot remains USB/BLE-only.
|
||||
return mesh::nrf52::registerTerminalEthernetShutdown(terminalShutdown, this);
|
||||
#else
|
||||
return beginHardware();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
bool RAK13800EthernetInterface::tryEnable() {
|
||||
if (_terminalStopping) { _spiError = "terminal shutdown"; return false; }
|
||||
if (_spiStarted) { SerialEthernetInterface::enable(); return true; }
|
||||
if (_ownsSharedSpi) { _spiError = "release stopped Ethernet with set eth off first"; return false; }
|
||||
if (!_prepareSpi || !_canReleaseSpi || !_releasedSpi) {
|
||||
_spiError = "OTA ownership hooks unavailable"; return false;
|
||||
}
|
||||
if (mesh::ota::ota_rak15002_sd_card_present()) {
|
||||
_spiError = "remove SD card: Ethernet and SD share CS26"; return false;
|
||||
}
|
||||
if (!_prepareSpi(_spiContext)) { _spiError = "OTA storage busy"; return false; }
|
||||
if (!mesh::ota::rak4631_try_acquire_spi(mesh::ota::RakSharedSpiOwner::Ethernet)) {
|
||||
(void)_releasedSpi(_spiContext);
|
||||
_spiError = "WisBlock SPI busy"; return false;
|
||||
}
|
||||
_ownsSharedSpi = true;
|
||||
if (!beginHardware()) {
|
||||
(void)shutdownForPowerOff(0);
|
||||
_terminalStopping = false;
|
||||
(void)_releasedSpi(_spiContext);
|
||||
_spiError = "Ethernet startup failed"; return false;
|
||||
}
|
||||
SerialEthernetInterface::enable();
|
||||
_spiError = "on";
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RAK13800EthernetInterface::tryDisable() {
|
||||
if (_terminalStopping) { _spiError = "terminal shutdown"; return false; }
|
||||
if (!_ownsSharedSpi) {
|
||||
SerialEthernetInterface::disable();
|
||||
_spiError = "off";
|
||||
return true;
|
||||
}
|
||||
if (_ownsSharedSpi && (!_canReleaseSpi || !_canReleaseSpi(_spiContext))) {
|
||||
_spiError = "OTA storage busy"; return false;
|
||||
}
|
||||
(void)shutdownForPowerOff(0);
|
||||
_terminalStopping = false;
|
||||
if (_releasedSpi && !_releasedSpi(_spiContext)) {
|
||||
_spiError = "OTA storage release pending"; return false;
|
||||
}
|
||||
_spiError = "off";
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
bool RAK13800EthernetInterface::beginHardware() {
|
||||
if (_terminalStopping) return false;
|
||||
if (!mesh::nrf52::registerTerminalEthernetShutdown(terminalShutdown, this)) return false;
|
||||
// Preserve existing startup/link timing. PoE supplies separate 5V through
|
||||
@@ -83,29 +144,53 @@ bool RAK13800EthernetInterface::shutdownForPowerOff(uint32_t timeout_ms) {
|
||||
// disable() cancels framed/session producers, but disconnectClient() must
|
||||
// not enter the vendor socket-stop/ACK wait during terminal shutdown.
|
||||
SerialEthernetInterface::disable();
|
||||
if (!_spiStarted) return true;
|
||||
for (uint8_t socket = 0; socket < 4; ++socket) {
|
||||
(void)mesh::nrf52::EthernetCliTransmit::close(socket);
|
||||
if (_spiStarted) {
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
// A newly inserted card also selects on CS26. Do not clock Ethernet
|
||||
// socket commands into it during recovery or terminal shutdown.
|
||||
if (!mesh::ota::ota_rak15002_sd_card_present())
|
||||
#endif
|
||||
for (uint8_t socket = 0; socket < 4; ++socket) {
|
||||
(void)mesh::nrf52::EthernetCliTransmit::close(socket);
|
||||
}
|
||||
client = EthernetClient();
|
||||
ETHERNET_SPI_PORT.end();
|
||||
_spiStarted = false;
|
||||
mesh::nrf52::releaseRakEthernetBusPads();
|
||||
}
|
||||
client = EthernetClient();
|
||||
ETHERNET_SPI_PORT.end();
|
||||
_spiStarted = false;
|
||||
mesh::nrf52::releaseRakEthernetBusPads();
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (_ownsSharedSpi) {
|
||||
mesh::ota::rak4631_release_spi(mesh::ota::RakSharedSpiOwner::Ethernet);
|
||||
_ownsSharedSpi = false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
int RAK13800EthernetInterface::available() {
|
||||
if (!_spiStarted || _terminalStopping) return 0;
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (mesh::ota::ota_rak15002_sd_card_present()
|
||||
|| !mesh::ota::rak4631_ethernet_owns_spi()) return 0;
|
||||
#endif
|
||||
return client.available();
|
||||
}
|
||||
|
||||
int RAK13800EthernetInterface::read() {
|
||||
if (!_spiStarted || _terminalStopping) return -1;
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (mesh::ota::ota_rak15002_sd_card_present()
|
||||
|| !mesh::ota::rak4631_ethernet_owns_spi()) return -1;
|
||||
#endif
|
||||
return client.read();
|
||||
}
|
||||
|
||||
size_t RAK13800EthernetInterface::write(const uint8_t *buf, size_t size) {
|
||||
if (!_spiStarted || _terminalStopping) return 0;
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (mesh::ota::ota_rak15002_sd_card_present()
|
||||
|| !mesh::ota::rak4631_ethernet_owns_spi()) return 0;
|
||||
#endif
|
||||
return client.write(buf, size);
|
||||
}
|
||||
|
||||
@@ -115,11 +200,31 @@ bool RAK13800EthernetInterface::isConnected() const {
|
||||
|
||||
void RAK13800EthernetInterface::disconnectClient() {
|
||||
_isConnected = false;
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (mesh::ota::ota_rak15002_sd_card_present()
|
||||
|| !mesh::ota::rak4631_ethernet_owns_spi()) return;
|
||||
#endif
|
||||
if (_spiStarted && !_terminalStopping) client.stop();
|
||||
}
|
||||
|
||||
void RAK13800EthernetInterface::loop() {
|
||||
if (!_spiStarted || _terminalStopping) return;
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (mesh::ota::ota_rak15002_sd_card_present()) {
|
||||
// Fail closed on insertion while Ethernet owns the bus. Do not send a
|
||||
// socket-close command on shared CS26 or switch a live internal OTA store.
|
||||
_terminalStopping = true;
|
||||
SerialEthernetInterface::disable();
|
||||
_terminalStopping = false;
|
||||
digitalWrite(PIN_ETHERNET_SS, HIGH);
|
||||
ETHERNET_SPI_PORT.end();
|
||||
_spiStarted = false;
|
||||
mesh::nrf52::releaseRakEthernetBusPads();
|
||||
_spiError = "SD inserted; set eth off before SD access";
|
||||
return; // Retain Ethernet's claim until the context permits release.
|
||||
}
|
||||
if (!mesh::ota::rak4631_ethernet_owns_spi()) return;
|
||||
#endif
|
||||
Ethernet.maintain();
|
||||
if (!isEnabled()) return;
|
||||
if (_isConnected && !client.connected()) {
|
||||
|
||||
@@ -11,6 +11,15 @@ class RAK13800EthernetInterface : public SerialEthernetInterface {
|
||||
bool _terminalStopping = false;
|
||||
EthernetServer server;
|
||||
EthernetClient client;
|
||||
bool beginHardware();
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
bool (*_prepareSpi)(void*) = nullptr;
|
||||
bool (*_canReleaseSpi)(void*) = nullptr;
|
||||
bool (*_releasedSpi)(void*) = nullptr;
|
||||
void* _spiContext = nullptr;
|
||||
bool _ownsSharedSpi = false;
|
||||
const char* _spiError = "off";
|
||||
#endif
|
||||
|
||||
protected:
|
||||
void disconnectClient() override;
|
||||
@@ -24,6 +33,21 @@ class RAK13800EthernetInterface : public SerialEthernetInterface {
|
||||
|
||||
bool begin();
|
||||
void loop() override;
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
void setSpiOwnershipHooks(bool (*prepare)(void*), bool (*can_release)(void*),
|
||||
bool (*released)(void*), void* context) {
|
||||
_prepareSpi = prepare; _canReleaseSpi = can_release;
|
||||
_releasedSpi = released; _spiContext = context;
|
||||
}
|
||||
bool tryEnable();
|
||||
bool tryDisable();
|
||||
bool hardwareActive() const { return _spiStarted; }
|
||||
const char* last_error() const { return _spiError; }
|
||||
// The transport manager enables every registered interface at boot. Do
|
||||
// not turn that logical operation into a physical shared-bus acquisition.
|
||||
void enable() override { if (_spiStarted) SerialEthernetInterface::enable(); }
|
||||
void disable() override { (void)tryDisable(); }
|
||||
#endif
|
||||
|
||||
// BaseSerialInterface methods
|
||||
bool isConnected() const override;
|
||||
|
||||
@@ -39,19 +39,28 @@ static SPIClass ETHERNET_SPI_PORT(NRF_SPIM1, PIN_SPI1_MISO, PIN_SPI1_SCK, PIN_SP
|
||||
|
||||
#define ETHERNET_RETRY_INTERVAL_MS 30000
|
||||
|
||||
// New optional-SD infrastructure recipes need the same cooperative, OFF by
|
||||
// default bus handoff as the combined prototype. Never start legacy DHCP on
|
||||
// the shared IO-slot CS merely because Ethernet was compiled into the image.
|
||||
#if defined(RAK4631_COMBINED_ETHERNET) || defined(OTA_RAK15002_SD_STORE)
|
||||
#define MESH_RAK_ETHERNET_CLI_RUNTIME 1
|
||||
#else
|
||||
#define MESH_RAK_ETHERNET_CLI_RUNTIME 0
|
||||
#endif
|
||||
|
||||
static EthernetServer ethernet_server(ETHERNET_TCP_PORT);
|
||||
#if !defined(RAK4631_COMBINED_ETHERNET)
|
||||
#if !MESH_RAK_ETHERNET_CLI_RUNTIME
|
||||
static EthernetClient ethernet_client;
|
||||
#endif
|
||||
static std::atomic<bool> ethernet_running{false};
|
||||
#if defined(RAK4631_COMBINED_ETHERNET)
|
||||
#if MESH_RAK_ETHERNET_CLI_RUNTIME
|
||||
static std::atomic<bool> ethernet_session_reset{false};
|
||||
static bool ethernet_line_discarding = false; // Main-thread framing state.
|
||||
#else
|
||||
static bool ethernet_session_reset = false;
|
||||
#endif
|
||||
static bool ethernet_take_session_reset() {
|
||||
#if defined(RAK4631_COMBINED_ETHERNET)
|
||||
#if MESH_RAK_ETHERNET_CLI_RUNTIME
|
||||
const bool changed = ethernet_session_reset.exchange(false);
|
||||
if (changed) ethernet_line_discarding = false;
|
||||
return changed;
|
||||
@@ -62,7 +71,7 @@ static bool ethernet_take_session_reset() {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(RAK4631_COMBINED_ETHERNET)
|
||||
#if MESH_RAK_ETHERNET_CLI_RUNTIME
|
||||
static void ethernet_check_client();
|
||||
#include "EthernetCliRuntime.h"
|
||||
#else
|
||||
@@ -174,7 +183,7 @@ static void ethernet_start_task() {
|
||||
|
||||
// Format ethernet status into reply buffer. Returns true if command was handled.
|
||||
static bool ethernet_handle_command(const char* command, char* reply) {
|
||||
#if defined(RAK4631_COMBINED_ETHERNET)
|
||||
#if MESH_RAK_ETHERNET_CLI_RUNTIME
|
||||
if (strcmp(command, "eth on") == 0 || strcmp(command, "set eth on") == 0) {
|
||||
(void)ethernet_request_start(reply, true);
|
||||
return true;
|
||||
@@ -193,7 +202,7 @@ static bool ethernet_handle_command(const char* command, char* reply) {
|
||||
}
|
||||
#endif
|
||||
if (strcmp(command, "eth.status") == 0) {
|
||||
#if defined(RAK4631_COMBINED_ETHERNET)
|
||||
#if MESH_RAK_ETHERNET_CLI_RUNTIME
|
||||
const EthernetCliState state = ethernet_state.load();
|
||||
if (state != EthernetCliState::Online) {
|
||||
const char* status = state == EthernetCliState::Off ? "off" :
|
||||
@@ -228,7 +237,8 @@ static bool ethernet_handle_command(const char* command, char* reply) {
|
||||
// available() also returns existing connected sockets that have data, which
|
||||
// would force us to disambiguate every inbound packet from a real new client.
|
||||
static void ethernet_check_client() {
|
||||
#if defined(RAK4631_COMBINED_ETHERNET)
|
||||
#if MESH_RAK_ETHERNET_CLI_RUNTIME
|
||||
if (ethernet_storage_conflict()) return;
|
||||
// Combined accept/relisten can call vendor controller commands; run only
|
||||
// in the background worker while the mesh-facing Stream is gated.
|
||||
auto newClient = ethernet_server.accept();
|
||||
@@ -272,7 +282,10 @@ static void ethernet_check_client() {
|
||||
|
||||
// Call from loop() to maintain DHCP and check for new clients
|
||||
static void ethernet_loop_maintain() {
|
||||
#if defined(RAK4631_COMBINED_ETHERNET)
|
||||
#if MESH_RAK_ETHERNET_CLI_RUNTIME
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (ethernet_enabled.load() && ethernet_storage_conflict()) return;
|
||||
#endif
|
||||
if (ethernet_state.load() == EthernetCliState::Stopping) {
|
||||
if (ethernet_worker_active.load() && !ethernet_worker_stopped.load()) {
|
||||
EthernetSpiAccess expected = EthernetSpiAccess::Idle;
|
||||
@@ -309,7 +322,7 @@ static void ethernet_loop_maintain() {
|
||||
// Returns true when a complete line is ready to process (command is null-terminated).
|
||||
// The caller should process the command and then reset ethernet_command[0] = 0.
|
||||
static bool ethernet_read_line(char* ethernet_command, size_t buf_size) {
|
||||
#if defined(RAK4631_COMBINED_ETHERNET)
|
||||
#if MESH_RAK_ETHERNET_CLI_RUNTIME
|
||||
if (buf_size < 2) return false;
|
||||
EthernetClientAccess access;
|
||||
if (!access || !ethernet_client_attached.load()) return false;
|
||||
@@ -389,7 +402,7 @@ static bool ethernet_read_line(char* ethernet_command, size_t buf_size) {
|
||||
// Send a reply to the Ethernet client
|
||||
static void ethernet_send_reply(const char* reply) {
|
||||
if (reply[0]) {
|
||||
#if defined(RAK4631_COMBINED_ETHERNET)
|
||||
#if MESH_RAK_ETHERNET_CLI_RUNTIME
|
||||
// One RAM-only enqueue keeps a synchronous command's complete reply even
|
||||
// if the worker begins renewal between command dispatch and this call.
|
||||
char frame[170];
|
||||
|
||||
@@ -3,13 +3,17 @@
|
||||
#include <cstdlib>
|
||||
#include "EthernetCliTransmit.h"
|
||||
|
||||
// Included by EthernetCLI.h only for the opt-in combined RAK4631 prototype.
|
||||
// Legacy Ethernet profiles retain their established implementation.
|
||||
// Included by EthernetCLI.h for combined or optional-SD RAK4631 recipes.
|
||||
// Both require explicit startup and a completed storage-owner handoff before
|
||||
// any worker may touch the IO-slot pins. Legacy-only profiles are unchanged.
|
||||
struct EthernetCliHooks {
|
||||
bool (*prepare)(void*, char*, size_t) = nullptr;
|
||||
bool (*can_release)(void*) = nullptr;
|
||||
bool (*released)(void*) = nullptr;
|
||||
bool (*save)(void*, bool) = nullptr;
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
bool (*storage_conflict)(void*) = nullptr; // GPIO-only, safe from either thread.
|
||||
#endif
|
||||
void* context = nullptr;
|
||||
};
|
||||
|
||||
@@ -41,6 +45,9 @@ static uint32_t ethernet_line_generation = 0; // Main-thread partial input owner
|
||||
static std::atomic<bool> ethernet_command_check_requested{false};
|
||||
static std::atomic<uint32_t> ethernet_command_check_started{0};
|
||||
static bool ethernet_controller_faulted = false;
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
static std::atomic<bool> ethernet_storage_faulted{false};
|
||||
#endif
|
||||
static mesh::nrf52::EthernetCliTransmit ethernet_transmit;
|
||||
|
||||
#ifndef ETHERNET_CLI_TX_BUFFER_BYTES
|
||||
@@ -71,6 +78,25 @@ static void ethernet_notify_worker() {
|
||||
taskEXIT_CRITICAL();
|
||||
}
|
||||
|
||||
static bool ethernet_storage_conflict() {
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (ethernet_storage_faulted.load()) return true;
|
||||
if (ethernet_bus_reserved && (!ethernet_hooks.storage_conflict ||
|
||||
ethernet_hooks.storage_conflict(ethernet_hooks.context))) {
|
||||
// A fitted card shares CS26. Gate new socket/controller transactions
|
||||
// immediately, but leave the worker to finish any already-entered vendor
|
||||
// call before ending SPI. Retain ownership until an explicit safe OFF.
|
||||
ethernet_storage_faulted.store(true);
|
||||
ethernet_running.store(false);
|
||||
ethernet_state.store(EthernetCliState::Faulted);
|
||||
ethernet_session_reset.store(true);
|
||||
ethernet_notify_worker();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ethernet_queue_clear() {
|
||||
taskENTER_CRITICAL();
|
||||
ethernet_tx_head = 0;
|
||||
@@ -116,10 +142,10 @@ class EthernetClientAccess {
|
||||
bool acquired = false;
|
||||
public:
|
||||
EthernetClientAccess() {
|
||||
if (!ethernet_running.load()) return;
|
||||
if (ethernet_storage_conflict() || !ethernet_running.load()) return;
|
||||
EthernetSpiAccess expected = EthernetSpiAccess::Idle;
|
||||
acquired = ethernet_spi_access.compare_exchange_strong(expected, EthernetSpiAccess::Client);
|
||||
if (acquired && !ethernet_running.load()) {
|
||||
if (acquired && (ethernet_storage_conflict() || !ethernet_running.load())) {
|
||||
ethernet_spi_access.store(EthernetSpiAccess::Idle);
|
||||
acquired = false;
|
||||
}
|
||||
@@ -210,7 +236,7 @@ static void ethernet_stop_hardware() {
|
||||
// The W5100S has four sockets; there is no EthernetServer::end() in the
|
||||
// library. Stop listener, accepted-client and DHCP sockets before SPI.end.
|
||||
// Never toggle the PHY reset or shared WisBlock supply during shutdown.
|
||||
if (ethernet_spi_started && ethernet_hardware_found) {
|
||||
if (!ethernet_storage_conflict() && ethernet_spi_started && ethernet_hardware_found) {
|
||||
for (uint8_t index = 0; index < 4; ++index) {
|
||||
(void)mesh::nrf52::EthernetCliTransmit::close(index);
|
||||
}
|
||||
@@ -319,6 +345,7 @@ static bool ethernet_publish_online() {
|
||||
}
|
||||
|
||||
static void ethernet_cache_ip() {
|
||||
if (ethernet_storage_conflict()) return;
|
||||
const IPAddress ip = Ethernet.localIP();
|
||||
ethernet_cached_ip.store(static_cast<uint32_t>(ip[0]) |
|
||||
(static_cast<uint32_t>(ip[1]) << 8) |
|
||||
@@ -334,6 +361,7 @@ static bool ethernet_has_tx_work() {
|
||||
}
|
||||
|
||||
static bool ethernet_controller_commands_idle() {
|
||||
if (ethernet_storage_conflict()) return false;
|
||||
SPIClass* spi = W5100.getSPI();
|
||||
if (!spi) return false;
|
||||
spi->beginTransaction(SPI_ETHERNET_SETTINGS);
|
||||
@@ -359,6 +387,7 @@ static void ethernet_poll_command_check() {
|
||||
// Worker-only, while SPI access is Worker. No library socketSend/execCmdSn
|
||||
// calls: stalled TCP acknowledgement must never hold the mesh loop.
|
||||
static void ethernet_pump_tx() {
|
||||
if (ethernet_storage_conflict()) return;
|
||||
ethernet_transmit.poll(millis());
|
||||
if (ethernet_transmit.failed()) {
|
||||
if (ethernet_raw_client) {
|
||||
@@ -395,9 +424,10 @@ static void ethernet_pump_tx() {
|
||||
}
|
||||
|
||||
static void ethernet_drain_before_stop() {
|
||||
if (!ethernet_spi_started || !ethernet_hardware_found) return;
|
||||
if (ethernet_storage_conflict() || !ethernet_spi_started || !ethernet_hardware_found) return;
|
||||
const uint32_t started = millis();
|
||||
while (ethernet_has_tx_work() && static_cast<uint32_t>(millis() - started) < 250) {
|
||||
if (ethernet_storage_conflict()) return;
|
||||
ethernet_pump_tx();
|
||||
if (!ethernet_has_tx_work()) break;
|
||||
(void)ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(10));
|
||||
@@ -409,7 +439,7 @@ static void ethernet_drain_before_stop() {
|
||||
// OFF interrupts retry waits, then lets an in-progress library call finish;
|
||||
// never delete another task in the middle of its SPI transaction.
|
||||
static void ethernet_task(void*) {
|
||||
if (ethernet_enabled.load()) {
|
||||
if (ethernet_enabled.load() && !ethernet_storage_conflict()) {
|
||||
pinMode(PIN_ETHERNET_RESET, OUTPUT);
|
||||
digitalWrite(PIN_ETHERNET_RESET, HIGH);
|
||||
ETHERNET_SPI_PORT.begin();
|
||||
@@ -418,7 +448,9 @@ static void ethernet_task(void*) {
|
||||
uint8_t mac[6];
|
||||
generateEthernetMac(mac);
|
||||
while (ethernet_enabled.load()) {
|
||||
if (ethernet_storage_conflict()) break;
|
||||
const bool connected = Ethernet.begin(mac, 10000, 2000) != 0;
|
||||
if (ethernet_storage_conflict()) break;
|
||||
ethernet_hardware_found = Ethernet.hardwareStatus() != EthernetNoHardware;
|
||||
if (!ethernet_enabled.load()) break;
|
||||
if (!ethernet_hardware_found) {
|
||||
@@ -427,6 +459,7 @@ static void ethernet_task(void*) {
|
||||
return;
|
||||
}
|
||||
if (connected) {
|
||||
if (ethernet_storage_conflict()) break;
|
||||
ethernet_server.begin();
|
||||
ethernet_cache_ip();
|
||||
ethernet_last_maintain.store(millis());
|
||||
@@ -435,10 +468,12 @@ static void ethernet_task(void*) {
|
||||
// An online OFF is notified by the next mesh-loop maintain call,
|
||||
// allowing a command received over Ethernet to send its reply first.
|
||||
ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(20));
|
||||
if (ethernet_storage_conflict()) break;
|
||||
if (!ethernet_enabled.load()) break;
|
||||
if (ethernet_controller_faulted) continue;
|
||||
const bool maintain = ethernet_maintain_requested.exchange(false);
|
||||
ethernet_worker_take_access();
|
||||
if (ethernet_storage_conflict()) break;
|
||||
ethernet_poll_command_check();
|
||||
if (ethernet_controller_faulted || ethernet_command_check_requested.load()) {
|
||||
// Preserve the maintenance request while command checking yields.
|
||||
@@ -446,6 +481,7 @@ static void ethernet_task(void*) {
|
||||
continue;
|
||||
}
|
||||
if (maintain) (void)Ethernet.maintain();
|
||||
if (ethernet_storage_conflict()) break;
|
||||
if (!ethernet_enabled.load()) break;
|
||||
if (maintain) ethernet_last_maintain.store(millis());
|
||||
// Do not enter vendor accept/relisten while SEND/RECV is pending.
|
||||
@@ -465,10 +501,17 @@ static void ethernet_task(void*) {
|
||||
ethernet_worker_take_access();
|
||||
ethernet_drain_before_stop();
|
||||
ethernet_stop_hardware();
|
||||
ethernet_finish_task(EthernetCliState::Stopping);
|
||||
ethernet_finish_task(ethernet_storage_conflict() && ethernet_enabled.load()
|
||||
? EthernetCliState::Faulted : EthernetCliState::Stopping);
|
||||
}
|
||||
|
||||
static bool ethernet_request_start(char* reply, bool persist) {
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (ethernet_storage_faulted.load() && ethernet_enabled.load()) {
|
||||
strcpy(reply, "Error: SD insertion stopped Ethernet; turn Ethernet off first");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
if (ethernet_state.load() == EthernetCliState::Stopping) {
|
||||
strcpy(reply, "Error: Ethernet is still stopping");
|
||||
return false;
|
||||
@@ -489,6 +532,12 @@ static bool ethernet_request_start(char* reply, bool persist) {
|
||||
strcpy(reply, "Error: Ethernet bus safety hooks unavailable");
|
||||
return false;
|
||||
}
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (!ethernet_hooks.storage_conflict) {
|
||||
strcpy(reply, "Error: Ethernet storage-conflict hook unavailable");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
reply[0] = 0;
|
||||
if (!ethernet_hooks.prepare(ethernet_hooks.context, reply, 160)) {
|
||||
if (!reply[0]) strcpy(reply, "Error: Ethernet bus is busy");
|
||||
@@ -510,6 +559,9 @@ static bool ethernet_request_start(char* reply, bool persist) {
|
||||
return false;
|
||||
}
|
||||
ethernet_enabled.store(true);
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
ethernet_storage_faulted.store(false);
|
||||
#endif
|
||||
ethernet_controller_faulted = false;
|
||||
ethernet_command_check_requested.store(false);
|
||||
ethernet_maintain_requested.store(false);
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(RAK4631_COMBINED_ETHERNET)
|
||||
#if defined(RAK4631_COMBINED_ETHERNET) || defined(OTA_RAK15002_SD_STORE)
|
||||
|
||||
#include <atomic>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mesh {
|
||||
namespace ota {
|
||||
@@ -11,17 +12,41 @@ namespace ota {
|
||||
// controller at a time. Reserve them before starting Ethernet's DHCP task;
|
||||
// release them only after that task and every Ethernet socket have stopped.
|
||||
// NOR discovery and QSPI staging must never touch these pins while reserved.
|
||||
inline std::atomic<bool>& rak4631_ethernet_spi_owner() {
|
||||
static std::atomic<bool> owner{false};
|
||||
enum class RakSharedSpiOwner : uint8_t { None, Ethernet, Sd, Nor };
|
||||
|
||||
inline std::atomic<RakSharedSpiOwner>& rak4631_shared_spi_owner() {
|
||||
static std::atomic<RakSharedSpiOwner> owner{RakSharedSpiOwner::None};
|
||||
return owner;
|
||||
}
|
||||
|
||||
inline RakSharedSpiOwner rak4631_spi_owner() {
|
||||
return rak4631_shared_spi_owner().load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
// Claims are main-loop lifetime reservations, not a recursive transaction
|
||||
// lock. The same sole backend may confirm its retained claim; another device
|
||||
// must never overwrite it, including on a failed mount or DHCP startup.
|
||||
inline bool rak4631_try_acquire_spi(RakSharedSpiOwner wanted) {
|
||||
if (wanted == RakSharedSpiOwner::None) return false;
|
||||
auto expected = RakSharedSpiOwner::None;
|
||||
return rak4631_shared_spi_owner().compare_exchange_strong(
|
||||
expected, wanted, std::memory_order_acq_rel) || expected == wanted;
|
||||
}
|
||||
|
||||
inline void rak4631_release_spi(RakSharedSpiOwner owner) {
|
||||
if (owner == RakSharedSpiOwner::None) return;
|
||||
auto expected = owner;
|
||||
(void)rak4631_shared_spi_owner().compare_exchange_strong(
|
||||
expected, RakSharedSpiOwner::None, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
inline bool rak4631_ethernet_owns_spi() {
|
||||
return rak4631_ethernet_spi_owner().load(std::memory_order_acquire);
|
||||
return rak4631_spi_owner() == RakSharedSpiOwner::Ethernet;
|
||||
}
|
||||
|
||||
inline void rak4631_set_ethernet_spi_owner(bool ethernet) {
|
||||
rak4631_ethernet_spi_owner().store(ethernet, std::memory_order_release);
|
||||
if (ethernet) (void)rak4631_try_acquire_spi(RakSharedSpiOwner::Ethernet);
|
||||
else rak4631_release_spi(RakSharedSpiOwner::Ethernet);
|
||||
}
|
||||
|
||||
} // namespace ota
|
||||
|
||||
@@ -466,7 +466,9 @@ bool ota_apply_detools_mota(const uint8_t*, uint32_t, const SignerAllowlist&, Ap
|
||||
static OtaStoreFlashNrf52* g_nrf52_apply_store = nullptr;
|
||||
#endif
|
||||
#if defined(OTA_QSPI_STORE)
|
||||
static uint8_t g_nrf52_qspi_handoff = GPREGRET2_OTA_STAGE_QSPI;
|
||||
// Set by the successfully verified external application path, never inferred
|
||||
// from compile-time store flags: the same RAK image supports NOR and SD.
|
||||
static uint8_t g_nrf52_external_handoff = GPREGRET2_OTA_STAGE_QSPI;
|
||||
#endif
|
||||
|
||||
static void ota_nrf52_set_reset_handoff(uint8_t request, uint8_t source) {
|
||||
@@ -514,13 +516,13 @@ void ota_reboot_to_apply() { // public: set the apply magic +
|
||||
#if defined(OTA_TOWER_AUTO_STORE)
|
||||
stage_handoff = GPREGRET2_OTA_STAGE_SD;
|
||||
#else
|
||||
stage_handoff = g_nrf52_qspi_handoff;
|
||||
stage_handoff = g_nrf52_external_handoff;
|
||||
#endif
|
||||
}
|
||||
#elif defined(OTA_SD_STORE)
|
||||
stage_handoff = GPREGRET2_OTA_STAGE_SD;
|
||||
#elif defined(OTA_QSPI_STORE)
|
||||
stage_handoff = g_nrf52_qspi_handoff;
|
||||
stage_handoff = g_nrf52_external_handoff;
|
||||
#elif defined(OTA_FLASH_STORE)
|
||||
if (g_nrf52_apply_store && g_nrf52_apply_store->is_hybrid()) {
|
||||
// The bootloader admits retained SRAM only after a clean software-reset
|
||||
@@ -1155,9 +1157,21 @@ static bool ota_prepare_bootloader_update_external(Store& store,
|
||||
#if defined(OTA_SD_STORE)
|
||||
bool ota_apply_mota_nrf52(OtaStoreSdNrf52& store, const SignerAllowlist& allow,
|
||||
ApplyState& st, char* msg) {
|
||||
#if defined(OTA_TOWER_AUTO_STORE)
|
||||
#if defined(OTA_TOWER_AUTO_STORE) || defined(OTA_RAK_AUTO_STORE)
|
||||
g_nrf52_apply_store = nullptr;
|
||||
#endif
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
OtaBootloaderIdentity rak_identity;
|
||||
const OtaBlCaps rak_caps = ota_bootloader_app_caps();
|
||||
if (rak_caps.optional_sd_app_storage != OTA_BL_STORAGE_SD ||
|
||||
!ota_installed_bootloader_identity(rak_identity) || !rak_identity.crc_ok ||
|
||||
(strcmp(rak_identity.device_name, "4631_DFU") != 0 &&
|
||||
strcmp(rak_identity.device_name, "4631_AUTO_DFU") != 0)) {
|
||||
st = ApplyState();
|
||||
strcpy(msg, "RAK SD application OTA requires the matching all-in-one OTAFIX bootloader");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
#if defined(OTA_SD_BOOTLOADER_UPDATE)
|
||||
OtaBootloaderIdentity installed;
|
||||
if (!ota_installed_bootloader_identity(installed) ||
|
||||
@@ -1170,7 +1184,12 @@ bool ota_apply_mota_nrf52(OtaStoreSdNrf52& store, const SignerAllowlist& allow,
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return ota_apply_mota_nrf52_external(store, allow, OTA_BL_STORAGE_SD, "SD", true, st, msg);
|
||||
if (!ota_apply_mota_nrf52_external(store, allow, OTA_BL_STORAGE_SD, "SD", true, st, msg))
|
||||
return false;
|
||||
#if defined(OTA_RAK15002_SD_STORE) && defined(OTA_RAK_AUTO_STORE)
|
||||
g_nrf52_external_handoff = GPREGRET2_OTA_STAGE_SD;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(OTA_SD_BOOTLOADER_UPDATE)
|
||||
@@ -1214,13 +1233,13 @@ bool ota_apply_mota_nrf52(OtaStoreQspiNrf52& store, const SignerAllowlist& allow
|
||||
#if defined(OTA_RAK_AUTO_STORE)
|
||||
g_nrf52_apply_store = nullptr;
|
||||
#endif
|
||||
g_nrf52_qspi_handoff = GPREGRET2_OTA_STAGE_QSPI;
|
||||
g_nrf52_external_handoff = GPREGRET2_OTA_STAGE_QSPI;
|
||||
if (!ota_apply_mota_nrf52_external(store, allow, OTA_BL_STORAGE_QSPI, "QSPI", false, st, msg)) {
|
||||
return false;
|
||||
}
|
||||
#if defined(OTA_RAK_AUTO_STORE)
|
||||
if (OtaStoreQspiNrf52::headerW25Detected()) {
|
||||
g_nrf52_qspi_handoff = GPREGRET2_OTA_STAGE_HEADER_W25;
|
||||
g_nrf52_external_handoff = GPREGRET2_OTA_STAGE_HEADER_W25;
|
||||
}
|
||||
#endif
|
||||
#if defined(OTA_RAK_AUTO_STORE) && !defined(RAK_3401)
|
||||
@@ -1228,7 +1247,7 @@ bool ota_apply_mota_nrf52(OtaStoreQspiNrf52& store, const SignerAllowlist& allow
|
||||
OtaBootloaderIdentity identity;
|
||||
if (ota_installed_bootloader_identity(identity) && identity.crc_ok &&
|
||||
strcmp(identity.device_name, "4631_AUTO_DFU") == 0) {
|
||||
g_nrf52_qspi_handoff = GPREGRET2_OTA_STAGE_RAK15001;
|
||||
g_nrf52_external_handoff = GPREGRET2_OTA_STAGE_RAK15001;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1338,6 +1357,16 @@ bool ota_prepare_bootloader_update_nrf52(OtaStoreFlashNrf52& store,
|
||||
ota_bl_optional_app_storage(image, OTA_BOOT_IMAGE_SIZE) != optional_storage) {
|
||||
strcpy(msg, "candidate must retain optional RAK application storage"); return false;
|
||||
}
|
||||
#if defined(RAK_4631) || defined(OTA_RAK15002_SD_STORE)
|
||||
const OtaBlCaps installed_app_caps = ota_bootloader_app_caps();
|
||||
if (installed_app_caps.optional_sd_app_storage != 0 &&
|
||||
ota_bl_rak_sd_app_storage(image, OTA_BOOT_IMAGE_SIZE,
|
||||
candidate_caps.storage_flags,
|
||||
ota_bl_optional_app_storage(image, OTA_BOOT_IMAGE_SIZE)) !=
|
||||
installed_app_caps.optional_sd_app_storage) {
|
||||
strcpy(msg, "candidate must retain authenticated RAK SD application storage"); return false;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
const OtaBootloaderContinuityGate continuity = ota_bootloader_continuity_gate(
|
||||
installed, candidate, m.fw_version, OTA_BOOT_CONTINUITY_FAMILY_S140,
|
||||
|
||||
@@ -94,6 +94,10 @@ bool ota_rescue_mota_nrf52(const uint8_t* buf, uint32_t len,
|
||||
uint32_t local_target_id, ApplyState& st, char* msg);
|
||||
#if defined(NRF52_PLATFORM) && defined(OTA_SD_STORE)
|
||||
class OtaStoreSdNrf52;
|
||||
// Removable-media application apply always requires a trusted signature and
|
||||
// contiguous staging plus retained authorization. RAK15002 additionally needs
|
||||
// the exact supplemental all-in-one loader capability; SD never stages its
|
||||
// bootloader packages, which continue through the internal-store overload.
|
||||
bool ota_apply_mota_nrf52(OtaStoreSdNrf52& store,
|
||||
const SignerAllowlist& allow, ApplyState& st, char* msg);
|
||||
#if defined(OTA_SD_BOOTLOADER_UPDATE)
|
||||
|
||||
@@ -29,6 +29,7 @@ struct OtaBlCaps {
|
||||
uint16_t codec_mask = 0; // bit i set => can apply codec_id i (in-place delta = bit 2)
|
||||
uint8_t storage_flags = 0; // OTA_BL_STORAGE_* capability bits
|
||||
uint8_t optional_app_storage = 0; // separate MOTASTOR record, scoped to its qualified primary profile
|
||||
uint8_t optional_sd_app_storage = 0; // supplemental MOTASDRA; application-only RAK15002 support
|
||||
};
|
||||
|
||||
// Independent marker for the reset-retained hybrid source. Keep this separate
|
||||
@@ -256,12 +257,37 @@ inline uint8_t ota_bl_profile_optional_app_storage(const uint8_t* bytes,
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The all-in-one RAK4631 loader deliberately keeps its deployed internal/NOR
|
||||
// capability bytes unchanged. SD application apply is a separate, exact ABI;
|
||||
// it never grants SD bootloader updates. Count every aligned magic, including
|
||||
// malformed/truncated declarations, so a second record cannot hide a conflict.
|
||||
inline uint8_t ota_bl_rak_sd_app_storage(const uint8_t* bytes, size_t len,
|
||||
uint8_t primary_storage,
|
||||
uint8_t optional_storage) {
|
||||
static const uint8_t marker[16] = {
|
||||
'M', 'O', 'T', 'A', 'S', 'D', 'R', 'A', 1, 0, 72, 0, 1, 0x53, 0, 0,
|
||||
};
|
||||
if (!bytes || primary_storage != OTA_BL_PROFILE_INTERNAL_BOOT_UPDATE ||
|
||||
optional_storage != (OTA_BL_STORAGE_QSPI | OTA_BL_STORAGE_HEADER_W25)) return 0;
|
||||
unsigned matches = 0;
|
||||
for (size_t off = 0; off + 8u <= len; off += 4u) {
|
||||
if (memcmp(bytes + off, marker, 8u) != 0) continue;
|
||||
if (++matches != 1u || off + sizeof(marker) > len ||
|
||||
memcmp(bytes + off, marker, sizeof(marker)) != 0) return 0;
|
||||
}
|
||||
return matches == 1u ? OTA_BL_STORAGE_SD : 0;
|
||||
}
|
||||
|
||||
inline OtaBlCaps ota_bl_app_caps_scan(const uint8_t* bytes, size_t len) {
|
||||
OtaBlCaps aligned = ota_bl_caps_scan_aligned(bytes, len, false);
|
||||
if (aligned.present && aligned.apply_abi >= 3) {
|
||||
aligned.optional_app_storage = ota_bl_profile_optional_app_storage(
|
||||
bytes, len, aligned.storage_flags);
|
||||
aligned.storage_flags |= aligned.optional_app_storage;
|
||||
#if !defined(NRF52_PLATFORM) || defined(RAK_4631) || defined(OTA_RAK15002_SD_STORE)
|
||||
aligned.optional_sd_app_storage = ota_bl_rak_sd_app_storage(
|
||||
bytes, len, aligned.storage_flags, aligned.optional_app_storage);
|
||||
#endif
|
||||
aligned.storage_flags |= aligned.optional_app_storage | aligned.optional_sd_app_storage;
|
||||
}
|
||||
if (aligned.present) return aligned;
|
||||
return ota_bl_legacy_app_caps_scan_halfword(bytes, len);
|
||||
@@ -276,6 +302,10 @@ inline OtaBlCaps ota_bl_update_caps_scan_aligned(const uint8_t* bytes, size_t le
|
||||
// require an existing optional application capability in a successor.
|
||||
caps.optional_app_storage = ota_bl_profile_optional_app_storage(
|
||||
bytes, len, caps.storage_flags);
|
||||
#if !defined(NRF52_PLATFORM) || defined(RAK_4631) || defined(OTA_RAK15002_SD_STORE)
|
||||
caps.optional_sd_app_storage = ota_bl_rak_sd_app_storage(
|
||||
bytes, len, caps.storage_flags, caps.optional_app_storage);
|
||||
#endif
|
||||
}
|
||||
return caps;
|
||||
}
|
||||
@@ -317,7 +347,15 @@ inline OtaBlCaps ota_bootloader_update_caps() {
|
||||
#if defined(OTA_INTERNAL_BOOTLOADER_UPDATE) && defined(OTA_RAK_AUTO_STORE)
|
||||
// Unified RAK applications support the existing internal board identity as
|
||||
// well as the adaptive successor. Both require one privileged marker.
|
||||
const OtaBlCaps caps = ota_bl_caps_scan_aligned(lo, (size_t)(hi - lo), true);
|
||||
OtaBlCaps caps = ota_bl_caps_scan_aligned(lo, (size_t)(hi - lo), true);
|
||||
if (caps.present) {
|
||||
caps.optional_app_storage = ota_bl_profile_optional_app_storage(
|
||||
lo, (size_t)(hi - lo), caps.storage_flags);
|
||||
#if defined(RAK_4631) || defined(OTA_RAK15002_SD_STORE)
|
||||
caps.optional_sd_app_storage = ota_bl_rak_sd_app_storage(
|
||||
lo, (size_t)(hi - lo), caps.storage_flags, caps.optional_app_storage);
|
||||
#endif
|
||||
}
|
||||
return ota_bootloader_self_update_caps_valid(caps) ? caps : OtaBlCaps();
|
||||
#else
|
||||
return ota_bl_update_caps_scan_aligned(
|
||||
|
||||
@@ -40,7 +40,8 @@
|
||||
#error "OTA_INTERNAL_BOOTLOADER_UPDATE requires nRF52 internal-flash staging"
|
||||
#endif
|
||||
#if (defined(OTA_QSPI_STORE) && !defined(OTA_RAK_AUTO_STORE)) || \
|
||||
defined(OTA_SD_STORE) || defined(QSPIFLASH)
|
||||
(defined(OTA_SD_STORE) && !(defined(OTA_RAK15002_SD_STORE) && \
|
||||
defined(OTA_RAK_AUTO_STORE) && defined(RAK_4631))) || defined(QSPIFLASH)
|
||||
#error "internal bootloader staging cannot share an external OTA/filesystem store"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace ota {
|
||||
const char* const OtaCacheSdNrf52::DIR = "/mota";
|
||||
const char* const OtaCacheSdNrf52::DISABLED_PATH = "/mota/cache.off";
|
||||
|
||||
OtaCacheSdNrf52::OtaCacheSdNrf52() : _file(new (std::nothrow) FsFile()) {}
|
||||
OtaCacheSdNrf52::OtaCacheSdNrf52() : _file(new (std::nothrow) OtaSdFile()) {}
|
||||
|
||||
OtaCacheSdNrf52::~OtaCacheSdNrf52() {
|
||||
if (_file) { _file->close(); delete _file; }
|
||||
@@ -58,6 +58,9 @@ bool OtaCacheSdNrf52::ensureDir() {
|
||||
}
|
||||
|
||||
bool OtaCacheSdNrf52::initialize() {
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (!ready()) return false;
|
||||
#endif
|
||||
if (_initialized) return true;
|
||||
_error[0] = 0;
|
||||
if (!ready() || !ensureDir()) return false;
|
||||
@@ -72,7 +75,7 @@ static int cache_hex_nibble(char c) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool OtaCacheSdNrf52::describeFile(FsFile& file, MotaDesc& out) const {
|
||||
bool OtaCacheSdNrf52::describeFile(OtaSdFile& file, MotaDesc& out) const {
|
||||
uint64_t size64 = file.fileSize();
|
||||
if (size64 < 8 + MOTA_MFL + 5 || size64 > UINT32_MAX) return false;
|
||||
const uint32_t total = (uint32_t)size64;
|
||||
@@ -111,9 +114,9 @@ bool OtaCacheSdNrf52::rescan() {
|
||||
_count = 0;
|
||||
if (!ready() || !ensureDir()) return false;
|
||||
|
||||
FsFile dir = _owner->_sd->open(DIR, O_RDONLY);
|
||||
OtaSdFile dir = _owner->_sd->open(DIR, O_RDONLY);
|
||||
if (!dir || !dir.isDir()) { fail("SD archive directory open failed"); return false; }
|
||||
FsFile file;
|
||||
OtaSdFile file;
|
||||
while (_count < OTA_SD_CACHE_MAX && file.openNext(&dir, O_RDONLY)) {
|
||||
if (!file.isDir()) {
|
||||
char name[24] = {0};
|
||||
@@ -156,7 +159,7 @@ bool OtaCacheSdNrf52::contains(const uint8_t mid[4]) {
|
||||
// never enough: malformed files must remain eligible for quarantine and a clean re-download.
|
||||
char path[32];
|
||||
pathFor(mid, "mota", path, sizeof(path));
|
||||
FsFile file = _owner->_sd->open(path, O_RDONLY);
|
||||
OtaSdFile file = _owner->_sd->open(path, O_RDONLY);
|
||||
MotaDesc d;
|
||||
bool valid = file && describeFile(file, d) && memcmp(d.mid, mid, 4) == 0;
|
||||
file.close();
|
||||
@@ -188,7 +191,7 @@ bool OtaCacheSdNrf52::setAutoCaptureEnabled(bool enabled) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
FsFile marker = _owner->_sd->open(DISABLED_PATH, O_WRONLY | O_CREAT | O_TRUNC);
|
||||
OtaSdFile marker = _owner->_sd->open(DISABLED_PATH, O_WRONLY | O_CREAT | O_TRUNC);
|
||||
static const uint8_t off[] = {'o', 'f', 'f', '\n'};
|
||||
if (!marker || marker.write(off, sizeof(off)) != sizeof(off) || !marker.sync()) {
|
||||
marker.close();
|
||||
@@ -295,6 +298,9 @@ bool OtaCacheSdNrf52::set_meta_size(uint32_t meta_bytes) {
|
||||
}
|
||||
|
||||
bool OtaCacheSdNrf52::write(uint32_t off, const uint8_t* data, uint32_t len) {
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (!_owner || !_owner->busAccessAllowed()) return false;
|
||||
#endif
|
||||
if (!_file || !*_file || (uint64_t)off + len > _total || !_file->seekSet(off) ||
|
||||
_file->write(data, len) != len) {
|
||||
fail("SD archive write failed");
|
||||
@@ -304,17 +310,26 @@ bool OtaCacheSdNrf52::write(uint32_t off, const uint8_t* data, uint32_t len) {
|
||||
}
|
||||
|
||||
bool OtaCacheSdNrf52::read(uint32_t off, uint8_t* buf, uint32_t len) const {
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (!_owner || !_owner->busAccessAllowed()) return false;
|
||||
#endif
|
||||
return _file && *_file && (uint64_t)off + len <= _total && _file->seekSet(off) &&
|
||||
_file->read(buf, len) == (int)len;
|
||||
}
|
||||
|
||||
uint32_t OtaCacheSdNrf52::capacity() const {
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (!_owner || !_owner->busAccessAllowed()) return 0;
|
||||
#endif
|
||||
if (!_owner || !_owner->_mounted || !_owner->_sd || !_owner->_sd->card()) return 0;
|
||||
uint64_t bytes = (uint64_t)_owner->_sd->card()->sectorCount() * 512;
|
||||
return bytes > UINT32_MAX ? UINT32_MAX : (uint32_t)bytes;
|
||||
}
|
||||
|
||||
void OtaCacheSdNrf52::checkpoint() {
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (!_owner || !_owner->busAccessAllowed()) return;
|
||||
#endif
|
||||
if (_file && *_file) {
|
||||
_file->sync();
|
||||
if (_owner && _owner->_sd->card()) _owner->_sd->card()->syncDevice();
|
||||
@@ -322,6 +337,9 @@ void OtaCacheSdNrf52::checkpoint() {
|
||||
}
|
||||
|
||||
bool OtaCacheSdNrf52::finalize() {
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (!_owner || !_owner->busAccessAllowed()) return false;
|
||||
#endif
|
||||
if (!_file || !*_file || !_total || !_file->sync()) { fail("SD archive sync failed"); return false; }
|
||||
if (_owner->_sd->card() && !_owner->_sd->card()->syncDevice()) {
|
||||
fail("SD archive card sync failed");
|
||||
@@ -332,7 +350,7 @@ bool OtaCacheSdNrf52::finalize() {
|
||||
pathFor(_mid, "part", part_path, sizeof(part_path));
|
||||
_file->close();
|
||||
|
||||
FsFile check = _owner->_sd->open(part_path, O_RDONLY);
|
||||
OtaSdFile check = _owner->_sd->open(part_path, O_RDONLY);
|
||||
MotaDesc d;
|
||||
bool valid = check && describeFile(check, d) && memcmp(d.mid, _mid, 4) == 0;
|
||||
check.close();
|
||||
@@ -396,11 +414,16 @@ bool OtaCacheSdNrf52::describe(uint8_t idx, MotaDesc& out) {
|
||||
}
|
||||
|
||||
bool OtaCacheSdNrf52::read(uint8_t idx, uint32_t off, uint8_t* buf, uint32_t len) {
|
||||
if (!_initialized || idx >= _count || (uint64_t)off + len > _entries[idx].total_size || !ready())
|
||||
return false;
|
||||
if (!_initialized || idx >= _count) return false;
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
const uint32_t total_size = _entries[idx].totalSize();
|
||||
#else
|
||||
const uint32_t total_size = _entries[idx].total_size;
|
||||
#endif
|
||||
if ((uint64_t)off + len > total_size || !ready()) return false;
|
||||
char path[32];
|
||||
pathFor(_entries[idx].mid, "mota", path, sizeof(path));
|
||||
FsFile file = _owner->_sd->open(path, O_RDONLY);
|
||||
OtaSdFile file = _owner->_sd->open(path, O_RDONLY);
|
||||
bool ok = file && file.seekSet(off) && file.read(buf, len) == (int)len;
|
||||
file.close();
|
||||
return ok;
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
|
||||
#include "OtaSource.h"
|
||||
#include "OtaStore.h"
|
||||
|
||||
class FsFile;
|
||||
#include "OtaSdTypesNrf52.h"
|
||||
|
||||
namespace mesh {
|
||||
namespace ota {
|
||||
@@ -23,7 +22,7 @@ class OtaStoreSdNrf52;
|
||||
|
||||
// Persistent capture destination and MotaSource for the SD OTA archive. Completed containers live as
|
||||
// /mota/<mid>.mota; an in-progress capture uses /mota/<mid>.part and can resume after interruption.
|
||||
// This object shares the staging store's mounted SdFs volume so FAT metadata never has two independent
|
||||
// This object shares the staging store's mounted volume so FAT metadata never has two independent
|
||||
// caches for the same card.
|
||||
class OtaCacheSdNrf52 : public OtaStore, public MotaSource {
|
||||
public:
|
||||
@@ -68,14 +67,48 @@ private:
|
||||
|
||||
bool ready();
|
||||
bool ensureDir();
|
||||
bool describeFile(FsFile& file, MotaDesc& out) const;
|
||||
bool describeFile(OtaSdFile& file, MotaDesc& out) const;
|
||||
bool quarantineFinal(const uint8_t mid[4]);
|
||||
void pathFor(const uint8_t mid[4], const char* ext, char* out, size_t cap) const;
|
||||
void fail(const char* message);
|
||||
|
||||
OtaStoreSdNrf52* _owner = nullptr;
|
||||
FsFile* _file = nullptr;
|
||||
OtaSdFile* _file = nullptr;
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
// Valid archive files all have the fixed manifest followed immediately by
|
||||
// leaves and payload. Keep every descriptor field without caching three
|
||||
// redundant offsets/sizes per entry (192 bytes saved at 16 entries).
|
||||
struct CachedDesc {
|
||||
uint8_t mid[4];
|
||||
uint32_t target_id, fw_version, block_count, payload_size;
|
||||
uint8_t codec_id, flags, block_size_log2, source_caps;
|
||||
CachedDesc& operator=(const MotaDesc& d) {
|
||||
for (unsigned i = 0; i < 4; ++i) mid[i] = d.mid[i];
|
||||
target_id = d.target_id; fw_version = d.fw_version;
|
||||
block_count = d.block_count; payload_size = d.payload_size;
|
||||
codec_id = d.codec_id; flags = d.flags;
|
||||
block_size_log2 = d.block_size_log2; source_caps = d.source_caps;
|
||||
return *this;
|
||||
}
|
||||
uint32_t totalSize() const { return 8u + MOTA_MFL + block_count * 4u + payload_size + 5u; }
|
||||
operator MotaDesc() const {
|
||||
MotaDesc d;
|
||||
for (unsigned i = 0; i < 4; ++i) d.mid[i] = mid[i];
|
||||
d.target_id = target_id; d.fw_version = fw_version;
|
||||
d.block_count = block_count; d.payload_size = payload_size;
|
||||
d.codec_id = codec_id; d.flags = flags;
|
||||
d.block_size_log2 = block_size_log2; d.source_caps = source_caps;
|
||||
d.leaves_off = 8u + MOTA_MFL;
|
||||
d.payload_off = d.leaves_off + block_count * 4u;
|
||||
d.total_size = totalSize();
|
||||
return d;
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(CachedDesc) == 24u, "bounded RAK SD index changed");
|
||||
CachedDesc _entries[OTA_SD_CACHE_MAX];
|
||||
#else
|
||||
MotaDesc _entries[OTA_SD_CACHE_MAX];
|
||||
#endif
|
||||
uint8_t _count = 0;
|
||||
uint8_t _mid[4] = {0};
|
||||
uint32_t _total = 0;
|
||||
|
||||
+73
-10
@@ -200,7 +200,7 @@ static __attribute__((noinline)) bool handle_status(char* reply, OtaContext& c)
|
||||
c.fetch_store.usesInternal() ? "internal" : "storage-ERR";
|
||||
#elif defined(OTA_RAK_AUTO_STORE)
|
||||
const char* bl_state = !bl.present ? "NONE" :
|
||||
c.fetch_store.usesExternal() ? "QSPI" :
|
||||
c.fetch_store.usesSd() ? "SD" : c.fetch_store.usesQspi() ? "QSPI" :
|
||||
c.fetch_store.usesInternal() ? "internal" : "storage-ERR";
|
||||
#elif defined(OTA_QSPI_STORE)
|
||||
const char* bl_state = !bl.present ? "NONE" :
|
||||
@@ -267,7 +267,8 @@ static __attribute__((noinline)) bool handle_neighbors(
|
||||
const OtaBlCaps& list_bl_update = c.bootloaderUpdateCaps();
|
||||
#endif
|
||||
#endif
|
||||
#if defined(NRF52_PLATFORM) && defined(OTA_FLASH_STORE) && !defined(OTA_SD_STORE) && \
|
||||
#if defined(NRF52_PLATFORM) && defined(OTA_FLASH_STORE) && \
|
||||
(!defined(OTA_SD_STORE) || defined(OTA_RAK15002_SD_STORE)) && \
|
||||
(!defined(OTA_QSPI_STORE) || defined(OTA_RAK_AUTO_STORE))
|
||||
SelfFwInfo list_self;
|
||||
bool list_has_endf = ota_self_firmware(list_self) && list_self.valid;
|
||||
@@ -337,11 +338,17 @@ static __attribute__((noinline)) bool handle_neighbors(
|
||||
installable = installable && c.fetch_store.compatible();
|
||||
if (h->codec == CODEC_FULL)
|
||||
installable = installable && c.fetch_store.usesExternal();
|
||||
#elif defined(OTA_SD_STORE)
|
||||
#elif defined(OTA_SD_STORE) && !defined(OTA_RAK_AUTO_STORE)
|
||||
installable = installable && (list_bl.storage_flags & OTA_BL_STORAGE_SD);
|
||||
#elif defined(OTA_RAK_AUTO_STORE)
|
||||
if (c.fetch_store.usesExternal())
|
||||
if (c.fetch_store.usesQspi())
|
||||
installable = installable && (list_bl.storage_flags & OTA_BL_STORAGE_QSPI);
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (c.fetch_store.usesSd())
|
||||
installable = installable && list_bl.optional_sd_app_storage == OTA_BL_STORAGE_SD &&
|
||||
(h->flags & MFLAG_SIGNED);
|
||||
#endif
|
||||
installable = installable && (c.fetch_store.usesExternal() || c.fetch_store.usesInternal());
|
||||
if (h->codec == CODEC_FULL)
|
||||
installable = installable && c.fetch_store.usesExternal();
|
||||
#elif defined(OTA_QSPI_STORE)
|
||||
@@ -388,6 +395,11 @@ bool handle_ota_command(const char* command, char* reply, mesh::MainBoard& board
|
||||
#endif
|
||||
const char* rest = a;
|
||||
if (*a == 0 || is_cmd(a, "status|st", &rest)) return handle_status(reply, c);
|
||||
#if defined(NRF52_PLATFORM) && defined(OTA_RAK15002_SD_STORE) && !defined(OTA_SEEDER_ONLY)
|
||||
// Radio/USB startup and status remain independent of removable storage.
|
||||
// Explicit transfer/catalog/cache work may prepare it at this main-loop boundary.
|
||||
if (!is_cmd(a, "qspi|storage|self|id|stats|help|?|h", &rest)) c.prepareRakStorage();
|
||||
#endif
|
||||
if (is_cmd(a, "neighbors|nbrs|updates|ls|n", &rest))
|
||||
return handle_neighbors(rest, reply, c);
|
||||
return handle_control_command(a, reply, board, c);
|
||||
@@ -425,7 +437,11 @@ static __attribute__((noinline)) bool handle_control_command(
|
||||
#endif
|
||||
#elif defined(NRF52_PLATFORM) && defined(OTA_RAK_AUTO_STORE)
|
||||
strcpy(reply,
|
||||
"OTA: status | stats | ls | get <id> flash | install | bootloader | cancel | announce | self | serve | storage | folder | config | key");
|
||||
"OTA: status | stats | ls | get <id> flash | install | bootloader | cancel | announce | self | serve | storage | folder | "
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
"cache | "
|
||||
#endif
|
||||
"config | key");
|
||||
#elif defined(NRF52_PLATFORM) && defined(OTA_QSPI_STORE)
|
||||
#if defined(OTA_QSPI_BOOTLOADER_UPDATE)
|
||||
strcpy(reply,
|
||||
@@ -658,7 +674,7 @@ static __attribute__((noinline)) bool handle_control_command(
|
||||
snprintf(reply, 160, "ERR OTA storage unsafe: %s", c.fetch_store.selectionReason());
|
||||
return true;
|
||||
}
|
||||
#elif defined(OTA_SD_STORE)
|
||||
#elif defined(OTA_SD_STORE) && !defined(OTA_RAK_AUTO_STORE)
|
||||
if (!(bl.storage_flags & OTA_BL_STORAGE_SD)) {
|
||||
strcpy(reply, "ERR bootloader cannot apply an update staged on SD; update it over USB first");
|
||||
return true;
|
||||
@@ -667,10 +683,26 @@ static __attribute__((noinline)) bool handle_control_command(
|
||||
// Bootloader packages passed their separate privileged checks above and
|
||||
// select internal staging when their manifest arrives. The currently
|
||||
// selected application backend must not veto that transition.
|
||||
if (!selboot && c.fetch_store.usesExternal() && !(bl.storage_flags & OTA_BL_STORAGE_QSPI)) {
|
||||
if (!selboot &&
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
c.fetch_store.usesQspi() &&
|
||||
#else
|
||||
c.fetch_store.usesExternal() &&
|
||||
#endif
|
||||
!(bl.storage_flags & OTA_BL_STORAGE_QSPI)) {
|
||||
strcpy(reply, "ERR bootloader cannot apply from detected QSPI storage");
|
||||
return true;
|
||||
}
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (!selboot && c.fetch_store.usesSd() && bl.optional_sd_app_storage != OTA_BL_STORAGE_SD) {
|
||||
strcpy(reply, "ERR bootloader lacks authenticated RAK SD application support");
|
||||
return true;
|
||||
}
|
||||
if (!selboot && c.fetch_store.usesSd() && !(selflags & MFLAG_SIGNED)) {
|
||||
strcpy(reply, "ERR SD application install requires a trusted signed package; use folder to inspect");
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
if (!selboot && !c.fetch_store.usesExternal() && !c.fetch_store.usesInternal()) {
|
||||
snprintf(reply, 160, "ERR OTA storage unsafe: %s", c.fetch_store.selectionReason());
|
||||
return true;
|
||||
@@ -682,7 +714,8 @@ static __attribute__((noinline)) bool handle_control_command(
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#if defined(NRF52_PLATFORM) && defined(OTA_FLASH_STORE) && !defined(OTA_SD_STORE) && \
|
||||
#if defined(NRF52_PLATFORM) && defined(OTA_FLASH_STORE) && \
|
||||
(!defined(OTA_SD_STORE) || defined(OTA_RAK15002_SD_STORE)) && \
|
||||
(!defined(OTA_QSPI_STORE) || defined(OTA_RAK_AUTO_STORE))
|
||||
SelfFwInfo self;
|
||||
bool has_endf = ota_self_firmware(self) && self.valid;
|
||||
@@ -767,6 +800,11 @@ static __attribute__((noinline)) bool handle_control_command(
|
||||
#endif
|
||||
const bool discarded = !was_folder && !was_sd_archive &&
|
||||
c.fetch_store.discard();
|
||||
#if defined(NRF52_PLATFORM) && defined(OTA_RAK15002_SD_STORE) && !defined(OTA_SEEDER_ONLY)
|
||||
// Keep cache sources/independent serving mounted; only refresh the
|
||||
// application policy after the selected staged file was invalidated.
|
||||
c.prepareRakStorage();
|
||||
#endif
|
||||
#if defined(NRF52_PLATFORM) && defined(OTA_TOWER_AUTO_STORE)
|
||||
if (discarded || (!c.fetch_store.usesExternal() && !c.fetch_store.usesInternal())) {
|
||||
c.fetch_store.resetSelection();
|
||||
@@ -837,7 +875,13 @@ static __attribute__((noinline)) bool handle_control_command(
|
||||
snprintf(reply, 160, "OTA storage: %s; capacity=%luK; SD primary, internal application deltas only",
|
||||
c.fetch_store.selectionReason(), (unsigned long)(c.fetch_store.capacity() / 1024));
|
||||
#elif defined(NRF52_PLATFORM) && defined(OTA_RAK_AUTO_STORE)
|
||||
if (c.fetch_store.usesExternal()) {
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (c.fetch_store.usesSd()) {
|
||||
snprintf(reply, 160, "OTA storage: RAK15002 SD; staged=%lu; use get sdcard free for media space",
|
||||
(unsigned long)c.fetch_store.sdStore().staged_size());
|
||||
} else
|
||||
#endif
|
||||
if (c.fetch_store.usesQspi()) {
|
||||
const uint32_t qspi_capacity = c.fetch_store.qspiCapacity();
|
||||
snprintf(reply, 160, "QSPI %s jedec=%06lX size=%luK sr1=%02X stage=%s%s%s",
|
||||
c.fetch_store.selectionReason(), (unsigned long)c.fetch_store.jedec_id(),
|
||||
@@ -845,16 +889,26 @@ static __attribute__((noinline)) bool handle_control_command(
|
||||
c.fetch_store.last_stage(), c.fetch_store.last_error()[0] ? " error=" : "",
|
||||
c.fetch_store.last_error());
|
||||
} else if (c.fetch_store.usesInternal()) {
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
snprintf(reply, 160, "OTA storage: %s; internal capacity=%luK",
|
||||
c.fetch_store.selectionReason(), (unsigned long)(c.fetch_store.capacity() / 1024));
|
||||
#else
|
||||
uint32_t rak_id = 0, w25_id = 0;
|
||||
OtaStoreQspiNrf52::autoProbeIds(rak_id, w25_id);
|
||||
snprintf(reply, 160, "OTA storage: %s; internal capacity=%luK; probe rak=%06lX w25=%06lX",
|
||||
c.fetch_store.selectionReason(), (unsigned long)(c.fetch_store.capacity() / 1024),
|
||||
(unsigned long)rak_id, (unsigned long)w25_id);
|
||||
#endif
|
||||
} else {
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
snprintf(reply, 160, "OTA storage: %s; optional storage is prepared by OTA transfer/cache work",
|
||||
c.fetch_store.selectionReason());
|
||||
#else
|
||||
uint32_t rak_id = 0, w25_id = 0;
|
||||
OtaStoreQspiNrf52::autoProbeIds(rak_id, w25_id);
|
||||
snprintf(reply, 160, "OTA storage unsafe: %s; probe rak=%06lX w25=%06lX",
|
||||
c.fetch_store.selectionReason(), (unsigned long)rak_id, (unsigned long)w25_id);
|
||||
#endif
|
||||
}
|
||||
#elif defined(NRF52_PLATFORM) && defined(OTA_QSPI_STORE)
|
||||
// This probe only reads JEDEC/SR1. capacity() deliberately preserves a
|
||||
@@ -889,7 +943,13 @@ static __attribute__((noinline)) bool handle_control_command(
|
||||
c.fetch_store.usesExternal() ? "SD" : c.fetch_store.usesInternal() ? "internal" : "unsafe",
|
||||
c.fetch_store.compatible() ? "apply OK" : "unsupported");
|
||||
#elif defined(OTA_RAK_AUTO_STORE)
|
||||
if (c.fetch_store.usesExternal()) {
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (c.fetch_store.usesSd()) {
|
||||
snprintf(reply + n, 160 - n, " | SD store | bootloader: %s",
|
||||
bl.optional_sd_app_storage == OTA_BL_STORAGE_SD ? "authenticated SD apply OK" : "NO SD apply");
|
||||
} else
|
||||
#endif
|
||||
if (c.fetch_store.usesQspi()) {
|
||||
const uint32_t qspi_capacity = c.fetch_store.qspiCapacity();
|
||||
snprintf(reply + n, 160 - n, " | QSPI store:%s%uK | bootloader: %s",
|
||||
qspi_capacity ? "" : "ERR ",
|
||||
@@ -1397,6 +1457,9 @@ static bool handle_dev(const char* d, char* reply, OtaContext& c) {
|
||||
strcpy(reply, "OK cleared SD archive session; partial retained for resume");
|
||||
} else {
|
||||
const bool discarded = c.fetch_store.discard();
|
||||
#if defined(NRF52_PLATFORM) && defined(OTA_RAK15002_SD_STORE) && !defined(OTA_SEEDER_ONLY)
|
||||
c.prepareRakStorage();
|
||||
#endif
|
||||
#if defined(NRF52_PLATFORM) && defined(OTA_TOWER_AUTO_STORE)
|
||||
if (discarded || (!c.fetch_store.usesExternal() && !c.fetch_store.usesInternal())) {
|
||||
c.fetch_store.resetSelection();
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
#include "OtaCacheSdNrf52.h"
|
||||
#elif defined(NRF52_PLATFORM) && defined(OTA_RAK_AUTO_STORE)
|
||||
#include "OtaStoreAdaptiveNrf52.h"
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
#include "OtaCacheSdNrf52.h"
|
||||
#endif
|
||||
#elif defined(NRF52_PLATFORM) && defined(OTA_QSPI_STORE)
|
||||
#include "OtaStoreQspiNrf52.h"
|
||||
#elif defined(NRF52_PLATFORM) && defined(OTA_SD_STORE)
|
||||
@@ -43,6 +46,9 @@
|
||||
#elif defined(ESP32_PLATFORM) && defined(OTA_FLASH_STORE)
|
||||
#include "OtaStoreFlashEsp32.h"
|
||||
#endif
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
#include "../nrf52/Rak4631SharedSpi.h"
|
||||
#endif
|
||||
#if defined(OTA_FOLDER_SERIAL)
|
||||
#include "MotaSourceSerial.h" // relay an external folder served by a host daemon over the USB serial
|
||||
#include "../UsbLogging.h"
|
||||
@@ -125,6 +131,9 @@ struct OtaContext {
|
||||
OtaCacheSdNrf52 sd_cache; // always owns the stable SD store
|
||||
#elif defined(NRF52_PLATFORM) && defined(OTA_RAK_AUTO_STORE)
|
||||
OtaStoreAdaptiveNrf52 fetch_store;
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
OtaCacheSdNrf52 sd_cache;
|
||||
#endif
|
||||
#elif defined(NRF52_PLATFORM) && defined(OTA_QSPI_STORE)
|
||||
OtaStoreQspiNrf52 fetch_store; // persistent raw QSPI staging, full + in-place delta
|
||||
#elif defined(NRF52_PLATFORM) && defined(OTA_SD_STORE)
|
||||
@@ -336,7 +345,17 @@ struct OtaContext {
|
||||
}
|
||||
}
|
||||
bool ok;
|
||||
#if defined(NRF52_PLATFORM) && (defined(OTA_RAK_AUTO_STORE) || defined(OTA_TOWER_AUTO_STORE))
|
||||
#if defined(NRF52_PLATFORM) && defined(OTA_RAK15002_SD_STORE) && defined(OTA_RAK_AUTO_STORE)
|
||||
ok = fetch_store.usesSd()
|
||||
? ota_apply_mota_nrf52(fetch_store.sdStore(), allow, apply_st, msg)
|
||||
: fetch_store.usesQspi()
|
||||
? ota_apply_mota_nrf52(fetch_store.externalStore(), allow, apply_st, msg)
|
||||
: fetch_store.usesInternal()
|
||||
? ota_apply_mota_nrf52(fetch_store.internalStore(), allow, apply_st, msg)
|
||||
: false;
|
||||
if (!fetch_store.usesExternal() && !fetch_store.usesInternal())
|
||||
strncpy(msg, fetch_store.selectionReason(), 96);
|
||||
#elif defined(NRF52_PLATFORM) && (defined(OTA_RAK_AUTO_STORE) || defined(OTA_TOWER_AUTO_STORE))
|
||||
ok = fetch_store.usesExternal()
|
||||
? ota_apply_mota_nrf52(fetch_store.externalStore(), allow, apply_st, msg)
|
||||
: fetch_store.usesInternal()
|
||||
@@ -685,12 +704,80 @@ struct OtaContext {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
bool canReleaseRakSdForEthernet() const {
|
||||
const bool own_image = manager.servingPrimaryManifest(serve_self_manifest);
|
||||
return manager.fetchState() == OtaManager::IDLE && fetch_store.staged_size() == 0u &&
|
||||
!apply_pending && !bootloader_apply_pending && !_sd_cache_fetching &&
|
||||
!manager.pendingServeJobs() && !manager.pendingManifestJobs() &&
|
||||
(!serving || own_image) && serve_expected == 0u && !folder_active &&
|
||||
!_folder_source && !folder_dest && !disconnected_folder_dest && !fetch_to_folder;
|
||||
}
|
||||
|
||||
bool prepareRakSdForEthernet() {
|
||||
if (!canReleaseRakSdForEthernet()) return false;
|
||||
if (_sd_cache_source_attached) manager.remove_source(&sd_cache);
|
||||
_sd_cache_source_attached = false;
|
||||
sd_cache.resetMedia();
|
||||
if (!sdStagingStore().releaseBus()) return false;
|
||||
#if !defined(OTA_SEEDER_ONLY)
|
||||
if (!fetch_store.resetSelection()) return false;
|
||||
manager.set_accept_full(false);
|
||||
#endif
|
||||
manager.clear_primary();
|
||||
serving = false;
|
||||
free(serve_self_leaves); free(serve_self_proof);
|
||||
serve_self_leaves = serve_self_proof = nullptr;
|
||||
releaseServeBuffer();
|
||||
serve_expected = 0;
|
||||
manager.set_archive_interest(false);
|
||||
_sd_cache_init_retry_at = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool releasedRakSdEthernet() {
|
||||
if (!canReleaseRakSdForEthernet()) return false;
|
||||
#if !defined(OTA_SEEDER_ONLY)
|
||||
if (!fetch_store.resetSelection()) return false;
|
||||
manager.set_accept_full(false);
|
||||
#endif
|
||||
manager.set_archive_interest(true);
|
||||
_sd_cache_init_retry_at = 0;
|
||||
return true; // The next normal main-loop service may probe, never this callback.
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(OTA_RAK15002_SD_STORE) && !defined(OTA_SEEDER_ONLY)
|
||||
// Only actual OTA work may probe the optional card. Boot/status paths leave
|
||||
// the selector untouched, and a selected transfer never changes its medium.
|
||||
bool prepareRakStorage() {
|
||||
const bool usable = fetch_store.selectStorage();
|
||||
const bool external = usable && fetch_store.usesExternal() && !rak4631_ethernet_owns_spi();
|
||||
manager.set_accept_full(external);
|
||||
manager.set_accept_bootloader(ota_bootloader_self_update_caps_valid(bootloaderUpdateCaps()));
|
||||
const bool was_self_serve_supported = self_serve_supported;
|
||||
self_serve_supported = ota_self_serve_supported(external);
|
||||
if (was_self_serve_supported && !self_serve_supported &&
|
||||
manager.servingPrimaryManifest(serve_self_manifest)) {
|
||||
manager.clear_primary();
|
||||
serving = false;
|
||||
}
|
||||
#if MESHCORE_OTA_DEVICE_DEFLATE
|
||||
manager.set_transport_deflate_encoder(self_serve_supported ? ota_transport_deflate : nullptr);
|
||||
#endif
|
||||
if (!fetch_store.usesSd()) manager.set_archive_interest(false);
|
||||
return usable;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(NRF52_PLATFORM) && defined(OTA_SD_STORE)
|
||||
OtaStoreSdNrf52& sdStagingStore() {
|
||||
#if defined(OTA_SEEDER_ONLY)
|
||||
return sd_archive_store;
|
||||
#elif defined(OTA_TOWER_AUTO_STORE)
|
||||
return fetch_store.sdStore();
|
||||
#elif defined(OTA_RAK15002_SD_STORE) && defined(OTA_RAK_AUTO_STORE)
|
||||
return fetch_store.sdStore();
|
||||
#else
|
||||
return fetch_store;
|
||||
#endif
|
||||
@@ -723,6 +810,12 @@ struct OtaContext {
|
||||
// Initialize and attach the persistent source lazily. This lets Mesh::begin finish quickly when no card
|
||||
// is inserted, while archive interest is already enabled so early OTA advertisements still get queried.
|
||||
bool ensureSdCache() {
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (rak4631_ethernet_owns_spi()) return false;
|
||||
#if !defined(OTA_SEEDER_ONLY)
|
||||
if (!prepareRakStorage() || !fetch_store.usesSd()) return false;
|
||||
#endif
|
||||
#endif
|
||||
sd_cache.attach(sdStagingStore());
|
||||
#if defined(OTA_TOWER_AUTO_STORE)
|
||||
if (!prepareTowerStorage() || !fetch_store.usesExternal()) return false;
|
||||
@@ -778,12 +871,20 @@ struct OtaContext {
|
||||
sd_cache.resetMedia();
|
||||
#if defined(OTA_TOWER_AUTO_STORE)
|
||||
fetch_store.resetSelection();
|
||||
#elif defined(OTA_RAK15002_SD_STORE) && !defined(OTA_SEEDER_ONLY)
|
||||
if (!fetch_store.resetSelection()) return;
|
||||
#endif
|
||||
_sd_cache_init_retry_at = now;
|
||||
ensureSdCache();
|
||||
}
|
||||
|
||||
void serviceSdCache(uint32_t now) {
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (rak4631_ethernet_owns_spi()) return;
|
||||
#if !defined(OTA_SEEDER_ONLY)
|
||||
if (!prepareRakStorage() || !fetch_store.usesSd()) return;
|
||||
#endif
|
||||
#endif
|
||||
#if defined(OTA_TOWER_AUTO_STORE)
|
||||
if (!prepareTowerStorage() || !fetch_store.usesExternal()) {
|
||||
if (_sd_cache_source_attached) manager.remove_source(&sd_cache);
|
||||
@@ -897,7 +998,11 @@ struct OtaContext {
|
||||
manager.set_accept_full(false);
|
||||
manager.set_apply_codec(CODEC_DETOOLS_INPLACE);
|
||||
#elif defined(NRF52_PLATFORM) && defined(OTA_RAK_AUTO_STORE)
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
manager.set_accept_full(false); // defer optional SD/NOR probing until startup finishes
|
||||
#else
|
||||
manager.set_accept_full(fetch_store.usesExternal());
|
||||
#endif
|
||||
manager.set_apply_codec(CODEC_DETOOLS_INPLACE);
|
||||
#elif defined(NRF52_PLATFORM) && (defined(OTA_SD_STORE) || defined(OTA_QSPI_STORE))
|
||||
manager.set_accept_full(true);
|
||||
@@ -925,7 +1030,8 @@ struct OtaContext {
|
||||
manager.set_accept_bootloader(false);
|
||||
#endif
|
||||
manager.set_fetch_store(&fetch_store);
|
||||
#if defined(NRF52_PLATFORM) && defined(OTA_TOWER_AUTO_STORE)
|
||||
#if defined(NRF52_PLATFORM) && (defined(OTA_TOWER_AUTO_STORE) || \
|
||||
(defined(OTA_RAK15002_SD_STORE) && !defined(OTA_SEEDER_ONLY)))
|
||||
self_serve_supported = false;
|
||||
#elif defined(NRF52_PLATFORM) && defined(OTA_RAK_AUTO_STORE) && !defined(OTA_SEEDER_ONLY)
|
||||
self_serve_supported = ota_self_serve_supported(fetch_store.usesExternal());
|
||||
|
||||
@@ -2,6 +2,17 @@
|
||||
|
||||
#include <SPI.h>
|
||||
|
||||
#if defined(OTA_RAK15002_SD_CACHE) && defined(OTA_RAK15002_SD_STORE)
|
||||
#error "RAK15002 seeder-only cache and adaptive SD receiver profiles are distinct"
|
||||
#endif
|
||||
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
#if !defined(NRF52_PLATFORM) || !defined(RAK_4631) || !defined(OTA_SD_STORE)
|
||||
#error "RAK15002 adaptive SD requires the exact nRF52 RAK4631 SD profile"
|
||||
#endif
|
||||
#include "../nrf52/Rak4631SharedSpi.h"
|
||||
#endif
|
||||
|
||||
#if defined(OTA_RAK15002_SD_CACHE)
|
||||
#if !defined(NRF52_PLATFORM) || !defined(RAK_4631) || !defined(OTA_SD_STORE) || !defined(OTA_SEEDER_ONLY)
|
||||
#error "RAK15002 SD cache requires the exact nRF52 RAK4631 seeder-only profile"
|
||||
@@ -9,10 +20,12 @@
|
||||
#if defined(ETHERNET_ENABLED) || defined(OTA_QSPI_STORE) || defined(OTA_RAK_AUTO_STORE) || defined(OTA_TOWER_AUTO_STORE)
|
||||
#error "RAK15002 SD cache cannot share the WisBlock SPI/CS with Ethernet or OTA NOR"
|
||||
#endif
|
||||
#endif
|
||||
#if defined(OTA_RAK15002_SD_CACHE) || defined(OTA_RAK15002_SD_STORE)
|
||||
#if SPI_INTERFACES_COUNT != 1 || (defined(SPI_32MHZ_INTERFACE) && SPI_32MHZ_INTERFACE != 0)
|
||||
#error "RAK15002 SD cache requires radio SPI on SPIM3 and reserves SPIM2 for the SD card"
|
||||
#endif
|
||||
#if defined(OTA_SD_BOOTLOADER_UPDATE) || defined(OTA_INTERNAL_BOOTLOADER_UPDATE) || defined(OTA_QSPI_BOOTLOADER_UPDATE)
|
||||
#if defined(OTA_RAK15002_SD_CACHE) && (defined(OTA_SD_BOOTLOADER_UPDATE) || defined(OTA_INTERNAL_BOOTLOADER_UPDATE) || defined(OTA_QSPI_BOOTLOADER_UPDATE))
|
||||
#error "RAK15002 cache profile has no qualified bootloader-update handoff"
|
||||
#endif
|
||||
#ifndef OTA_SD_CS_PIN
|
||||
@@ -20,14 +33,26 @@
|
||||
#endif
|
||||
static_assert(OTA_SD_CS_PIN == 26 && PIN_SPI_MISO == 29 && PIN_SPI_SCK == 3 && PIN_SPI_MOSI == 30,
|
||||
"RAK15002 exact WisBlock SPI pin map changed; requalify the profile");
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
static_assert(WB_IO6 == 10, "RAK15002 card detect must use the mapped WisBlock IO6");
|
||||
#endif
|
||||
#elif !defined(OTA_SD_CS_PIN)
|
||||
#define OTA_SD_CS_PIN PIN_SPI1_NSS
|
||||
#endif
|
||||
|
||||
namespace mesh { namespace ota {
|
||||
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
inline bool ota_rak15002_sd_card_present() {
|
||||
// RAK15002 CD is active-low WisBlock IO6 (Arduino 10 / P0.10), not pin 6.
|
||||
// GPIO-only detection must precede any SD or NOR command on shared CS26.
|
||||
pinMode(WB_IO6, INPUT_PULLUP);
|
||||
return digitalRead(WB_IO6) == LOW;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline SPIClass& ota_sd_spi_bus() {
|
||||
#if defined(OTA_RAK15002_SD_CACHE)
|
||||
#if defined(OTA_RAK15002_SD_CACHE) || defined(OTA_RAK15002_SD_STORE)
|
||||
// The RAK radio reassigns global SPI/SPIM3 to its private pins. Never use
|
||||
// that object for the external WisBlock bus, or reconfigure it on SD mount.
|
||||
static SPIClass sd_spi(NRF_SPIM2, 29, 3, 30);
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(NRF52_PLATFORM) && defined(OTA_SD_STORE)
|
||||
|
||||
// Keep SdFat implementation headers out of application headers: its global
|
||||
// File typedef conflicts with Adafruit LittleFS's File. Only the two SD
|
||||
// implementation translation units need complete volume/file definitions.
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
class SdFat32;
|
||||
class FatFile;
|
||||
#else
|
||||
class SdFs;
|
||||
class FsFile;
|
||||
#endif
|
||||
|
||||
namespace mesh {
|
||||
namespace ota {
|
||||
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
using OtaSdFs = SdFat32;
|
||||
using OtaSdFile = FatFile;
|
||||
#else
|
||||
using OtaSdFs = SdFs;
|
||||
using OtaSdFile = FsFile;
|
||||
#endif
|
||||
|
||||
} // namespace ota
|
||||
} // namespace mesh
|
||||
|
||||
#endif
|
||||
@@ -8,7 +8,11 @@
|
||||
#include "OtaStoreFlashNrf52.h"
|
||||
#include "OtaStoreQspiNrf52.h"
|
||||
#include "OtaRakStoragePolicy.h"
|
||||
#if defined(RAK4631_COMBINED_ETHERNET)
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
#include "OtaStoreSdNrf52.h"
|
||||
#include "OtaSdSpiBusNrf52.h"
|
||||
#endif
|
||||
#if defined(RAK4631_COMBINED_ETHERNET) || defined(OTA_RAK15002_SD_STORE)
|
||||
#include "../nrf52/Rak4631SharedSpi.h"
|
||||
#endif
|
||||
#include <new>
|
||||
@@ -17,14 +21,21 @@ namespace mesh {
|
||||
namespace ota {
|
||||
|
||||
// One RAK application image supports the board's internal OTA store and its
|
||||
// explicitly matched external NOR. Application placement follows the detected
|
||||
// explicitly matched external NOR or RAK15002 SD. Application placement follows the detected
|
||||
// hardware. Bootloader packages always use internal flash; select the backend
|
||||
// before begin(), never move a partially fetched container between stores.
|
||||
class OtaStoreAdaptiveNrf52 : public OtaStore {
|
||||
enum Mode : uint8_t { UNSELECTED, INTERNAL_MODE, QSPI_MODE, UNSAFE };
|
||||
enum Mode : uint8_t { UNSELECTED, INTERNAL_MODE, QSPI_MODE, SD_MODE, UNSAFE };
|
||||
mutable Mode _mode = UNSELECTED;
|
||||
mutable const char* _reason = "not probed";
|
||||
bool _bootloader_store = false;
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
// The SD cache retains a stable owner even while a bootloader package uses
|
||||
// internal flash. Card discovery is deferred until an explicit main-loop
|
||||
// prepare; status/capability getters must not clock an optional empty slot.
|
||||
mutable OtaStoreSdNrf52 _sd;
|
||||
bool _prepared = false;
|
||||
#endif
|
||||
// Only one backend is usable for a given board/bootloader pairing. Sharing
|
||||
// their two flash-page buffers saves 8 KiB of scarce nRF52840 runtime RAM.
|
||||
union StoreStorage {
|
||||
@@ -46,6 +57,9 @@ class OtaStoreAdaptiveNrf52 : public OtaStore {
|
||||
|
||||
bool selectBootloader() {
|
||||
if (!ota_bootloader_self_update_caps_valid(ota_bootloader_update_caps())) return false;
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (_sd.staged_size() != 0u) return false;
|
||||
#endif
|
||||
if (_mode != INTERNAL_MODE) {
|
||||
if (_mode == QSPI_MODE) _storage.external.~OtaStoreQspiNrf52();
|
||||
activateInternal();
|
||||
@@ -61,18 +75,43 @@ class OtaStoreAdaptiveNrf52 : public OtaStore {
|
||||
_mode = UNSELECTED;
|
||||
_bootloader_store = false;
|
||||
}
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
selectStorage();
|
||||
#else
|
||||
select();
|
||||
#endif
|
||||
}
|
||||
|
||||
void select() const {
|
||||
if (_mode != UNSELECTED) return;
|
||||
#if defined(RAK4631_COMBINED_ETHERNET)
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (!_prepared) return;
|
||||
#endif
|
||||
#if defined(RAK4631_COMBINED_ETHERNET) || defined(OTA_RAK15002_SD_STORE)
|
||||
const bool ethernet = rak4631_ethernet_owns_spi();
|
||||
const uint8_t detected = ethernet ? 0u : OtaStoreQspiNrf52::autoDetect();
|
||||
#else
|
||||
const uint8_t detected = OtaStoreQspiNrf52::autoDetect();
|
||||
const bool ethernet = false;
|
||||
#endif
|
||||
const OtaBlCaps caps = ota_bootloader_app_caps();
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
// Card detect is GPIO-only. If a card is fitted, never issue JEDEC clocks
|
||||
// to the same CS as a fallback, even when its media/loader is unsuitable.
|
||||
const bool sd_present = !ethernet && ota_rak15002_sd_card_present();
|
||||
if (sd_present && caps.optional_sd_app_storage == OTA_BL_STORAGE_SD) {
|
||||
OtaBootloaderIdentity sd_identity;
|
||||
if (ota_installed_bootloader_identity(sd_identity) && sd_identity.crc_ok &&
|
||||
(strcmp(sd_identity.device_name, "4631_DFU") == 0 ||
|
||||
strcmp(sd_identity.device_name, "4631_AUTO_DFU") == 0) &&
|
||||
_sd.probeMedia()) {
|
||||
_mode = SD_MODE;
|
||||
_reason = "RAK15002 SD";
|
||||
return;
|
||||
}
|
||||
}
|
||||
const uint8_t detected = (ethernet || sd_present) ? 0u : OtaStoreQspiNrf52::autoDetect();
|
||||
#else
|
||||
const uint8_t detected = ethernet ? 0u : OtaStoreQspiNrf52::autoDetect();
|
||||
#endif
|
||||
if (detected == 3u) {
|
||||
_mode = UNSAFE;
|
||||
_reason = "both external NOR types detected";
|
||||
@@ -100,7 +139,7 @@ class OtaStoreAdaptiveNrf52 : public OtaStore {
|
||||
caps.optional_app_storage == (OTA_BL_STORAGE_QSPI | OTA_BL_STORAGE_HEADER_W25));
|
||||
if (choice == RakStorageChoice::Internal) {
|
||||
activateInternal();
|
||||
#if defined(RAK4631_COMBINED_ETHERNET)
|
||||
#if defined(RAK4631_COMBINED_ETHERNET) || defined(OTA_RAK15002_SD_STORE)
|
||||
if (ethernet) {
|
||||
_reason = "Ethernet active; internal application deltas only";
|
||||
return;
|
||||
@@ -108,6 +147,13 @@ class OtaStoreAdaptiveNrf52 : public OtaStore {
|
||||
#endif
|
||||
_reason = detected == 0u ? "no external NOR" :
|
||||
"external NOR fitted; internal bootloader";
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (sd_present) {
|
||||
_reason = caps.optional_sd_app_storage == OTA_BL_STORAGE_SD
|
||||
? "SD unavailable; internal application deltas only"
|
||||
: "SD needs newer OTAFIX; internal application deltas only";
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
if (choice == RakStorageChoice::Qspi) {
|
||||
@@ -117,7 +163,7 @@ class OtaStoreAdaptiveNrf52 : public OtaStore {
|
||||
return;
|
||||
}
|
||||
_mode = UNSAFE;
|
||||
#if defined(RAK4631_COMBINED_ETHERNET)
|
||||
#if defined(RAK4631_COMBINED_ETHERNET) || defined(OTA_RAK15002_SD_STORE)
|
||||
if (ethernet) {
|
||||
_reason = "Ethernet active; bootloader lacks internal OTA";
|
||||
return;
|
||||
@@ -134,27 +180,55 @@ class OtaStoreAdaptiveNrf52 : public OtaStore {
|
||||
|
||||
OtaStore* active() {
|
||||
select();
|
||||
#if defined(RAK4631_COMBINED_ETHERNET)
|
||||
if (_mode == QSPI_MODE && rak4631_ethernet_owns_spi()) return nullptr;
|
||||
#if defined(RAK4631_COMBINED_ETHERNET) || defined(OTA_RAK15002_SD_STORE)
|
||||
if ((_mode == QSPI_MODE || _mode == SD_MODE) && rak4631_ethernet_owns_spi()) return nullptr;
|
||||
#endif
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (_mode == SD_MODE) return &_sd;
|
||||
#endif
|
||||
return _mode == QSPI_MODE ? static_cast<OtaStore*>(&_storage.external) :
|
||||
_mode == INTERNAL_MODE ? static_cast<OtaStore*>(&_storage.internal) : nullptr;
|
||||
}
|
||||
const OtaStore* active() const {
|
||||
select();
|
||||
#if defined(RAK4631_COMBINED_ETHERNET)
|
||||
if (_mode == QSPI_MODE && rak4631_ethernet_owns_spi()) return nullptr;
|
||||
#if defined(RAK4631_COMBINED_ETHERNET) || defined(OTA_RAK15002_SD_STORE)
|
||||
if ((_mode == QSPI_MODE || _mode == SD_MODE) && rak4631_ethernet_owns_spi()) return nullptr;
|
||||
#endif
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (_mode == SD_MODE) return &_sd;
|
||||
#endif
|
||||
return _mode == QSPI_MODE ? static_cast<const OtaStore*>(&_storage.external) :
|
||||
_mode == INTERNAL_MODE ? static_cast<const OtaStore*>(&_storage.internal) : nullptr;
|
||||
}
|
||||
|
||||
public:
|
||||
#if defined(RAK4631_COMBINED_ETHERNET)
|
||||
bool selectStorage() {
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
// A cancelled/cleared privileged fetch may return to its application
|
||||
// backend without tearing down the independent SD cache owner. Never
|
||||
// reselect while internal bootloader staging still contains data.
|
||||
if (_bootloader_store && _mode == INTERNAL_MODE &&
|
||||
_storage.internal.staged_size() == 0u) {
|
||||
_storage.internal.~OtaStoreFlashNrf52();
|
||||
_mode = UNSELECTED;
|
||||
_bootloader_store = false;
|
||||
}
|
||||
_prepared = true;
|
||||
#endif
|
||||
select();
|
||||
return _mode != UNSELECTED && _mode != UNSAFE;
|
||||
}
|
||||
#if defined(RAK4631_COMBINED_ETHERNET) || defined(OTA_RAK15002_SD_STORE)
|
||||
// Only the main-loop handoff may reset the selection, after OtaContext has
|
||||
// proved that no receive/apply session is active. Never discard staged data
|
||||
// as a side effect of changing a network setting.
|
||||
bool resetSelection() {
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (_sd.staged_size() != 0u) return false;
|
||||
if ((_mode == QSPI_MODE && _storage.external.staged_size() != 0u) ||
|
||||
(_mode == INTERNAL_MODE && _storage.internal.staged_size() != 0u) ||
|
||||
!_sd.releaseBus()) return false;
|
||||
#endif
|
||||
if (_mode == QSPI_MODE) {
|
||||
if (_storage.external.staged_size() != 0u) return false;
|
||||
_storage.external.~OtaStoreQspiNrf52();
|
||||
@@ -162,6 +236,9 @@ public:
|
||||
if (_storage.internal.staged_size() != 0u) return false;
|
||||
_storage.internal.~OtaStoreFlashNrf52();
|
||||
}
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
_prepared = false;
|
||||
#endif
|
||||
_mode = UNSELECTED;
|
||||
_reason = "not probed";
|
||||
_bootloader_store = false;
|
||||
@@ -172,17 +249,25 @@ public:
|
||||
if (_mode == QSPI_MODE) _storage.external.~OtaStoreQspiNrf52();
|
||||
else if (_mode == INTERNAL_MODE) _storage.internal.~OtaStoreFlashNrf52();
|
||||
}
|
||||
bool usesExternal() const { select(); return _mode == QSPI_MODE; }
|
||||
bool usesExternal() const { select(); return _mode == QSPI_MODE || _mode == SD_MODE; }
|
||||
bool usesQspi() const { select(); return _mode == QSPI_MODE; }
|
||||
bool usesSd() const { select(); return _mode == SD_MODE; }
|
||||
bool usesInternal() const { select(); return _mode == INTERNAL_MODE; }
|
||||
const char* selectionReason() const { select(); return _reason; }
|
||||
OtaStoreFlashNrf52& internalStore() { select(); return _storage.internal; }
|
||||
OtaStoreQspiNrf52& externalStore() { select(); return _storage.external; }
|
||||
uint32_t qspiCapacity() const { return usesExternal() ? _storage.external.capacity() : 0u; }
|
||||
uint32_t jedec_id() const { return usesExternal() ? _storage.external.jedec_id() : 0u; }
|
||||
uint8_t status1() const { return usesExternal() ? _storage.external.status1() : 0xFFu; }
|
||||
const char* last_stage() const { return usesExternal() ? _storage.external.last_stage() : "inactive"; }
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
OtaStoreSdNrf52& sdStore() { return _sd; }
|
||||
#endif
|
||||
uint32_t qspiCapacity() const { return usesQspi() ? _storage.external.capacity() : 0u; }
|
||||
uint32_t jedec_id() const { return usesQspi() ? _storage.external.jedec_id() : 0u; }
|
||||
uint8_t status1() const { return usesQspi() ? _storage.external.status1() : 0xFFu; }
|
||||
const char* last_stage() const { return usesQspi() ? _storage.external.last_stage() : "inactive"; }
|
||||
const char* last_error() const {
|
||||
return usesExternal() ? _storage.external.last_error() : selectionReason();
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (usesSd()) return _sd.last_error();
|
||||
#endif
|
||||
return usesQspi() ? _storage.external.last_error() : selectionReason();
|
||||
}
|
||||
|
||||
bool begin(uint32_t n) override { OtaStore* s = active(); return s && s->begin(n); }
|
||||
|
||||
@@ -13,9 +13,12 @@
|
||||
#include <SPI.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#if defined(RAK4631_COMBINED_ETHERNET)
|
||||
#if defined(RAK4631_COMBINED_ETHERNET) || defined(OTA_RAK15002_SD_STORE)
|
||||
#include "../nrf52/Rak4631SharedSpi.h"
|
||||
#endif
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
#include "OtaSdSpiBusNrf52.h"
|
||||
#endif
|
||||
|
||||
namespace mesh {
|
||||
namespace ota {
|
||||
@@ -327,12 +330,20 @@ static uint32_t probe_nor(uint8_t cs) {
|
||||
|
||||
#if defined(OTA_RAK_AUTO_STORE)
|
||||
uint8_t OtaStoreQspiNrf52::autoDetect() {
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
// SD and the RAK15001 use the same CS26. Even an unmounted/unsupported
|
||||
// inserted card must never see the NOR wake or JEDEC command sequence.
|
||||
if (ota_rak15002_sd_card_present()) return 0u;
|
||||
#endif
|
||||
#if defined(RAK4631_COMBINED_ETHERNET)
|
||||
// Do not even bit-bang a JEDEC probe while the Ethernet task owns SPI.
|
||||
// Leave the cached physical discovery unchanged for the next idle handoff.
|
||||
if (rak4631_ethernet_owns_spi()) return 0u;
|
||||
#endif
|
||||
if (auto_detection != 0xFFu) return auto_detection;
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (!rak4631_try_acquire_spi(RakSharedSpiOwner::Nor)) return 0u;
|
||||
#endif
|
||||
|
||||
const uint8_t w25_cs = arduino_to_physical(31);
|
||||
nrf_gpio_pin_set(w25_cs);
|
||||
@@ -382,6 +393,9 @@ uint8_t OtaStoreQspiNrf52::autoDetect() {
|
||||
auto_cs_pin = w25_cs;
|
||||
auto_jedec_id = 0xEF4015UL;
|
||||
}
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
rak4631_release_spi(RakSharedSpiOwner::Nor);
|
||||
#endif
|
||||
return auto_detection;
|
||||
}
|
||||
|
||||
@@ -487,6 +501,12 @@ bool OtaStoreQspiNrf52::waitMemoryReady(uint32_t timeout_ms) {
|
||||
}
|
||||
|
||||
bool OtaStoreQspiNrf52::ensureFlash() {
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (ota_rak15002_sd_card_present() || !rak4631_try_acquire_spi(RakSharedSpiOwner::Nor)) {
|
||||
fail("SD card present or WisBlock SPI owned by SD/Ethernet");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
#if defined(RAK4631_COMBINED_ETHERNET)
|
||||
if (rak4631_ethernet_owns_spi()) {
|
||||
fail("Ethernet owns WisBlock SPI; external OTA unavailable");
|
||||
@@ -627,8 +647,13 @@ bool OtaStoreQspiNrf52::ensureFlash() {
|
||||
}
|
||||
|
||||
void OtaStoreQspiNrf52::releaseFlash() {
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
// The failed-acquire path must not touch somebody else's live controller,
|
||||
// chip select or supply. No callback may forcibly overwrite this claim.
|
||||
if (rak4631_spi_owner() != RakSharedSpiOwner::Nor) return;
|
||||
#endif
|
||||
bool send_power_down = _qspi_awake && !_memory_operation_pending;
|
||||
#if defined(RAK4631_COMBINED_ETHERNET)
|
||||
#if defined(RAK4631_COMBINED_ETHERNET) || defined(OTA_RAK15002_SD_STORE)
|
||||
send_power_down = send_power_down && !rak4631_ethernet_owns_spi();
|
||||
#endif
|
||||
if (send_power_down) {
|
||||
@@ -650,7 +675,7 @@ void OtaStoreQspiNrf52::releaseFlash() {
|
||||
// disabling the peripheral. Trigger it after every successful ENABLE, even
|
||||
// when wake or JEDEC identification failed before _qspi_ready was set.
|
||||
if (_qspi_active) {
|
||||
#if defined(RAK4631_COMBINED_ETHERNET)
|
||||
#if defined(RAK4631_COMBINED_ETHERNET) || defined(OTA_RAK15002_SD_STORE)
|
||||
// Also release the QSPI pin assignments after a successful operation so
|
||||
// the Ethernet SPIM can safely acquire the same pads at an idle handoff.
|
||||
const bool disconnect_pins = true;
|
||||
@@ -699,6 +724,11 @@ void OtaStoreQspiNrf52::releaseFlash() {
|
||||
_shared_radio_bus_acquired = false;
|
||||
}
|
||||
#endif
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
// An uncertain program/erase retains exclusive ownership until a later
|
||||
// successful status poll proves the NOR idle; never hand its nets to SD.
|
||||
if (!_memory_operation_pending) rak4631_release_spi(RakSharedSpiOwner::Nor);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool OtaStoreQspiNrf52::dmaReadAligned(uint32_t address, uint32_t length) {
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
#endif
|
||||
|
||||
#if defined(OTA_QSPI_SHARED_WISBLOCK_SPI) && defined(ETHERNET_ENABLED) && \
|
||||
!defined(RAK4631_COMBINED_ETHERNET)
|
||||
!defined(RAK4631_COMBINED_ETHERNET) && \
|
||||
!(defined(OTA_RAK15002_SD_STORE) && defined(NRF52_PLATFORM) && \
|
||||
defined(RAK_4631) && defined(OTA_RAK_AUTO_STORE))
|
||||
#error "WisBlock SPI OTA staging cannot share the bus/chip-select with Ethernet"
|
||||
#endif
|
||||
|
||||
@@ -17,7 +19,8 @@
|
||||
#error "Combined RAK4631 Ethernet requires its adaptive OTA and shared-SPI ownership contract"
|
||||
#endif
|
||||
|
||||
#if defined(OTA_QSPI_SHARED_WISBLOCK_SPI) && defined(OTA_SD_STORE)
|
||||
#if defined(OTA_QSPI_SHARED_WISBLOCK_SPI) && defined(OTA_SD_STORE) && \
|
||||
!(defined(OTA_RAK15002_SD_STORE) && defined(RAK_4631) && defined(OTA_RAK_AUTO_STORE))
|
||||
#error "WisBlock SPI OTA staging cannot share the bus/chip-select with SD staging"
|
||||
#endif
|
||||
|
||||
|
||||
@@ -22,6 +22,14 @@
|
||||
#define OTA_SD_SCK_MHZ 8
|
||||
#endif
|
||||
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
// The mounted FAT/exFAT volume and both retained file handles (staging and
|
||||
// archive) are lazy heap objects, not linked globals. Bind their total plus
|
||||
// allocator metadata to the runtime RAM policy's separate 2 KiB allowance.
|
||||
static_assert(sizeof(mesh::ota::OtaSdFs) + 2u * sizeof(mesh::ota::OtaSdFile) + 3u * 32u <= 2048u,
|
||||
"RAK15002 FAT volume/file allocations exceed the RAM allowance");
|
||||
#endif
|
||||
|
||||
namespace mesh {
|
||||
namespace ota {
|
||||
|
||||
@@ -35,6 +43,7 @@ static void clear_sd_auth_record() {
|
||||
__DSB();
|
||||
}
|
||||
|
||||
#if !defined(OTA_SEEDER_ONLY)
|
||||
static bool publish_sd_auth_record(const uint8_t record[MOTA_SD_AUTH_LEN]) {
|
||||
volatile uint8_t* const retained =
|
||||
reinterpret_cast<volatile uint8_t*>(MOTA_SD_AUTH_ADDR);
|
||||
@@ -52,13 +61,17 @@ static bool publish_sd_auth_record(const uint8_t record[MOTA_SD_AUTH_LEN]) {
|
||||
if (retained[i] != record[i]) return false;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
const char* const OtaStoreSdNrf52::PATH = "/meshcore-ota.mota";
|
||||
|
||||
OtaStoreSdNrf52::OtaStoreSdNrf52()
|
||||
: _sd(new (std::nothrow) SdFs()), _file(new (std::nothrow) FsFile()) {
|
||||
#if !defined(OTA_RAK15002_SD_STORE)
|
||||
: _sd(new (std::nothrow) OtaSdFs()), _file(new (std::nothrow) OtaSdFile())
|
||||
#endif
|
||||
{
|
||||
// If an earlier reset did not enter OTAFIX, stale authorization must not arm a
|
||||
// later unrelated reboot. OTAFIX runs before application constructors and
|
||||
// consumes a valid record on the intended apply boot.
|
||||
@@ -66,8 +79,59 @@ OtaStoreSdNrf52::OtaStoreSdNrf52()
|
||||
}
|
||||
|
||||
OtaStoreSdNrf52::~OtaStoreSdNrf52() {
|
||||
if (_file) { _file->close(); delete _file; }
|
||||
if (_sd) { _sd->end(); delete _sd; }
|
||||
resetStoreState();
|
||||
if (_file) delete _file;
|
||||
if (_sd) delete _sd;
|
||||
releaseBusClaim();
|
||||
}
|
||||
|
||||
bool OtaStoreSdNrf52::acquireBus() {
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (!ota_rak15002_sd_card_present()) { fail("SD card absent"); return false; }
|
||||
if (!rak4631_try_acquire_spi(RakSharedSpiOwner::Sd)) {
|
||||
fail("WisBlock SPI owned by Ethernet or NOR"); return false;
|
||||
}
|
||||
_bus_owned = true;
|
||||
if (!_sd) _sd = new (std::nothrow) OtaSdFs();
|
||||
if (!_file) _file = new (std::nothrow) OtaSdFile();
|
||||
if (!_sd || !_file) {
|
||||
fail("SD allocation failed"); releaseBusClaim(); return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OtaStoreSdNrf52::busAccessAllowed() const {
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
return _bus_owned && rak4631_spi_owner() == RakSharedSpiOwner::Sd
|
||||
&& ota_rak15002_sd_card_present();
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void OtaStoreSdNrf52::releaseBusClaim() {
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
if (!_bus_owned) return;
|
||||
if (_bus_started) {
|
||||
ota_sd_spi_bus().end();
|
||||
// Leave the powered, unswitched card deselected, and stop driving the
|
||||
// shared clock/data pads before another peripheral claims them.
|
||||
digitalWrite(OTA_SD_CS_PIN, HIGH);
|
||||
pinMode(OTA_SD_CS_PIN, OUTPUT);
|
||||
pinMode(3, INPUT); pinMode(29, INPUT); pinMode(30, INPUT);
|
||||
_bus_started = false;
|
||||
}
|
||||
rak4631_release_spi(RakSharedSpiOwner::Sd);
|
||||
_bus_owned = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool OtaStoreSdNrf52::releaseBus() {
|
||||
if (_total) { fail("SD staged update is pinned"); return false; }
|
||||
resetStoreState();
|
||||
releaseBusClaim();
|
||||
return true;
|
||||
}
|
||||
|
||||
void OtaStoreSdNrf52::fail(const char* message) {
|
||||
@@ -80,31 +144,48 @@ void OtaStoreSdNrf52::resetStoreState() {
|
||||
_first_sector = 0;
|
||||
_allocated_sectors = 0;
|
||||
_planned_bootloader = false;
|
||||
if (_file && *_file) _file->close();
|
||||
if (_sd) _sd->end();
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
// Ownership persists if a card is physically removed. Cleanup still owns
|
||||
// the controller and can release it, but no other device may steal it.
|
||||
const bool access = _bus_owned && rak4631_spi_owner() == RakSharedSpiOwner::Sd;
|
||||
#else
|
||||
const bool access = true;
|
||||
#endif
|
||||
if (access && _file && *_file) _file->close();
|
||||
if (access && _sd) _sd->end();
|
||||
_mounted = false;
|
||||
}
|
||||
|
||||
bool OtaStoreSdNrf52::beginCardOnly() {
|
||||
_error[0] = 0;
|
||||
if (!acquireBus()) return false;
|
||||
resetStoreState();
|
||||
ota_sd_prepare_chip_select();
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
_bus_started = true;
|
||||
#endif
|
||||
if (!_sd || !_file ||
|
||||
!_sd->cardBegin(SdSpiConfig(OTA_SD_CS_PIN, DEDICATED_SPI,
|
||||
SD_SCK_MHZ(OTA_SD_SCK_MHZ), &ota_sd_spi_bus()))) {
|
||||
fail("SD card init failed");
|
||||
resetStoreState(); releaseBusClaim();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OtaStoreSdNrf52::mount() {
|
||||
if (_mounted) return true;
|
||||
if (_mounted) return busAccessAllowed();
|
||||
_error[0] = 0;
|
||||
if (!acquireBus()) return false;
|
||||
ota_sd_prepare_chip_select();
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
_bus_started = true;
|
||||
#endif
|
||||
if (!_sd || !_file || !_sd->begin(SdSpiConfig(OTA_SD_CS_PIN, DEDICATED_SPI,
|
||||
SD_SCK_MHZ(OTA_SD_SCK_MHZ), &ota_sd_spi_bus()))) {
|
||||
fail("SD mount failed");
|
||||
resetStoreState(); releaseBusClaim();
|
||||
return false;
|
||||
}
|
||||
_mounted = true;
|
||||
@@ -119,12 +200,14 @@ bool OtaStoreSdNrf52::formatCard(MainBoard& board) {
|
||||
if (!_sd->format()) {
|
||||
fail("SD format failed");
|
||||
_sd->end();
|
||||
releaseBusClaim();
|
||||
return false;
|
||||
}
|
||||
board.serviceWatchdog();
|
||||
if (!_sd->volumeBegin()) {
|
||||
fail("SD remount after format failed");
|
||||
_sd->end();
|
||||
releaseBusClaim();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -142,6 +225,7 @@ bool OtaStoreSdNrf52::eraseCard(MainBoard& board) {
|
||||
if (!card || sector_count == 0) {
|
||||
fail("SD sector count failed");
|
||||
_sd->end();
|
||||
releaseBusClaim();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -159,6 +243,7 @@ bool OtaStoreSdNrf52::eraseCard(MainBoard& board) {
|
||||
if (!card->erase(first_sector, last_sector)) {
|
||||
fail("SD erase failed");
|
||||
_sd->end();
|
||||
releaseBusClaim();
|
||||
return false;
|
||||
}
|
||||
first_sector += count;
|
||||
@@ -168,9 +253,11 @@ bool OtaStoreSdNrf52::eraseCard(MainBoard& board) {
|
||||
if (!card->syncDevice()) {
|
||||
fail("SD erase sync failed");
|
||||
_sd->end();
|
||||
releaseBusClaim();
|
||||
return false;
|
||||
}
|
||||
_sd->end();
|
||||
releaseBusClaim();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -257,8 +344,8 @@ static bool append_sd_list_entry(SdListState& state, const char* path, uint64_t
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool scan_sd_files(FsFile& dir, SdListState& state) {
|
||||
FsFile file;
|
||||
static bool scan_sd_files(OtaSdFile& dir, SdListState& state) {
|
||||
OtaSdFile file;
|
||||
while (file.openNext(&dir, O_RDONLY)) {
|
||||
state.board.serviceWatchdog();
|
||||
const size_t parent_len = state.path_len;
|
||||
@@ -309,7 +396,7 @@ bool OtaStoreSdNrf52::listFiles(MainBoard& board, uint16_t page,
|
||||
_error[0] = 0;
|
||||
if (!mount()) return false;
|
||||
|
||||
FsFile root = _sd->open("/", O_RDONLY);
|
||||
OtaSdFile root = _sd->open("/", O_RDONLY);
|
||||
if (!root || !root.isDir()) { fail("SD root directory open failed"); return false; }
|
||||
SdListState state(board, (uint32_t)(page - 1) * SD_LIST_PAGE_SIZE);
|
||||
bool scanned = ensure_list_path(state, 2) && scan_sd_files(root, state);
|
||||
@@ -331,7 +418,37 @@ bool OtaStoreSdNrf52::listFiles(MainBoard& board, uint16_t page,
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t OtaStoreSdNrf52::capacity() const {
|
||||
if (!busAccessAllowed() || !_mounted || !_sd || !_sd->card()) return 0;
|
||||
uint64_t bytes = (uint64_t)_sd->card()->sectorCount() * MOTA_SD_AUTH_SECTOR_SIZE;
|
||||
return bytes > UINT32_MAX ? UINT32_MAX : (uint32_t)bytes;
|
||||
}
|
||||
|
||||
#if defined(OTA_SEEDER_ONLY)
|
||||
// The source-only context uses OtaStoreRam<1> for install fetches and this
|
||||
// object only owns the FAT volume shared with OtaCacheSdNrf52. Its archive
|
||||
// has its own file/read/write methods. Do not retain unreachable installer
|
||||
// vtable code (or permit accidental staging/approval) in a Companion image.
|
||||
bool OtaStoreSdNrf52::plan_layout(bool, uint32_t, uint32_t, uint32_t, bool) {
|
||||
fail("source-only SD archive cannot stage/apply"); return false;
|
||||
}
|
||||
bool OtaStoreSdNrf52::begin(uint32_t) {
|
||||
fail("source-only SD archive cannot stage/apply"); return false;
|
||||
}
|
||||
bool OtaStoreSdNrf52::set_meta_size(uint32_t) { return false; }
|
||||
bool OtaStoreSdNrf52::write(uint32_t, const uint8_t*, uint32_t) { return false; }
|
||||
bool OtaStoreSdNrf52::read(uint32_t, uint8_t*, uint32_t) const { return false; }
|
||||
bool OtaStoreSdNrf52::finalize() { return false; }
|
||||
void OtaStoreSdNrf52::checkpoint() {}
|
||||
bool OtaStoreSdNrf52::reopen() { return false; }
|
||||
bool OtaStoreSdNrf52::discard() { return false; }
|
||||
void OtaStoreSdNrf52::clear() {}
|
||||
bool OtaStoreSdNrf52::approve_for_bootloader(const uint8_t[32], const uint8_t[32]) {
|
||||
fail("source-only SD archive cannot stage/apply"); return false;
|
||||
}
|
||||
#else
|
||||
bool OtaStoreSdNrf52::locate_file() {
|
||||
if (!busAccessAllowed()) return false;
|
||||
Sector_t first = 0, last = 0;
|
||||
if (!_file || !_file->contiguousRange(&first, &last) || last < first) {
|
||||
fail("OTA file is not contiguous");
|
||||
@@ -418,7 +535,7 @@ bool OtaStoreSdNrf52::set_meta_size(uint32_t meta_bytes) {
|
||||
}
|
||||
|
||||
bool OtaStoreSdNrf52::write(uint32_t offset, const uint8_t* data, uint32_t len) {
|
||||
if (!_file || !*_file || (uint64_t)offset + len > _total || !_file->seekSet(offset) ||
|
||||
if (!busAccessAllowed() || !_file || !*_file || (uint64_t)offset + len > _total || !_file->seekSet(offset) ||
|
||||
_file->write(data, len) != len) {
|
||||
fail("SD OTA write failed");
|
||||
return false;
|
||||
@@ -427,20 +544,15 @@ bool OtaStoreSdNrf52::write(uint32_t offset, const uint8_t* data, uint32_t len)
|
||||
}
|
||||
|
||||
bool OtaStoreSdNrf52::read(uint32_t offset, uint8_t* buf, uint32_t len) const {
|
||||
if (!_file || !*_file || (uint64_t)offset + len > _total || !_file->seekSet(offset) ||
|
||||
if (!busAccessAllowed() || !_file || !*_file || (uint64_t)offset + len > _total || !_file->seekSet(offset) ||
|
||||
_file->read(buf, len) != (int)len) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t OtaStoreSdNrf52::capacity() const {
|
||||
if (!_mounted || !_sd || !_sd->card()) return 0;
|
||||
uint64_t bytes = (uint64_t)_sd->card()->sectorCount() * MOTA_SD_AUTH_SECTOR_SIZE;
|
||||
return bytes > UINT32_MAX ? UINT32_MAX : (uint32_t)bytes;
|
||||
}
|
||||
|
||||
bool OtaStoreSdNrf52::finalize() {
|
||||
if (!busAccessAllowed()) return false;
|
||||
SdCard* const card = _sd ? _sd->card() : nullptr;
|
||||
if (!_file || !*_file || !card || !_file->sync() || !card->syncDevice()) {
|
||||
fail("SD OTA sync failed");
|
||||
@@ -450,7 +562,7 @@ bool OtaStoreSdNrf52::finalize() {
|
||||
}
|
||||
|
||||
void OtaStoreSdNrf52::checkpoint() {
|
||||
if (_file && *_file) {
|
||||
if (busAccessAllowed() && _file && *_file) {
|
||||
_file->sync();
|
||||
if (_sd->card()) _sd->card()->syncDevice();
|
||||
}
|
||||
@@ -604,6 +716,7 @@ bool OtaStoreSdNrf52::approve_for_bootloader(
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif // OTA_SEEDER_ONLY
|
||||
|
||||
} // namespace ota
|
||||
} // namespace mesh
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
#if defined(NRF52_PLATFORM) && defined(OTA_SD_STORE)
|
||||
|
||||
#include "OtaStore.h"
|
||||
|
||||
class SdFs;
|
||||
class FsFile;
|
||||
#include "OtaSdTypesNrf52.h"
|
||||
|
||||
namespace mesh {
|
||||
|
||||
@@ -55,6 +53,9 @@ public:
|
||||
// Mount-only probe for the MeshTower selector. Never opens/removes staging
|
||||
// files or changes their live session state.
|
||||
bool probeMedia() { return mount() && capacity() != 0u; }
|
||||
// Caller first detaches the archive and proves no queued/pinned SD source
|
||||
// remains. Never unmount an installable or partially received container.
|
||||
bool releaseBus();
|
||||
const char* last_error() const { return _error; }
|
||||
|
||||
private:
|
||||
@@ -62,14 +63,21 @@ private:
|
||||
static const char* const PATH;
|
||||
|
||||
bool mount();
|
||||
bool acquireBus();
|
||||
bool busAccessAllowed() const;
|
||||
void releaseBusClaim();
|
||||
bool beginCardOnly();
|
||||
bool locate_file();
|
||||
void resetStoreState();
|
||||
void fail(const char* message);
|
||||
|
||||
SdFs* _sd = nullptr;
|
||||
mutable FsFile* _file = nullptr;
|
||||
OtaSdFs* _sd = nullptr;
|
||||
mutable OtaSdFile* _file = nullptr;
|
||||
bool _mounted = false;
|
||||
#if defined(OTA_RAK15002_SD_STORE)
|
||||
bool _bus_owned = false;
|
||||
bool _bus_started = false;
|
||||
#endif
|
||||
bool _planned_bootloader = false;
|
||||
uint32_t _total = 0;
|
||||
uint32_t _first_sector = 0;
|
||||
|
||||
+532
-287
@@ -3,7 +3,7 @@
|
||||
#include <stddef.h>
|
||||
|
||||
// AUTO-GENERATED by tools/mota/gen_targets.py - do not edit by hand.
|
||||
// 659 OTA-capable build targets. Maps target_id (= sha2-256:4 of the target name, LE uint32)
|
||||
// 683 OTA-capable build targets. Maps target_id (= sha2-256:4 of the target name, LE uint32)
|
||||
// to the human-readable env name, so a node/tool can name a target seen over the air WITHOUT
|
||||
// transmitting the string in the .mota / LoRa protocol. Regenerate when the OTA env set changes.
|
||||
// Size-constrained receivers can set OTA_TARGET_NAME_TABLE=0. They still match targets by ID;
|
||||
@@ -19,6 +19,9 @@
|
||||
|
||||
#if OTA_TARGET_NAME_TABLE && OTA_TARGET_NAME_FRONT_CODED
|
||||
#include "tinf/tinf.h"
|
||||
#if defined(OTA_RAK15002_SD_STORE) && defined(COMPANION_RADIO_FULL)
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace mesh { namespace ota {
|
||||
@@ -47,68 +50,71 @@ inline const char* ota_target_env_name(uint32_t target_id, char* buffer, size_t
|
||||
0x2f9f8e7d, 0xc9dc5d8c, 0x34b0e5f3, 0xb4d0ad97, 0xcfa0e233, 0x17d5e1ff, 0xc99313c6, 0xffb3854f,
|
||||
0x21a73973, 0x3067f656, 0xfdb25057, 0x836e5931, 0x0f1767cd, 0x57172fcc, 0xa529b4f5, 0x85a8c944,
|
||||
0x3c60586d, 0x0a9dbbf0, 0xb519a89f, 0xa3e8d8ce, 0xb16009a0, 0xdc780e80, 0x28b8007c, 0x4aa63180,
|
||||
0x6fddcbf1, 0xf4fb5484, 0x2e5384e2, 0xb62a1e75, 0x9e64845d, 0x19232e8b, 0xfaf164f4, 0x38b948b4,
|
||||
0x462ddb9b, 0xed21ca4f, 0x9f5f39a7, 0x081d2219, 0x7c498bc4, 0xc283ad60, 0x4fbdc1e1, 0xc797fd73,
|
||||
0xab9871c8, 0x2075687c, 0x5d726067, 0x9969bbc9, 0x804f7a3a, 0x0823a21a, 0x22f900de, 0xaca0e153,
|
||||
0x516c9c13, 0xcb1c2e65, 0xd1b29b18, 0x644bb68d, 0xd19a9759, 0xde40f56f, 0x6dc15ab3, 0xc59d294e,
|
||||
0xceeddfaf, 0x21519537, 0x382bb181, 0xad1bcd63, 0x5a2980e6, 0x90581c83, 0x90a6a854, 0x356df17c,
|
||||
0x99a084fc, 0x64c9dfc9, 0x2a2ffc92, 0x2c13b8e9, 0x1ee7d867, 0xb016979a, 0xb49b6b55, 0x01d8f124,
|
||||
0x86fb85f0, 0xd33b0986, 0x1a4d0096, 0xa8f5940f, 0x1cf5e14c, 0x2707d3d1, 0x86ac3b1b, 0x7af848da,
|
||||
0xd522a14f, 0x76657d76, 0x21ee03bd, 0x5977d941, 0xe2a1907b, 0xbb0ca8db, 0xf75feb3e, 0xb0a1e71f,
|
||||
0xbc9cdc70, 0x19e31fc6, 0xa01b330e, 0x36c78d86, 0xdf722326, 0xfa901c87, 0xeebe3469, 0xb0f5aff6,
|
||||
0x5729ad07, 0xaa2aef42, 0xb4cb035a, 0xbb429dde, 0x883e3edc, 0x4a9d1c6c, 0xa0965a6b, 0x59ea25fa,
|
||||
0x1758bdb9, 0x1313f16d, 0x0372b0f1, 0xa2fb4192, 0xdd39457b, 0x7964461c, 0x1d1c0d92, 0x5fc52bcb,
|
||||
0x0dacb683, 0xe792a051, 0x2d5ea842, 0x30c59b1d, 0xab74db9e, 0xeed78ce4, 0x7778b7e1, 0x0b6847ed,
|
||||
0xab3e1ad3, 0x04a8b763, 0xc456437e, 0xb3ecafca, 0xf3afcde6, 0x87513d56, 0xca812b41, 0x18594231,
|
||||
0x188f3ac1, 0x402055ec, 0x12393f1f, 0x16fbab07, 0xed3ef5b8, 0x8ea86381, 0x09f57289, 0x148aeaab,
|
||||
0xcbb2bf38, 0x6e9f7fec, 0x9a340cd3, 0x6a25d024, 0xc5a2cb41, 0xc4a11710, 0x753947a4, 0xe6fa98b4,
|
||||
0xf8c27cf4, 0xa139c6ae, 0x90e227d9, 0x89e8d957, 0x812f5e52, 0x61f961c5, 0x1ddd15c8, 0x49d67d0d,
|
||||
0xbc003322, 0x835b70c0, 0xd7460575, 0x36acced5, 0x33e2c171, 0x5be91148, 0xa165ae99, 0x04c5c2b7,
|
||||
0x6c1ca659, 0xa295fb04, 0x61c405ca, 0xe893fe91, 0x2b599d31, 0xf1442d25, 0x15082ede, 0x6ff350d1,
|
||||
0xe03d0cd9, 0x82e1eb2c, 0x0ee19b12, 0x6c67ed89, 0xd1c05d0d, 0xb90150b0, 0x7285bdb3, 0x77cadc99,
|
||||
0xc177e6cd, 0xf7a38993, 0x83762f33, 0x86cadda9, 0x7e49da49, 0x305d6f92, 0xbc6b870b, 0x78845fdd,
|
||||
0x6d35f434, 0xa52d76a8, 0xd8de9639, 0x8ab5c51b, 0x80097676, 0xffe70df5, 0x3da80417, 0x47ca3c13,
|
||||
0x28b499c7, 0xf1ab4c28, 0xe5331f02, 0xfba7177b, 0xde7dc472, 0x3625bb80, 0x69df7765, 0x988cc4e1,
|
||||
0xe9fbc9be, 0x40818863, 0x65deac33, 0xd86cf67a, 0xed73ac03, 0xab0d550a, 0x1bd2a266, 0x3655c748,
|
||||
0x9a5ae8fc, 0x1e9eb97a, 0x139536f4, 0x0716c724, 0x8de23fa7, 0xb92ec96b, 0x420ebc63, 0x967ccaee,
|
||||
0x8021afa2, 0x5f7c7688, 0xbd04e6e7, 0x1aeac884, 0x07849209, 0x0c79b100, 0xbfb60e7c, 0x8a63de3a,
|
||||
0x96036a68, 0xb76a745c, 0x43023193, 0xa7d97db7, 0x468a133e, 0xb59ea2ed, 0xcb75495b, 0xbe372c6d,
|
||||
0xb762985a, 0x6215e9eb, 0x07907102, 0x3898ea56, 0x2fb7e218, 0x8c61d4c8, 0x4f722e70, 0x694eed25,
|
||||
0x85b8b9d7, 0xe8421e36, 0x82eaaf9e, 0x9f9caba4, 0xe4a2de74, 0x582c7826, 0xaeb637f1, 0x86813271,
|
||||
0x67b2ff84, 0xd0e2e616, 0x3f9edfe3, 0xc23f8082, 0x0e74ae16, 0x8f256e56, 0x6915c6e1, 0xf1407f39,
|
||||
0x1b4dc5ab, 0xe90a3181, 0x3b1b4237, 0x21c6d08d, 0x34302c14, 0x268d6fc1, 0xeabe3b40, 0x3c172d27,
|
||||
0xf7c5d584, 0x81960cc0, 0x504020ea, 0x9d8b60ae, 0xa2ce002f, 0xba4f47f3, 0x6f16479e, 0x1018e5d1,
|
||||
0xc0ab5040, 0xa2bf90bd, 0xe6bff8f9, 0xb9cd26cb, 0x9bc34bd5, 0x144504b0, 0xdbfe2675, 0xb00241d0,
|
||||
0x88e77fee, 0xae2d9caa, 0xa0043e00, 0x26bbf4ed, 0xdcc0f158, 0xe3320463, 0x852b928a, 0x0ec870e9,
|
||||
0x8f00c1f2, 0xcea95e20, 0xd45277ff, 0x2cad9a9d, 0x02a4a8c1, 0x4a709348, 0x35d960bd, 0x62977023,
|
||||
0x17a7ed8c, 0x07f5f5b5, 0xfd0d4b8f, 0x8d88f33c, 0xf5afb7dd, 0x3a0ea830, 0x6ebf28cb, 0x2d589527,
|
||||
0x77d0810c, 0x11b131e7, 0x54850763, 0x0fa61805, 0x8039574f, 0xa65555d6, 0x22b1804c, 0xa9f631b1,
|
||||
0x49d11eca, 0xd41f0638, 0xe3105eb8, 0xf8259880, 0x063f1f00, 0x70d71f92, 0xa8a79da5, 0xc0d3815b,
|
||||
0x966ac88e, 0x104b3f8b, 0x23b49348, 0xc42cc90d, 0xc24791c3, 0x15e11067, 0x2dbb2669, 0x90799c32,
|
||||
0x881a6a48, 0xf26af51c, 0x8174cbdc, 0x0bf0f061, 0x2509dd80, 0x56293b24, 0x8c81078c, 0xbd6a1c97,
|
||||
0xf4d98c12, 0xccac4283, 0xa68c09e9, 0x5f606274, 0x84923735, 0x2c0b8b05, 0xdba69401, 0xcb6555ee,
|
||||
0xd60daf25, 0x410bd800, 0x9aca380e, 0xd8641710, 0x4d0b1601, 0xab2ac09e, 0xa17fc4f7, 0xe4b2bd22,
|
||||
0x90c4eb3f, 0x19d9ce91, 0x121cc72f, 0xfa8510fa, 0xd34d8461, 0x98077550, 0x11628e29, 0x2ed959aa,
|
||||
0xf1e7cadb, 0xced7e127, 0x6925aaf0, 0x2fa509c1, 0xa52ba3c8, 0xaf0b81dd, 0x9f4d58ac, 0x7a55dec3,
|
||||
0x5e69738a, 0x48d3b5d4, 0x14e6965d, 0x76f3c984, 0x41e33a97, 0x29a0da19, 0x29bc38dc, 0x05f5ffae,
|
||||
0xc62da371, 0xf1d3c5a8, 0xc6d55752, 0x60683191, 0x8a7cb79b, 0x4fa4ae55, 0xd1d61a8b, 0x9cb0b232,
|
||||
0x51fa1a49, 0xdb73638b, 0xd904c2d5, 0x3a14aac7, 0x620569f4, 0x08483f6b, 0x0db48f35, 0x20532f6c,
|
||||
0x293ced32, 0xb38ebf22, 0x7c89c73d, 0x2d7c11e8, 0x5bb567cd, 0x61b32037, 0xad1cd53d, 0x0e18b360,
|
||||
0x3caf966e, 0xcb59ea4e, 0xe3a28284, 0xa8cb8e8b, 0x05747eb6, 0x75587f24, 0xf2128c81, 0x1b34e7b4,
|
||||
0x8e549407, 0x6ca142f4, 0x1deac038, 0x2a2f303b, 0x0ba4453d, 0xf8d1958f, 0x75e85141, 0xd62ed92e,
|
||||
0x7abaf0d5, 0x87edc08b, 0x3c49caf8, 0x58689ef9, 0x91878dd8, 0x72a93c45, 0x4dbf035e, 0xff4102d6,
|
||||
0x2f9a9185, 0x000fc519, 0x7b071fa0, 0x3e55e34d, 0x54606a4f, 0x16482630, 0xce0f07ad, 0x01c43d49,
|
||||
0x51fe3801, 0x857149e5, 0xd9d64938, 0xcb7da3f5, 0x9952fbe3, 0x3729cd74, 0xdc27c37c, 0x9b9f8775,
|
||||
0xb27514a3, 0xe9ce038c, 0xe295a7a4, 0x189660b3, 0x99907475, 0x2082078d, 0x24a94c81, 0x3750e80d,
|
||||
0xe4b49973, 0xe1372b52, 0x5a79bac1, 0x6f339514, 0x8eaa289e, 0x70e91bd9, 0x5a7e9c2d, 0x1211b151,
|
||||
0x0a32044b, 0xa13fe853, 0x79b9ff01, 0xc3decea2, 0x3c012018, 0x6afd6f75, 0x7517d400, 0xd7598668,
|
||||
0x61bdb52a, 0x413287d8, 0xe8cd2377, 0x3309bdaf, 0x7330afbb, 0x9df48ce6, 0xa5cb783a, 0x4b9f8283,
|
||||
0x311846c9, 0x8b6b29b7, 0x37928233, 0x88ac45da, 0x087f99c0, 0xdf41affe, 0x2afe6c63, 0xf2d61a1c,
|
||||
0x14b1b097, 0xec334f3f, 0x1da30414, 0xae8fe1c9, 0x67acd73f, 0xfb118ed8, 0xe4213729, 0x1298038d,
|
||||
0x2c47acff, 0x7d641646, 0x51efdbfe, 0xf2aada5b, 0xe59c9373, 0x236f605c, 0x93994fed, 0x66c47cfd,
|
||||
0x48061a01, 0x7ed7137d, 0xa01688a7, 0xa5f4a562, 0xef83222b, 0xc36ec867, 0xb932238e, 0x92f5bbea,
|
||||
0x26d91ab2, 0x708ac4dc, 0xdc51bf13, 0xc27f8304, 0x7190df40, 0x609d50b3, 0x5718c7ea, 0x37443a5b,
|
||||
0x603384a7, 0xce3ef40f, 0x475a2a6a, 0xf4175d2c, 0x3d831006, 0x556eb1bc, 0xb67370b3, 0x0c689b90,
|
||||
0x6fddcbf1, 0xf4fb5484, 0x2e5384e2, 0xb62a1e75, 0x9e64845d, 0x19232e8b, 0x10f41878, 0xfaf164f4,
|
||||
0x38b948b4, 0x462ddb9b, 0xed21ca4f, 0x9f5f39a7, 0x081d2219, 0x7c498bc4, 0xc283ad60, 0x4fbdc1e1,
|
||||
0xc797fd73, 0xab9871c8, 0x2075687c, 0x5d726067, 0x9969bbc9, 0x804f7a3a, 0x0823a21a, 0x22f900de,
|
||||
0xaca0e153, 0x516c9c13, 0xcb1c2e65, 0xd1b29b18, 0x644bb68d, 0xd19a9759, 0xde40f56f, 0x6dc15ab3,
|
||||
0xc59d294e, 0xceeddfaf, 0x21519537, 0x382bb181, 0xad1bcd63, 0x5a2980e6, 0x90581c83, 0x90a6a854,
|
||||
0x356df17c, 0x99a084fc, 0x64c9dfc9, 0x2a2ffc92, 0x2c13b8e9, 0x1ee7d867, 0xb016979a, 0xb49b6b55,
|
||||
0x01d8f124, 0x64140fd9, 0x86fb85f0, 0xd33b0986, 0x1a4d0096, 0xa8f5940f, 0x1cf5e14c, 0x2707d3d1,
|
||||
0x86ac3b1b, 0x7af848da, 0xd522a14f, 0x76657d76, 0x21ee03bd, 0x5977d941, 0xe2a1907b, 0xbb0ca8db,
|
||||
0xf75feb3e, 0xb0a1e71f, 0xbc9cdc70, 0x19e31fc6, 0xa01b330e, 0x36c78d86, 0xdf722326, 0xfa901c87,
|
||||
0xeebe3469, 0xb0f5aff6, 0x5729ad07, 0xaa2aef42, 0xb4cb035a, 0xbb429dde, 0x883e3edc, 0x4a9d1c6c,
|
||||
0xa0965a6b, 0x59ea25fa, 0x1758bdb9, 0x1313f16d, 0x0372b0f1, 0xa2fb4192, 0xdd39457b, 0x7964461c,
|
||||
0x1d1c0d92, 0x5fc52bcb, 0x0dacb683, 0xe792a051, 0x2d5ea842, 0x30c59b1d, 0xab74db9e, 0xeed78ce4,
|
||||
0x7778b7e1, 0x0b6847ed, 0xab3e1ad3, 0x04a8b763, 0xc456437e, 0xb3ecafca, 0xf3afcde6, 0x87513d56,
|
||||
0xca812b41, 0x18594231, 0x188f3ac1, 0x402055ec, 0x12393f1f, 0x16fbab07, 0xed3ef5b8, 0x8ea86381,
|
||||
0x09f57289, 0x148aeaab, 0xcbb2bf38, 0x6e9f7fec, 0x9a340cd3, 0x6a25d024, 0xc5a2cb41, 0xc4a11710,
|
||||
0x753947a4, 0xe6fa98b4, 0xf8c27cf4, 0xa139c6ae, 0x90e227d9, 0x89e8d957, 0x812f5e52, 0x61f961c5,
|
||||
0x1ddd15c8, 0x49d67d0d, 0xbc003322, 0x835b70c0, 0xd7460575, 0x36acced5, 0x33e2c171, 0x5be91148,
|
||||
0xa165ae99, 0x04c5c2b7, 0x6c1ca659, 0xa295fb04, 0x61c405ca, 0xe893fe91, 0x2b599d31, 0xf1442d25,
|
||||
0x15082ede, 0x6ff350d1, 0xe03d0cd9, 0x82e1eb2c, 0x0ee19b12, 0x6c67ed89, 0xd1c05d0d, 0xb90150b0,
|
||||
0x7285bdb3, 0x77cadc99, 0xc177e6cd, 0xf7a38993, 0x83762f33, 0x86cadda9, 0x7e49da49, 0x305d6f92,
|
||||
0xbc6b870b, 0x78845fdd, 0x6d35f434, 0xa52d76a8, 0xd8de9639, 0x8ab5c51b, 0x80097676, 0xffe70df5,
|
||||
0x3da80417, 0x47ca3c13, 0x28b499c7, 0xf1ab4c28, 0xe5331f02, 0xfba7177b, 0xde7dc472, 0x3625bb80,
|
||||
0x69df7765, 0x988cc4e1, 0xe9fbc9be, 0x40818863, 0x65deac33, 0xd86cf67a, 0xed73ac03, 0xab0d550a,
|
||||
0x1bd2a266, 0x3655c748, 0x9a5ae8fc, 0x1e9eb97a, 0x139536f4, 0x0716c724, 0x8de23fa7, 0xb92ec96b,
|
||||
0x420ebc63, 0x967ccaee, 0x8021afa2, 0x5f7c7688, 0xbd04e6e7, 0x1aeac884, 0x07849209, 0x0c79b100,
|
||||
0xbfb60e7c, 0x8a63de3a, 0x96036a68, 0xb76a745c, 0x43023193, 0xa7d97db7, 0x468a133e, 0xb59ea2ed,
|
||||
0xcb75495b, 0xbe372c6d, 0xb762985a, 0x6215e9eb, 0x07907102, 0x3898ea56, 0x2fb7e218, 0x8c61d4c8,
|
||||
0x4f722e70, 0x694eed25, 0x85b8b9d7, 0xe8421e36, 0x82eaaf9e, 0x9f9caba4, 0xe4a2de74, 0x582c7826,
|
||||
0xaeb637f1, 0x86813271, 0x67b2ff84, 0xd0e2e616, 0x3f9edfe3, 0xc23f8082, 0x0e74ae16, 0x8f256e56,
|
||||
0x6915c6e1, 0xf1407f39, 0x1b4dc5ab, 0xe90a3181, 0x3b1b4237, 0x21c6d08d, 0x34302c14, 0x268d6fc1,
|
||||
0xeabe3b40, 0x3c172d27, 0xf7c5d584, 0x81960cc0, 0x504020ea, 0x9d8b60ae, 0xa2ce002f, 0xba4f47f3,
|
||||
0x6f16479e, 0x1018e5d1, 0xc0ab5040, 0xa2bf90bd, 0xe6bff8f9, 0xb9cd26cb, 0x9bc34bd5, 0x144504b0,
|
||||
0xdbfe2675, 0xb00241d0, 0x88e77fee, 0xae2d9caa, 0xa0043e00, 0x26bbf4ed, 0xdcc0f158, 0xe3320463,
|
||||
0x852b928a, 0x0ec870e9, 0x8f00c1f2, 0xcea95e20, 0xd45277ff, 0x2cad9a9d, 0x02a4a8c1, 0x4a709348,
|
||||
0x35d960bd, 0x62977023, 0x17a7ed8c, 0x07f5f5b5, 0xfd0d4b8f, 0x8d88f33c, 0xf5afb7dd, 0x3a0ea830,
|
||||
0x6ebf28cb, 0x2d589527, 0x77d0810c, 0x11b131e7, 0x54850763, 0x0fa61805, 0x8039574f, 0xa65555d6,
|
||||
0x22b1804c, 0xa9f631b1, 0x49d11eca, 0xd41f0638, 0xe3105eb8, 0xba76cc33, 0x944263f8, 0xc7a8c754,
|
||||
0xf8259880, 0x063f1f00, 0x70d71f92, 0xa8a79da5, 0xc0d3815b, 0x966ac88e, 0x104b3f8b, 0x23b49348,
|
||||
0xc42cc90d, 0xc24791c3, 0x15e11067, 0x2dbb2669, 0x90799c32, 0x881a6a48, 0xf26af51c, 0x8174cbdc,
|
||||
0x0bf0f061, 0x2509dd80, 0x56293b24, 0x8c81078c, 0xbd6a1c97, 0xf4d98c12, 0xccac4283, 0xa68c09e9,
|
||||
0x5f606274, 0x84923735, 0x2c0b8b05, 0xdba69401, 0xcb6555ee, 0xd60daf25, 0x410bd800, 0x9aca380e,
|
||||
0xd8641710, 0x4d0b1601, 0xab2ac09e, 0xa17fc4f7, 0xe4b2bd22, 0x90c4eb3f, 0x19d9ce91, 0x121cc72f,
|
||||
0xfa8510fa, 0xd34d8461, 0x98077550, 0x11628e29, 0x2ed959aa, 0xf1e7cadb, 0xced7e127, 0x6925aaf0,
|
||||
0x2fa509c1, 0xa52ba3c8, 0xaf0b81dd, 0x9f4d58ac, 0x7a55dec3, 0x5e69738a, 0x48d3b5d4, 0x14e6965d,
|
||||
0x76f3c984, 0x41e33a97, 0x29a0da19, 0x29bc38dc, 0xd5fc71d4, 0x05f5ffae, 0xc62da371, 0x96fc4c26,
|
||||
0x8a6dc63b, 0xb48950bb, 0xf1d3c5a8, 0xc6d55752, 0x60683191, 0x8a7cb79b, 0x4fa4ae55, 0xd1d61a8b,
|
||||
0x9cb0b232, 0x51fa1a49, 0xdb73638b, 0xd904c2d5, 0x3a14aac7, 0x620569f4, 0x08483f6b, 0x0db48f35,
|
||||
0x20532f6c, 0x293ced32, 0xb38ebf22, 0x7c89c73d, 0x2d7c11e8, 0x5bb567cd, 0x61b32037, 0xad1cd53d,
|
||||
0x0e18b360, 0x3caf966e, 0xcb59ea4e, 0xe3a28284, 0xa8cb8e8b, 0x05747eb6, 0x75587f24, 0xf2128c81,
|
||||
0x1b34e7b4, 0x8e549407, 0x6ca142f4, 0x1deac038, 0x2a2f303b, 0x0ba4453d, 0xf8d1958f, 0x75e85141,
|
||||
0xd62ed92e, 0x7abaf0d5, 0x87edc08b, 0xc50b0e48, 0x3c49caf8, 0x58689ef9, 0x91878dd8, 0x72a93c45,
|
||||
0x347e087a, 0x4dbf035e, 0xff4102d6, 0x2f9a9185, 0x000fc519, 0x7b071fa0, 0x3e55e34d, 0x54606a4f,
|
||||
0x16482630, 0xce0f07ad, 0x01c43d49, 0x51fe3801, 0x857149e5, 0xd9d64938, 0xcb7da3f5, 0x9952fbe3,
|
||||
0x3729cd74, 0xdc27c37c, 0x9b9f8775, 0xb27514a3, 0xe9ce038c, 0xe295a7a4, 0x189660b3, 0x99907475,
|
||||
0x2082078d, 0x24a94c81, 0x3750e80d, 0xe4b49973, 0xe1372b52, 0x5a79bac1, 0x6f339514, 0x8eaa289e,
|
||||
0x70e91bd9, 0x5a7e9c2d, 0x1211b151, 0x0a32044b, 0xa13fe853, 0x79b9ff01, 0xc3decea2, 0x3c012018,
|
||||
0x6afd6f75, 0x7517d400, 0xd7598668, 0x61bdb52a, 0x413287d8, 0xe8cd2377, 0x3309bdaf, 0x7330afbb,
|
||||
0x9df48ce6, 0xa5cb783a, 0x4b9f8283, 0x311846c9, 0x8b6b29b7, 0x37928233, 0x88ac45da, 0x087f99c0,
|
||||
0xdf41affe, 0x2afe6c63, 0xf2d61a1c, 0x14b1b097, 0xec334f3f, 0x1da30414, 0xae8fe1c9, 0x67acd73f,
|
||||
0xfb118ed8, 0xe4213729, 0x1298038d, 0x2c47acff, 0x7d641646, 0x51efdbfe, 0xf2aada5b, 0xe59c9373,
|
||||
0x236f605c, 0x93994fed, 0x66c47cfd, 0x48061a01, 0x7ed7137d, 0xa01688a7, 0xa5f4a562, 0xef83222b,
|
||||
0xc36ec867, 0xb932238e, 0x92f5bbea, 0x26d91ab2, 0x708ac4dc, 0xdc51bf13, 0xc27f8304, 0x7190df40,
|
||||
0x609d50b3, 0x5718c7ea, 0x7bbf1081, 0xb151c2aa, 0x3b0174fd, 0xc1fd2578, 0xeb440352, 0xa297f85a,
|
||||
0xcbe54778, 0x0343bdf0, 0x3de413b1, 0x37443a5b, 0x603384a7, 0x76456c88, 0x28c4948b, 0xb34a83c5,
|
||||
0x63fe9591, 0xce3ef40f, 0x475a2a6a, 0xf4175d2c, 0x3d831006, 0x556eb1bc, 0xb67370b3, 0x0c689b90,
|
||||
0x91eac424, 0x7a84a8c4, 0x67843a5f, 0x0e83fd51, 0xfad357ab, 0x16af5c67, 0x8c105104, 0xa80042a0,
|
||||
0x4bff0748, 0x77c8f2b5, 0x71ee0e15, 0x8824cd0c, 0xe5439198, 0xe90a6e74, 0x833e5cdc, 0x93145fbb,
|
||||
0x8d3dd6d5, 0x33a154ff, 0x6658b418, 0x0cfb9c00, 0x964f4f5c, 0x0a5dc760, 0xd08496ce, 0x293ac2c8,
|
||||
@@ -116,19 +122,205 @@ inline const char* ota_target_env_name(uint32_t target_id, char* buffer, size_t
|
||||
0x396fecc7, 0xf94e3407, 0xe1930103, 0xa4740508, 0x9f19bcd1, 0xfcebff61, 0xac5c1405, 0xccb734e2,
|
||||
0x634ff632, 0xf967a300, 0xa0cc1c36,
|
||||
};
|
||||
#if defined(OTA_RAK15002_SD_STORE) && defined(COMPANION_RADIO_FULL)
|
||||
enum { DECODE_CHUNK_BYTES = 4096 };
|
||||
static const uint16_t OFFSETS[] = {
|
||||
0, 227, 448, 665, 896, 1112, 1319, 1536, 1768, 1937, 2118, 2349,
|
||||
2591, 2847, 3082, 3330, 3535, 3739, 3912, 4128, 4330,
|
||||
0, 1066, 2165, 2715,
|
||||
};
|
||||
static const uint16_t RAW_LENGTHS[] = {
|
||||
510, 512, 505, 509, 505, 512, 494, 506, 512, 499, 511, 507,
|
||||
507, 509, 481, 501, 498, 511, 488, 388,
|
||||
4087, 4061, 2042,
|
||||
};
|
||||
static const uint16_t FIRSTS[] = {
|
||||
0, 27, 64, 95, 121, 158, 192, 226, 262, 295, 330, 366,
|
||||
398, 431, 463, 486, 522, 554, 596, 628, 659,
|
||||
0, 274, 536, 683,
|
||||
};
|
||||
// 4330 encoded bytes; 20 independent chunks, at most 512 decoded bytes.
|
||||
// 2715 encoded bytes; 3 independent chunks, at most 4096 decoded bytes.
|
||||
static const uint8_t NAMES[] = {
|
||||
0xad, 0x57, 0x57, 0x9b, 0xa3, 0x38, 0x10, 0xd4, 0xe5, 0xbb, 0xc9, 0x39, 0x3a, 0x6f, 0xce, 0x36,
|
||||
0xde, 0xf8, 0x76, 0x69, 0x73, 0xce, 0x8f, 0xfd, 0xc9, 0x20, 0xaf, 0xf9, 0x0c, 0x88, 0x93, 0x34,
|
||||
0xe9, 0xdf, 0xdf, 0x08, 0x31, 0xb8, 0xd1, 0xca, 0x6c, 0xde, 0x09, 0xc2, 0x1a, 0xba, 0xaa, 0xab,
|
||||
0xab, 0x1b, 0x44, 0xee, 0x0e, 0x8e, 0x14, 0x83, 0xbb, 0xfc, 0x15, 0xbd, 0xf2, 0xba, 0x0f, 0x3e,
|
||||
0x8f, 0x53, 0x9a, 0x84, 0x3c, 0x01, 0x41, 0x83, 0x90, 0xc3, 0x20, 0x62, 0xa4, 0xb1, 0x27, 0x07,
|
||||
0x64, 0x61, 0x1c, 0x4a, 0x09, 0x31, 0x0f, 0x58, 0x4c, 0x16, 0x5e, 0xb1, 0x94, 0x51, 0xc5, 0x04,
|
||||
0x59, 0x10, 0xf9, 0x0a, 0xf8, 0x40, 0x32, 0xb1, 0xcf, 0x04, 0xc4, 0xff, 0x29, 0x45, 0x16, 0x39,
|
||||
0x8f, 0xc1, 0x7c, 0x40, 0xb6, 0xad, 0xbd, 0x05, 0xc5, 0x44, 0x1c, 0x26, 0x34, 0x02, 0x7f, 0x44,
|
||||
0x15, 0x21, 0xf7, 0xff, 0x7a, 0x73, 0xe3, 0xa6, 0x07, 0xfd, 0xee, 0x6b, 0x78, 0xca, 0xe4, 0x08,
|
||||
0x1e, 0x87, 0xca, 0x49, 0xe3, 0xb4, 0xa6, 0xb1, 0x86, 0x68, 0xac, 0x15, 0xe0, 0x11, 0x17, 0x14,
|
||||
0xb8, 0xa2, 0x90, 0x70, 0x60, 0x87, 0x8a, 0x09, 0x1d, 0x5d, 0xb2, 0x44, 0x72, 0x21, 0xc9, 0x3a,
|
||||
0xe2, 0xf2, 0x5b, 0x86, 0x70, 0xf7, 0xdd, 0xdf, 0xf0, 0x42, 0x70, 0x70, 0xc5, 0x22, 0xb5, 0xcf,
|
||||
0x8f, 0x36, 0xf7, 0x46, 0x50, 0x7f, 0xcc, 0x84, 0x0e, 0xe6, 0xa4, 0x7c, 0x5e, 0x53, 0xde, 0x42,
|
||||
0x30, 0x5b, 0x9f, 0x47, 0x79, 0x1b, 0x83, 0xbc, 0xa7, 0xca, 0x1f, 0xf5, 0xdc, 0xa5, 0xc1, 0x72,
|
||||
0xfc, 0xc0, 0x12, 0x26, 0x42, 0x1f, 0xee, 0x7a, 0x1e, 0xce, 0x6c, 0x4e, 0x1e, 0xf6, 0xbc, 0x63,
|
||||
0x7d, 0x8b, 0x04, 0x97, 0x6f, 0x4f, 0xd6, 0x7f, 0xbc, 0x7e, 0xf1, 0xec, 0xf9, 0xfb, 0x2c, 0x74,
|
||||
0x1e, 0x55, 0x33, 0x5e, 0x34, 0xfb, 0x82, 0x2c, 0x65, 0x3c, 0xf6, 0x05, 0x59, 0x2c, 0xd7, 0xec,
|
||||
0x87, 0xbb, 0x2f, 0x5e, 0xfd, 0x03, 0x4f, 0xc2, 0x64, 0x3c, 0x8c, 0xf8, 0x01, 0xdc, 0xe9, 0x76,
|
||||
0x27, 0x21, 0xc9, 0x03, 0x16, 0x29, 0xe6, 0x83, 0xaf, 0x6e, 0x7a, 0x4e, 0xce, 0x4d, 0x48, 0x25,
|
||||
0xa9, 0x69, 0x9c, 0x39, 0x4c, 0xb3, 0x08, 0xb0, 0x06, 0x03, 0x11, 0x06, 0x1f, 0x18, 0x30, 0x99,
|
||||
0x26, 0xfc, 0x80, 0xcc, 0x19, 0x55, 0xc8, 0x6f, 0x77, 0x3d, 0xb7, 0x0a, 0x5f, 0x12, 0x6c, 0xbd,
|
||||
0xec, 0xc5, 0x79, 0x24, 0xf4, 0xa6, 0xe5, 0xd3, 0x3f, 0xee, 0x74, 0x11, 0x9a, 0xc6, 0xd9, 0xd0,
|
||||
0x38, 0xdb, 0x7a, 0xf9, 0xfd, 0xd1, 0x7e, 0x8b, 0xb5, 0x33, 0x25, 0x8f, 0xa8, 0x40, 0x5a, 0x8e,
|
||||
0x8c, 0x96, 0xc2, 0xef, 0xbb, 0xb5, 0xac, 0x0d, 0xf7, 0xa2, 0xc8, 0xe4, 0x5f, 0x3b, 0x08, 0x87,
|
||||
0xe1, 0x77, 0xe7, 0x55, 0xa8, 0x3f, 0x57, 0x76, 0xc0, 0xdc, 0x41, 0xa8, 0x46, 0x7c, 0x4f, 0x41,
|
||||
0x10, 0xca, 0x34, 0xa2, 0x47, 0x4e, 0x76, 0x97, 0x33, 0x76, 0x97, 0x35, 0xbb, 0xcb, 0x19, 0xbb,
|
||||
0x5a, 0xc1, 0xe8, 0xb4, 0xc5, 0xe8, 0x4c, 0x19, 0xb5, 0x8e, 0x18, 0x9d, 0xb3, 0x18, 0xd5, 0x0c,
|
||||
0xa3, 0xc2, 0x68, 0xaa, 0x7b, 0xe7, 0xa6, 0x0b, 0x1e, 0x86, 0x2c, 0xe6, 0xc3, 0x21, 0x39, 0x9d,
|
||||
0x64, 0x02, 0xa1, 0x4b, 0xa7, 0x48, 0x27, 0x84, 0x84, 0xf4, 0xfa, 0xde, 0x27, 0x66, 0x40, 0xd5,
|
||||
0x2e, 0x56, 0xb3, 0x50, 0xef, 0xf7, 0x5e, 0xef, 0x7a, 0xb5, 0x75, 0xab, 0xf9, 0x7c, 0x05, 0xe4,
|
||||
0xe7, 0x55, 0x48, 0xc3, 0xdb, 0x55, 0x29, 0x40, 0xcf, 0x54, 0x82, 0xe2, 0x1a, 0xfd, 0xf6, 0xa6,
|
||||
0x77, 0xa7, 0xeb, 0x2c, 0x82, 0xd1, 0x9e, 0xb4, 0xb2, 0xb5, 0x3b, 0x51, 0xb2, 0x5e, 0xf2, 0x02,
|
||||
0x54, 0xd8, 0x13, 0xc8, 0x96, 0xd5, 0x36, 0xaa, 0x07, 0x9f, 0x37, 0x53, 0x7f, 0xe7, 0x07, 0x4c,
|
||||
0xc0, 0x3e, 0x1a, 0x84, 0x5b, 0xd5, 0x37, 0x2c, 0xc9, 0xc0, 0xa7, 0x22, 0xf8, 0xbc, 0xf0, 0x45,
|
||||
0xab, 0xaa, 0xfc, 0x91, 0xb0, 0xdf, 0x03, 0xc4, 0xac, 0x44, 0x1a, 0x3d, 0x43, 0xec, 0x9d, 0x25,
|
||||
0xaf, 0xca, 0xc9, 0x17, 0x13, 0xd2, 0xd1, 0x2d, 0x95, 0x5d, 0x1f, 0xaf, 0xb5, 0xb2, 0x68, 0x4b,
|
||||
0xb7, 0xd8, 0xc9, 0xf5, 0xa5, 0x84, 0xac, 0x20, 0xb1, 0x57, 0x8a, 0xa4, 0x77, 0xac, 0xc6, 0xeb,
|
||||
0x98, 0x52, 0xef, 0x96, 0x79, 0xac, 0xa2, 0xda, 0xd6, 0x2d, 0x8e, 0x2b, 0xb9, 0xc1, 0x56, 0x4a,
|
||||
0x13, 0xa1, 0x68, 0xc7, 0x7d, 0xf7, 0xa4, 0xaa, 0xeb, 0xa9, 0xbf, 0xa3, 0xed, 0xb6, 0xa3, 0x79,
|
||||
0x92, 0x19, 0xc4, 0x6e, 0xa6, 0x60, 0x37, 0x8b, 0x70, 0x67, 0xca, 0xf1, 0x7f, 0xef, 0x57, 0xc4,
|
||||
0xd5, 0xaa, 0xe0, 0xe8, 0x0d, 0x43, 0xd5, 0x0d, 0xb2, 0x62, 0x49, 0xb0, 0x63, 0x24, 0x58, 0x2d,
|
||||
0xa7, 0xd9, 0x02, 0x19, 0xc6, 0x25, 0x42, 0xeb, 0x96, 0x10, 0x33, 0x46, 0x08, 0x8b, 0x68, 0xe1,
|
||||
0x84, 0xfd, 0xeb, 0xe0, 0xe9, 0x1f, 0x1f, 0xf3, 0x46, 0x35, 0x9c, 0xe9, 0x57, 0x15, 0xbc, 0x95,
|
||||
0xca, 0x7c, 0x69, 0x26, 0x7d, 0x71, 0x81, 0x2a, 0x5f, 0xc3, 0x65, 0x6f, 0x6b, 0x62, 0x27, 0x17,
|
||||
0x73, 0xec, 0xf0, 0x38, 0xb0, 0x3c, 0x8e, 0x3c, 0x0e, 0x15, 0xa8, 0xa1, 0xaa, 0x82, 0x9a, 0xfb,
|
||||
0xc4, 0x7e, 0x0b, 0xe3, 0xb7, 0x10, 0x7e, 0x0b, 0xe3, 0xcf, 0xb8, 0x4b, 0x94, 0xef, 0x76, 0x12,
|
||||
0xd2, 0xc8, 0x33, 0x4a, 0x4c, 0xb5, 0xcc, 0x96, 0xfe, 0xb8, 0x48, 0xf4, 0x4c, 0x62, 0x6a, 0x98,
|
||||
0xef, 0x34, 0x4d, 0x46, 0x46, 0x2c, 0x9c, 0xd0, 0xa4, 0x8f, 0x9b, 0x56, 0x5d, 0xb6, 0xa6, 0xb6,
|
||||
0xd7, 0x66, 0x55, 0x92, 0x09, 0xb9, 0x96, 0x4a, 0x72, 0x09, 0x17, 0x07, 0xdb, 0x27, 0xa5, 0x42,
|
||||
0x85, 0x4a, 0xdf, 0x96, 0xb1, 0x08, 0xb4, 0x43, 0xc5, 0x6d, 0xa7, 0x27, 0x5b, 0xda, 0x93, 0xf5,
|
||||
0xcc, 0x93, 0xf5, 0x2c, 0xcb, 0xcc, 0x93, 0xf3, 0x28, 0xda, 0x7c, 0x41, 0xde, 0x36, 0xd5, 0x02,
|
||||
0x32, 0xdc, 0x96, 0xb5, 0x37, 0x9f, 0x1b, 0x6e, 0xbe, 0x6c, 0xb8, 0x05, 0x77, 0x52, 0xa4, 0x9d,
|
||||
0x31, 0x68, 0x6b, 0x06, 0xed, 0x8c, 0xc1, 0x32, 0x62, 0xb0, 0x9c, 0x72, 0xa1, 0x04, 0x45, 0x3a,
|
||||
0x5a, 0x60, 0xbb, 0x53, 0x55, 0x5c, 0x2e, 0xc8, 0x6f, 0xdb, 0xa3, 0x01, 0x91, 0xaf, 0xd9, 0x77,
|
||||
0xe5, 0xe4, 0x97, 0xcb, 0xe4, 0x67, 0xa7, 0x75, 0xe5, 0x6a, 0xc4, 0x3e, 0x50, 0xff, 0x08, 0x26,
|
||||
0xba, 0x2b, 0x26, 0x95, 0xdd, 0xa5, 0x5f, 0xd1, 0x9f, 0xb3, 0x95, 0x1e, 0x68, 0xa0, 0xfa, 0xeb,
|
||||
0x83, 0xcf, 0xc9, 0x12, 0x59, 0x72, 0xa1, 0xc8, 0x7f, 0xc3, 0xe2, 0x8c, 0x8f, 0x3d, 0x0b, 0x39,
|
||||
0xfa, 0x82, 0x7b, 0x4c, 0xbe, 0x0f, 0x05, 0x8b, 0x98, 0x94, 0xf0, 0x82, 0xa6, 0x4c, 0x38, 0xeb,
|
||||
0x77, 0x41, 0xdb, 0xe8, 0xac, 0x2e, 0xdf, 0x06, 0x2a, 0xdc, 0x46, 0x81, 0xde, 0xb0, 0xd0, 0x9b,
|
||||
0x96, 0xd9, 0x11, 0x99, 0xb6, 0xfd, 0x9c, 0x31, 0x27, 0x17, 0x37, 0xee, 0x25, 0x8d, 0x3b, 0xfd,
|
||||
0xe8, 0x42, 0x5a, 0x16, 0x6e, 0xbb, 0x1c, 0x1b, 0x1f, 0x5e, 0x4e, 0x59, 0xb8, 0xbf, 0xbf, 0x7e,
|
||||
0xd2, 0xaf, 0x3e, 0x14, 0x98, 0x79, 0x56, 0xf1, 0xee, 0x5a, 0x33, 0xd3, 0xfa, 0x2b, 0x5e, 0x61,
|
||||
0x49, 0x38, 0xe6, 0x63, 0x0a, 0x23, 0x9a, 0x04, 0x23, 0x16, 0x05, 0x90, 0x88, 0x21, 0x30, 0x4f,
|
||||
0x9f, 0x3c, 0x83, 0x41, 0x0c, 0x53, 0xde, 0x22, 0x49, 0x2f, 0xeb, 0x1f, 0xc1, 0x15, 0x55, 0x2c,
|
||||
0x70, 0xfe, 0xc5, 0x9d, 0xac, 0xc7, 0x27, 0x65, 0x41, 0x54, 0x56, 0x91, 0x80, 0xbf, 0x26, 0x34,
|
||||
0xe1, 0x19, 0xa8, 0xe7, 0x69, 0x40, 0x57, 0xa8, 0x33, 0x3a, 0xd4, 0x3a, 0xba, 0x69, 0x7d, 0xe2,
|
||||
0x35, 0x14, 0x76, 0x51, 0x53, 0xfe, 0xa6, 0x08, 0xff, 0x03, 0xbd, 0x96, 0x05, 0x93, 0xe3, 0x38,
|
||||
0x10, 0x85, 0xb5, 0x98, 0xcc, 0x62, 0x38, 0xcb, 0x70, 0xcc, 0x67, 0x58, 0x2c, 0x3c, 0x5a, 0xe6,
|
||||
0xc1, 0xe2, 0x2e, 0xc5, 0xe9, 0x49, 0x54, 0xb1, 0xa5, 0xac, 0xa4, 0x0c, 0xfd, 0xfa, 0x1b, 0x85,
|
||||
0x2c, 0xab, 0x14, 0x1f, 0x5f, 0x71, 0x62, 0xab, 0xdf, 0xd7, 0xfd, 0xba, 0xe5, 0x26, 0x6c, 0x24,
|
||||
0x46, 0x14, 0x38, 0xe5, 0x02, 0xb8, 0xdc, 0x85, 0x38, 0xee, 0xf7, 0x32, 0x48, 0x44, 0x36, 0xa6,
|
||||
0x9c, 0x09, 0x0e, 0x92, 0xf6, 0x99, 0x80, 0x5e, 0x8a, 0xe4, 0xf3, 0x89, 0xea, 0x91, 0xf6, 0x88,
|
||||
0x29, 0x05, 0x99, 0xe8, 0x63, 0x46, 0xda, 0x12, 0xc7, 0x48, 0x35, 0x4a, 0xd2, 0x11, 0x22, 0x03,
|
||||
0x85, 0x72, 0x0f, 0x25, 0x39, 0xab, 0x34, 0x4b, 0x46, 0xd3, 0x58, 0x51, 0xb4, 0x2a, 0xd6, 0x17,
|
||||
0x26, 0x56, 0xc7, 0x8a, 0xd5, 0x59, 0xc6, 0xea, 0x5a, 0xb1, 0x6a, 0x71, 0xf0, 0x0f, 0x23, 0xd4,
|
||||
0xe3, 0x7f, 0x18, 0x80, 0xbc, 0x42, 0x1c, 0x6b, 0x44, 0xfe, 0x7a, 0x33, 0x84, 0xe5, 0x1b, 0x2d,
|
||||
0x48, 0x85, 0xa4, 0x20, 0x34, 0x05, 0x2e, 0x00, 0x0f, 0x34, 0x4a, 0x4e, 0x53, 0x50, 0xc8, 0x95,
|
||||
0x90, 0x8a, 0x90, 0xd7, 0x2c, 0x3d, 0x7c, 0x26, 0x60, 0xf3, 0xfb, 0x27, 0xc9, 0x50, 0x7c, 0xff,
|
||||
0x9a, 0x69, 0xf4, 0x32, 0x7c, 0x6a, 0x18, 0x9a, 0x16, 0x43, 0x93, 0x0b, 0x0e, 0x6a, 0x88, 0x69,
|
||||
0xea, 0x7d, 0xff, 0xfb, 0xe9, 0xfb, 0x39, 0x85, 0xc5, 0x79, 0x11, 0x7e, 0xa5, 0xb2, 0xff, 0x27,
|
||||
0x55, 0xbc, 0x11, 0x2e, 0xf9, 0xce, 0xde, 0x32, 0x67, 0x2f, 0x59, 0x67, 0x2f, 0x2d, 0xcf, 0x5e,
|
||||
0xb6, 0xce, 0x56, 0xe3, 0x8d, 0x18, 0xd4, 0x41, 0x18, 0x3d, 0x88, 0xfc, 0xc5, 0x86, 0xb1, 0x2a,
|
||||
0xe3, 0xb8, 0x0e, 0x3d, 0xc9, 0xfa, 0x03, 0x04, 0x54, 0x63, 0x2e, 0xf6, 0xc9, 0x0d, 0xd1, 0x9b,
|
||||
0x45, 0x86, 0xec, 0xa3, 0xd6, 0x05, 0xcc, 0x5b, 0x50, 0x7c, 0xd6, 0xd4, 0x28, 0x33, 0x66, 0xaa,
|
||||
0x9f, 0x0c, 0xa9, 0x26, 0xb5, 0x87, 0x0f, 0xbc, 0x04, 0xff, 0x8b, 0x78, 0x15, 0x5e, 0x64, 0xe3,
|
||||
0x49, 0xaa, 0x10, 0xde, 0xa7, 0x13, 0x95, 0xb7, 0x4b, 0xf5, 0x17, 0xa4, 0x19, 0x84, 0x3b, 0x7e,
|
||||
0x32, 0x53, 0x9b, 0x3b, 0xbb, 0x93, 0x34, 0x25, 0x77, 0x0c, 0xe4, 0x9d, 0x7d, 0xb6, 0xcb, 0x48,
|
||||
0xcd, 0x42, 0xad, 0x2d, 0x03, 0x5d, 0x71, 0x50, 0xaf, 0x16, 0x71, 0xea, 0x16, 0xea, 0x75, 0x07,
|
||||
0xb5, 0xfa, 0x1b, 0x26, 0x23, 0x2f, 0xc0, 0x4d, 0xa3, 0x7a, 0xd1, 0xd2, 0xbb, 0x98, 0x83, 0x3f,
|
||||
0xd9, 0x7c, 0x0e, 0x4f, 0x52, 0xa6, 0xb1, 0xcc, 0xdd, 0xaf, 0x4d, 0x80, 0xab, 0x56, 0x80, 0xab,
|
||||
0xcb, 0x00, 0x77, 0x1d, 0x8a, 0x6b, 0x16, 0xe1, 0x67, 0x2e, 0xe1, 0x74, 0xa6, 0x7e, 0xf5, 0xfa,
|
||||
0x07, 0xfe, 0x82, 0x80, 0x9d, 0x32, 0x90, 0xea, 0x6b, 0x13, 0x61, 0x3b, 0x82, 0x10, 0x42, 0x78,
|
||||
0xe0, 0x67, 0x35, 0xd5, 0x9e, 0xce, 0xfe, 0x17, 0xa6, 0xce, 0xfe, 0x1b, 0xc0, 0xf5, 0x19, 0x0a,
|
||||
0x57, 0xc2, 0x5d, 0xf7, 0x61, 0xa7, 0xd8, 0x05, 0xe4, 0xcd, 0xfd, 0x0d, 0x4d, 0x93, 0x11, 0x6c,
|
||||
0x71, 0xa6, 0x8f, 0xf3, 0x79, 0xed, 0x05, 0xb9, 0x6b, 0x18, 0xea, 0x96, 0x7a, 0x7d, 0xa9, 0xde,
|
||||
0xb0, 0xc4, 0x4e, 0xa0, 0x1a, 0xc2, 0x58, 0x24, 0x23, 0xd4, 0x7f, 0xfa, 0xfa, 0x39, 0x4d, 0xfb,
|
||||
0x7b, 0xc8, 0xf5, 0x44, 0xa2, 0x2c, 0xb1, 0xed, 0x4f, 0xde, 0x80, 0x6e, 0x76, 0xad, 0x47, 0xff,
|
||||
0x62, 0xb0, 0xd3, 0x2c, 0x63, 0x7e, 0xbb, 0xab, 0xb9, 0xc5, 0x24, 0x43, 0x35, 0xe4, 0x22, 0x15,
|
||||
0x83, 0x43, 0xd8, 0x0f, 0xfd, 0xb9, 0xdc, 0x9e, 0xce, 0xcf, 0x6d, 0x03, 0x71, 0x7b, 0xea, 0xeb,
|
||||
0x65, 0x0b, 0xe5, 0x72, 0x8e, 0xe2, 0xcc, 0xcf, 0x95, 0x62, 0x07, 0xd6, 0x2c, 0xd2, 0x6b, 0x4e,
|
||||
0x77, 0x5e, 0x9e, 0x55, 0x97, 0x5c, 0x76, 0xcd, 0x66, 0x1c, 0xf7, 0x15, 0x66, 0x0c, 0x32, 0x8c,
|
||||
0xee, 0xa7, 0x2a, 0x08, 0x21, 0xbf, 0x59, 0xca, 0x7d, 0x3a, 0xf1, 0xea, 0x09, 0xa8, 0xd8, 0x9b,
|
||||
0x4f, 0xd7, 0x64, 0xd2, 0x9d, 0x66, 0x52, 0xc9, 0x6f, 0x5c, 0x87, 0xbe, 0x2b, 0x55, 0x14, 0x47,
|
||||
0xa4, 0x6a, 0x51, 0x57, 0xe6, 0x94, 0x15, 0x87, 0x32, 0x13, 0x52, 0x21, 0xf4, 0x90, 0x27, 0x43,
|
||||
0x90, 0x74, 0x74, 0xef, 0x41, 0x1c, 0xe6, 0xba, 0xe4, 0x82, 0x0e, 0x1e, 0x3f, 0xb0, 0x7e, 0x9f,
|
||||
0x1d, 0x4b, 0xd1, 0x9f, 0x24, 0x7a, 0xc6, 0xe4, 0xbe, 0x4d, 0xde, 0x9a, 0x65, 0xe1, 0x59, 0x04,
|
||||
0x5b, 0xa9, 0x96, 0x34, 0xcf, 0x96, 0x70, 0xd6, 0x33, 0xde, 0xa9, 0x44, 0x22, 0x72, 0x48, 0x04,
|
||||
0xe7, 0x98, 0x68, 0xbf, 0xbd, 0x5f, 0x18, 0xbf, 0x60, 0xda, 0x35, 0x30, 0x9b, 0x44, 0xb0, 0xbb,
|
||||
0x07, 0xf2, 0xf6, 0x01, 0x72, 0xbb, 0x90, 0x75, 0x61, 0x16, 0xdd, 0xd9, 0x03, 0x52, 0x39, 0x42,
|
||||
0x29, 0xca, 0xb5, 0x3f, 0x9b, 0x69, 0x7f, 0x36, 0xd5, 0xfe, 0x6c, 0xa6, 0xdd, 0xca, 0xe5, 0x6e,
|
||||
0x3a, 0x72, 0x6d, 0x5b, 0xae, 0xe5, 0xc8, 0x91, 0xf7, 0x52, 0xbc, 0x61, 0x89, 0x14, 0x5e, 0x17,
|
||||
0xaf, 0x1a, 0x17, 0xd7, 0xac, 0x4e, 0x5c, 0x5b, 0x16, 0xab, 0xbe, 0xf0, 0x72, 0xea, 0xa1, 0x89,
|
||||
0xcf, 0x68, 0x1a, 0x92, 0x46, 0x69, 0xc3, 0x9c, 0xb3, 0x9c, 0x5e, 0x9b, 0x3b, 0xbd, 0xe6, 0x38,
|
||||
0xbd, 0x1e, 0xbe, 0x45, 0x3f, 0x4d, 0xc7, 0xd0, 0x9c, 0xb5, 0x68, 0xce, 0x2e, 0x69, 0x2e, 0x95,
|
||||
0x37, 0x6a, 0xa5, 0xb0, 0xdf, 0xcd, 0x74, 0xcf, 0x16, 0x75, 0x4f, 0xfc, 0xfc, 0x0a, 0xe2, 0x70,
|
||||
0xc5, 0x74, 0x5e, 0x35, 0x15, 0x9f, 0x55, 0xe3, 0xaa, 0xa9, 0x77, 0x79, 0x4d, 0xf2, 0xaf, 0xdb,
|
||||
0xac, 0xbf, 0x1b, 0xc5, 0x41, 0xb4, 0x8b, 0xd0, 0x72, 0x86, 0x74, 0x45, 0x51, 0xce, 0xdc, 0xb3,
|
||||
0xa6, 0xb2, 0x3c, 0xd5, 0x86, 0xa4, 0xa3, 0x30, 0x8e, 0x83, 0x08, 0xf6, 0xa3, 0xfb, 0x1f, 0xc3,
|
||||
0x07, 0xcb, 0xb7, 0x49, 0x63, 0xc2, 0x8f, 0xd1, 0xb1, 0x9f, 0xff, 0x73, 0xda, 0x0c, 0x86, 0x3f,
|
||||
0x61, 0xd4, 0x43, 0x94, 0x1c, 0xb5, 0x95, 0xba, 0x3f, 0x69, 0x6f, 0x1b, 0x94, 0x23, 0x7e, 0x1e,
|
||||
0x41, 0x79, 0x0a, 0x7f, 0x9c, 0xe0, 0xfd, 0x20, 0x08, 0x41, 0xa5, 0x42, 0x43, 0x92, 0xa7, 0x73,
|
||||
0x35, 0x02, 0xd5, 0x07, 0x85, 0xd8, 0x47, 0x09, 0x82, 0xa7, 0x87, 0x9e, 0x94, 0x1b, 0x6e, 0x55,
|
||||
0x2c, 0x37, 0x60, 0x91, 0x74, 0x39, 0x5e, 0xbb, 0xec, 0xe9, 0xc2, 0xc1, 0xf2, 0x10, 0x8e, 0xbd,
|
||||
0xa7, 0x77, 0x98, 0x7a, 0x63, 0xbe, 0x93, 0x9b, 0x74, 0xe0, 0xb5, 0xc3, 0xec, 0x55, 0x2b, 0x37,
|
||||
0xaa, 0x52, 0x25, 0x7b, 0xa3, 0xaa, 0xcd, 0x9b, 0x8b, 0x6c, 0x20, 0x57, 0xf8, 0x2b, 0x1d, 0xc3,
|
||||
0x86, 0x48, 0xa9, 0xb4, 0xd6, 0xbc, 0x17, 0xbc, 0xcf, 0x12, 0xaa, 0x85, 0xfc, 0xfe, 0xc9, 0xc6,
|
||||
0xfb, 0xb7, 0x62, 0x7f, 0x0a, 0x33, 0xe7, 0x30, 0x08, 0x8d, 0xd7, 0x62, 0x9d, 0x7e, 0xff, 0x36,
|
||||
0x7c, 0xb0, 0x1e, 0x39, 0x8f, 0x60, 0xb6, 0x8c, 0xb8, 0x07, 0x3e, 0x9f, 0xfd, 0x4f, 0x94, 0x11,
|
||||
0x3a, 0x60, 0x54, 0x40, 0x1c, 0x6c, 0xc0, 0x5f, 0x5c, 0xd4, 0x3b, 0x85, 0x1e, 0x2b, 0xec, 0xed,
|
||||
0x57, 0x73, 0x23, 0xcf, 0xc7, 0xff, 0x51, 0x60, 0xb2, 0xa1, 0xa9, 0x36, 0x31, 0x9f, 0x99, 0xbe,
|
||||
0x1d, 0x0c, 0x18, 0x1f, 0xc0, 0xca, 0xdd, 0xfb, 0xfc, 0xf2, 0x49, 0xd3, 0x79, 0xb2, 0x16, 0xc3,
|
||||
0x71, 0x51, 0xe3, 0xc8, 0xbf, 0x4c, 0x99, 0x29, 0x9b, 0xad, 0x54, 0x77, 0x4d, 0xc5, 0x8a, 0x8b,
|
||||
0x95, 0xab, 0x4a, 0xea, 0x32, 0xca, 0x7f, 0xdc, 0x70, 0xee, 0x90, 0xb6, 0x95, 0xc6, 0x6d, 0xe7,
|
||||
0x59, 0x6b, 0xde, 0x02, 0x8d, 0xc5, 0xe1, 0xab, 0xce, 0x0b, 0xf6, 0xea, 0xe6, 0x06, 0xae, 0x2f,
|
||||
0xfa, 0x47, 0x87, 0x41, 0x10, 0xe0, 0xea, 0xef, 0x7e, 0x25, 0x87, 0xb7, 0xbf, 0xfe, 0xe5, 0x9d,
|
||||
0xea, 0xdb, 0x02, 0x7e, 0x07, 0xb5, 0x54, 0x55, 0xb7, 0xdb, 0x30, 0x0c, 0xd6, 0x18, 0x0a, 0x63,
|
||||
0x66, 0x66, 0x48, 0x7a, 0xf1, 0x71, 0xcc, 0xcc, 0x4f, 0x3a, 0x4e, 0xab, 0xae, 0x3e, 0x4d, 0xec,
|
||||
0xcc, 0x4e, 0xe1, 0xe7, 0x2f, 0x2e, 0x78, 0x8e, 0xe7, 0xf1, 0xee, 0xab, 0x2d, 0x7d, 0x20, 0x82,
|
||||
0xb7, 0x78, 0x9b, 0x58, 0x86, 0x6f, 0x5a, 0xf8, 0x66, 0x90, 0x2b, 0xca, 0x08, 0xdf, 0x7c, 0x8c,
|
||||
0xe2, 0xa5, 0x18, 0xdb, 0x32, 0xcb, 0x99, 0xe0, 0x52, 0xa0, 0x62, 0x1d, 0x2e, 0x31, 0x49, 0x09,
|
||||
0xae, 0x62, 0xae, 0xe1, 0xd2, 0x88, 0x77, 0x39, 0x1c, 0xea, 0x73, 0xad, 0x31, 0x93, 0x1d, 0xca,
|
||||
0xe0, 0x90, 0xa2, 0x9c, 0x58, 0x41, 0x0a, 0x4e, 0x61, 0xa2, 0x78, 0xe7, 0x33, 0x21, 0xe9, 0x5c,
|
||||
0xc8, 0x11, 0x9c, 0x96, 0x89, 0x26, 0x35, 0x24, 0x85, 0xd9, 0x97, 0xa2, 0x80, 0xc3, 0x52, 0x66,
|
||||
0x38, 0x7d, 0x80, 0xb3, 0x58, 0xfd, 0x5b, 0x97, 0x18, 0x1d, 0x3f, 0x21, 0x3f, 0x69, 0xc8, 0x1b,
|
||||
0x0e, 0x6d, 0xc3, 0xd2, 0xee, 0xf3, 0xb0, 0x9a, 0x0e, 0xcf, 0x41, 0xef, 0x6f, 0xfb, 0xf2, 0xd2,
|
||||
0x5a, 0xc2, 0xaf, 0x23, 0xa1, 0x0b, 0xa6, 0xf0, 0x4e, 0x0b, 0xf5, 0x78, 0xe2, 0xc5, 0x81, 0xdc,
|
||||
0x6d, 0x21, 0x0f, 0x7b, 0x85, 0xda, 0xb9, 0xf2, 0x7b, 0x71, 0xeb, 0x7a, 0x5c, 0xf4, 0x9f, 0x97,
|
||||
0x41, 0xf8, 0x2c, 0x0a, 0xda, 0x38, 0x36, 0xd0, 0x49, 0xd8, 0x46, 0x45, 0x76, 0x2d, 0x0e, 0x67,
|
||||
0x77, 0x07, 0x69, 0x0a, 0xc7, 0xca, 0x20, 0xce, 0xd2, 0x29, 0xd6, 0x31, 0xd3, 0xee, 0x2a, 0xe2,
|
||||
0x6b, 0x5b, 0x18, 0x4f, 0x5d, 0x43, 0x39, 0x14, 0x8d, 0x32, 0x22, 0xe3, 0x82, 0xa5, 0xd8, 0xee,
|
||||
0xb1, 0x02, 0x6a, 0xad, 0x3f, 0xd5, 0xbb, 0x0f, 0x53, 0xa9, 0x18, 0xca, 0x82, 0xa1, 0x90, 0x48,
|
||||
0xe3, 0xf2, 0xcd, 0xa0, 0x69, 0x12, 0x5a, 0x2a, 0x5d, 0xb5, 0xb3, 0xf8, 0xe3, 0x9e, 0xae, 0xa5,
|
||||
0xa7, 0xa5, 0x7f, 0xea, 0xc1, 0x72, 0x38, 0x9b, 0x8a, 0x1e, 0x29, 0x41, 0xc5, 0x5c, 0xb9, 0xab,
|
||||
0xf8, 0x5f, 0xc7, 0xb3, 0xb6, 0x1a, 0xe2, 0xc4, 0x09, 0x09, 0x4e, 0x59, 0x30, 0x4c, 0x83, 0x2e,
|
||||
0x2e, 0x02, 0x7c, 0x60, 0x43, 0xd2, 0x3d, 0xa6, 0xc8, 0xdc, 0x8e, 0xa7, 0xaf, 0xa3, 0x28, 0x0e,
|
||||
0x0f, 0xe4, 0x59, 0x23, 0x7f, 0xaf, 0x83, 0xb8, 0x37, 0x67, 0xaa, 0xe0, 0x85, 0x89, 0xa2, 0x71,
|
||||
0x19, 0xde, 0x21, 0x85, 0x73, 0x12, 0x4f, 0xed, 0x45, 0xcb, 0xe8, 0xff, 0xec, 0xb5, 0xee, 0x8f,
|
||||
0x7a, 0x3f, 0xfb, 0x1c, 0xf7, 0x27, 0xfc, 0xe5, 0x7c, 0xf8, 0x29, 0xbe, 0x19, 0x2f, 0x62, 0xc2,
|
||||
0x4c, 0x83, 0x83, 0x85, 0x68, 0x7e, 0xf3, 0xbb, 0xae, 0x7c, 0x7b, 0xab, 0x58, 0xbb, 0x4f, 0x0a,
|
||||
0x9f, 0x86, 0xf7, 0xe5, 0x84, 0x31, 0xb7, 0xc3, 0x6a, 0xd9, 0xe9, 0x70, 0xc3, 0xa8, 0x8c, 0x19,
|
||||
0x65, 0x51, 0x14, 0xdd, 0x44, 0x1b, 0x00, 0x1f, 0xb8, 0x9c, 0x41, 0x3e, 0x8d, 0xd6, 0x70, 0x1f,
|
||||
0xea, 0xf7, 0xb8, 0xe8, 0x07, 0xf1, 0x77, 0x39, 0xd0, 0xf0, 0x91, 0x33, 0x69, 0x2e, 0x55, 0x28,
|
||||
0xf0, 0x88, 0xd9, 0x9d, 0x83, 0x46, 0xcd, 0xc1, 0xc9, 0xec, 0x6d, 0x75, 0x12, 0xb7, 0x5a, 0x4d,
|
||||
0xdb, 0x1c, 0xd2, 0xcd, 0xc1, 0x6d, 0xc0, 0x70, 0x26, 0xc2, 0x26, 0xa1, 0xba, 0x8b, 0x71, 0x98,
|
||||
0xdb, 0xd0, 0xd6, 0x9c, 0xb4, 0x9a, 0x25, 0xdc, 0x33, 0x5f, 0x4f, 0xa5, 0xe3, 0x56, 0x0c, 0x75,
|
||||
0x87, 0x7f, 0xd3, 0x9b, 0x5f, 0x39, 0x09, 0x7b, 0xd8, 0xe9, 0x6d, 0xfc, 0xae, 0xea, 0xd0, 0xb8,
|
||||
0x16, 0xf7, 0x78, 0x03, 0xb5, 0x75, 0x5a, 0x7c, 0xd8, 0xfa, 0xe1, 0xd1, 0x8b, 0xf0, 0x80, 0x18,
|
||||
0xee, 0xa3, 0x93, 0x3d, 0x3e, 0x3a, 0xbb, 0x40, 0x47, 0x8d, 0x92, 0xa3, 0x93, 0x9a, 0xd6, 0x1d,
|
||||
0x3d, 0xf5, 0xef, 0xd7, 0x02, 0xea, 0x56, 0xe3, 0x5e, 0x4f, 0xe3, 0xbe, 0xaa, 0x8e, 0x86, 0xa3,
|
||||
0xf1, 0x80, 0xa7, 0xb1, 0x3e, 0xd3, 0x58, 0xaf, 0xde, 0xae, 0xaf,
|
||||
};
|
||||
#else
|
||||
enum { DECODE_CHUNK_BYTES = 512 };
|
||||
static const uint16_t OFFSETS[] = {
|
||||
0, 227, 448, 665, 896, 1116, 1323, 1537, 1779, 1926, 2134, 2376,
|
||||
2609, 2878, 3114, 3328, 3569, 3806, 3999, 4200, 4442, 4662,
|
||||
};
|
||||
static const uint16_t RAW_LENGTHS[] = {
|
||||
510, 512, 505, 509, 512, 500, 502, 511, 489, 512, 510, 504,
|
||||
505, 501, 486, 504, 499, 504, 504, 509, 460,
|
||||
};
|
||||
static const uint16_t FIRSTS[] = {
|
||||
0, 27, 64, 95, 121, 159, 193, 227, 262, 295, 329, 364,
|
||||
396, 426, 461, 481, 510, 544, 578, 618, 647, 683,
|
||||
};
|
||||
// 4662 encoded bytes; 21 independent chunks, at most 512 decoded bytes.
|
||||
static const uint8_t NAMES[] = {
|
||||
0x8c, 0x51, 0x03, 0x6f, 0x40, 0x41, 0x0c, 0xee, 0x82, 0xd9, 0x76, 0x30, 0xdb, 0x88, 0x67, 0x9b,
|
||||
0x71, 0x73, 0x68, 0xf2, 0xdc, 0x77, 0x98, 0x7e, 0xfd, 0x6c, 0x47, 0x77, 0xf5, 0x07, 0x58, 0x95,
|
||||
@@ -186,228 +378,257 @@ inline const char* ota_target_env_name(uint32_t target_id, char* buffer, size_t
|
||||
0x0a, 0xa6, 0x65, 0xce, 0xf7, 0xe0, 0x37, 0xad, 0xd7, 0x4c, 0x44, 0x35, 0xa0, 0x57, 0xec, 0x62,
|
||||
0xd6, 0x4b, 0x7a, 0xb3, 0x23, 0xa8, 0x6f, 0xb2, 0xf2, 0x36, 0xd4, 0x44, 0xd7, 0x49, 0xc8, 0x75,
|
||||
0xe1, 0x2e, 0x85, 0x33, 0xb7, 0x10, 0xc7, 0xf5, 0xba, 0x9a, 0xd7, 0x9c, 0xed, 0x8c, 0xfe, 0x01,
|
||||
0x7d, 0x51, 0x35, 0x76, 0x03, 0x31, 0x10, 0xfd, 0x5d, 0xa8, 0x0a, 0x33, 0xf4, 0xa9, 0x0c, 0x87,
|
||||
0xc8, 0x2d, 0x66, 0x69, 0x14, 0xeb, 0x59, 0x2c, 0x79, 0x7d, 0x7c, 0x33, 0x7b, 0x59, 0xac, 0x3f,
|
||||
0x1f, 0x30, 0x62, 0x95, 0xb8, 0xa4, 0x14, 0xf2, 0x72, 0xcc, 0x81, 0xea, 0x3e, 0x95, 0x56, 0xbb,
|
||||
0xdc, 0x48, 0x6b, 0x28, 0xe4, 0x95, 0xb4, 0x34, 0x95, 0x42, 0x92, 0x60, 0x6d, 0x85, 0xc0, 0xaf,
|
||||
0xc1, 0xdd, 0x58, 0xc6, 0x48, 0xda, 0x56, 0xac, 0x71, 0x17, 0xd8, 0x71, 0x9e, 0x38, 0xe0, 0x8d,
|
||||
0x8a, 0x20, 0xab, 0x7f, 0x26, 0x8e, 0xce, 0xd8, 0x29, 0xde, 0x6d, 0x11, 0x39, 0xd4, 0x1c, 0x48,
|
||||
0xfb, 0x94, 0x70, 0x6f, 0xad, 0xa6, 0xf5, 0x02, 0x3e, 0xe9, 0x78, 0xef, 0x2e, 0xb2, 0x89, 0x36,
|
||||
0xe0, 0x2e, 0x71, 0xd0, 0xd2, 0xe4, 0x8a, 0xca, 0x51, 0x9e, 0x80, 0xbf, 0x35, 0xb3, 0x06, 0x46,
|
||||
0x85, 0xe2, 0x05, 0x8a, 0x8b, 0x78, 0x9b, 0xc4, 0x02, 0x6f, 0x4b, 0x82, 0xb8, 0x3e, 0xa0, 0x75,
|
||||
0xbd, 0xa3, 0x75, 0x73, 0x50, 0xf7, 0xfa, 0x18, 0xff, 0x72, 0xd0, 0x81, 0x2b, 0x26, 0x4a, 0x1d,
|
||||
0xa2, 0x7f, 0xad, 0xa9, 0x36, 0x17, 0xb9, 0x3b, 0xd1, 0xfe, 0x16, 0x62, 0x7f, 0xd0, 0xc7, 0xfd,
|
||||
0xb1, 0xcc, 0x1f, 0x8a, 0x52, 0x1f, 0x11, 0x7a, 0x3c, 0x31, 0xe2, 0x7a, 0x6d, 0xc4, 0x29, 0xd1,
|
||||
0x6d, 0x44, 0xf5, 0x90, 0xfa, 0xcb, 0xe6, 0x9c, 0xf7, 0x92, 0xed, 0x2a, 0x21, 0x83, 0xeb, 0x46,
|
||||
0x55, 0xdb, 0xf8, 0x7e, 0x5c, 0xdc, 0x0e, 0xe7, 0x85, 0x4f, 0x83, 0x6e, 0x44, 0x51, 0x10, 0x3d,
|
||||
0x71, 0x56, 0x61, 0x6d, 0x06, 0xb5, 0xdb, 0xbf, 0x99, 0xa7, 0xb9, 0xe9, 0xd3, 0xf5, 0xe2, 0xef,
|
||||
0xd7, 0x66, 0x34, 0x3c, 0xc2, 0x3f, 0x17, 0x9e, 0x63, 0x6a, 0x7d, 0xd1, 0x27, 0xc5, 0xaa, 0xd4,
|
||||
0xa1, 0x4c, 0x95, 0x24, 0x1b, 0x26, 0xa9, 0x22, 0xd1, 0x2c, 0x0a, 0x12, 0x5c, 0x2a, 0x21, 0x70,
|
||||
0xd6, 0x74, 0xd1, 0xb4, 0x6f, 0xa7, 0x22, 0x9d, 0x0c, 0xd7, 0xa5, 0xf1, 0x7e, 0x32, 0xd4, 0xb9,
|
||||
0xa3, 0x43, 0xe9, 0xfa, 0x14, 0x79, 0xea, 0xc9, 0x0b, 0xbf, 0xc2, 0x19, 0x15, 0x3c, 0x7d, 0xde,
|
||||
0x71, 0xbf, 0x9a, 0xd7, 0xbf, 0x9a, 0xd3, 0xbf, 0x9a, 0xd7, 0xaf, 0xae, 0x61, 0xc0, 0xf9, 0xf0,
|
||||
0x2a, 0x71, 0xa1, 0xdd, 0xb8, 0x3b, 0xe9, 0xe3, 0x97, 0xd7, 0x03, 0xf8, 0x7d, 0xff, 0x34, 0xa5,
|
||||
0x93, 0xb8, 0x9c, 0xa6, 0x91, 0xa8, 0x2e, 0x84, 0xb1, 0xac, 0x39, 0xf4, 0x6c, 0x71, 0x49, 0x2a,
|
||||
0x72, 0x6c, 0x5b, 0x6c, 0x69, 0xf0, 0x8c, 0x23, 0xa5, 0x4a, 0x1a, 0x2f, 0x16, 0x2f, 0x87, 0xdb,
|
||||
0x02, 0x4a, 0xbc, 0x6a, 0x87, 0xc7, 0x69, 0x46, 0x89, 0x6a, 0x9e, 0x3a, 0x47, 0xa5, 0x4a, 0xb8,
|
||||
0x44, 0x55, 0x87, 0xd6, 0xa7, 0x7e, 0x00, 0x1b, 0xba, 0x48, 0xd8, 0xa2, 0x6a, 0xff, 0xd6, 0xb1,
|
||||
0xe1, 0x8a, 0xb4, 0xc3, 0xf9, 0x80, 0x08, 0xe7, 0xc3, 0x94, 0x83, 0x3c, 0x68, 0xcc, 0xb1, 0x35,
|
||||
0xa6, 0xe6, 0xf7, 0x97, 0x2c, 0xf6, 0x00, 0x6c, 0x50, 0x45, 0x72, 0x05, 0x41, 0x08, 0x65, 0x1b,
|
||||
0x77, 0xf7, 0x33, 0x44, 0x6f, 0x43, 0xb5, 0x30, 0x7f, 0x18, 0xa3, 0x03, 0xc4, 0x4e, 0x1f, 0xd7,
|
||||
0xae, 0xac, 0x70, 0x9e, 0x40, 0x4b, 0x83, 0x53, 0xc2, 0xfb, 0x0b, 0xd4, 0x1b, 0x54, 0x91, 0x11,
|
||||
0x8d, 0xf4, 0x9e, 0x14, 0x76, 0x51, 0xe2, 0x47, 0x8a, 0xe3, 0xad, 0x3b, 0x2c, 0x19, 0x4d, 0x26,
|
||||
0x0a, 0x4b, 0x4e, 0x3a, 0xf2, 0x14, 0x06, 0x4c, 0x6d, 0x70, 0x58, 0x6e, 0x1c, 0x93, 0x8c, 0x25,
|
||||
0x4c, 0x2c, 0x13, 0x6a, 0xc8, 0x2c, 0x18, 0x07, 0x82, 0xb3, 0xe6, 0x6e, 0x18, 0xe0, 0xec, 0xce,
|
||||
0x22, 0x9c, 0x3d, 0x70, 0xc3, 0xb0, 0xd6, 0xb3, 0x19, 0x8e, 0x92, 0x69, 0x84, 0xb5, 0x22, 0xea,
|
||||
0x1a, 0xd8, 0x51, 0xa9, 0x50, 0x78, 0xfd, 0x58, 0x81, 0x1d, 0xfc, 0x10, 0xa9, 0x26, 0x6b, 0x5f,
|
||||
0x17, 0xb0, 0x57, 0x4d, 0xd6, 0x7f, 0x91, 0x3f, 0xac, 0xaf, 0x3e, 0xc9, 0xaf, 0xfd, 0x25, 0xbf,
|
||||
0xf0, 0xf5, 0x6b, 0x1d, 0xa3, 0x72, 0x9e, 0x11, 0x92, 0x95, 0x49, 0x1e, 0x60, 0x63, 0xa0, 0x59,
|
||||
0x48, 0x4f, 0x58, 0x82, 0x3a, 0xfb, 0x9b, 0x32, 0x27, 0x73, 0xd8, 0xf8, 0xfb, 0x75, 0xe1, 0x17,
|
||||
0xe2, 0x56, 0x85, 0x38, 0xff, 0x89, 0x38, 0x5f, 0x21, 0xfe, 0x6f, 0x17, 0x36, 0x34, 0xca, 0x04,
|
||||
0xc7, 0x6f, 0xa6, 0x7d, 0xe5, 0xaf, 0xd6, 0xbd, 0x0c, 0xc6, 0x04, 0x05, 0x20, 0x94, 0xcd, 0x07,
|
||||
0xf7, 0xbf, 0x18, 0x9a, 0x9b, 0xf9, 0x91, 0x5c, 0xc3, 0x07, 0xb5, 0x9d, 0x0f, 0xd5, 0x76, 0x00,
|
||||
0x74, 0xce, 0x83, 0x72, 0x6c, 0x41, 0x10, 0x06, 0xe0, 0x2e, 0x5e, 0xc4, 0xb6, 0x6d, 0xeb, 0x09,
|
||||
0x62, 0xab, 0xdc, 0x35, 0xe8, 0xcd, 0xce, 0xd1, 0x9c, 0xf4, 0x4c, 0xb2, 0xaf, 0x9f, 0xac, 0x5d,
|
||||
0x6e, 0x7e, 0x3f, 0x5c, 0x50, 0xe4, 0x49, 0xe1, 0xbb, 0x61, 0x8a, 0xc8, 0x39, 0x7c, 0x10, 0x29,
|
||||
0x31, 0x2a, 0x1b, 0xa7, 0x22, 0x31, 0x36, 0x41, 0x16, 0xda, 0x58, 0x94, 0x11, 0xc1, 0x1a, 0xa6,
|
||||
0x0e, 0x96, 0xbf, 0x9c, 0x84, 0xe1, 0xd0, 0xfc, 0x6e, 0xc6, 0x56, 0x53, 0x0c, 0xc3, 0x4c, 0x29,
|
||||
0x09, 0x4f, 0x0c, 0xd3, 0x28, 0xd9, 0xe8, 0x0f, 0x42, 0x72, 0x69, 0x62, 0x73, 0x30, 0x63, 0xa5,
|
||||
0x23, 0xfe, 0x26, 0xc6, 0xf8, 0xd3, 0x7b, 0x18, 0xb1, 0x36, 0xc6, 0x62, 0x03, 0xe6, 0xb0, 0x7e,
|
||||
0xd6, 0xfb, 0xc2, 0x42, 0x85, 0x6d, 0xdc, 0x8d, 0xbc, 0xbb, 0x9a, 0x77, 0x47, 0x6b, 0xdc, 0xd1,
|
||||
0x8a, 0x3b, 0xdb, 0xe0, 0xce, 0xd5, 0xff, 0x1e, 0xab, 0x71, 0x17, 0x1a, 0xdc, 0xbf, 0xcf, 0x37,
|
||||
0x07, 0x2d, 0xcd, 0x99, 0xbc, 0x39, 0x99, 0x37, 0x27, 0x73, 0x26, 0x63, 0xa0, 0xb3, 0xa2, 0x0d,
|
||||
0x36, 0x68, 0x93, 0xec, 0xf6, 0x0f, 0xf6, 0x61, 0xa8, 0xfe, 0x71, 0x57, 0x0d, 0x3a, 0xd2, 0x80,
|
||||
0x76, 0x3a, 0x4a, 0x9c, 0x65, 0x00, 0x13, 0xda, 0x50, 0x60, 0x56, 0x24, 0x3a, 0x4b, 0x91, 0xc6,
|
||||
0x84, 0x33, 0x48, 0xfb, 0xfb, 0x78, 0xb0, 0xab, 0x65, 0x8c, 0xbb, 0x67, 0xc7, 0x2d, 0x93, 0xed,
|
||||
0xe5, 0x43, 0xcd, 0xb1, 0xf5, 0xc2, 0x93, 0x6e, 0xb9, 0x71, 0x96, 0xdf, 0xf8, 0x99, 0x2c, 0x22,
|
||||
0x5a, 0x90, 0x9c, 0x22, 0x8c, 0x14, 0x80, 0x00, 0xa5, 0xd1, 0xb1, 0x4a, 0xc0, 0x40, 0x0c, 0x80,
|
||||
0xe1, 0x4c, 0xae, 0x2a, 0xd8, 0xfa, 0x04, 0xba, 0x15, 0x6a, 0xfb, 0x0c, 0xe2, 0x60, 0xc7, 0xee,
|
||||
0x21, 0x6d, 0x23, 0x1e, 0x77, 0x97, 0x94, 0xe4, 0x14, 0x7d, 0x7b, 0xeb, 0x52, 0x14, 0x04, 0x87,
|
||||
0x5b, 0x43, 0xf8, 0xf8, 0x43, 0x20, 0x44, 0x8d, 0x84, 0x42, 0xa2, 0x28, 0xf6, 0x82, 0xc3, 0xb0,
|
||||
0x2d, 0x19, 0x57, 0xcd, 0x3b, 0x49, 0x50, 0x41, 0xa3, 0x2d, 0x28, 0x2e, 0x89, 0xe1, 0xee, 0xcd,
|
||||
0x17, 0x68, 0x62, 0x70, 0xc7, 0xac, 0x1b, 0x67, 0x68, 0x8c, 0x77, 0xa6, 0xc2, 0x06, 0xad, 0x6a,
|
||||
0x46, 0x67, 0x7b, 0x67, 0x83, 0xcb, 0xb1, 0xaf, 0x14, 0xae, 0xc6, 0x4a, 0xe0, 0xc2, 0x4b, 0x58,
|
||||
0xe3, 0x3f, 0xe7, 0xdc, 0x7f, 0x5b, 0xed, 0x0f, 0xab, 0x3d, 0xad, 0xdb, 0x5f, 0x31, 0x7d, 0xa5,
|
||||
0x70, 0x3d, 0x56, 0x02, 0xf0, 0xcc, 0xbc, 0x17, 0x66, 0x99, 0xe6, 0x07, 0x3c, 0x37, 0x6e, 0x30,
|
||||
0xa9, 0x11, 0x6a, 0x21, 0x3c, 0x5e, 0xc7, 0x1f, 0xc7, 0x4c, 0x28, 0xa1, 0xb3, 0xb8, 0x9a, 0x03,
|
||||
0x4c, 0x21, 0x7d, 0x3e, 0x29, 0xce, 0xdd, 0xe3, 0xfa, 0xaa, 0xdd, 0x14, 0x0a, 0xff, 0xd9, 0xf0,
|
||||
0x05, 0x7c, 0x50, 0xb5, 0x5a, 0x06, 0x41, 0x0c, 0x4c, 0x87, 0x3b, 0x15, 0xee, 0x15, 0xae, 0x3d,
|
||||
0x6e, 0x1d, 0xf4, 0x39, 0xcb, 0xc7, 0xad, 0x66, 0x0d, 0x7b, 0x7a, 0x5c, 0x7f, 0xab, 0xc7, 0x07,
|
||||
0xae, 0x85, 0x7e, 0x3e, 0x63, 0xbc, 0x5d, 0x3b, 0x29, 0x6b, 0x5e, 0xbb, 0x16, 0x89, 0xb0, 0x64,
|
||||
0xe3, 0x72, 0x2b, 0xd8, 0x62, 0xc8, 0x2b, 0xc1, 0x78, 0x1f, 0x0b, 0x18, 0x53, 0x22, 0x46, 0x34,
|
||||
0x5c, 0x91, 0x81, 0x31, 0xfb, 0x06, 0xc5, 0x9a, 0xb4, 0x6e, 0xa2, 0x16, 0x9a, 0x60, 0xed, 0x83,
|
||||
0x1f, 0xc8, 0x51, 0x9e, 0x28, 0xc0, 0x38, 0xb3, 0xc1, 0x48, 0xe1, 0x81, 0x02, 0x0c, 0xe0, 0x51,
|
||||
0x1e, 0xaa, 0x96, 0xaa, 0xc5, 0xc6, 0x94, 0xd6, 0x0e, 0x83, 0xad, 0xb4, 0x33, 0xef, 0xda, 0xc1,
|
||||
0x3f, 0xda, 0xc1, 0x1f, 0xed, 0xd0, 0x1f, 0x6d, 0xf7, 0xce, 0xcd, 0x0e, 0xc6, 0xa7, 0xad, 0xed,
|
||||
0xfd, 0xed, 0x96, 0x15, 0x56, 0xd0, 0xc5, 0x4e, 0x3d, 0x26, 0xb1, 0x08, 0xa2, 0xba, 0x23, 0xa4,
|
||||
0xe8, 0x2c, 0x3f, 0xc2, 0x14, 0x17, 0x9f, 0xce, 0x68, 0x7c, 0x4a, 0xff, 0x6a, 0xce, 0xe0, 0x7f,
|
||||
0x6c, 0xec, 0x4d, 0x6f, 0x84, 0xcd, 0xdf, 0x1e, 0xab, 0xf3, 0x04, 0xc3, 0x07, 0xaf, 0x33, 0xc3,
|
||||
0xe6, 0x02, 0xfa, 0x58, 0x0e, 0x00, 0x6d, 0x90, 0xb5, 0x72, 0x04, 0x31, 0x10, 0x44, 0x27, 0x33,
|
||||
0x33, 0x33, 0x53, 0x66, 0xce, 0xcd, 0xcc, 0x14, 0xf6, 0xd2, 0x9c, 0x4b, 0x75, 0xd2, 0xce, 0x5a,
|
||||
0xda, 0x35, 0xfc, 0xbd, 0xeb, 0x18, 0x33, 0xe1, 0xeb, 0x37, 0x4d, 0xb7, 0x4a, 0xff, 0x5d, 0x08,
|
||||
0x5e, 0x71, 0x65, 0x92, 0x4c, 0x3b, 0xc6, 0xa3, 0xce, 0x1c, 0x2c, 0x27, 0xec, 0xa7, 0x6c, 0xa9,
|
||||
0xf3, 0x98, 0x7d, 0x83, 0x9d, 0x0f, 0x84, 0x62, 0x12, 0x3f, 0x56, 0x12, 0xc3, 0xfa, 0x91, 0x12,
|
||||
0x04, 0x9a, 0x69, 0x05, 0x89, 0xa3, 0xc5, 0x5c, 0xa6, 0x35, 0x2d, 0x66, 0x2e, 0xa0, 0xc5, 0x1f,
|
||||
0x95, 0x53, 0x34, 0x98, 0x57, 0xce, 0xc1, 0x48, 0xc4, 0x86, 0x06, 0xab, 0xa0, 0x49, 0x04, 0x56,
|
||||
0x45, 0x9f, 0x0c, 0x76, 0x49, 0x2c, 0x3f, 0x34, 0x25, 0x81, 0x63, 0xfb, 0xcd, 0x16, 0xe6, 0x2b,
|
||||
0x4d, 0x69, 0x48, 0xc4, 0xa0, 0x74, 0x40, 0x33, 0x68, 0xbc, 0xeb, 0x3c, 0xe5, 0x30, 0xdf, 0x56,
|
||||
0x60, 0xae, 0x90, 0xda, 0x57, 0x97, 0xd7, 0x57, 0x13, 0x3f, 0x7b, 0xbd, 0xc4, 0x99, 0x56, 0x29,
|
||||
0xc3, 0xfd, 0xee, 0xec, 0x1e, 0xee, 0xb6, 0x05, 0x6c, 0x15, 0x00, 0x53, 0x75, 0x80, 0xa9, 0x2a,
|
||||
0x60, 0xa9, 0xc9, 0x62, 0xba, 0xce, 0x70, 0xb5, 0xd9, 0x50, 0x8b, 0xf5, 0x71, 0x72, 0xd8, 0x2e,
|
||||
0x03, 0xed, 0x0b, 0x41, 0x6d, 0xe4, 0xc2, 0xa6, 0xf3, 0xb6, 0x40, 0x78, 0xdf, 0xc5, 0x0e, 0x76,
|
||||
0x70, 0xd8, 0xde, 0xb5, 0xd0, 0xf6, 0x7a, 0x41, 0x78, 0xbd, 0xd8, 0xf3, 0x78, 0x1d, 0x76, 0xbc,
|
||||
0xaa, 0x3d, 0xdf, 0xa8, 0x06, 0x9a, 0xa8, 0xf3, 0x5e, 0x6a, 0xbe, 0xfc, 0x07, 0xad, 0xcf, 0xb5,
|
||||
0x5a, 0x2c, 0x41, 0x10, 0x05, 0xe0, 0xba, 0x17, 0x8d, 0x70, 0x77, 0x8f, 0x71, 0x88, 0x71, 0x4d,
|
||||
0xb0, 0xf4, 0x7c, 0x23, 0xb5, 0x3b, 0x3d, 0xd2, 0x35, 0x2d, 0x6b, 0x4f, 0x8f, 0x3b, 0x84, 0xa4,
|
||||
0xa5, 0xff, 0xa1, 0x0b, 0x95, 0xb7, 0x8e, 0x05, 0x37, 0x17, 0x62, 0x03, 0xdc, 0xad, 0x63, 0x0d,
|
||||
0x6b, 0xd8, 0x86, 0x67, 0x5b, 0x28, 0x1d, 0xe4, 0x88, 0x92, 0xc0, 0x13, 0x5d, 0x6e, 0x5d, 0xfb,
|
||||
0x20, 0xca, 0x70, 0xab, 0x95, 0xc7, 0xfe, 0xf6, 0x05, 0x22, 0x29, 0xca, 0x40, 0x2b, 0xd1, 0xb0,
|
||||
0x41, 0xac, 0x04, 0x61, 0xce, 0x34, 0x5f, 0x73, 0x21, 0xf5, 0x67, 0xca, 0x39, 0x14, 0x12, 0x73,
|
||||
0x41, 0xfd, 0x96, 0x4b, 0x0e, 0x3c, 0x5b, 0x1a, 0x10, 0x29, 0xe0, 0xd8, 0xd6, 0xd9, 0xd2, 0x3f,
|
||||
0x76, 0x09, 0x4a, 0x89, 0x32, 0xf6, 0x78, 0x1f, 0x18, 0x42, 0xfe, 0xf4, 0x5f, 0x7c, 0x00, 0x2d,
|
||||
0xe0, 0xa6, 0x67, 0xfb, 0xf4, 0xdd, 0xb1, 0x76, 0x62, 0x1d, 0xb5, 0x07, 0x71, 0x9d, 0xb5, 0xaf,
|
||||
0x59, 0xb6, 0x70, 0xcd, 0xb5, 0xf5, 0xed, 0xf5, 0x5f, 0x05, 0x2b, 0x4f, 0x82, 0x91, 0x4f, 0x82,
|
||||
0x91, 0xf7, 0x07, 0xa3, 0x9f, 0x04, 0x23, 0x5f, 0xd3, 0x0d, 0xed, 0xfe, 0xe1, 0xb1, 0x76, 0x55,
|
||||
0xa8, 0xdf, 0xce, 0x81, 0xba, 0xdf, 0xd6, 0x41, 0x54, 0xb0, 0x4b, 0xb4, 0xe4, 0x52, 0x6d, 0xa1,
|
||||
0xb1, 0xf6, 0x7b, 0x96, 0xd9, 0x4a, 0x2d, 0xcf, 0x69, 0xf6, 0x09, 0x31, 0xdb, 0x50, 0x15, 0x45,
|
||||
0xbd, 0x9f, 0x28, 0xbd, 0x1f, 0x14, 0x84, 0x56, 0xc5, 0x55, 0x06, 0xbb, 0x52, 0x4b, 0x83, 0xc6,
|
||||
0x24, 0x7c, 0x81, 0xa1, 0x30, 0xde, 0x53, 0xdf, 0x27, 0xe9, 0x04, 0xbe, 0xf6, 0x1e, 0x00, 0x7c,
|
||||
0x8e, 0xc5, 0x72, 0x03, 0x31, 0x0c, 0x86, 0xd5, 0xd3, 0xf6, 0x54, 0x66, 0xe6, 0x6b, 0xf8, 0x0d,
|
||||
0xca, 0x8c, 0x67, 0xcd, 0x82, 0x92, 0x78, 0x6a, 0x5b, 0x19, 0x6b, 0x83, 0x4f, 0x5f, 0xa5, 0xcc,
|
||||
0x66, 0xfc, 0xbf, 0x0f, 0x1c, 0x49, 0xd3, 0xb3, 0xe5, 0x46, 0x1f, 0xbb, 0xa5, 0x32, 0x0a, 0x79,
|
||||
0xe1, 0x00, 0xe3, 0x39, 0x05, 0x67, 0x7c, 0x6c, 0x31, 0x6d, 0xc6, 0x39, 0xc0, 0x85, 0xf1, 0xd4,
|
||||
0x15, 0x72, 0x06, 0x1d, 0x95, 0x6b, 0x56, 0x8a, 0x25, 0x0c, 0xd4, 0xa2, 0x58, 0x9f, 0xc1, 0x32,
|
||||
0x5a, 0x0e, 0x31, 0x72, 0x1e, 0xa3, 0x67, 0xa4, 0x9e, 0x9e, 0xe9, 0xc7, 0xd7, 0x24, 0x81, 0x91,
|
||||
0xb3, 0x03, 0x94, 0x0a, 0xa6, 0xec, 0x5a, 0xb1, 0x37, 0xec, 0x31, 0xc4, 0x99, 0x61, 0x4c, 0x2c,
|
||||
0xc1, 0x7c, 0x5b, 0x12, 0x98, 0xef, 0x9a, 0xba, 0x81, 0xe8, 0x3d, 0x6e, 0x1c, 0x93, 0x60, 0xb2,
|
||||
0x06, 0x21, 0x49, 0xcb, 0x73, 0x17, 0xe6, 0x83, 0x94, 0x2b, 0x65, 0x18, 0x65, 0x76, 0x9a, 0x19,
|
||||
0x3a, 0x14, 0x20, 0x7a, 0xb5, 0x8c, 0xbe, 0x59, 0x5e, 0xc6, 0x2a, 0x70, 0x54, 0xc6, 0x07, 0x9b,
|
||||
0x87, 0xf8, 0x43, 0x10, 0xbc, 0x49, 0x14, 0x87, 0x92, 0x06, 0x22, 0xaf, 0x26, 0xde, 0x53, 0x9a,
|
||||
0xff, 0x66, 0x84, 0xb0, 0x57, 0x6f, 0x5b, 0xab, 0x93, 0x9a, 0xe9, 0x38, 0x54, 0x43, 0x98, 0x7b,
|
||||
0x34, 0x22, 0xe8, 0x38, 0x23, 0xa7, 0x9b, 0xb7, 0x58, 0x84, 0xf5, 0x2f, 0xa2, 0x08, 0xf3, 0x1f,
|
||||
0x8a, 0xfa, 0xee, 0x8b, 0x1b, 0x42, 0x34, 0xa0, 0xc0, 0xff, 0xb3, 0x77, 0x86, 0x6c, 0x9d, 0x94,
|
||||
0xad, 0xe3, 0x0b, 0x7b, 0xe6, 0x03, 0xb7, 0xfa, 0x0d, 0x37, 0xfb, 0x19, 0x37, 0xf3, 0x0d, 0x07,
|
||||
0xd7, 0x81, 0x2f, 0x4c, 0xfa, 0xb4, 0xa2, 0x7c, 0xac, 0x01, 0x2f, 0x09, 0x0a, 0x78, 0x00, 0x7c,
|
||||
0x90, 0x45, 0x76, 0xc4, 0x40, 0x0c, 0x44, 0x15, 0x66, 0xe6, 0x53, 0x98, 0xbd, 0xcf, 0x36, 0x9c,
|
||||
0xb9, 0x80, 0x9e, 0xd9, 0x6d, 0x92, 0x47, 0xdd, 0x03, 0xb7, 0x1f, 0x66, 0x5a, 0x0a, 0xab, 0xea,
|
||||
0xc3, 0x1f, 0xd3, 0xb7, 0x08, 0x98, 0x30, 0x17, 0x52, 0x62, 0x49, 0x61, 0x54, 0xc2, 0x19, 0x47,
|
||||
0x75, 0xe4, 0xa9, 0x88, 0xe1, 0x0e, 0x7d, 0x16, 0x61, 0x12, 0x21, 0x4b, 0xd3, 0x32, 0x51, 0x46,
|
||||
0x2c, 0xbc, 0xc2, 0x80, 0xfb, 0x82, 0xd8, 0x43, 0x52, 0x1e, 0x56, 0x84, 0x51, 0x77, 0xb0, 0x59,
|
||||
0x79, 0xc5, 0x60, 0x5a, 0x49, 0x62, 0x09, 0xe7, 0x44, 0xe5, 0x70, 0xb5, 0x1d, 0x31, 0x9c, 0x8d,
|
||||
0x9b, 0x70, 0x36, 0xd8, 0x29, 0xc5, 0x70, 0x2b, 0x48, 0x3d, 0x05, 0xd0, 0x30, 0x7e, 0x22, 0xc2,
|
||||
0x80, 0xca, 0xda, 0xab, 0x04, 0x55, 0xc8, 0x5e, 0x28, 0x08, 0xfd, 0x22, 0x82, 0xe7, 0x96, 0xf4,
|
||||
0xe1, 0x78, 0xc1, 0xcd, 0xf1, 0xcc, 0xcd, 0x35, 0xee, 0xd4, 0x3d, 0x59, 0xd0, 0x3d, 0x9e, 0xe8,
|
||||
0x1e, 0x2f, 0xeb, 0xee, 0xbd, 0x7f, 0xa2, 0x65, 0x18, 0xe6, 0x46, 0xe5, 0xb7, 0xb8, 0x55, 0x14,
|
||||
0xf0, 0x36, 0xd4, 0x7f, 0xeb, 0x88, 0x58, 0xc0, 0xd9, 0x6e, 0x26, 0x91, 0xac, 0x2b, 0xea, 0xc0,
|
||||
0xdb, 0x88, 0x0d, 0xdc, 0x93, 0x3f, 0xd6, 0xc6, 0xb2, 0xa9, 0xd4, 0x12, 0x84, 0x47, 0x5c, 0x9e,
|
||||
0x6d, 0x81, 0x72, 0x64, 0xeb, 0x06, 0x4e, 0x65, 0x76, 0x47, 0xbd, 0x67, 0x2f, 0x37, 0x2c, 0x4b,
|
||||
0x37, 0xb1, 0x63, 0x3a, 0x4d, 0xc3, 0x9d, 0x6d, 0xc3, 0x7d, 0xab, 0x1a, 0x58, 0x8f, 0xc2, 0x79,
|
||||
0xe7, 0xd0, 0x76, 0xad, 0xfe, 0x0c, 0xb1, 0x7a, 0x18, 0x00, 0x7d, 0x50, 0x35, 0x77, 0x03, 0x31,
|
||||
0x0c, 0x56, 0xb9, 0x9d, 0xca, 0x34, 0x95, 0xb7, 0x52, 0x70, 0x2e, 0x33, 0xe3, 0xa8, 0xa7, 0xdc,
|
||||
0x29, 0x89, 0x5f, 0x7c, 0xd6, 0x55, 0x76, 0xe0, 0xdf, 0x97, 0x99, 0x46, 0xc1, 0x87, 0x70, 0xb1,
|
||||
0x7e, 0x88, 0xf9, 0x62, 0x2e, 0x83, 0x91, 0x24, 0x29, 0x39, 0x23, 0x0e, 0x95, 0x62, 0x23, 0xc8,
|
||||
0xa1, 0xca, 0xea, 0x38, 0xc0, 0x64, 0xb9, 0x6e, 0x2d, 0x4c, 0xd6, 0x7d, 0x09, 0xfa, 0x6a, 0xc6,
|
||||
0x7b, 0x4c, 0x24, 0xe6, 0x04, 0xfa, 0x94, 0x53, 0xa6, 0xc0, 0x8a, 0x25, 0x35, 0x71, 0x85, 0x51,
|
||||
0x7d, 0x36, 0x97, 0x45, 0xcf, 0x6a, 0xc8, 0x66, 0xd0, 0x8a, 0x12, 0x4a, 0x20, 0x74, 0x82, 0xdc,
|
||||
0x0a, 0xac, 0x8e, 0x2c, 0x7a, 0x76, 0x5e, 0xd4, 0xc3, 0x42, 0xf6, 0xff, 0xfb, 0xd0, 0xff, 0x57,
|
||||
0xa5, 0x5a, 0xa6, 0xb0, 0xba, 0x9a, 0x41, 0x6f, 0x25, 0x60, 0xf4, 0xce, 0x05, 0x43, 0x75, 0x67,
|
||||
0xca, 0x86, 0xe3, 0x4f, 0x9b, 0x66, 0xb6, 0x70, 0x97, 0x29, 0x7e, 0x2c, 0xfa, 0x02, 0x6b, 0x62,
|
||||
0x9e, 0xe8, 0xa2, 0x2a, 0x05, 0xe8, 0xbc, 0x35, 0xfe, 0x98, 0x7d, 0x15, 0xaf, 0xa8, 0xf2, 0xa3,
|
||||
0x82, 0x92, 0x65, 0x98, 0x7e, 0xca, 0x3d, 0xf0, 0x29, 0xf7, 0xc0, 0x5b, 0x6e, 0x98, 0xf8, 0x3f,
|
||||
0xc4, 0xa0, 0x48, 0x82, 0x9e, 0xb5, 0xc1, 0x0a, 0x03, 0x2f, 0x4b, 0x80, 0x4b, 0x76, 0x9e, 0x37,
|
||||
0x29, 0xc5, 0x4b, 0xb1, 0xa4, 0xf8, 0xce, 0xd5, 0xbb, 0xef, 0x62, 0x13, 0x51, 0x10, 0x5d, 0xda,
|
||||
0xbe, 0x3c, 0x3b, 0x91, 0xe6, 0xb3, 0x99, 0x57, 0x1f, 0x4f, 0x16, 0x86, 0x8e, 0xe4, 0x82, 0x96,
|
||||
0x4e, 0x32, 0xc5, 0x8b, 0xec, 0xb7, 0x13, 0x36, 0x4d, 0xd9, 0xc0, 0xd8, 0x77, 0xc0, 0xc2, 0xcb,
|
||||
0xfe, 0x01, 0xb5, 0x8f, 0xb5, 0x95, 0xc4, 0x60, 0x0c, 0x84, 0x15, 0x1d, 0x33, 0x33, 0x54, 0x60,
|
||||
0x6a, 0xe1, 0x20, 0x3c, 0x2a, 0x40, 0xcf, 0xa0, 0xf5, 0x93, 0x49, 0xfe, 0x61, 0xa1, 0xfb, 0x65,
|
||||
0x5e, 0xa7, 0x97, 0x89, 0x66, 0xe6, 0x13, 0x18, 0x29, 0x42, 0xdd, 0xe3, 0x50, 0x30, 0x70, 0xff,
|
||||
0x30, 0x96, 0xb2, 0x0e, 0x2b, 0x96, 0x0a, 0x75, 0x98, 0xb0, 0x60, 0x54, 0x10, 0x3c, 0xb5, 0x4d,
|
||||
0x04, 0x47, 0x39, 0x1b, 0x83, 0xa5, 0x24, 0x54, 0xc2, 0x91, 0xa6, 0x9a, 0x42, 0x4b, 0x1a, 0xae,
|
||||
0x30, 0xd2, 0x9c, 0xa4, 0x84, 0xda, 0xf8, 0x81, 0x0f, 0xc7, 0x22, 0x25, 0x1a, 0xd2, 0x9d, 0xe1,
|
||||
0xea, 0x16, 0x0b, 0xd1, 0x21, 0x8a, 0x0d, 0x61, 0x3f, 0xf8, 0x27, 0x63, 0xf8, 0xb3, 0xa1, 0x1d,
|
||||
0x79, 0x7e, 0xfa, 0x58, 0x48, 0x9a, 0x72, 0x95, 0xe2, 0xdc, 0xe2, 0x7e, 0x66, 0x41, 0xa6, 0xae,
|
||||
0xa4, 0x0b, 0xfb, 0xf3, 0xcd, 0xf9, 0xda, 0x66, 0x37, 0xc0, 0xf7, 0xbf, 0xef, 0xc0, 0x6f, 0x84,
|
||||
0x7c, 0x6d, 0xb5, 0x8b, 0x02, 0x5e, 0x47, 0xa8, 0xaf, 0x5d, 0x6e, 0x31, 0x9c, 0x2e, 0x01, 0x9f,
|
||||
0x6e, 0xa4, 0x9e, 0x6a, 0x7f, 0xd1, 0x3c, 0xa0, 0x44, 0x13, 0x6a, 0x2c, 0x95, 0xb5, 0x70, 0xb9,
|
||||
0xf4, 0xc6, 0xf3, 0xda, 0xee, 0x6c, 0x26, 0xba, 0x5d, 0x5f, 0xcc, 0x45, 0x9b, 0x86, 0x60, 0x3d,
|
||||
0xd7, 0x75, 0xa9, 0x11, 0xfc, 0x7a, 0x84, 0xbc, 0xbd, 0x04, 0xbb, 0x3d, 0xe7, 0x1a, 0x00, 0x54,
|
||||
0x4e, 0x85, 0x4d, 0x45, 0x41, 0x10, 0xdc, 0x28, 0xb4, 0xf0, 0x88, 0xe1, 0xee, 0x56, 0x00, 0x25,
|
||||
0xe0, 0xd1, 0xc9, 0xc9, 0x42, 0x9e, 0xdc, 0xed, 0xd9, 0x97, 0xee, 0xbf, 0x6b, 0x7c, 0x7c, 0xa8,
|
||||
0x3c, 0xdc, 0xdf, 0xdf, 0x33, 0x12, 0x07, 0x56, 0x85, 0x13, 0x3a, 0x49, 0x0a, 0x52, 0x14, 0xbc,
|
||||
0x80, 0x87, 0x13, 0xc6, 0xab, 0x0e, 0x99, 0x7d, 0x96, 0x94, 0x69, 0x57, 0xc4, 0x21, 0x73, 0xea,
|
||||
0x73, 0xa2, 0x9d, 0x39, 0x49, 0xf4, 0x89, 0x37, 0x56, 0x0e, 0x1f, 0x4f, 0xf8, 0xe8, 0x85, 0xc4,
|
||||
0x8e, 0xf1, 0xf1, 0xfb, 0xf0, 0xf8, 0xfa, 0x08, 0x23, 0x2e, 0x28, 0x5f, 0x8b, 0x47, 0x52, 0xb6,
|
||||
0x16, 0xe8, 0x8e, 0xe9, 0x1a, 0x21, 0xd3, 0xc5, 0xa0, 0xfe, 0xab, 0xa9, 0x6a, 0xeb, 0x9c, 0xe1,
|
||||
0xc4, 0xb2, 0xa3, 0x6a, 0xb9, 0x4f, 0x07, 0xd0, 0xa9, 0xb6, 0xff, 0x0c, 0xce, 0xc1, 0xcb, 0x80,
|
||||
0x0e, 0x45, 0xcf, 0x07, 0xe1, 0x62, 0x29, 0xb4, 0xb7, 0xf1, 0xe0, 0x18, 0xdb, 0xda, 0x78, 0x8c,
|
||||
0x49, 0x40, 0x77, 0xe0, 0xb3, 0x5c, 0x01, 0x64, 0x39, 0x2f, 0x92, 0xb5, 0xbc, 0x70, 0x6b, 0x45,
|
||||
0xd1, 0xcc, 0xe2, 0x43, 0xb2, 0x47, 0x02, 0x4d, 0x8e, 0xcb, 0xdc, 0x8c, 0x96, 0xc6, 0x33, 0x02,
|
||||
0xc3, 0xb5, 0x24, 0xb1, 0x28, 0xde, 0xd9, 0x38, 0xbe, 0xb8, 0x02, 0xec, 0x17, 0x24, 0x23, 0x85,
|
||||
0xe0, 0x46, 0x4a, 0xa1, 0x05, 0x94, 0x80, 0x05, 0x71, 0xea, 0x00, 0xb5, 0x51, 0x45, 0x56, 0x04,
|
||||
0x51, 0x0c, 0xcc, 0x1a, 0xdb, 0xcd, 0x0e, 0x3b, 0x02, 0xce, 0x25, 0x70, 0xd8, 0xe7, 0xb5, 0xd4,
|
||||
0xd0, 0x69, 0x49, 0xfa, 0x25, 0x7f, 0xe4, 0xf6, 0xb8, 0xbb, 0xee, 0xcb, 0x8b, 0xce, 0x2a, 0xd1,
|
||||
0xe6, 0xc0, 0x4a, 0xf0, 0xfe, 0x3a, 0x17, 0xd6, 0xf5, 0x99, 0x8a, 0x29, 0x7b, 0x56, 0x8a, 0x71,
|
||||
0xde, 0x82, 0x96, 0x46, 0x91, 0xd3, 0x7c, 0x23, 0x11, 0xdc, 0x59, 0x89, 0x8e, 0xe6, 0x1d, 0x3d,
|
||||
0xb2, 0x04, 0xa7, 0x05, 0xb3, 0x8e, 0x03, 0x3e, 0x86, 0xd3, 0xec, 0xc6, 0xdb, 0xec, 0xe1, 0xa8,
|
||||
0x6d, 0x69, 0x29, 0xe0, 0x92, 0xb5, 0xb7, 0x5a, 0x4b, 0x13, 0x19, 0xca, 0x73, 0xc5, 0x93, 0x7b,
|
||||
0xc5, 0x01, 0xe7, 0x2e, 0xe5, 0x39, 0x18, 0xd1, 0xab, 0x4d, 0x68, 0xde, 0x9f, 0x58, 0xcc, 0x27,
|
||||
0x78, 0x27, 0x9a, 0xb5, 0x5c, 0x54, 0x59, 0xa2, 0xd9, 0xcd, 0xef, 0xe6, 0x1d, 0x70, 0x6b, 0x9e,
|
||||
0xb1, 0xa5, 0x8c, 0xd5, 0x18, 0xd3, 0x04, 0xbf, 0x56, 0x0b, 0x68, 0x98, 0xc7, 0xf3, 0x3a, 0xdb,
|
||||
0x6f, 0x8a, 0xaf, 0x72, 0x1f, 0xff, 0xda, 0x69, 0xe7, 0x57, 0x1f, 0xec, 0xbe, 0xcd, 0x46, 0xaa,
|
||||
0xe0, 0x8a, 0x74, 0x9f, 0xfc, 0x31, 0xf1, 0x25, 0x62, 0x08, 0xc9, 0xc8, 0xcc, 0xcb, 0xf6, 0xcb,
|
||||
0x4f, 0x01, 0xb4, 0x41, 0x0d, 0xb8, 0x15, 0x05, 0x51, 0xf4, 0x06, 0xb5, 0xed, 0x35, 0xd4, 0x8a,
|
||||
0x53, 0x33, 0xaa, 0xa3, 0x93, 0x67, 0xcf, 0x7d, 0x83, 0x8f, 0xe5, 0xf7, 0x9b, 0x63, 0x1f, 0x05,
|
||||
0x78, 0xbf, 0x44, 0x96, 0x68, 0x8d, 0xa2, 0xb1, 0x29, 0x68, 0x41, 0x05, 0x65, 0xe0, 0x98, 0x40,
|
||||
0xd1, 0x06, 0xd8, 0xd5, 0x81, 0xaa, 0x06, 0x0a, 0x85, 0x34, 0x86, 0x16, 0x99, 0x0b, 0xb4, 0x0f,
|
||||
0x68, 0x7b, 0xe4, 0x6e, 0xee, 0x1a, 0x1e, 0x17, 0xa5, 0x23, 0x12, 0x16, 0x50, 0x8e, 0x9f, 0x30,
|
||||
0xdc, 0x3c, 0x00, 0x1d, 0x54, 0xb4, 0xdb, 0x18, 0x6b, 0x49, 0x98, 0x80, 0x16, 0x6c, 0x34, 0x18,
|
||||
0xc4, 0x05, 0xd1, 0xcf, 0xd3, 0xdf, 0xc9, 0xd1, 0xc9, 0x39, 0x5c, 0xc7, 0x8f, 0x02, 0x3b, 0xe8,
|
||||
0x62, 0xff, 0x2f, 0xd5, 0x1a, 0x87, 0xb5, 0xe2, 0xf8, 0xf8, 0xf8, 0x08, 0x3d, 0xe1, 0xf4, 0x93,
|
||||
0xf0, 0xa7, 0x72, 0xbc, 0x2c, 0x50, 0x6f, 0xc7, 0x36, 0x88, 0x96, 0xac, 0x86, 0x1c, 0xbb, 0xeb,
|
||||
0x9c, 0x95, 0x03, 0x36, 0x0e, 0x04, 0x23, 0xa8, 0x37, 0xce, 0x84, 0x93, 0x43, 0x07, 0x42, 0xb3,
|
||||
0xd2, 0x43, 0x21, 0xcc, 0xdf, 0x37, 0x22, 0xb4, 0xe2, 0xaf, 0x0c, 0x40, 0xd3, 0x6f, 0xe2, 0x30,
|
||||
0x6e, 0x4f, 0xad, 0x0f, 0xf7, 0x50, 0x6a, 0xda, 0x6e, 0xaa, 0xd9, 0x6e, 0x66, 0x44, 0xd3, 0x03,
|
||||
0x1f, 0xa7, 0x7b, 0x9a, 0x66, 0x06, 0x48, 0x27, 0x2f, 0xec, 0xa1, 0x58, 0x7f, 0x82, 0xfe, 0x01,
|
||||
0x6d, 0x8e, 0x05, 0x72, 0x03, 0x31, 0x0c, 0x00, 0x55, 0x0e, 0x94, 0x99, 0xfb, 0x86, 0xd2, 0x23,
|
||||
0x3a, 0x50, 0xa6, 0x41, 0xcd, 0xf1, 0xe9, 0x48, 0x8e, 0xe4, 0xc0, 0xef, 0xc3, 0x9c, 0x0c, 0x98,
|
||||
0xbd, 0xbb, 0xf0, 0x4f, 0x0e, 0x63, 0x21, 0xe1, 0xf3, 0x03, 0x7a, 0x9c, 0x1b, 0xa7, 0x20, 0x2e,
|
||||
0x50, 0x1c, 0x9f, 0x18, 0xdd, 0x2c, 0x80, 0xab, 0xba, 0xba, 0x50, 0x4d, 0x49, 0x15, 0x73, 0xf6,
|
||||
0x83, 0x1c, 0xaa, 0x12, 0x98, 0xc0, 0xb1, 0x81, 0xc0, 0x11, 0xba, 0x42, 0x7e, 0x14, 0xa0, 0xe8,
|
||||
0xc3, 0xe3, 0x03, 0x6c, 0x33, 0xe7, 0xa8, 0x81, 0x34, 0x02, 0x81, 0x8d, 0xaf, 0xc7, 0xe5, 0x34,
|
||||
0x34, 0x0a, 0xe7, 0x3d, 0x64, 0x69, 0x0a, 0x59, 0x1a, 0x23, 0xf7, 0x47, 0xc8, 0x40, 0x4d, 0xc1,
|
||||
0x4d, 0x38, 0x60, 0x77, 0x40, 0xc4, 0xbc, 0x66, 0x2d, 0x94, 0xa7, 0x14, 0x47, 0x38, 0x7b, 0x57,
|
||||
0xd2, 0xa0, 0x50, 0x16, 0x28, 0xfd, 0xbd, 0xbc, 0x2d, 0x75, 0xdf, 0xf5, 0xdc, 0xd7, 0x61, 0x3d,
|
||||
0xcb, 0xe0, 0x5a, 0x03, 0x21, 0xa7, 0x3b, 0xf7, 0x4a, 0xae, 0x9b, 0x14, 0x12, 0x6c, 0x4f, 0xf5,
|
||||
0x6c, 0x1b, 0x47, 0x2c, 0xd9, 0xde, 0xf7, 0xa0, 0xd5, 0xe5, 0xf8, 0x5d, 0xdd, 0xf6, 0xb8, 0xf1,
|
||||
0x78, 0xae, 0xf1, 0x64, 0xb6, 0x63, 0x67, 0xaa, 0xf1, 0x6c, 0xae, 0x71, 0x7b, 0xd8, 0xb8, 0xdd,
|
||||
0xe5, 0xe4, 0x54, 0x38, 0x19, 0x7a, 0xb1, 0x63, 0xa1, 0x03,
|
||||
0x7d, 0x51, 0x45, 0x76, 0x03, 0x31, 0x0c, 0xfd, 0xbb, 0xd2, 0xaa, 0xcc, 0xb8, 0xed, 0x2a, 0x70,
|
||||
0x88, 0xde, 0x42, 0x43, 0x72, 0xe3, 0x17, 0xb3, 0x95, 0xc9, 0xf1, 0x0b, 0x61, 0x36, 0xa3, 0xf4,
|
||||
0x01, 0x03, 0x36, 0xc2, 0x35, 0x49, 0x2a, 0xeb, 0x21, 0x27, 0x6a, 0xbb, 0x54, 0x7b, 0x1b, 0x4a,
|
||||
0xa7, 0xbd, 0xa3, 0x54, 0x36, 0xda, 0xd3, 0x58, 0x2b, 0x4d, 0x8a, 0xad, 0x57, 0x0a, 0x9f, 0x0e,
|
||||
0x17, 0x43, 0x9d, 0x33, 0x59, 0xdf, 0xb0, 0xc5, 0x45, 0xe2, 0xc0, 0xa5, 0x70, 0xc2, 0x03, 0x55,
|
||||
0x49, 0x37, 0xdf, 0x4c, 0x9c, 0x83, 0xf3, 0x63, 0x7c, 0xa4, 0xdc, 0xed, 0x75, 0xf1, 0xe8, 0xab,
|
||||
0xcc, 0xa9, 0xe5, 0x44, 0x36, 0x8a, 0xe0, 0xd2, 0x7b, 0x4b, 0xd3, 0x03, 0x3c, 0xd3, 0xfa, 0xdd,
|
||||
0x45, 0x66, 0x97, 0x7d, 0xc2, 0x85, 0x70, 0xb2, 0xda, 0x95, 0x86, 0xea, 0x41, 0x29, 0xc0, 0xd7,
|
||||
0x14, 0xe0, 0x0e, 0x60, 0x95, 0x61, 0x3c, 0x53, 0xc8, 0x78, 0x18, 0xe5, 0x0a, 0x0f, 0xff, 0x38,
|
||||
0x71, 0xba, 0x82, 0xee, 0x74, 0x81, 0xee, 0x6c, 0x25, 0xef, 0xe9, 0x7a, 0xfc, 0xe3, 0xde, 0x81,
|
||||
0xb8, 0x6a, 0x64, 0xcc, 0x6a, 0xf4, 0x97, 0x29, 0xd4, 0xdd, 0x49, 0x2e, 0x36, 0x24, 0x78, 0x98,
|
||||
0x4a, 0x70, 0xb9, 0x4e, 0xf3, 0x8d, 0xb2, 0xb6, 0x6b, 0x80, 0xae, 0x37, 0x84, 0x38, 0x9d, 0x0a,
|
||||
0xb1, 0x09, 0x74, 0xee, 0x54, 0xdb, 0xa7, 0xee, 0xff, 0xb0, 0x8d, 0xfb, 0x1f, 0xed, 0xc4, 0x28,
|
||||
0x87, 0xd3, 0x9d, 0xac, 0xe6, 0x2e, 0xbe, 0x85, 0x3c, 0x5f, 0xfe, 0x02, 0x85, 0x4f, 0xc3, 0x76,
|
||||
0x44, 0x41, 0x10, 0xbd, 0xdb, 0xd1, 0x36, 0x36, 0x36, 0xb1, 0x93, 0xbf, 0xa9, 0x79, 0xa8, 0x3e,
|
||||
0xe9, 0x87, 0xf6, 0xe0, 0xef, 0xc7, 0xe6, 0xaa, 0x78, 0x85, 0x7f, 0x2e, 0x02, 0x27, 0xd4, 0xfe,
|
||||
0xa2, 0x4f, 0x4a, 0x74, 0x69, 0x22, 0x25, 0xb5, 0x22, 0x17, 0xa5, 0x52, 0x93, 0x68, 0x15, 0x05,
|
||||
0x09, 0x2e, 0xb5, 0x10, 0x38, 0x6b, 0xf9, 0x78, 0xd6, 0x77, 0xa4, 0x90, 0xd3, 0xe1, 0xba, 0xb4,
|
||||
0x21, 0x4c, 0x87, 0x3a, 0x77, 0x4d, 0xa4, 0xbc, 0xd4, 0x2a, 0x97, 0x81, 0x82, 0x08, 0x6b, 0x9c,
|
||||
0x71, 0xc1, 0xb3, 0xe7, 0x3d, 0xf7, 0xab, 0x45, 0xfd, 0xab, 0x05, 0xfd, 0xab, 0x45, 0xfd, 0xea,
|
||||
0x06, 0x06, 0x9c, 0x4f, 0xaf, 0x37, 0x0a, 0x17, 0xc6, 0x8f, 0x26, 0x85, 0x93, 0x01, 0xc7, 0xe4,
|
||||
0x34, 0x5f, 0x0b, 0x81, 0xfb, 0xc1, 0x69, 0x46, 0xa9, 0x70, 0x39, 0x4b, 0xa4, 0x50, 0x5d, 0x0a,
|
||||
0xe4, 0xd8, 0x70, 0x14, 0xd8, 0xe1, 0x92, 0x74, 0xec, 0xd9, 0xb5, 0xd9, 0xd1, 0xf0, 0x19, 0x47,
|
||||
0x5a, 0x97, 0x34, 0x59, 0x2c, 0x5f, 0x0e, 0x77, 0x85, 0x54, 0x78, 0x35, 0x1e, 0x8f, 0xb3, 0x9c,
|
||||
0x0a, 0xd5, 0x5c, 0x7a, 0x4f, 0xa5, 0x4e, 0xb9, 0x44, 0xd5, 0x44, 0x2e, 0xc8, 0x30, 0x84, 0x8d,
|
||||
0x5c, 0xa4, 0xec, 0x50, 0x75, 0x7f, 0x9b, 0xd8, 0x70, 0x45, 0xc6, 0xe3, 0x7c, 0x48, 0x84, 0xf3,
|
||||
0x51, 0xca, 0x61, 0x1e, 0x34, 0x16, 0xd8, 0x1a, 0x33, 0xf3, 0x7d, 0x75, 0x50, 0xc5, 0x95, 0x04,
|
||||
0x41, 0x08, 0xe5, 0xba, 0xee, 0xee, 0x31, 0xac, 0x66, 0xc3, 0x2b, 0xa1, 0x67, 0x68, 0xa3, 0x84,
|
||||
0xb5, 0xe8, 0xc7, 0x5d, 0x4e, 0x38, 0x5f, 0xa0, 0x4b, 0xb5, 0x92, 0xc3, 0x9f, 0x37, 0x4c, 0x5f,
|
||||
0x98, 0x28, 0x90, 0x51, 0x4a, 0x28, 0x36, 0x53, 0xfa, 0x19, 0x24, 0x4d, 0x54, 0x85, 0x43, 0x91,
|
||||
0x06, 0xc7, 0x0d, 0xb8, 0x5e, 0x99, 0x1d, 0x64, 0x6a, 0xb3, 0x24, 0x38, 0x18, 0x9c, 0x35, 0xdc,
|
||||
0x9a, 0x1a, 0x5d, 0xd7, 0x0c, 0x4e, 0x0a, 0x45, 0x27, 0x4d, 0x30, 0x2d, 0x4b, 0x8b, 0xc9, 0x78,
|
||||
0x16, 0xb4, 0x35, 0xc1, 0x4b, 0xf1, 0x5d, 0xd7, 0xf0, 0xf2, 0x9d, 0x2d, 0xbc, 0xfc, 0x72, 0xc1,
|
||||
0x70, 0x52, 0x71, 0xce, 0xd8, 0x88, 0xa7, 0x06, 0x4e, 0x82, 0x24, 0x4d, 0x86, 0x75, 0x1b, 0x91,
|
||||
0xbb, 0x39, 0x91, 0x95, 0xc9, 0xc9, 0xf4, 0x02, 0x6e, 0x56, 0x26, 0xa7, 0x0b, 0xe4, 0xef, 0x57,
|
||||
0xaf, 0x26, 0xe4, 0x4f, 0x96, 0xc9, 0xef, 0x4d, 0x7f, 0x9d, 0xa2, 0x4d, 0xec, 0x3b, 0x84, 0x94,
|
||||
0x43, 0x2b, 0xbf, 0x70, 0x56, 0x53, 0xc7, 0xb8, 0x7f, 0x0c, 0x26, 0x29, 0xeb, 0x50, 0x99, 0x52,
|
||||
0x56, 0x38, 0x5b, 0xfe, 0xba, 0xb7, 0x80, 0x78, 0xb1, 0x82, 0xb8, 0x3b, 0x41, 0xdc, 0x5d, 0x41,
|
||||
0xdc, 0x6c, 0x17, 0x16, 0xd4, 0x48, 0x0b, 0x8f, 0x43, 0xd3, 0xa6, 0xf9, 0xc0, 0xba, 0x69, 0x3a,
|
||||
0x34, 0x70, 0x92, 0x1f, 0xce, 0xf4, 0x5f, 0xae, 0x70, 0x3e, 0x5a, 0x60, 0x73, 0x38, 0x41, 0xef,
|
||||
0x03, 0x75, 0xce, 0x83, 0x72, 0x04, 0x41, 0x10, 0x06, 0xe0, 0x2e, 0xc6, 0xb6, 0x6d, 0x3b, 0x79,
|
||||
0x82, 0xd8, 0x2a, 0x77, 0x0d, 0x7a, 0xb3, 0xb3, 0x9a, 0xcd, 0xcc, 0xe4, 0xee, 0xf5, 0x73, 0xf6,
|
||||
0x95, 0x9b, 0xdf, 0x0f, 0x3e, 0x45, 0x8e, 0x04, 0x66, 0x4e, 0xd1, 0x79, 0x0e, 0x1d, 0x99, 0x58,
|
||||
0x25, 0x2c, 0x42, 0xe1, 0x33, 0x07, 0x70, 0x53, 0x1c, 0x7e, 0x2b, 0x43, 0x11, 0x59, 0x8b, 0x2f,
|
||||
0x2c, 0x25, 0x83, 0x42, 0xc7, 0x29, 0x4b, 0x94, 0x4e, 0xd0, 0x30, 0xa9, 0x34, 0xf2, 0x88, 0x60,
|
||||
0x0b, 0x53, 0x0b, 0xeb, 0x7f, 0x96, 0xc3, 0x78, 0xa8, 0x72, 0x9b, 0xb1, 0x96, 0x14, 0xc3, 0xb8,
|
||||
0xa1, 0x94, 0x58, 0xee, 0x29, 0xcc, 0x23, 0x37, 0x4a, 0xfe, 0x10, 0x92, 0x4d, 0x13, 0x9d, 0x85,
|
||||
0x05, 0xcd, 0x2d, 0x99, 0x0c, 0x19, 0x8c, 0x7f, 0x9d, 0x83, 0x09, 0xad, 0x63, 0x2c, 0x36, 0x60,
|
||||
0x09, 0xeb, 0x67, 0x83, 0x1f, 0x86, 0x89, 0xb0, 0x8d, 0xbb, 0x93, 0x77, 0x37, 0xf3, 0xee, 0x64,
|
||||
0x8d, 0x3b, 0x59, 0x71, 0x17, 0x1b, 0xdc, 0xa5, 0xfa, 0xdf, 0x53, 0x35, 0xee, 0x4a, 0x83, 0xdb,
|
||||
0xf9, 0xfe, 0x70, 0xd2, 0xd2, 0x5c, 0xc8, 0x9b, 0xb3, 0x79, 0x73, 0x36, 0xab, 0x3c, 0x05, 0xbd,
|
||||
0x15, 0x6d, 0xb4, 0x41, 0x9b, 0x35, 0xf6, 0xf8, 0xe4, 0x18, 0xc6, 0xea, 0x1f, 0xf7, 0xd5, 0xa0,
|
||||
0x13, 0x0d, 0x68, 0xaf, 0xa5, 0xc4, 0x6a, 0x03, 0xa0, 0x42, 0x1d, 0x32, 0xf4, 0x59, 0x22, 0x7d,
|
||||
0x8a, 0x24, 0x26, 0xc6, 0x43, 0x3a, 0x3e, 0xc6, 0x93, 0x43, 0xc9, 0x63, 0x3c, 0xbc, 0x3a, 0x6f,
|
||||
0x99, 0xec, 0x28, 0x1f, 0x6a, 0xc9, 0x68, 0xc7, 0x1c, 0xc9, 0x96, 0x1b, 0x57, 0xf9, 0x8d, 0xb9,
|
||||
0x4a, 0xe0, 0x7f, 0xa5, 0xcf, 0x31, 0x0e, 0xc2, 0x30, 0x0c, 0x85, 0x61, 0x4f, 0x5d, 0x01, 0xa1,
|
||||
0x96, 0x13, 0xc0, 0x5c, 0x92, 0x63, 0xc0, 0xc8, 0x6e, 0xa5, 0x8d, 0x51, 0xa3, 0x34, 0x76, 0xe5,
|
||||
0x14, 0xce, 0x8f, 0xca, 0x50, 0x95, 0x89, 0x21, 0xfb, 0xef, 0x4f, 0x7e, 0x10, 0xa2, 0x44, 0x87,
|
||||
0x83, 0x63, 0x3f, 0xd0, 0xe8, 0x91, 0xf5, 0x89, 0x64, 0x0c, 0xda, 0xd6, 0x77, 0x09, 0x55, 0x24,
|
||||
0x61, 0x26, 0x7d, 0x93, 0xc2, 0x31, 0x86, 0x9c, 0x31, 0x89, 0xa7, 0x04, 0x15, 0x3b, 0x96, 0x6f,
|
||||
0x6b, 0xcc, 0xd2, 0xf5, 0x92, 0x26, 0xc7, 0x41, 0x18, 0xd5, 0xf9, 0x20, 0xd8, 0x8d, 0x04, 0xe7,
|
||||
0x57, 0xee, 0xa0, 0xde, 0x1c, 0xd5, 0x4a, 0x13, 0xb9, 0x99, 0x14, 0x9a, 0x0d, 0xbb, 0xb3, 0x6d,
|
||||
0xa1, 0xb0, 0xb7, 0x85, 0x40, 0x95, 0xe7, 0xd0, 0xc7, 0x3f, 0x73, 0x2e, 0x8b, 0xd5, 0x6c, 0xac,
|
||||
0x66, 0xb5, 0x4e, 0x3f, 0xcf, 0xb4, 0x85, 0xc2, 0xc1, 0x16, 0x02, 0x70, 0x23, 0x9a, 0x66, 0x22,
|
||||
0xbe, 0x3f, 0xae, 0xb8, 0x16, 0x1f, 0x8c, 0x8e, 0x35, 0x57, 0x04, 0x51, 0x0c, 0x85, 0xd3, 0xe1,
|
||||
0x4e, 0x85, 0x7b, 0x85, 0x6b, 0x8f, 0x5b, 0xc7, 0xf6, 0xf7, 0x8c, 0xe4, 0xb0, 0x6f, 0x24, 0x79,
|
||||
0x86, 0xfd, 0x7a, 0xdc, 0xbd, 0xbd, 0xfa, 0xd1, 0x09, 0xb3, 0x8d, 0xcc, 0x72, 0xda, 0x58, 0x81,
|
||||
0x67, 0xcb, 0x49, 0x64, 0x8f, 0x4a, 0x7d, 0x02, 0x8d, 0x09, 0x44, 0xc1, 0xd7, 0x91, 0xbd, 0x24,
|
||||
0x15, 0x02, 0x4b, 0x50, 0x1f, 0x88, 0x4e, 0x4d, 0x75, 0x73, 0xa0, 0x68, 0x2c, 0xec, 0x65, 0x4d,
|
||||
0x5d, 0x38, 0x35, 0x91, 0x91, 0x69, 0x6d, 0x13, 0x31, 0x2a, 0xf0, 0x49, 0x6e, 0x14, 0x69, 0xc5,
|
||||
0x34, 0x7d, 0x11, 0x52, 0x1a, 0x28, 0x4d, 0x08, 0xa8, 0x35, 0xe7, 0x9a, 0x06, 0x44, 0x05, 0xa1,
|
||||
0xc9, 0x55, 0xf5, 0x6d, 0x7e, 0xe1, 0x31, 0xff, 0xc2, 0x40, 0x83, 0xaa, 0x35, 0x02, 0xfb, 0x4b,
|
||||
0xf6, 0xd4, 0x85, 0x9d, 0xc4, 0xe7, 0xff, 0x7c, 0xf9, 0x76, 0xa1, 0xfb, 0xbb, 0xee, 0xd8, 0x43,
|
||||
0xb7, 0xfb, 0x5d, 0xb7, 0xfb, 0xb5, 0xdb, 0xf3, 0xae, 0xdb, 0xba, 0x76, 0xb6, 0x86, 0x70, 0xbd,
|
||||
0xb2, 0xba, 0xb9, 0xfa, 0x2d, 0xc2, 0x1c, 0x6c, 0xf8, 0x8d, 0x63, 0x18, 0xa9, 0x37, 0xf9, 0x39,
|
||||
0x83, 0x83, 0x15, 0xbd, 0xa2, 0x11, 0x4d, 0x9f, 0x96, 0x51, 0xbb, 0x18, 0x3f, 0x60, 0x8e, 0xe1,
|
||||
0xa3, 0x37, 0x10, 0xd9, 0xd7, 0x46, 0x92, 0x0a, 0x59, 0x33, 0x89, 0xd4, 0xbb, 0x75, 0x37, 0x33,
|
||||
0x6c, 0x2e, 0xa0, 0xc0, 0x72, 0x00, 0x6d, 0x90, 0x35, 0x7b, 0x03, 0x31, 0x10, 0x44, 0xb7, 0x0b,
|
||||
0x33, 0x33, 0x53, 0x67, 0x76, 0x1d, 0x66, 0xa6, 0x72, 0x4c, 0xeb, 0x44, 0x9f, 0xa5, 0xd3, 0x9d,
|
||||
0x20, 0xf0, 0xeb, 0xc3, 0x60, 0x38, 0x71, 0xf5, 0xe6, 0x69, 0xe8, 0x44, 0xc8, 0xd7, 0x7d, 0x8d,
|
||||
0x9b, 0xf4, 0x75, 0x1a, 0xf6, 0x25, 0x99, 0xca, 0xe7, 0x60, 0xb4, 0x56, 0xb0, 0x6c, 0x9e, 0xd8,
|
||||
0xd0, 0x2c, 0x74, 0xe9, 0xfb, 0x09, 0x15, 0x39, 0x47, 0x43, 0x8e, 0x8d, 0x12, 0x41, 0x51, 0xa2,
|
||||
0xfc, 0x58, 0x74, 0xd4, 0x8e, 0x43, 0x15, 0x7a, 0x69, 0x19, 0x17, 0xd2, 0x5b, 0x18, 0x0e, 0xb9,
|
||||
0xe8, 0xd8, 0x50, 0xfb, 0x16, 0x17, 0x15, 0x92, 0xf7, 0x28, 0x6b, 0x15, 0x16, 0x03, 0xa1, 0x03,
|
||||
0x98, 0x62, 0x45, 0x68, 0x94, 0x24, 0xd3, 0x12, 0x42, 0x4b, 0xf3, 0x55, 0x2f, 0x25, 0xcd, 0x7b,
|
||||
0x5b, 0xa2, 0xf9, 0x67, 0x51, 0x15, 0xd4, 0x5f, 0x13, 0xd6, 0x42, 0xe9, 0x0a, 0x2b, 0xea, 0xff,
|
||||
0x03, 0x8d, 0xa3, 0x64, 0x44, 0xe5, 0x81, 0xc1, 0x36, 0x0c, 0xf4, 0x33, 0x4d, 0x34, 0xea, 0x0c,
|
||||
0xd4, 0xa9, 0x4e, 0x35, 0xa9, 0xb6, 0xef, 0x70, 0xb9, 0x16, 0x2b, 0x30, 0xf3, 0x99, 0xda, 0x53,
|
||||
0x97, 0xd7, 0xf3, 0x2f, 0xbe, 0x7b, 0x73, 0x80, 0x5d, 0x29, 0x1c, 0x7f, 0xb5, 0x91, 0x4b, 0xc5,
|
||||
0x02, 0x36, 0x3e, 0x01, 0x13, 0x75, 0x80, 0x89, 0x3f, 0xc0, 0x42, 0x93, 0xc5, 0x64, 0x9d, 0xe1,
|
||||
0x72, 0xb3, 0xa1, 0xd4, 0xa6, 0x88, 0xed, 0x5c, 0x5c, 0x06, 0xe2, 0x0b, 0x41, 0xfd, 0x97, 0x41,
|
||||
0xed, 0x27, 0x9f, 0x84, 0xbb, 0x14, 0x92, 0x1f, 0x33, 0x17, 0xef, 0xfa, 0xd9, 0xf6, 0xea, 0xa7,
|
||||
0xf0, 0xea, 0x57, 0xcf, 0xa3, 0x75, 0xd8, 0x77, 0xad, 0x8f, 0x35, 0x5b, 0x04, 0x61, 0x0c, 0x84,
|
||||
0x83, 0x53, 0xe1, 0x52, 0xe1, 0x52, 0xe3, 0x50, 0xe3, 0xda, 0x60, 0xed, 0x3c, 0x2b, 0x39, 0x36,
|
||||
0x6b, 0xd9, 0x4f, 0xce, 0x7e, 0x3d, 0xee, 0x50, 0x5e, 0x19, 0x99, 0x99, 0x77, 0xe8, 0x52, 0xf2,
|
||||
0xf6, 0x89, 0xe2, 0xf6, 0x52, 0x6d, 0x80, 0xfb, 0x0d, 0xac, 0x63, 0x1d, 0x3b, 0xb0, 0x5c, 0x71,
|
||||
0xe0, 0xd9, 0xd2, 0x2c, 0x34, 0x74, 0x6c, 0x1b, 0x6c, 0x51, 0x18, 0xef, 0x41, 0xd3, 0xaa, 0x05,
|
||||
0xde, 0x36, 0xb4, 0xf0, 0xfb, 0x38, 0xf5, 0x2c, 0x29, 0xa4, 0x0c, 0x72, 0x44, 0x49, 0xe0, 0x89,
|
||||
0xae, 0xb6, 0x6f, 0x7c, 0x10, 0x65, 0xb8, 0x2b, 0xc5, 0xe3, 0x60, 0xe7, 0x12, 0x91, 0x16, 0x55,
|
||||
0x50, 0x8a, 0x96, 0xb0, 0x41, 0x2c, 0x8a, 0x30, 0x67, 0x5a, 0xa8, 0xbb, 0x90, 0x46, 0x33, 0x71,
|
||||
0x0e, 0x85, 0xc6, 0x5c, 0xd0, 0xe8, 0x67, 0xfa, 0xd8, 0xb7, 0xb0, 0x2e, 0x76, 0x09, 0x2a, 0x8d,
|
||||
0x32, 0xf6, 0x5f, 0x78, 0x13, 0xc8, 0x5f, 0xb8, 0xd5, 0x07, 0x28, 0x15, 0xdc, 0x7a, 0xde, 0xbd,
|
||||
0xa4, 0x3b, 0x2e, 0x9d, 0x5a, 0x47, 0xbd, 0x41, 0xdc, 0xe0, 0xd2, 0xd7, 0x2d, 0x5b, 0xb8, 0xd6,
|
||||
0xfa, 0xc6, 0xce, 0xc6, 0xbf, 0x04, 0xab, 0x2f, 0x04, 0x53, 0xdf, 0x08, 0xa6, 0x3e, 0x03, 0xbe,
|
||||
0xd5, 0xfd, 0xdd, 0x6e, 0x62, 0xaf, 0x83, 0x66, 0xbd, 0x52, 0xc8, 0x7f, 0x76, 0xa0, 0xc1, 0x0f,
|
||||
0x39, 0x88, 0x0a, 0x76, 0x49, 0xa9, 0xb9, 0x3e, 0xb4, 0xd1, 0x5c, 0xff, 0xbf, 0xcb, 0x5c, 0xad,
|
||||
0x9e, 0xe7, 0x34, 0xf7, 0x02, 0x31, 0xd7, 0x94, 0x9a, 0xd0, 0xf0, 0x37, 0x94, 0xe1, 0x4f, 0x94,
|
||||
0x27, 0x6d, 0x8f, 0xb5, 0x76, 0x43, 0x31, 0x0c, 0x40, 0x55, 0x66, 0x58, 0xca, 0xb4, 0x75, 0x0d,
|
||||
0xd3, 0x5e, 0xa6, 0xad, 0xb3, 0xce, 0x03, 0x25, 0xf1, 0x89, 0x6d, 0xbd, 0xca, 0x0e, 0xfd, 0x7d,
|
||||
0xc3, 0x6c, 0x46, 0xe9, 0x5e, 0x30, 0xe4, 0xea, 0x96, 0x35, 0xd7, 0xba, 0xd8, 0xce, 0x64, 0x51,
|
||||
0x28, 0xa1, 0xc0, 0x93, 0x60, 0x28, 0x2a, 0xae, 0x11, 0x92, 0x4b, 0x2c, 0xb7, 0xe1, 0x92, 0x43,
|
||||
0x47, 0xd2, 0x22, 0x41, 0xf3, 0xe7, 0x3d, 0x9c, 0x32, 0x1b, 0x1c, 0x1e, 0xc0, 0x35, 0xce, 0xdf,
|
||||
0x9d, 0x38, 0xb2, 0x8e, 0x05, 0x4e, 0x3c, 0x89, 0x51, 0x36, 0xd0, 0x18, 0xd5, 0x03, 0x0f, 0xf0,
|
||||
0xad, 0x2c, 0xb5, 0x1d, 0x19, 0x85, 0x86, 0xb2, 0x05, 0xed, 0xd2, 0x99, 0x49, 0x32, 0xb8, 0x41,
|
||||
0xcd, 0x12, 0x20, 0xfb, 0x00, 0x2d, 0x23, 0x75, 0x3c, 0x49, 0xff, 0xe3, 0x30, 0x92, 0x83, 0xb5,
|
||||
0xcf, 0x67, 0x74, 0x39, 0x8c, 0xd8, 0x24, 0x81, 0x55, 0x6c, 0x51, 0x82, 0x58, 0x31, 0x86, 0x9a,
|
||||
0xe0, 0xa2, 0xe9, 0x42, 0xb8, 0x68, 0xab, 0xaa, 0x82, 0x9d, 0x49, 0xb8, 0x93, 0x05, 0xfa, 0x0b,
|
||||
0x71, 0xd9, 0x5c, 0x16, 0x76, 0x67, 0xa8, 0x77, 0x46, 0x94, 0x3b, 0x0b, 0x94, 0x86, 0xc5, 0x11,
|
||||
0x86, 0x64, 0xa3, 0x3a, 0x4a, 0xd0, 0xc8, 0x17, 0x73, 0x99, 0x69, 0x5e, 0x38, 0xf4, 0xe9, 0x4a,
|
||||
0x71, 0x66, 0xbf, 0x9d, 0x08, 0xc7, 0xcd, 0xc8, 0xf7, 0xd6, 0x2b, 0x5e, 0xc3, 0x4f, 0x60, 0x19,
|
||||
0x5f, 0xb3, 0xf8, 0xab, 0xbd, 0x04, 0x53, 0x5b, 0xb0, 0x2a, 0x0c, 0x35, 0xa1, 0x8b, 0x84, 0xc8,
|
||||
0x62, 0xc4, 0xd6, 0x52, 0xe4, 0x57, 0xe9, 0x21, 0x3c, 0x56, 0x9b, 0x5a, 0xf7, 0xa6, 0x9e, 0x66,
|
||||
0x6f, 0xec, 0x7b, 0x22, 0x9c, 0x37, 0x94, 0x73, 0x68, 0x38, 0x26, 0xd3, 0xdb, 0x8c, 0xc3, 0x22,
|
||||
0x3c, 0xcc, 0x59, 0x23, 0x5c, 0x4c, 0x7d, 0x7b, 0xef, 0xe6, 0x44, 0x11, 0xfe, 0x01, 0x7d, 0x90,
|
||||
0x45, 0x5a, 0x04, 0x41, 0x0c, 0x46, 0x83, 0xbb, 0xbb, 0xed, 0x38, 0xc0, 0xc8, 0x09, 0xd8, 0xe2,
|
||||
0x70, 0x81, 0xb4, 0x65, 0x20, 0x2d, 0x95, 0x26, 0x55, 0xe8, 0xe9, 0xa9, 0x71, 0x9f, 0xee, 0x72,
|
||||
0x7b, 0xff, 0xf7, 0xc0, 0x70, 0x14, 0xe5, 0x84, 0x7f, 0xa4, 0x82, 0xb1, 0x18, 0x43, 0xb1, 0xc3,
|
||||
0x58, 0x8a, 0x32, 0x34, 0x2c, 0x06, 0x35, 0x4c, 0x58, 0xb0, 0x79, 0x00, 0xae, 0x1b, 0x9f, 0x79,
|
||||
0xee, 0xbb, 0x4f, 0x1b, 0xf9, 0xf6, 0x9b, 0x1b, 0x8c, 0x70, 0xa8, 0x54, 0x52, 0xe8, 0x48, 0x11,
|
||||
0xae, 0x22, 0xe5, 0xe4, 0x8d, 0x90, 0x6c, 0x69, 0xe4, 0x1b, 0xe1, 0x48, 0xa4, 0x40, 0x4b, 0xfa,
|
||||
0xd5, 0xdc, 0x3c, 0x74, 0xa4, 0x05, 0x9b, 0x30, 0xc7, 0xf8, 0x3d, 0x74, 0x08, 0xf0, 0xac, 0xf2,
|
||||
0xc0, 0xb1, 0xca, 0x24, 0x14, 0x9c, 0x79, 0x04, 0xac, 0x65, 0x6c, 0x2d, 0x16, 0x92, 0x50, 0x01,
|
||||
0x6b, 0x5d, 0x0c, 0xec, 0x61, 0x07, 0xa3, 0xb6, 0x56, 0xaf, 0x35, 0xdf, 0xe7, 0x30, 0xaf, 0xc2,
|
||||
0x7e, 0x2e, 0x1a, 0xa2, 0xb8, 0x10, 0x8d, 0x20, 0xfd, 0x38, 0xd2, 0x26, 0xcb, 0x92, 0xb1, 0xa2,
|
||||
0x16, 0xd6, 0xfb, 0x51, 0x60, 0xad, 0xb5, 0xe8, 0xfb, 0xa1, 0x44, 0x00, 0xaf, 0xd5, 0x47, 0x9a,
|
||||
0x9c, 0xe6, 0xb8, 0x99, 0x66, 0x79, 0x20, 0xcd, 0x72, 0x2f, 0xcd, 0x36, 0xce, 0xe4, 0xae, 0x0c,
|
||||
0x70, 0x97, 0x3b, 0xdc, 0xe5, 0x61, 0xee, 0xdc, 0xcd, 0x1d, 0xd6, 0xab, 0xd5, 0xda, 0x64, 0x0f,
|
||||
0x4d, 0xe3, 0x6d, 0x1b, 0x67, 0x4d, 0xdf, 0xb3, 0x9c, 0xf4, 0xd5, 0xc3, 0x59, 0xcb, 0x0d, 0xec,
|
||||
0x4b, 0xd4, 0xd1, 0x5f, 0x7c, 0x38, 0x37, 0x24, 0xe1, 0x1f, 0x62, 0x08, 0x72, 0xf4, 0x06, 0x10,
|
||||
0x3e, 0xdd, 0x58, 0x0a, 0xc4, 0x30, 0x54, 0x9b, 0x77, 0x5a, 0xba, 0x39, 0xc0, 0xd6, 0x93, 0x7d,
|
||||
0x1d, 0x3d, 0x07, 0xb1, 0xf8, 0x61, 0x5b, 0x20, 0x8b, 0x70, 0xfb, 0xcd, 0xa1, 0x83, 0x4a, 0xf1,
|
||||
0x27, 0x9c, 0x86, 0x61, 0x44, 0x61, 0xce, 0x58, 0x49, 0x8e, 0x24, 0xc8, 0xee, 0xa7, 0xc9, 0x7b,
|
||||
0x55, 0x68, 0x2a, 0x95, 0xca, 0x02, 0x8d, 0x92, 0xe4, 0x58, 0x6c, 0x42, 0xbf, 0xb1, 0x0a, 0x0f,
|
||||
0x73, 0x3f, 0xa0, 0xd0, 0x8e, 0xac, 0x92, 0x60, 0x62, 0xb1, 0xc8, 0x6a, 0xb1, 0x30, 0xd2, 0x59,
|
||||
0x49, 0x3e, 0xff, 0xbe, 0x81, 0x15, 0x56, 0x62, 0xb7, 0xc3, 0x34, 0xf5, 0x23, 0x9e, 0xc6, 0x65,
|
||||
0x3f, 0x98, 0xbf, 0x6f, 0x58, 0x1d, 0x4a, 0x5c, 0x47, 0x0a, 0xff, 0x9b, 0xfb, 0xd9, 0x4c, 0x03,
|
||||
0x7a, 0xce, 0x3b, 0x5b, 0x22, 0x17, 0x14, 0x1b, 0x22, 0xa3, 0x4b, 0x04, 0x2d, 0xe9, 0x86, 0xa4,
|
||||
0x90, 0x42, 0xbb, 0x3e, 0xa4, 0x04, 0xed, 0xa1, 0x3a, 0x68, 0xb6, 0xb1, 0x56, 0xcc, 0x1c, 0x28,
|
||||
0x43, 0xf3, 0xe7, 0xc6, 0x49, 0x0c, 0xaf, 0x84, 0x52, 0xc7, 0x69, 0xfc, 0x0c, 0x15, 0x6d, 0x1a,
|
||||
0x2e, 0x5b, 0x7c, 0x19, 0xaf, 0x44, 0xb8, 0x1e, 0x70, 0xe9, 0xfb, 0x01, 0x6b, 0x62, 0x45, 0xff,
|
||||
0x1f, 0xa7, 0xfd, 0xd0, 0x0f, 0x1f, 0x7f, 0x14, 0x48, 0x90, 0x4b, 0x7a, 0x5f, 0x25, 0x16, 0x2f,
|
||||
0x0b, 0xa1, 0x87, 0x0a, 0x17, 0x52, 0x5c, 0xc0, 0x3c, 0x8d, 0xdf, 0x79, 0xa2, 0x78, 0x65, 0x01,
|
||||
0xb4, 0x4f, 0x03, 0x8f, 0x05, 0x41, 0x0c, 0xee, 0xd9, 0xb6, 0x1d, 0x9e, 0x15, 0x27, 0x67, 0x9b,
|
||||
0x71, 0x33, 0x58, 0xcc, 0x5b, 0x74, 0xd3, 0x99, 0x87, 0x7f, 0x7f, 0xb6, 0xc2, 0x0b, 0xea, 0x7e,
|
||||
0x80, 0x8b, 0xf5, 0x43, 0x5c, 0x5e, 0x5d, 0x5a, 0x40, 0xeb, 0xa5, 0x96, 0x18, 0x63, 0x62, 0x81,
|
||||
0xe4, 0x04, 0xa6, 0x84, 0x5e, 0xc9, 0x79, 0x9c, 0x8a, 0xf8, 0x65, 0x67, 0xa1, 0xee, 0xa1, 0x4f,
|
||||
0xcc, 0xe3, 0x44, 0x85, 0xc2, 0x41, 0xe5, 0xad, 0xb1, 0xc7, 0x9e, 0x0d, 0xf1, 0x4a, 0x04, 0xa8,
|
||||
0x28, 0xc9, 0x44, 0x6a, 0x28, 0x45, 0x16, 0xda, 0x10, 0xca, 0xd8, 0x83, 0xd1, 0xbc, 0x95, 0xd0,
|
||||
0x1a, 0x19, 0x6b, 0x31, 0x21, 0xed, 0x25, 0xd0, 0xca, 0x5e, 0xe6, 0x09, 0xe7, 0x31, 0xf4, 0xfe,
|
||||
0xcd, 0xd4, 0x46, 0x94, 0x3c, 0x34, 0x5c, 0xf0, 0x18, 0x5a, 0x9f, 0x87, 0x00, 0x97, 0x0f, 0xd9,
|
||||
0xdb, 0x14, 0x19, 0x5e, 0x52, 0x2c, 0x18, 0xdf, 0xb0, 0x6a, 0xf7, 0x53, 0x6d, 0x94, 0x70, 0xc4,
|
||||
0x33, 0xdb, 0x97, 0x67, 0x27, 0x54, 0x7c, 0x12, 0xf3, 0xa2, 0xe3, 0x51, 0x42, 0xfb, 0x11, 0x5d,
|
||||
0x88, 0x99, 0x93, 0x85, 0xd5, 0x8b, 0xc5, 0x2f, 0x2b, 0x2c, 0x1a, 0xdf, 0x40, 0xf7, 0xd7, 0x87,
|
||||
0xa9, 0xe7, 0x39, 0xd8, 0x47, 0xa2, 0x92, 0x11, 0x84, 0x4b, 0xf3, 0x97, 0x3f, 0x5a, 0x1c, 0x7e,
|
||||
0x3c, 0x6f, 0xfe, 0x60, 0xb1, 0xf9, 0x4d, 0x56, 0x37, 0x4a, 0x36, 0x3a, 0xf0, 0x90, 0xed, 0xe2,
|
||||
0xd2, 0x22, 0xb4, 0x7c, 0xb0, 0xd4, 0xf7, 0xe6, 0x1e, 0x1a, 0x96, 0xfe, 0x09, 0x18, 0x2e, 0x9d,
|
||||
0x70, 0x8f, 0x98, 0xf7, 0x73, 0x37, 0x02, 0x0a, 0xa6, 0xa7, 0x67, 0xe6, 0xa5, 0x23, 0x82, 0x0c,
|
||||
0x00, 0x6d, 0x51, 0x03, 0x8f, 0xc4, 0x50, 0x10, 0x9e, 0xe8, 0x6c, 0x5b, 0xd1, 0x19, 0xab, 0x18,
|
||||
0xe7, 0xf8, 0x8c, 0x70, 0x52, 0xcc, 0x36, 0xaf, 0x9a, 0x3e, 0x2c, 0xfe, 0xfd, 0x9a, 0x4d, 0xc3,
|
||||
0xf1, 0x7c, 0x80, 0x2f, 0x63, 0x19, 0xc1, 0x31, 0xbe, 0xe6, 0x30, 0x64, 0xcf, 0x13, 0xb1, 0x87,
|
||||
0x8a, 0x12, 0xb2, 0x0c, 0x29, 0xb4, 0x95, 0x70, 0x3d, 0x42, 0xd2, 0x49, 0xcc, 0x35, 0x98, 0xed,
|
||||
0xd7, 0x61, 0x35, 0xd5, 0x99, 0xce, 0xe3, 0xf3, 0xd7, 0x7b, 0x3e, 0x87, 0x0e, 0x47, 0x89, 0x15,
|
||||
0xb7, 0xcf, 0x29, 0xcb, 0x15, 0x8c, 0x76, 0x48, 0x70, 0x5c, 0xae, 0x84, 0x21, 0x1c, 0x57, 0xb4,
|
||||
0x0d, 0xc7, 0x35, 0x51, 0x16, 0xb0, 0x1c, 0x08, 0xad, 0x31, 0x62, 0x97, 0x22, 0x58, 0x4e, 0xff,
|
||||
0x84, 0x65, 0x95, 0x1b, 0x26, 0x7b, 0xc8, 0xb6, 0x26, 0x55, 0x25, 0x85, 0x91, 0x34, 0x06, 0xd6,
|
||||
0x99, 0x23, 0xec, 0x16, 0xe0, 0x30, 0xd5, 0x5b, 0xd3, 0x14, 0x6b, 0x56, 0xb0, 0xd2, 0x5f, 0xde,
|
||||
0x4e, 0x0d, 0xac, 0xf4, 0x97, 0x33, 0x0e, 0x2f, 0xf7, 0x96, 0xc1, 0xdc, 0xdd, 0xde, 0xde, 0x52,
|
||||
0x26, 0x91, 0xcd, 0x36, 0x85, 0xc9, 0x11, 0xf0, 0x93, 0x03, 0x9c, 0x8b, 0x18, 0xb2, 0xb2, 0x90,
|
||||
0x8d, 0x85, 0x31, 0x23, 0xd5, 0x5b, 0xb5, 0xd8, 0x0a, 0xb1, 0x7b, 0x54, 0xc3, 0xd4, 0xc8, 0xe7,
|
||||
0xc9, 0xfe, 0xa7, 0x6f, 0x7c, 0x20, 0x2b, 0xc2, 0xaf, 0x3c, 0x7e, 0x55, 0x12, 0x45, 0x11, 0xe1,
|
||||
0xd7, 0xff, 0x5d, 0xae, 0x94, 0x2d, 0xe2, 0x25, 0x26, 0x1a, 0xce, 0x3a, 0xf2, 0x6d, 0x8f, 0x20,
|
||||
0xd8, 0x1e, 0x20, 0x38, 0x4e, 0x59, 0x72, 0x32, 0xce, 0x6f, 0x67, 0x04, 0x41, 0x13, 0xb5, 0x50,
|
||||
0xb5, 0x56, 0x05, 0x31, 0x10, 0x9d, 0x2d, 0x71, 0x77, 0xfd, 0x04, 0x1c, 0x6a, 0x68, 0x71, 0xef,
|
||||
0xee, 0x59, 0x99, 0x07, 0x39, 0x2f, 0x2e, 0x2c, 0x7f, 0x8f, 0xbb, 0x6b, 0x95, 0x8c, 0x5d, 0xa3,
|
||||
0x7d, 0xac, 0x72, 0xae, 0xb0, 0x37, 0x8f, 0xbd, 0x64, 0x3d, 0x2b, 0xc6, 0xde, 0xf1, 0xec, 0xdc,
|
||||
0xd2, 0x1c, 0xbc, 0x31, 0x0a, 0x81, 0xfd, 0x19, 0x7b, 0x98, 0xe2, 0xee, 0xa3, 0x5c, 0x8c, 0x94,
|
||||
0x15, 0x9c, 0xab, 0xfb, 0xb5, 0xd2, 0x28, 0x9b, 0x6b, 0x61, 0x34, 0x7c, 0x5e, 0x09, 0x83, 0x42,
|
||||
0x32, 0x4d, 0xc3, 0x06, 0xea, 0x68, 0x8a, 0x10, 0xa0, 0x4c, 0xc5, 0x8a, 0x3a, 0x3c, 0x5b, 0xce,
|
||||
0x23, 0x7b, 0x1a, 0x78, 0x81, 0xd5, 0xf9, 0xc8, 0x42, 0xc3, 0x2f, 0x66, 0xad, 0xcb, 0x4b, 0xff,
|
||||
0x09, 0x9f, 0xb1, 0x0e, 0x31, 0xf7, 0x58, 0x9b, 0x47, 0x38, 0xbf, 0xf1, 0xf2, 0x04, 0xb2, 0xf7,
|
||||
0x01, 0x72, 0x14, 0x85, 0x17, 0xd5, 0x09, 0x83, 0x83, 0xd5, 0xa6, 0xa6, 0xee, 0x95, 0xaf, 0xed,
|
||||
0x65, 0xa7, 0x42, 0x37, 0x37, 0x4d, 0xc5, 0xd8, 0x98, 0x7d, 0xd3, 0xc6, 0x44, 0x0a, 0xc5, 0x3b,
|
||||
0x36, 0x9e, 0xca, 0x6e, 0x9b, 0x7b, 0xfb, 0xba, 0x91, 0xa4, 0xa4, 0x89, 0xab, 0x25, 0x91, 0xcb,
|
||||
0x5b, 0xac, 0x89, 0x5a, 0x34, 0xc4, 0x73, 0xc4, 0xdd, 0xc7, 0x60, 0x9e, 0xab, 0xbb, 0x04, 0x95,
|
||||
0xd0, 0x41, 0x4b, 0xc4, 0x30, 0x10, 0x05, 0xe0, 0xb9, 0x97, 0x7a, 0x13, 0xbc, 0x14, 0xfc, 0x0d,
|
||||
0x8a, 0x8a, 0x3f, 0x42, 0x0f, 0xe2, 0xfd, 0x91, 0x6e, 0xdf, 0xda, 0xb0, 0x49, 0xa6, 0xce, 0x64,
|
||||
0x5d, 0x7f, 0xbe, 0x68, 0x0f, 0x6e, 0x21, 0x08, 0x9e, 0x43, 0xde, 0xf7, 0xde, 0xc8, 0xeb, 0x1c,
|
||||
0xcb, 0xe1, 0x59, 0x27, 0xe2, 0xe9, 0x06, 0xa6, 0x9a, 0xe1, 0xb4, 0x0f, 0x9a, 0xf4, 0x95, 0x96,
|
||||
0x63, 0x09, 0x09, 0xbb, 0x39, 0x54, 0xe9, 0x6e, 0xb1, 0xd3, 0xbc, 0x84, 0x12, 0xb5, 0xc0, 0xc2,
|
||||
0x14, 0x15, 0x63, 0xa2, 0x0c, 0x47, 0x1f, 0xa5, 0x3f, 0x44, 0x77, 0x64, 0x9d, 0x98, 0xa5, 0x37,
|
||||
0x2e, 0x0c, 0x95, 0x26, 0x97, 0x48, 0x6a, 0x01, 0x5a, 0x03, 0x8a, 0x82, 0x9f, 0x95, 0xf6, 0x9d,
|
||||
0xe6, 0x2c, 0xae, 0xe6, 0x72, 0x71, 0x66, 0x75, 0x77, 0xcd, 0xf0, 0x6b, 0x2c, 0x2e, 0xc3, 0xfe,
|
||||
0x98, 0x92, 0x0c, 0x4e, 0x8b, 0x21, 0xad, 0xde, 0x70, 0x8a, 0xfb, 0xb8, 0x55, 0x5f, 0x7e, 0xd5,
|
||||
0xd1, 0xe2, 0xf4, 0x46, 0xd0, 0x97, 0xa2, 0x27, 0xe9, 0xff, 0xda, 0x74, 0xff, 0xdf, 0x4d, 0x9b,
|
||||
0xd2, 0x0f, 0xed, 0xdf, 0xac, 0x33, 0xad, 0xb0, 0xae, 0xcd, 0xdb, 0x8d, 0xb7, 0x77, 0xd2, 0x71,
|
||||
0x8d, 0x44, 0x7e, 0xaf, 0x75, 0x63, 0x5c, 0x61, 0xfb, 0xd6, 0x3d, 0xb6, 0x4c, 0xfc, 0x20, 0x58,
|
||||
0x15, 0xb4, 0x19, 0x9c, 0xe7, 0x42, 0xbe, 0x00, 0x6c, 0x50, 0x35, 0x76, 0xc3, 0x60, 0x0c, 0x56,
|
||||
0xe6, 0x32, 0x33, 0xe3, 0x16, 0xbe, 0x40, 0x99, 0x96, 0x72, 0x3b, 0xe9, 0xc9, 0xb1, 0x5e, 0x6b,
|
||||
0x94, 0x7f, 0x08, 0x1c, 0x3f, 0xcc, 0x9e, 0xc4, 0xfa, 0x00, 0xbe, 0xa9, 0xc6, 0xe6, 0x9f, 0x34,
|
||||
0xe3, 0x7b, 0x11, 0x5f, 0xde, 0xf2, 0xf9, 0x42, 0x1e, 0x2b, 0x12, 0x25, 0x14, 0x7b, 0x12, 0xa3,
|
||||
0x26, 0xd7, 0x13, 0x74, 0x42, 0x86, 0xd3, 0xaa, 0x71, 0x60, 0x35, 0xf0, 0x8c, 0xc1, 0x48, 0x5c,
|
||||
0x8e, 0x60, 0x35, 0x21, 0x6d, 0x3d, 0xdb, 0xde, 0xe2, 0x46, 0x6b, 0xdd, 0x65, 0x8d, 0x9a, 0x13,
|
||||
0x26, 0xdb, 0x4a, 0xc4, 0x31, 0xac, 0x6b, 0xad, 0x24, 0x52, 0xd6, 0xc2, 0xa5, 0x48, 0x84, 0xed,
|
||||
0xc6, 0xd4, 0x64, 0xb5, 0x7f, 0x01, 0xbb, 0x13, 0x93, 0xb5, 0xe1, 0x0d, 0x1c, 0x4c, 0xcc, 0x32,
|
||||
0x0f, 0xbf, 0x85, 0x5c, 0xa1, 0x8c, 0x0e, 0xb9, 0x7f, 0x9c, 0xc6, 0x16, 0x61, 0x7e, 0x40, 0x05,
|
||||
0x32, 0xad, 0xde, 0x87, 0xa6, 0x4a, 0xd0, 0x2a, 0x5e, 0x0a, 0xa9, 0xe2, 0x0e, 0xda, 0xe2, 0x16,
|
||||
0x06, 0x5c, 0x16, 0x47, 0xb0, 0xa1, 0xde, 0xda, 0xa9, 0x47, 0xf9, 0x7c, 0x3e, 0x87, 0x83, 0x05,
|
||||
0xf8, 0xf6, 0xa4, 0xf7, 0xf2, 0x25, 0xdd, 0xae, 0xbd, 0xf6, 0xc7, 0xb9, 0x11, 0xbb, 0xe6, 0x06,
|
||||
0xc7, 0x6b, 0x18, 0x8a, 0x26, 0x14, 0x4b, 0x18, 0x0b, 0x72, 0xa3, 0xd5, 0x8b, 0x29, 0x44, 0xc3,
|
||||
0xb1, 0x11, 0x6d, 0x60, 0x7e, 0x04, 0x7c, 0xf6, 0xd6, 0x8b, 0x83, 0xd4, 0xff, 0x4b, 0x23, 0xaf,
|
||||
0xe1, 0xc7, 0x23, 0xc1, 0xeb, 0x62, 0xea, 0xe2, 0x0e, 0x26, 0x06, 0x36, 0x9b, 0x03, 0xb9, 0x46,
|
||||
0xa2, 0x3c, 0x33, 0x2d, 0x93, 0x81, 0x03, 0x49, 0x23, 0x00, 0x6d, 0x8f, 0x05, 0x72, 0x03, 0x31,
|
||||
0x0c, 0x45, 0x55, 0x0e, 0x94, 0x99, 0x7b, 0x86, 0xe2, 0x05, 0x3a, 0xd4, 0x81, 0x32, 0x0d, 0x6a,
|
||||
0x16, 0xb4, 0xad, 0x97, 0xe4, 0x48, 0x0e, 0xdc, 0x3e, 0xcc, 0xc9, 0x80, 0xf9, 0xff, 0xf7, 0x0c,
|
||||
0xbf, 0xc6, 0x63, 0x7c, 0xbc, 0x45, 0x21, 0x4b, 0x9e, 0x23, 0x81, 0x22, 0x73, 0x86, 0x4a, 0x52,
|
||||
0x23, 0x81, 0xd5, 0x07, 0x0c, 0x38, 0xb3, 0x5e, 0x6e, 0x38, 0x47, 0xf1, 0x42, 0xc3, 0xe8, 0xa7,
|
||||
0x84, 0x50, 0x48, 0x8c, 0x2a, 0x66, 0x1c, 0x52, 0x06, 0x85, 0x41, 0x12, 0x61, 0x25, 0x97, 0xe8,
|
||||
0xfe, 0x66, 0x5e, 0x04, 0xce, 0xaa, 0xea, 0x43, 0x79, 0x2c, 0x56, 0x1e, 0x02, 0xf7, 0xd0, 0x17,
|
||||
0x13, 0xfe, 0x11, 0x8a, 0xde, 0xdc, 0xde, 0xc0, 0xfa, 0x18, 0x7f, 0xe5, 0xe3, 0x76, 0x7e, 0x1b,
|
||||
0x5a, 0x85, 0xe3, 0x4e, 0xe5, 0x5c, 0x13, 0xd8, 0x1e, 0x54, 0x92, 0xda, 0x9c, 0xeb, 0xb0, 0xc3,
|
||||
0x7e, 0xaf, 0x11, 0xb3, 0x8a, 0x73, 0x13, 0x5f, 0xdc, 0xc3, 0xc9, 0xbb, 0x82, 0x52, 0xae, 0x2c,
|
||||
0x50, 0xf8, 0x79, 0x7a, 0x99, 0xcb, 0xbe, 0xea, 0xb0, 0xcf, 0xa3, 0x6a, 0x9a, 0xc2, 0xb9, 0x92,
|
||||
0x18, 0xaf, 0x3d, 0x77, 0x4c, 0xce, 0xeb, 0x26, 0x32, 0xb0, 0x3e, 0xe6, 0xb3, 0x6e, 0x3d, 0x71,
|
||||
0xc6, 0x75, 0xe2, 0xd4, 0x68, 0xf7, 0x84, 0x24, 0xb0, 0x3e, 0x74, 0xdc, 0x9f, 0x72, 0x3c, 0x98,
|
||||
0xf4, 0xd8, 0x18, 0x73, 0x3c, 0x9a, 0x72, 0x5c, 0xef, 0x3b, 0xae, 0x3b, 0x92, 0xcc, 0xe4, 0x5e,
|
||||
0x8a, 0xc1, 0xbf, 0xe7, 0xa0, 0x05,
|
||||
};
|
||||
#endif
|
||||
for (unsigned i = 0; i < sizeof(IDS) / sizeof(IDS[0]); i++) {
|
||||
if (IDS[i] != target_id) continue;
|
||||
unsigned group = 0;
|
||||
while (i >= FIRSTS[group + 1]) group++;
|
||||
uint8_t raw[512];
|
||||
unsigned int produced = sizeof raw;
|
||||
#if defined(OTA_RAK15002_SD_STORE) && defined(COMPANION_RADIO_FULL)
|
||||
// Rare display lookup: larger chunks save flash without growing the loop stack.
|
||||
uint8_t* raw = (uint8_t*)malloc(DECODE_CHUNK_BYTES);
|
||||
if (!raw) return nullptr;
|
||||
struct Scratch { uint8_t* bytes; ~Scratch() { free(bytes); } } scratch = {raw};
|
||||
#else
|
||||
uint8_t raw[DECODE_CHUNK_BYTES];
|
||||
#endif
|
||||
unsigned int produced = DECODE_CHUNK_BYTES;
|
||||
if (tinf_uncompress_exact(raw, &produced, NAMES + OFFSETS[group],
|
||||
OFFSETS[group + 1] - OFFSETS[group]) != TINF_OK ||
|
||||
produced != RAW_LENGTHS[group]) return nullptr;
|
||||
@@ -563,6 +784,7 @@ inline const char* ota_target_env_name(uint32_t target_id) {
|
||||
{ 0xb62a1e75, "heltec_tracker_v2_kiss_modem" },
|
||||
{ 0x9e64845d, "heltec_tracker_v2_repeater" },
|
||||
{ 0x19232e8b, "heltec_tracker_v2_repeater_bridge_espnow" },
|
||||
{ 0x10f41878, "heltec_tracker_v2_repeater_bridge_rs232" },
|
||||
{ 0xfaf164f4, "heltec_tracker_v2_repeater_observer_mqtt" },
|
||||
{ 0x38b948b4, "heltec_tracker_v2_room_server" },
|
||||
{ 0x462ddb9b, "heltec_tracker_v2_room_server_observer_mqtt" },
|
||||
@@ -605,6 +827,7 @@ inline const char* ota_target_env_name(uint32_t target_id) {
|
||||
{ 0xb016979a, "heltec_v4_3_tft_companion_radio_usb_femoff" },
|
||||
{ 0xb49b6b55, "heltec_v4_3_tft_companion_radio_wifi_femoff" },
|
||||
{ 0x01d8f124, "heltec_v4_companion_radio_ble" },
|
||||
{ 0x64140fd9, "heltec_v4_companion_radio_ble_femoff" },
|
||||
{ 0x86fb85f0, "heltec_v4_companion_radio_ble_femon" },
|
||||
{ 0xd33b0986, "heltec_v4_companion_radio_ble_ps_femon" },
|
||||
{ 0x1a4d0096, "heltec_v4_companion_radio_usb" },
|
||||
@@ -848,6 +1071,9 @@ inline const char* ota_target_env_name(uint32_t target_id) {
|
||||
{ 0x49d11eca, "MKE_s3_room_server" },
|
||||
{ 0xd41f0638, "MKE_s3_sensor" },
|
||||
{ 0xe3105eb8, "MKE_s3_terminal_chat" },
|
||||
{ 0xba76cc33, "morse_bench_rak4631_companion" },
|
||||
{ 0x944263f8, "morse_bench_t096_companion" },
|
||||
{ 0xc7a8c754, "morse_production_rak4631_companion" },
|
||||
{ 0xf8259880, "Nano_G2_Ultra_repeater" },
|
||||
{ 0x063f1f00, "nibble_screen_connect_companion_radio_ble_" },
|
||||
{ 0x70d71f92, "nibble_screen_connect_companion_radio_full_" },
|
||||
@@ -908,8 +1134,12 @@ inline const char* ota_target_env_name(uint32_t target_id) {
|
||||
{ 0x41e33a97, "RAK_4631_repeater_bridge_rs232_serial2_lora_ota_no_external_sensors" },
|
||||
{ 0x29a0da19, "RAK_4631_repeater_lora_ota_no_external_sensors" },
|
||||
{ 0x29bc38dc, "RAK_4631_repeater_rak15001_slot_c_lora_ota" },
|
||||
{ 0xd5fc71d4, "RAK_4631_repeater_rak15002_sd_seeder_only" },
|
||||
{ 0x05f5ffae, "RAK_4631_repeater_unified_lora_ota" },
|
||||
{ 0xc62da371, "RAK_4631_repeater_w25q16_lora_ota" },
|
||||
{ 0x96fc4c26, "RAK_4631_room_server_ethernet_lora_ota_no_external_sensors" },
|
||||
{ 0x8a6dc63b, "RAK_4631_room_server_lora_ota_no_external_sensors" },
|
||||
{ 0xb48950bb, "RAK_4631_sensor_lora_ota_no_external_sensors" },
|
||||
{ 0xf1d3c5a8, "RAK_4631_terminal_chat" },
|
||||
{ 0xc6d55752, "RAK_WisMesh_Tag_companion_radio_ble" },
|
||||
{ 0x60683191, "RAK_WisMesh_Tag_companion_radio_usb" },
|
||||
@@ -951,10 +1181,12 @@ inline const char* ota_target_env_name(uint32_t target_id) {
|
||||
{ 0xd62ed92e, "Station_G3_ESP32_r2_repeater_observer_mqtt" },
|
||||
{ 0x7abaf0d5, "Station_G3_ESP32_r2_room_server" },
|
||||
{ 0x87edc08b, "Station_G3_ESP32_r2_room_server_observer_mqtt" },
|
||||
{ 0xc50b0e48, "Station_G3_ESP32_r2_sensor" },
|
||||
{ 0x3c49caf8, "Station_G3_ESP32_repeater" },
|
||||
{ 0x58689ef9, "Station_G3_ESP32_repeater_observer_mqtt" },
|
||||
{ 0x91878dd8, "Station_G3_ESP32_room_server" },
|
||||
{ 0x72a93c45, "Station_G3_ESP32_room_server_observer_mqtt" },
|
||||
{ 0x347e087a, "Station_G3_ESP32_sensor" },
|
||||
{ 0x4dbf035e, "t1000e_companion_radio_ble" },
|
||||
{ 0xff4102d6, "t1000e_companion_radio_usb" },
|
||||
{ 0x2f9a9185, "t1000e_kiss_modem" },
|
||||
@@ -1044,8 +1276,21 @@ inline const char* ota_target_env_name(uint32_t target_id) {
|
||||
{ 0x7190df40, "ThinkNode_M9_kiss_modem" },
|
||||
{ 0x609d50b3, "ThinkNode_M9_repeater_" },
|
||||
{ 0x5718c7ea, "ThinkNode_M9_room_server_" },
|
||||
{ 0x7bbf1081, "Waveshare_S3_LR1121_companion_radio_ble" },
|
||||
{ 0xb151c2aa, "Waveshare_S3_LR1121_companion_radio_usb" },
|
||||
{ 0x3b0174fd, "Waveshare_S3_LR1121_kiss_modem" },
|
||||
{ 0xc1fd2578, "Waveshare_S3_LR1121_partition_expander_repeater_observer_mqtt" },
|
||||
{ 0xeb440352, "Waveshare_S3_LR1121_partition_expander_room_server_observer_mqtt" },
|
||||
{ 0xa297f85a, "Waveshare_S3_LR1121_repeater" },
|
||||
{ 0xcbe54778, "Waveshare_S3_LR1121_repeater_observer_mqtt" },
|
||||
{ 0x0343bdf0, "Waveshare_S3_LR1121_room_server" },
|
||||
{ 0x3de413b1, "Waveshare_S3_LR1121_room_server_observer_mqtt" },
|
||||
{ 0x37443a5b, "WHY2025_badge_companion_radio_ble_" },
|
||||
{ 0x603384a7, "WHY2025_badge_repeater_" },
|
||||
{ 0x76456c88, "Wio_Tracker_L2_companion_radio_ble" },
|
||||
{ 0x28c4948b, "Wio_Tracker_L2_companion_radio_usb" },
|
||||
{ 0xb34a83c5, "Wio_Tracker_L2_repeater" },
|
||||
{ 0x63fe9591, "Wio_Tracker_L2_room_server" },
|
||||
{ 0xce3ef40f, "wio_wm1110_repeater" },
|
||||
{ 0x475a2a6a, "WioTrackerL1_companion_radio_ble" },
|
||||
{ 0xf4175d2c, "WioTrackerL1_companion_radio_usb" },
|
||||
|
||||
@@ -1383,7 +1383,7 @@ uint8_t EnvironmentSensorManager::detectWisBlockStorageHolds() {
|
||||
|| (w25_id != 0 && w25_id != 0xFFFFFFUL)) {
|
||||
holds |= mesh::gps::ExternalStorage;
|
||||
}
|
||||
#elif defined(OTA_QSPI_SHARED_WISBLOCK_SPI) || (defined(OTA_SD_STORE) && !defined(OTA_RAK15002_SD_CACHE))
|
||||
#elif defined(OTA_QSPI_SHARED_WISBLOCK_SPI) || (defined(OTA_SD_STORE) && !defined(OTA_RAK15002_SD_CACHE) && !defined(OTA_RAK15002_SD_STORE))
|
||||
holds |= mesh::gps::ExternalStorage;
|
||||
#endif
|
||||
// Exact RAK15002 uses connector pin 5 (unswitched 3V3), not 3V3_S. Its
|
||||
|
||||
Reference in new issue
Block a user