mirror of https://github.com/LaskaKit/ESPlan.git
updated
parent
71a2c4fe37
commit
b350b06595
|
|
@ -0,0 +1,70 @@
|
|||
#include <Arduino.h>
|
||||
|
||||
extern "C" {
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_system.h"
|
||||
}
|
||||
|
||||
static bool isVddSdioFixedTo3v3(){
|
||||
bool force = esp_efuse_read_field_bit(ESP_EFUSE_XPD_SDIO_FORCE);
|
||||
bool reg = esp_efuse_read_field_bit(ESP_EFUSE_XPD_SDIO_REG);
|
||||
bool tieh = esp_efuse_read_field_bit(ESP_EFUSE_XPD_SDIO_TIEH);
|
||||
|
||||
return force && reg && tieh;
|
||||
}
|
||||
|
||||
static void burnVddSdio3v3Once(){
|
||||
Serial.println();
|
||||
Serial.println("Checking VDD_SDIO eFuse...");
|
||||
|
||||
bool force = esp_efuse_read_field_bit(ESP_EFUSE_XPD_SDIO_FORCE);
|
||||
bool reg = esp_efuse_read_field_bit(ESP_EFUSE_XPD_SDIO_REG);
|
||||
bool tieh = esp_efuse_read_field_bit(ESP_EFUSE_XPD_SDIO_TIEH);
|
||||
|
||||
Serial.printf("XPD_SDIO_FORCE: %d\n", force);
|
||||
Serial.printf("XPD_SDIO_REG: %d\n", reg);
|
||||
Serial.printf("XPD_SDIO_TIEH: %d\n", tieh);
|
||||
|
||||
if (isVddSdioFixedTo3v3()){
|
||||
Serial.println("VDD_SDIO already fixed to 3.3V.");
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println("Burning eFuse: VDD_SDIO fixed to 3.3V.");
|
||||
Serial.println("This is permanent.");
|
||||
|
||||
esp_err_t err;
|
||||
|
||||
err = esp_efuse_write_field_bit(ESP_EFUSE_XPD_SDIO_FORCE);
|
||||
if (err != ESP_OK){
|
||||
Serial.printf("Failed to burn XPD_SDIO_FORCE: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = esp_efuse_write_field_bit(ESP_EFUSE_XPD_SDIO_REG);
|
||||
if (err != ESP_OK){
|
||||
Serial.printf("Failed to burn XPD_SDIO_REG: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = esp_efuse_write_field_bit(ESP_EFUSE_XPD_SDIO_TIEH);
|
||||
if (err != ESP_OK){
|
||||
Serial.printf("Failed to burn XPD_SDIO_TIEH: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println("eFuse burned. Restarting...");
|
||||
delay(1000);
|
||||
esp_restart();
|
||||
}
|
||||
|
||||
void setup(){
|
||||
Serial.begin(115200);
|
||||
delay(5000);
|
||||
|
||||
burnVddSdio3v3Once();
|
||||
}
|
||||
|
||||
void loop(){
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ETH.h>
|
||||
|
||||
#define ETH_PHY_TYPE ETH_PHY_LAN8720
|
||||
#define ETH_PHY_ADDR 0
|
||||
#define ETH_PHY_MDC 23
|
||||
#define ETH_PHY_MDIO 18
|
||||
#define ETH_PHY_POWER -1
|
||||
#define ETH_CLK_MODE ETH_CLOCK_GPIO17_OUT
|
||||
|
||||
static constexpr int PIN_RS485_RX = 36;
|
||||
static constexpr int PIN_RS485_TX = 4;
|
||||
|
||||
static constexpr uint8_t DEFAULT_MODBUS_ADDR = 0x01;
|
||||
static constexpr uint32_t DEFAULT_MODBUS_BAUD = 4800;
|
||||
|
||||
static constexpr uint16_t REG_DATA_START = 500;
|
||||
static constexpr uint16_t REG_DATA_COUNT = 16;
|
||||
|
||||
static constexpr uint16_t REG_CFG_WIND_DIR_OFFSET = 0x6000;
|
||||
static constexpr uint16_t REG_CFG_RAIN_SENSITIVITY = 0x6003;
|
||||
|
||||
// Wind zero command prefix without CRC. CRC is appended automatically in software.
|
||||
// User-requested raw frame prefix: 01 AB 01 06 01 02 00 5A A9 CD
|
||||
static constexpr const char* CMD_WIND_ZERO = "01AB01060102005AA9CD";
|
||||
|
||||
static constexpr uint16_t REG_CFG_RAIN_ZERO = 0x0104;
|
||||
static constexpr uint16_t CFG_RAIN_ZERO = 0x005A;
|
||||
|
||||
static constexpr unsigned long SENSOR_POLL_MS = 2000;
|
||||
static constexpr unsigned long DETECT_RECHECK_MS = 30000;
|
||||
static constexpr unsigned long ETH_LOG_MS = 10000;
|
||||
|
||||
static constexpr size_t HTTP_RESERVE_LARGE = 32000;
|
||||
static constexpr size_t HTTP_RESERVE_MED = 12000;
|
||||
|
||||
enum class AirQualityMode : uint8_t {
|
||||
Auto = 0,
|
||||
PM = 1,
|
||||
CO2 = 2
|
||||
};
|
||||
|
|
@ -0,0 +1,262 @@
|
|||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
struct Texts {
|
||||
const char* appTitle;
|
||||
const char* tabMain;
|
||||
const char* tabConfig;
|
||||
const char* language;
|
||||
const char* sensorStatus;
|
||||
const char* values;
|
||||
const char* present;
|
||||
const char* absent;
|
||||
const char* pollAge;
|
||||
const char* seconds;
|
||||
const char* windSpeed;
|
||||
const char* beaufort;
|
||||
const char* windDir8;
|
||||
const char* windDirDeg;
|
||||
const char* humidity;
|
||||
const char* temperature;
|
||||
const char* noise;
|
||||
const char* pressure;
|
||||
const char* lightHigh;
|
||||
const char* lightLow;
|
||||
const char* lightLux100;
|
||||
const char* rain;
|
||||
const char* compass;
|
||||
const char* solarRadiation;
|
||||
const char* sensorWind;
|
||||
const char* sensorHumidityTemp;
|
||||
const char* sensorNoise;
|
||||
const char* sensorAir;
|
||||
const char* sensorPressure;
|
||||
const char* sensorLight;
|
||||
const char* sensorRain;
|
||||
const char* sensorCompass;
|
||||
const char* sensorSolar;
|
||||
const char* configTitle;
|
||||
const char* address;
|
||||
const char* baudrate;
|
||||
const char* save;
|
||||
const char* writeOk;
|
||||
const char* writeFail;
|
||||
const char* execute;
|
||||
const char* windOffset;
|
||||
const char* rainSensitivity;
|
||||
const char* commandWindZero;
|
||||
const char* commandRainZero;
|
||||
const char* tableItem;
|
||||
const char* tableSetting;
|
||||
const char* tableNote;
|
||||
const char* modbusLog;
|
||||
const char* modbusFrames;
|
||||
const char* modbusLastStatus;
|
||||
const char* modbusAction;
|
||||
const char* modbusDuration;
|
||||
const char* modbusCounters;
|
||||
const char* modbusError;
|
||||
const char* modbusTx;
|
||||
const char* modbusRx;
|
||||
const char* noteAddress;
|
||||
const char* noteBaudrate;
|
||||
const char* noteWindOffset;
|
||||
const char* noteRainSensitivity;
|
||||
const char* noteWindZero;
|
||||
const char* noteRainZero;
|
||||
const char* rawRegisters;
|
||||
const char* manualCommand;
|
||||
const char* manualAddress;
|
||||
const char* manualRegisterHex;
|
||||
const char* manualValueHex;
|
||||
const char* manualSend;
|
||||
const char* manualPreview;
|
||||
const char* manualNote;
|
||||
const char* rawHexTitle;
|
||||
const char* rawHexInput;
|
||||
const char* rawHexSend;
|
||||
const char* rawHexNote;
|
||||
const char* noResult;
|
||||
const char* statusOkShort;
|
||||
const char* statusErrorShort;
|
||||
};
|
||||
|
||||
enum class UiLang : uint8_t {
|
||||
CZ = 0,
|
||||
EN = 1
|
||||
};
|
||||
|
||||
inline UiLang parseLang(const String& v) {
|
||||
String s = v;
|
||||
s.toLowerCase();
|
||||
return (s == "en") ? UiLang::EN : UiLang::CZ;
|
||||
}
|
||||
|
||||
inline const char* langCode(UiLang lang) {
|
||||
return (lang == UiLang::EN) ? "en" : "cz";
|
||||
}
|
||||
|
||||
inline const Texts& T(UiLang lang) {
|
||||
static const Texts cz = {
|
||||
"ESPlan Meteostanice RS-FSXCS-N01",
|
||||
"Hlavní stránka",
|
||||
"Konfigurace",
|
||||
"Jazyk",
|
||||
"Stav čidel",
|
||||
"Aktuální hodnoty",
|
||||
"Přítomno",
|
||||
"Nepřítomno",
|
||||
"Stáří dat",
|
||||
"s",
|
||||
"Rychlost větru",
|
||||
"Síla větru",
|
||||
"Směr větru 0-7",
|
||||
"Směr větru",
|
||||
"Vlhkost",
|
||||
"Teplota",
|
||||
"Hluk",
|
||||
"Tlak",
|
||||
"Osvětlení high",
|
||||
"Osvětlení low",
|
||||
"Osvětlení",
|
||||
"Déšť",
|
||||
"Kompas",
|
||||
"Sluneční radiace",
|
||||
"Vítr",
|
||||
"Vlhkost / Teplota",
|
||||
"Hluk",
|
||||
"Kvalita vzduchu",
|
||||
"Tlak",
|
||||
"Světlo",
|
||||
"Déšť",
|
||||
"Kompas",
|
||||
"Solární",
|
||||
"Konfigurace snímače",
|
||||
"Adresa (ESP32)",
|
||||
"Baudrate (ESP32)",
|
||||
"Uložit",
|
||||
"Zápis OK",
|
||||
"Zápis CHYBA",
|
||||
"Provést",
|
||||
"Offset směru větru",
|
||||
"Citlivost optického deště",
|
||||
"Nulování větru",
|
||||
"Nulování deště",
|
||||
"Položka",
|
||||
"Nastavení",
|
||||
"Poznámka",
|
||||
"Modbus log",
|
||||
"Modbus rámce",
|
||||
"Stav",
|
||||
"Akce",
|
||||
"Doba",
|
||||
"Počítadla",
|
||||
"Chyba",
|
||||
"TX",
|
||||
"RX",
|
||||
"Toto nastavení mění pouze komunikaci ESP32, ne konfiguraci samotného snímače.",
|
||||
"Toto nastavení mění pouze komunikaci ESP32, ne konfiguraci samotného snímače.",
|
||||
"Registr 0x6000, HEX hodnota.",
|
||||
"Registr 0x6003, HEX hodnota.",
|
||||
"Zapíše kalibrační příkaz do snímače.",
|
||||
"Zapíše nulovací příkaz do snímače.",
|
||||
"Surové registry",
|
||||
"Ruční Modbus příkaz",
|
||||
"Adresa",
|
||||
"Registr (HEX)",
|
||||
"Hodnota (HEX)",
|
||||
"Odeslat",
|
||||
"Rámec s CRC",
|
||||
"Odešle se funkce 0x06. Adresa je decimálně, registr a hodnota jsou HEX. CRC se počítá automaticky.",
|
||||
"Celý HEX příkaz",
|
||||
"HEX rámec",
|
||||
"Odeslat HEX",
|
||||
"Zadej celý rámec v HEX bez CRC(dopočítá se automaticky). Neověřuje se správnost rámce, odesílá se tak jak je zadán.",
|
||||
"Zatím bez výsledku",
|
||||
"OK",
|
||||
"CHYBA"
|
||||
};
|
||||
|
||||
static const Texts en = {
|
||||
"ESPlan Weather Station RS-FSXCS-N01",
|
||||
"Main page",
|
||||
"Configuration",
|
||||
"Language",
|
||||
"Sensor status",
|
||||
"Current values",
|
||||
"Present",
|
||||
"Absent",
|
||||
"Data age",
|
||||
"s",
|
||||
"Wind speed",
|
||||
"Beaufort",
|
||||
"Wind direction 0-7",
|
||||
"Wind direction",
|
||||
"Humidity",
|
||||
"Temperature",
|
||||
"Noise",
|
||||
"Pressure",
|
||||
"Light high",
|
||||
"Light low",
|
||||
"Light",
|
||||
"Rain",
|
||||
"Compass",
|
||||
"Solar radiation",
|
||||
"Wind",
|
||||
"Humidity / Temperature",
|
||||
"Noise",
|
||||
"Air quality",
|
||||
"Pressure",
|
||||
"Light",
|
||||
"Rain",
|
||||
"Compass",
|
||||
"Solar",
|
||||
"Sensor configuration",
|
||||
"Address (ESP32)",
|
||||
"Baudrate (ESP32)",
|
||||
"Save",
|
||||
"Write OK",
|
||||
"Write FAIL",
|
||||
"Execute",
|
||||
"Wind direction offset",
|
||||
"Optical rain sensitivity",
|
||||
"Zero wind",
|
||||
"Zero rain",
|
||||
"Item",
|
||||
"Setting",
|
||||
"Note",
|
||||
"Modbus log",
|
||||
"Modbus frames",
|
||||
"Status",
|
||||
"Action",
|
||||
"Duration",
|
||||
"Counters",
|
||||
"Error",
|
||||
"TX",
|
||||
"RX",
|
||||
"This setting affects only ESP32 communication, not the sensor configuration itself.",
|
||||
"This setting affects only ESP32 communication, not the sensor configuration itself.",
|
||||
"Register 0x6000, HEX value.",
|
||||
"Register 0x6003, HEX value.",
|
||||
"Writes the calibration command to the sensor.",
|
||||
"Writes the reset command to the sensor.",
|
||||
"Raw registers",
|
||||
"Manual Modbus command",
|
||||
"Address",
|
||||
"Register (HEX)",
|
||||
"Value (HEX)",
|
||||
"Send",
|
||||
"Frame with CRC",
|
||||
"Function 0x06 will be sent. Address is decimal, register and value are HEX. CRC is calculated automatically.",
|
||||
"Full HEX command",
|
||||
"HEX frame",
|
||||
"Send HEX",
|
||||
"Enter the entire frame in HEX without CRC (it will be calculated automatically). The frame is not verified for correctness, it is sent as entered.",
|
||||
"No result yet",
|
||||
"OK",
|
||||
"ERROR"
|
||||
};
|
||||
|
||||
return (lang == UiLang::EN) ? en : cz;
|
||||
}
|
||||
|
|
@ -0,0 +1,531 @@
|
|||
#include "WeatherStation.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static bool parseHexStringLocal(const String& input, uint8_t* out, size_t& outLen, size_t maxLen) {
|
||||
String s = input;
|
||||
s.trim();
|
||||
s.replace(" ", "");
|
||||
s.replace("\t", "");
|
||||
s.replace("\r", "");
|
||||
s.replace("\n", "");
|
||||
|
||||
if (s.length() == 0 || (s.length() % 2) != 0) {
|
||||
outLen = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t bytes = s.length() / 2;
|
||||
if (bytes > maxLen) {
|
||||
outLen = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
outLen = 0;
|
||||
for (size_t i = 0; i < bytes; i++) {
|
||||
const String tok = s.substring(i * 2, i * 2 + 2);
|
||||
char* endptr = nullptr;
|
||||
const unsigned long v = strtoul(tok.c_str(), &endptr, 16);
|
||||
if (*endptr != '\0' || v > 0xFFUL) {
|
||||
outLen = 0;
|
||||
return false;
|
||||
}
|
||||
out[outLen++] = static_cast<uint8_t>(v);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
WeatherStation::WeatherStation(HardwareSerial& serial)
|
||||
: _serial(serial) {}
|
||||
|
||||
void WeatherStation::begin() {
|
||||
_serial.begin(_config.baudrate, SERIAL_8N1, PIN_RS485_RX, PIN_RS485_TX);
|
||||
}
|
||||
|
||||
bool WeatherStation::setBaudrate(uint32_t baud) {
|
||||
_config.baudrate = baud;
|
||||
_serial.updateBaudRate(baud);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t WeatherStation::crc16(const uint8_t* data, size_t len) const {
|
||||
uint16_t crc = 0xFFFF;
|
||||
for (size_t pos = 0; pos < len; pos++) {
|
||||
crc ^= static_cast<uint16_t>(data[pos]);
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
if (crc & 0x0001) {
|
||||
crc >>= 1;
|
||||
crc ^= 0xA001;
|
||||
} else {
|
||||
crc >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
int16_t WeatherStation::toSigned(uint16_t v) {
|
||||
return static_cast<int16_t>(v);
|
||||
}
|
||||
|
||||
String WeatherStation::toHex(const uint8_t* data, size_t len) {
|
||||
static const char* HEX_CHARS = "0123456789ABCDEF";
|
||||
String out;
|
||||
out.reserve(len * 3);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (i) out += ' ';
|
||||
out += HEX_CHARS[(data[i] >> 4) & 0x0F];
|
||||
out += HEX_CHARS[data[i] & 0x0F];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
const __FlashStringHelper* WeatherStation::exceptionText(uint8_t code) {
|
||||
switch (code) {
|
||||
case 0x01: return F("illegal function");
|
||||
case 0x02: return F("illegal data address");
|
||||
case 0x03: return F("illegal data value");
|
||||
case 0x04: return F("slave device failure");
|
||||
case 0x05: return F("acknowledge");
|
||||
case 0x06: return F("slave device busy");
|
||||
case 0x08: return F("memory parity error");
|
||||
case 0x0A: return F("gateway path unavailable");
|
||||
case 0x0B: return F("gateway target failed");
|
||||
default: return F("modbus exception");
|
||||
}
|
||||
}
|
||||
|
||||
void WeatherStation::setSimpleError(const String& error) {
|
||||
_commLog.lastOk = false;
|
||||
_commLog.lastDurationMs = 0;
|
||||
_commLog.lastAction = String();
|
||||
_commLog.lastRequestHex = String();
|
||||
_commLog.lastResponseHex = String();
|
||||
_commLog.lastError = error;
|
||||
_commLog.errorCount++;
|
||||
}
|
||||
|
||||
void WeatherStation::setCommResult(
|
||||
bool ok,
|
||||
uint32_t durationMs,
|
||||
const String& action,
|
||||
const uint8_t* req,
|
||||
size_t reqLen,
|
||||
const uint8_t* resp,
|
||||
size_t respLen,
|
||||
const String& error) {
|
||||
_commLog.lastOk = ok;
|
||||
_commLog.lastDurationMs = durationMs;
|
||||
_commLog.lastAction = action;
|
||||
_commLog.lastRequestHex = req ? toHex(req, reqLen) : String();
|
||||
_commLog.lastResponseHex = resp ? toHex(resp, respLen) : String();
|
||||
_commLog.lastError = error;
|
||||
if (ok) {
|
||||
_commLog.successCount++;
|
||||
} else {
|
||||
_commLog.errorCount++;
|
||||
}
|
||||
}
|
||||
|
||||
bool WeatherStation::transact(
|
||||
const uint8_t* request,
|
||||
size_t reqLen,
|
||||
uint8_t* response,
|
||||
size_t responseCap,
|
||||
uint32_t timeoutMs,
|
||||
const String& action,
|
||||
size_t* actualLen) {
|
||||
while (_serial.available()) {
|
||||
_serial.read();
|
||||
}
|
||||
|
||||
const uint32_t t0 = millis();
|
||||
_serial.write(request, reqLen);
|
||||
_serial.flush();
|
||||
|
||||
size_t got = 0;
|
||||
uint32_t lastByteAt = 0;
|
||||
bool seenAnyByte = false;
|
||||
|
||||
while ((millis() - t0) < timeoutMs && got < responseCap) {
|
||||
bool gotByteNow = false;
|
||||
|
||||
while (_serial.available() && got < responseCap) {
|
||||
response[got++] = static_cast<uint8_t>(_serial.read());
|
||||
lastByteAt = millis();
|
||||
seenAnyByte = true;
|
||||
gotByteNow = true;
|
||||
}
|
||||
|
||||
if (seenAnyByte && !gotByteNow && (millis() - lastByteAt) >= 20) {
|
||||
break;
|
||||
}
|
||||
delay(1);
|
||||
}
|
||||
|
||||
if (actualLen) {
|
||||
*actualLen = got;
|
||||
}
|
||||
|
||||
if (!seenAnyByte) {
|
||||
setCommResult(false, millis() - t0, action, request, reqLen, response, 0, F("timeout"));
|
||||
return false;
|
||||
}
|
||||
|
||||
setCommResult(true, millis() - t0, action, request, reqLen, response, got, String());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WeatherStation::sendRawFrame(const uint8_t* request, size_t reqLen, uint8_t* response, size_t responseCapacity, uint32_t timeoutMs, const String& action) {
|
||||
if (request == nullptr || reqLen == 0) {
|
||||
setSimpleError(F("invalid args"));
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t frame[260] = {0};
|
||||
if (reqLen > sizeof(frame)) {
|
||||
setSimpleError(F("raw frame too long"));
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(frame, request, reqLen);
|
||||
size_t frameLen = reqLen;
|
||||
|
||||
bool hasValidCrc = false;
|
||||
if (frameLen >= 4) {
|
||||
const uint16_t crcProvided = static_cast<uint16_t>(frame[frameLen - 2]) | (static_cast<uint16_t>(frame[frameLen - 1]) << 8);
|
||||
const uint16_t crcCalculated = crc16(frame, frameLen - 2);
|
||||
hasValidCrc = (crcProvided == crcCalculated);
|
||||
}
|
||||
|
||||
if (!hasValidCrc) {
|
||||
if ((frameLen + 2) > sizeof(frame)) {
|
||||
setSimpleError(F("raw frame too long"));
|
||||
return false;
|
||||
}
|
||||
const uint16_t crc = crc16(frame, frameLen);
|
||||
frame[frameLen++] = static_cast<uint8_t>(crc & 0xFF);
|
||||
frame[frameLen++] = static_cast<uint8_t>((crc >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
size_t actualLen = 0;
|
||||
const uint32_t effectiveTimeoutMs = timeoutMs < 2000 ? 2000 : timeoutMs;
|
||||
return transact(frame, frameLen, response, responseCapacity, effectiveTimeoutMs, action, &actualLen);
|
||||
}
|
||||
|
||||
bool WeatherStation::sendRawFrame(const uint8_t* request, size_t reqLen, uint32_t timeoutMs, const String& action) {
|
||||
uint8_t resp[128] = {0};
|
||||
return sendRawFrame(request, reqLen, resp, sizeof(resp), timeoutMs, action);
|
||||
}
|
||||
|
||||
bool WeatherStation::readHoldingRegisters(uint16_t startReg, uint16_t count, uint16_t* out) {
|
||||
if (count == 0 || out == nullptr) {
|
||||
setSimpleError(F("invalid args"));
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t req[8];
|
||||
req[0] = _config.address;
|
||||
req[1] = 0x03;
|
||||
req[2] = static_cast<uint8_t>((startReg >> 8) & 0xFF);
|
||||
req[3] = static_cast<uint8_t>(startReg & 0xFF);
|
||||
req[4] = static_cast<uint8_t>((count >> 8) & 0xFF);
|
||||
req[5] = static_cast<uint8_t>(count & 0xFF);
|
||||
const uint16_t crc = crc16(req, 6);
|
||||
req[6] = static_cast<uint8_t>(crc & 0xFF);
|
||||
req[7] = static_cast<uint8_t>((crc >> 8) & 0xFF);
|
||||
|
||||
uint8_t resp[64] = {0};
|
||||
size_t respLen = 0;
|
||||
|
||||
char regHex[5];
|
||||
snprintf(regHex, sizeof(regHex), "%04X", startReg);
|
||||
String action = F("read 0x");
|
||||
action += regHex;
|
||||
action += F(" + ");
|
||||
action += String(count);
|
||||
|
||||
if (!transact(req, sizeof(req), resp, sizeof(resp), 2000, action, &respLen)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (respLen < 5) {
|
||||
setCommResult(false, _commLog.lastDurationMs, action, req, sizeof(req), resp, respLen, F("short response"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (resp[0] != _config.address) {
|
||||
setCommResult(false, _commLog.lastDurationMs, action, req, sizeof(req), resp, respLen, F("wrong slave address"));
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint16_t crcResp = static_cast<uint16_t>(resp[respLen - 2]) | (static_cast<uint16_t>(resp[respLen - 1]) << 8);
|
||||
const uint16_t crcCalc = crc16(resp, respLen - 2);
|
||||
if (crcResp != crcCalc) {
|
||||
setCommResult(false, _commLog.lastDurationMs, action, req, sizeof(req), resp, respLen, F("crc mismatch"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (resp[1] == static_cast<uint8_t>(0x03 | 0x80)) {
|
||||
String err = F("modbus exception: ");
|
||||
err += String(exceptionText(resp[2]));
|
||||
setCommResult(false, _commLog.lastDurationMs, action, req, sizeof(req), resp, respLen, err);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (resp[1] != 0x03) {
|
||||
setCommResult(false, _commLog.lastDurationMs, action, req, sizeof(req), resp, respLen, F("bad function"));
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t expectedLen = 5 + static_cast<size_t>(count) * 2;
|
||||
if (respLen != expectedLen) {
|
||||
setCommResult(false, _commLog.lastDurationMs, action, req, sizeof(req), resp, respLen, F("bad length"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (resp[2] != count * 2) {
|
||||
setCommResult(false, _commLog.lastDurationMs, action, req, sizeof(req), resp, respLen, F("bad byte count"));
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < count; i++) {
|
||||
out[i] = (static_cast<uint16_t>(resp[3 + i * 2]) << 8) | static_cast<uint16_t>(resp[4 + i * 2]);
|
||||
}
|
||||
|
||||
_commLog.lastOk = true;
|
||||
_commLog.lastError = String();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WeatherStation::writeRegister(uint16_t reg, uint16_t value) {
|
||||
uint8_t req[8];
|
||||
req[0] = _config.address;
|
||||
req[1] = 0x06;
|
||||
req[2] = static_cast<uint8_t>((reg >> 8) & 0xFF);
|
||||
req[3] = static_cast<uint8_t>(reg & 0xFF);
|
||||
req[4] = static_cast<uint8_t>((value >> 8) & 0xFF);
|
||||
req[5] = static_cast<uint8_t>(value & 0xFF);
|
||||
const uint16_t crc = crc16(req, 6);
|
||||
req[6] = static_cast<uint8_t>(crc & 0xFF);
|
||||
req[7] = static_cast<uint8_t>((crc >> 8) & 0xFF);
|
||||
|
||||
uint8_t resp[16] = {0};
|
||||
size_t respLen = 0;
|
||||
|
||||
char regHex[5];
|
||||
char valHex[5];
|
||||
snprintf(regHex, sizeof(regHex), "%04X", reg);
|
||||
snprintf(valHex, sizeof(valHex), "%04X", value);
|
||||
String action = F("write 0x");
|
||||
action += regHex;
|
||||
action += F(" = 0x");
|
||||
action += valHex;
|
||||
|
||||
if (!transact(req, sizeof(req), resp, sizeof(resp), 2000, action, &respLen)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (respLen < 5) {
|
||||
setCommResult(false, _commLog.lastDurationMs, action, req, sizeof(req), resp, respLen, F("short response"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (resp[0] != _config.address) {
|
||||
setCommResult(false, _commLog.lastDurationMs, action, req, sizeof(req), resp, respLen, F("wrong slave address"));
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint16_t crcResp = static_cast<uint16_t>(resp[respLen - 2]) | (static_cast<uint16_t>(resp[respLen - 1]) << 8);
|
||||
const uint16_t crcCalc = crc16(resp, respLen - 2);
|
||||
if (crcResp != crcCalc) {
|
||||
setCommResult(false, _commLog.lastDurationMs, action, req, sizeof(req), resp, respLen, F("crc mismatch"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (resp[1] == static_cast<uint8_t>(0x06 | 0x80)) {
|
||||
String err = F("modbus exception: ");
|
||||
err += String(exceptionText(resp[2]));
|
||||
setCommResult(false, _commLog.lastDurationMs, action, req, sizeof(req), resp, respLen, err);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (resp[1] != 0x06) {
|
||||
setCommResult(false, _commLog.lastDurationMs, action, req, sizeof(req), resp, respLen, F("bad function"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (respLen != 8) {
|
||||
setCommResult(false, _commLog.lastDurationMs, action, req, sizeof(req), resp, respLen, F("bad length"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (memcmp(req, resp, 6) != 0) {
|
||||
setCommResult(false, _commLog.lastDurationMs, action, req, sizeof(req), resp, respLen, F("write echo mismatch"));
|
||||
return false;
|
||||
}
|
||||
|
||||
_commLog.lastOk = true;
|
||||
_commLog.lastError = String();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WeatherStation::readAll() {
|
||||
uint16_t regs[REG_DATA_COUNT] = {0};
|
||||
if (!readHoldingRegisters(REG_DATA_START, REG_DATA_COUNT, regs)) {
|
||||
_values.registersValid = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < REG_DATA_COUNT; i++) {
|
||||
_values.raw[i] = regs[i];
|
||||
}
|
||||
|
||||
_values.registersValid = true;
|
||||
_values.lastReadMs = millis();
|
||||
decodeRegisters();
|
||||
detectPresence();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WeatherStation::readSensorConfig() {
|
||||
uint16_t regs[4] = {0};
|
||||
if (!readHoldingRegisters(REG_CFG_WIND_DIR_OFFSET, 4, regs)) {
|
||||
_config.sensorConfigReadOk = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
_config.windOffset = regs[0];
|
||||
_config.rainSensitivity = regs[3];
|
||||
_config.sensorConfigReadOk = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void WeatherStation::decodeRegisters() {
|
||||
_values.windSpeed = _values.raw[0] / 10.0f;
|
||||
_values.windForce = static_cast<int>(_values.raw[1]);
|
||||
_values.windDir8 = static_cast<int>(_values.raw[2]);
|
||||
_values.windDirDeg = static_cast<int>(_values.raw[3]);
|
||||
_values.humidity = _values.raw[4] / 10.0f;
|
||||
_values.temperature = toSigned(_values.raw[5]) / 10.0f;
|
||||
_values.noise = _values.raw[6] / 10.0f;
|
||||
_values.air1 = static_cast<int>(_values.raw[7]);
|
||||
_values.air2 = static_cast<int>(_values.raw[8]);
|
||||
_values.pressureKpa = _values.raw[9] / 10.0f;
|
||||
_values.lightHigh = _values.raw[10];
|
||||
_values.lightLow = _values.raw[11];
|
||||
_values.lightLux = _values.raw[12];
|
||||
_values.rain = _values.raw[13] / 10.0f;
|
||||
_values.compassDeg = _values.raw[14] / 100.0f;
|
||||
_values.solarRadiation = static_cast<int>(_values.raw[15]);
|
||||
}
|
||||
|
||||
void WeatherStation::detectPresence() {
|
||||
_presence.wind =
|
||||
(_values.windSpeed >= 0.0f) &&
|
||||
(_values.windDirDeg >= 0) &&
|
||||
(_values.windDirDeg <= 359);
|
||||
|
||||
_presence.humidityTemp =
|
||||
isfinite(_values.humidity) &&
|
||||
isfinite(_values.temperature) &&
|
||||
(_values.humidity >= 0.0f && _values.humidity <= 100.0f) &&
|
||||
(_values.temperature > -50.0f && _values.temperature < 90.0f);
|
||||
|
||||
if (isfinite(_values.noise) &&
|
||||
_values.noise >= 29.5f &&
|
||||
_values.noise <= 30.5f) {
|
||||
_presence.noise = false;
|
||||
_values.noise = NAN;
|
||||
} else {
|
||||
_presence.noise = isfinite(_values.noise) && (_values.noise > 0.0f) && (_values.noise <= 150.0f);
|
||||
}
|
||||
|
||||
_presence.air = (_values.air1 > 0 || _values.air2 > 0);
|
||||
if (!_presence.air) {
|
||||
_values.air1 = -1;
|
||||
_values.air2 = -1;
|
||||
}
|
||||
|
||||
_presence.pressure = isfinite(_values.pressureKpa) && (_values.pressureKpa > 10.0f);
|
||||
if (!_presence.pressure) _values.pressureKpa = NAN;
|
||||
|
||||
_presence.light = (_values.lightLux > 0) || (_values.lightHigh > 0) || (_values.lightLow > 0);
|
||||
if (!_presence.light) {
|
||||
_values.lightLux = 0;
|
||||
_values.lightHigh = 0;
|
||||
_values.lightLow = 0;
|
||||
}
|
||||
|
||||
_presence.rain = isfinite(_values.rain) && (_values.rain >= 0.0f);
|
||||
if (!_presence.rain) _values.rain = NAN;
|
||||
|
||||
_presence.compass = isfinite(_values.compassDeg) && (_values.compassDeg > 0.01f);
|
||||
if (!_presence.compass) _values.compassDeg = NAN;
|
||||
|
||||
_presence.solar = (_values.solarRadiation > 0);
|
||||
if (!_presence.solar) _values.solarRadiation = -1;
|
||||
}
|
||||
|
||||
bool WeatherStation::commandZeroWind() {
|
||||
uint8_t req[64];
|
||||
size_t reqLen = 0;
|
||||
|
||||
if (!parseHexStringLocal(String(CMD_WIND_ZERO), req, reqLen, sizeof(req))) {
|
||||
setSimpleError(F("bad wind zero prefix"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (reqLen + 2 > sizeof(req)) {
|
||||
setSimpleError(F("wind zero frame too long"));
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint16_t crc = crc16(req, reqLen);
|
||||
req[reqLen++] = static_cast<uint8_t>(crc & 0xFF);
|
||||
req[reqLen++] = static_cast<uint8_t>((crc >> 8) & 0xFF);
|
||||
|
||||
uint8_t resp[32] = {0};
|
||||
size_t respLen = 0;
|
||||
|
||||
if (!transact(req, reqLen, resp, sizeof(resp), 2000, F("wind zero raw"), &respLen)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (respLen == 0) {
|
||||
setCommResult(false, _commLog.lastDurationMs, F("wind zero raw"), req, reqLen, resp, respLen, F("no response"));
|
||||
return false;
|
||||
}
|
||||
|
||||
_commLog.lastOk = true;
|
||||
_commLog.lastError = String();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WeatherStation::commandZeroRain() {
|
||||
return writeRegister(REG_CFG_RAIN_ZERO, CFG_RAIN_ZERO);
|
||||
}
|
||||
|
||||
void WeatherStation::pushConfigLog() {
|
||||
_lastConfigLog = _commLog;
|
||||
_hasConfigLog = true;
|
||||
}
|
||||
|
||||
const CommLog& WeatherStation::configLogAt(size_t reverseIndex) const {
|
||||
static const CommLog empty;
|
||||
if (!_hasConfigLog || reverseIndex != 0) {
|
||||
return empty;
|
||||
}
|
||||
return _lastConfigLog;
|
||||
}
|
||||
|
||||
String WeatherStation::airLabel1() const {
|
||||
if (_config.airMode == AirQualityMode::CO2) return F("CO2");
|
||||
return F("PM2.5");
|
||||
}
|
||||
|
||||
String WeatherStation::airLabel2() const {
|
||||
if (_config.airMode == AirQualityMode::CO2) return F("CO2");
|
||||
return F("PM10");
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include "Config.h"
|
||||
|
||||
struct VariantPresence {
|
||||
bool wind = false;
|
||||
bool humidityTemp = false;
|
||||
bool noise = false;
|
||||
bool air = false;
|
||||
bool pressure = false;
|
||||
bool light = false;
|
||||
bool rain = false;
|
||||
bool compass = false;
|
||||
bool solar = false;
|
||||
};
|
||||
|
||||
struct WeatherValues {
|
||||
uint16_t raw[REG_DATA_COUNT] = {0};
|
||||
bool registersValid = false;
|
||||
uint32_t lastReadMs = 0;
|
||||
|
||||
float windSpeed = NAN;
|
||||
int windForce = -1;
|
||||
int windDir8 = -1;
|
||||
int windDirDeg = -1;
|
||||
float humidity = NAN;
|
||||
float temperature = NAN;
|
||||
float noise = NAN;
|
||||
int air1 = -1;
|
||||
int air2 = -1;
|
||||
float pressureKpa = NAN;
|
||||
uint16_t lightHigh = 0;
|
||||
uint16_t lightLow = 0;
|
||||
uint32_t lightLux = 0;
|
||||
float rain = NAN;
|
||||
float compassDeg = NAN;
|
||||
int solarRadiation = -1;
|
||||
};
|
||||
|
||||
struct RuntimeConfig {
|
||||
uint8_t address = DEFAULT_MODBUS_ADDR;
|
||||
uint32_t baudrate = DEFAULT_MODBUS_BAUD;
|
||||
AirQualityMode airMode = AirQualityMode::Auto;
|
||||
uint16_t windOffset = 0;
|
||||
uint16_t rainSensitivity = 0x0011;
|
||||
bool sensorConfigReadOk = false;
|
||||
};
|
||||
|
||||
struct CommLog {
|
||||
bool lastOk = false;
|
||||
uint32_t lastDurationMs = 0;
|
||||
uint32_t successCount = 0;
|
||||
uint32_t errorCount = 0;
|
||||
String lastAction;
|
||||
String lastRequestHex;
|
||||
String lastResponseHex;
|
||||
String lastError;
|
||||
};
|
||||
|
||||
class WeatherStation {
|
||||
public:
|
||||
explicit WeatherStation(HardwareSerial& serial);
|
||||
|
||||
void begin();
|
||||
bool setBaudrate(uint32_t baud);
|
||||
|
||||
bool readAll();
|
||||
bool readSensorConfig();
|
||||
bool writeRegister(uint16_t reg, uint16_t value);
|
||||
|
||||
bool commandZeroWind();
|
||||
bool commandZeroRain();
|
||||
|
||||
bool sendRawFrame(const uint8_t* request, size_t reqLen, uint8_t* response, size_t responseCapacity, uint32_t timeoutMs, const String& action);
|
||||
bool sendRawFrame(const uint8_t* request, size_t reqLen, uint32_t timeoutMs, const String& action);
|
||||
|
||||
void pushConfigLog();
|
||||
size_t configLogCount() const { return _hasConfigLog ? 1 : 0; }
|
||||
const CommLog& configLogAt(size_t reverseIndex) const;
|
||||
|
||||
const WeatherValues& values() const { return _values; }
|
||||
const VariantPresence& presence() const { return _presence; }
|
||||
RuntimeConfig& config() { return _config; }
|
||||
const RuntimeConfig& config() const { return _config; }
|
||||
const CommLog& commLog() const { return _commLog; }
|
||||
|
||||
String airLabel1() const;
|
||||
String airLabel2() const;
|
||||
|
||||
private:
|
||||
HardwareSerial& _serial;
|
||||
WeatherValues _values;
|
||||
VariantPresence _presence;
|
||||
RuntimeConfig _config;
|
||||
CommLog _commLog;
|
||||
|
||||
CommLog _lastConfigLog;
|
||||
bool _hasConfigLog = false;
|
||||
|
||||
uint16_t crc16(const uint8_t* data, size_t len) const;
|
||||
bool transact(const uint8_t* request, size_t reqLen, uint8_t* response, size_t responseCap, uint32_t timeoutMs, const String& action, size_t* actualLen = nullptr);
|
||||
bool readHoldingRegisters(uint16_t startReg, uint16_t count, uint16_t* out);
|
||||
void decodeRegisters();
|
||||
void detectPresence();
|
||||
void setCommResult(bool ok, uint32_t durationMs, const String& action, const uint8_t* req, size_t reqLen, const uint8_t* resp, size_t respLen, const String& error);
|
||||
void setSimpleError(const String& error);
|
||||
static int16_t toSigned(uint16_t v);
|
||||
static String toHex(const uint8_t* data, size_t len);
|
||||
static const __FlashStringHelper* exceptionText(uint8_t code);
|
||||
};
|
||||
|
|
@ -0,0 +1,645 @@
|
|||
#include "WebUi.h"
|
||||
#include "logo_web.h"
|
||||
|
||||
String htmlEscape(const String& in) {
|
||||
String out;
|
||||
out.reserve(in.length() + 16);
|
||||
for (size_t i = 0; i < in.length(); i++) {
|
||||
switch (in[i]) {
|
||||
case '&': out += F("&"); break;
|
||||
case '<': out += F("<"); break;
|
||||
case '>': out += F(">"); break;
|
||||
case '"': out += F("""); break;
|
||||
case '\'': out += F("'"); break;
|
||||
default: out += in[i]; break;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
String fmtFloat(float v, uint8_t decimals) {
|
||||
if (isnan(v) || !isfinite(v)) return F("-");
|
||||
return String(static_cast<double>(v), static_cast<unsigned int>(decimals));
|
||||
}
|
||||
|
||||
static String jsonFloat(float v, uint8_t decimals = 1) {
|
||||
if (isnan(v) || !isfinite(v)) return F("null");
|
||||
return String(static_cast<double>(v), static_cast<unsigned int>(decimals));
|
||||
}
|
||||
|
||||
String jsonString(const String& in) {
|
||||
String out;
|
||||
out.reserve(in.length() + 8);
|
||||
|
||||
for (size_t i = 0; i < in.length(); i++) {
|
||||
char c = in[i];
|
||||
switch (c) {
|
||||
case '\"': out += F("\\\""); break;
|
||||
case '\\': out += F("\\\\"); break;
|
||||
case '\n': out += F("\\n"); break;
|
||||
case '\r': out += F("\\r"); break;
|
||||
case '\t': out += F("\\t"); break;
|
||||
case '\b': out += F("\\b"); break;
|
||||
case '\f': out += F("\\f"); break;
|
||||
default:
|
||||
if ((uint8_t)c < 32) {
|
||||
out += '?';
|
||||
} else {
|
||||
out += c;
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
static String hex16(uint16_t value) {
|
||||
char buf[5];
|
||||
snprintf(buf, sizeof(buf), "%04X", value);
|
||||
return String(buf);
|
||||
}
|
||||
|
||||
static String statusBadge(bool present, const Texts& t) {
|
||||
String s;
|
||||
s.reserve(64);
|
||||
s += F("<span class='");
|
||||
s += present ? F("ok'>") : F("bad'>");
|
||||
s += present ? t.present : t.absent;
|
||||
s += F("</span>");
|
||||
return s;
|
||||
}
|
||||
|
||||
String buildStyle(const Texts&, UiLang) {
|
||||
return F(
|
||||
"<style>"
|
||||
"body{font-family:Arial,sans-serif;background:#f4f7fb;color:#222;margin:0;padding:20px;}"
|
||||
".wrap{max-width:1800px;margin:0 auto;}"
|
||||
".grid{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;align-items:stretch;}"
|
||||
".card{background:#fff;border-radius:14px;padding:16px;box-shadow:0 2px 12px rgba(0,0,0,.08);min-width:0;height:100%;box-sizing:border-box;display:flex;flex-direction:column;}"
|
||||
".card-wide{grid-column:1 / -1;}"
|
||||
".top{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:20px;}"
|
||||
".title{display:flex;align-items:center;gap:18px;flex-wrap:wrap}"
|
||||
".brand-logo{display:block;max-width:180px;width:100%;height:auto}"
|
||||
".nav{display:flex;gap:10px;flex-wrap:wrap;margin:10px 0 18px 0}"
|
||||
".nav a{display:inline-block;padding:10px 14px;border-radius:10px;background:#e8eef8;color:#1f6feb;text-decoration:none;font-weight:bold}"
|
||||
".nav a.active{background:#1f6feb;color:#fff}"
|
||||
"table{width:100%;border-collapse:collapse;table-layout:fixed}"
|
||||
"th,td{padding:8px;border-bottom:1px solid #ddd;text-align:left;font-size:14px;vertical-align:top;word-break:break-word}"
|
||||
".ok{color:#0a7a2f;font-weight:bold}.bad{color:#b00020;font-weight:bold}"
|
||||
".sub{color:#637186;font-size:13px}"
|
||||
".mono{font-family:monospace;white-space:pre-wrap;background:#eef2f7;padding:10px;border-radius:10px;overflow:auto}"
|
||||
".mono-frames{max-height:140px;font-size:12px;line-height:1.3}"
|
||||
".mono-raw{max-height:420px;font-size:12px;line-height:1.3}"
|
||||
".cfg-table td:first-child{width:22%;font-weight:bold}"
|
||||
".cfg-table td:nth-child(2){width:28%}"
|
||||
".cfg-table td:nth-child(3){width:50%}"
|
||||
".cfg-inline-form{margin:0}"
|
||||
".cfg-inline-form input,.cfg-inline-form select,.cfg-inline-form textarea{margin:0}"
|
||||
"label{display:block;margin:8px 0 4px;font-weight:bold}"
|
||||
"input[type=text],input[type=number],select,textarea{width:100%;padding:10px;border:1px solid #ccc;border-radius:8px;box-sizing:border-box}"
|
||||
"textarea{resize:vertical;min-height:88px;font-family:monospace}"
|
||||
"button{padding:10px 14px;border:0;border-radius:10px;background:#1f6feb;color:#fff;cursor:pointer;margin-top:8px}"
|
||||
"button:hover{opacity:.92}"
|
||||
".row2{display:grid;grid-template-columns:1fr 1fr;gap:12px}"
|
||||
".msg{padding:10px 12px;border-radius:10px;margin-bottom:12px}"
|
||||
".note{font-size:13px;color:#5e6a7a}"
|
||||
"@media (max-width:1400px){.grid{grid-template-columns:repeat(2,1fr);}}"
|
||||
"@media (max-width:800px){.grid{grid-template-columns:1fr}.row2{grid-template-columns:1fr}.brand-logo{max-width:240px;}}"
|
||||
"</style>");
|
||||
}
|
||||
|
||||
static void appendTop(String& html, UiLang lang, const Texts& t, const char* active) {
|
||||
html += F("<div class='top'><div class='title'><img src='/logo.png' alt='logo' class='brand-logo'><div><h1>");
|
||||
html += t.appTitle;
|
||||
html += F("</h1></div></div>");
|
||||
|
||||
html += F("<form method='GET' action='");
|
||||
html += (strcmp(active, "main") == 0) ? F("/") : F("/config");
|
||||
html += F("' style='display:flex;gap:8px;align-items:center;margin:0;'>");
|
||||
html += F("<label style='margin:0;font-weight:bold;'>");
|
||||
html += t.language;
|
||||
html += F("</label><select name='lang' onchange='this.form.submit()'>");
|
||||
html += F("<option value='cz'");
|
||||
if (lang == UiLang::CZ) html += F(" selected");
|
||||
html += F(">CZ</option><option value='en'");
|
||||
if (lang == UiLang::EN) html += F(" selected");
|
||||
html += F(">ENG</option></select></form></div>");
|
||||
|
||||
html += F("<div class='nav'>");
|
||||
html += F("<a href='/?lang="); html += langCode(lang); html += F("' class='");
|
||||
html += (strcmp(active, "main") == 0) ? F("active") : F("");
|
||||
html += F("'>"); html += t.tabMain; html += F("</a>");
|
||||
html += F("<a href='/config?lang="); html += langCode(lang); html += F("' class='");
|
||||
html += (strcmp(active, "config") == 0) ? F("active") : F("");
|
||||
html += F("'>"); html += t.tabConfig; html += F("</a>");
|
||||
html += F("</div>");
|
||||
}
|
||||
|
||||
static void appendRow(String& html, const String& id, const String& label, const String& value) {
|
||||
html += F("<tr><td>");
|
||||
html += label;
|
||||
html += F("</td><td id='");
|
||||
html += id;
|
||||
html += F("'>");
|
||||
html += value;
|
||||
html += F("</td></tr>");
|
||||
}
|
||||
|
||||
static String buildConfigHistoryBox(const Texts& t, const WeatherStation& ws) {
|
||||
String html;
|
||||
html.reserve(1800);
|
||||
|
||||
html += F("<div class='card card-wide' style='margin-bottom:16px;'><h2>");
|
||||
html += t.modbusLog;
|
||||
html += F("</h2>");
|
||||
|
||||
if (ws.configLogCount() == 0) {
|
||||
html += F("<div class='note'>");
|
||||
html += t.noResult;
|
||||
html += F("</div></div>");
|
||||
return html;
|
||||
}
|
||||
|
||||
const CommLog& c = ws.configLogAt(0);
|
||||
|
||||
html += F("<table>");
|
||||
appendRow(html, F("cfg-log-state"), t.modbusLastStatus, c.lastOk ? String(F("<span class='ok'>")) + t.statusOkShort + F("</span>") : String(F("<span class='bad'>")) + t.statusErrorShort + F("</span>"));
|
||||
appendRow(html, F("cfg-log-action"), t.modbusAction, htmlEscape(c.lastAction));
|
||||
appendRow(html, F("cfg-log-duration"), t.modbusDuration, String(c.lastDurationMs) + F(" ms"));
|
||||
appendRow(html, F("cfg-log-error"), t.modbusError, c.lastError.length() ? htmlEscape(c.lastError) : F("-"));
|
||||
html += F("</table>");
|
||||
|
||||
html += F("<div class='sub' style='margin-top:10px'>");
|
||||
html += t.modbusTx;
|
||||
html += F("</div><div class='mono'>");
|
||||
html += htmlEscape(c.lastRequestHex);
|
||||
html += F("</div>");
|
||||
|
||||
html += F("<div class='sub' style='margin-top:10px'>");
|
||||
html += t.modbusRx;
|
||||
html += F("</div><div class='mono'>");
|
||||
html += htmlEscape(c.lastResponseHex);
|
||||
html += F("</div>");
|
||||
|
||||
html += F("</div>");
|
||||
return html;
|
||||
}
|
||||
|
||||
static void appendMainCards(String& html, const Texts& t, const WeatherStation& ws, bool ethUp, const String& ip, const String& mac) {
|
||||
(void)ethUp;
|
||||
(void)ip;
|
||||
(void)mac;
|
||||
|
||||
const auto& p = ws.presence();
|
||||
const auto& v = ws.values();
|
||||
const auto& c = ws.commLog();
|
||||
|
||||
html += F("<div class='grid'>");
|
||||
|
||||
html += F("<div class='card'><h2>");
|
||||
html += t.sensorStatus;
|
||||
html += F("</h2><table>");
|
||||
appendRow(html, F("st-wind"), t.sensorWind, statusBadge(p.wind, t));
|
||||
appendRow(html, F("st-th"), t.sensorHumidityTemp, statusBadge(p.humidityTemp, t));
|
||||
appendRow(html, F("st-noise"), t.sensorNoise, statusBadge(p.noise, t));
|
||||
appendRow(html, F("st-air"), t.sensorAir, statusBadge(p.air, t));
|
||||
appendRow(html, F("st-pressure"), t.sensorPressure, statusBadge(p.pressure, t));
|
||||
appendRow(html, F("st-light"), t.sensorLight, statusBadge(p.light, t));
|
||||
appendRow(html, F("st-rain"), t.sensorRain, statusBadge(p.rain, t));
|
||||
appendRow(html, F("st-compass"), t.sensorCompass, statusBadge(p.compass, t));
|
||||
appendRow(html, F("st-solar"), t.sensorSolar, statusBadge(p.solar, t));
|
||||
html += F("</table></div>");
|
||||
|
||||
html += F("<div class='card'><h2>");
|
||||
html += t.values;
|
||||
html += F("</h2><table>");
|
||||
appendRow(html, F("v-wind-short"), t.windSpeed, fmtFloat(v.windSpeed, 1));
|
||||
appendRow(html, F("v-beaufort-short"), t.beaufort, (v.windForce >= 0 ? String(v.windForce) : F("-")));
|
||||
appendRow(html, F("v-dir8-short"), t.windDir8, (v.windDir8 >= 0 ? String(v.windDir8) : F("-")));
|
||||
appendRow(html, F("v-dirdeg-short"), t.windDirDeg, (v.windDirDeg >= 0 ? String(v.windDirDeg) : F("-")));
|
||||
appendRow(html, F("v-hum-short"), t.humidity, fmtFloat(v.humidity, 1));
|
||||
appendRow(html, F("v-temp-short"), t.temperature, fmtFloat(v.temperature, 1));
|
||||
appendRow(html, F("v-noise-short"), t.noise, fmtFloat(v.noise, 1));
|
||||
appendRow(html, F("v-air1-short"), ws.airLabel1(), (v.air1 >= 0 ? String(v.air1) : F("-")));
|
||||
appendRow(html, F("v-air2-short"), ws.airLabel2(), (v.air2 >= 0 ? String(v.air2) : F("-")));
|
||||
appendRow(html, F("v-pressure-short"), t.pressure, fmtFloat(v.pressureKpa, 1));
|
||||
appendRow(html, F("v-luxh-short"), t.lightHigh, String(v.lightHigh));
|
||||
appendRow(html, F("v-luxl-short"), t.lightLow, String(v.lightLow));
|
||||
appendRow(html, F("v-lux-short"), t.lightLux100, String(v.lightLux));
|
||||
appendRow(html, F("v-rain-short"), t.rain, fmtFloat(v.rain, 1));
|
||||
appendRow(html, F("v-compass-short"), t.compass, fmtFloat(v.compassDeg, 2));
|
||||
appendRow(html, F("v-solar-short"), t.solarRadiation, (v.solarRadiation >= 0 ? String(v.solarRadiation) : F("-")));
|
||||
appendRow(html, F("data-age"), t.pollAge, String((millis() - v.lastReadMs) / 1000UL) + String(F(" ")) + t.seconds);
|
||||
html += F("</table></div>");
|
||||
|
||||
html += F("<div class='card'><h2>");
|
||||
html += t.modbusLog;
|
||||
html += F("</h2><table>");
|
||||
appendRow(html, F("mb-state"), t.modbusLastStatus, c.lastOk ? String(F("<span class='ok'>")) + t.statusOkShort + F("</span>") : String(F("<span class='bad'>")) + t.statusErrorShort + F("</span>"));
|
||||
appendRow(html, F("mb-action"), t.modbusAction, htmlEscape(c.lastAction));
|
||||
appendRow(html, F("mb-dur"), t.modbusDuration, String(c.lastDurationMs) + F(" ms"));
|
||||
appendRow(html, F("mb-stats"), t.modbusCounters, String(c.successCount) + F(" / ") + String(c.errorCount));
|
||||
appendRow(html, F("mb-err"), t.modbusError, c.lastError.length() ? htmlEscape(c.lastError) : F("-"));
|
||||
html += F("</table></div>");
|
||||
|
||||
html += F("<div class='card'><h2>");
|
||||
html += t.modbusFrames;
|
||||
html += F("</h2>");
|
||||
html += F("<div class='sub'>");
|
||||
html += t.modbusTx;
|
||||
html += F("</div><div class='mono mono-frames' id='mb-tx'>");
|
||||
html += htmlEscape(c.lastRequestHex);
|
||||
html += F("</div>");
|
||||
html += F("<div class='sub' style='margin-top:10px'>");
|
||||
html += t.modbusRx;
|
||||
html += F("</div><div class='mono mono-frames' id='mb-rx'>");
|
||||
html += htmlEscape(c.lastResponseHex);
|
||||
html += F("</div>");
|
||||
|
||||
html += F("<div class='sub' style='margin-top:12px'>");
|
||||
html += t.rawRegisters;
|
||||
html += F("</div><div class='mono mono-raw' id='raw-regs'>");
|
||||
for (uint8_t i = 0; i < REG_DATA_COUNT; i++) {
|
||||
html += F("R");
|
||||
html += String(REG_DATA_START + i);
|
||||
html += F(" = ");
|
||||
html += String(v.raw[i]);
|
||||
if (i + 1 < REG_DATA_COUNT) html += '\n';
|
||||
}
|
||||
html += F("</div></div>");
|
||||
|
||||
html += F("</div>");
|
||||
}
|
||||
|
||||
static String buildMainScript(UiLang lang, const Texts& t) {
|
||||
String s;
|
||||
s.reserve(9000);
|
||||
|
||||
s += F("<script>");
|
||||
s += F("const L={present:\""); s += t.present;
|
||||
s += F("\",absent:\""); s += t.absent;
|
||||
s += F("\",seconds:\""); s += t.seconds;
|
||||
s += F("\",ok:\""); s += t.statusOkShort;
|
||||
s += F("\",err:\""); s += t.statusErrorShort;
|
||||
s += F("\"};");
|
||||
|
||||
s += F("function badge(v){return \"<span class='\"+(v?\"ok\":\"bad\")+\"'>\"+(v?L.present:L.absent)+\"</span>\";}");
|
||||
s += F("function setHtml(id,v){const e=document.getElementById(id);if(e)e.innerHTML=v;}");
|
||||
s += F("function setText(id,v){const e=document.getElementById(id);if(e)e.textContent=v;}");
|
||||
s += F("function num(v,d){if(v===null||v===undefined||v==='-'||Number.isNaN(Number(v)))return '-';return Number(v).toFixed(d);}");
|
||||
|
||||
s += F("async function tick(){");
|
||||
s += F("try{");
|
||||
s += F("const url='/data.json?lang="); s += langCode(lang); s += F("&_=' + Date.now();");
|
||||
s += F("const r=await fetch(url,{cache:'no-store'});");
|
||||
s += F("if(!r.ok)return;");
|
||||
s += F("const d=await r.json();");
|
||||
|
||||
s += F("setHtml('st-wind',badge(d.pwind));");
|
||||
s += F("setHtml('st-th',badge(d.pth));");
|
||||
s += F("setHtml('st-noise',badge(d.pnoise));");
|
||||
s += F("setHtml('st-air',badge(d.pair));");
|
||||
s += F("setHtml('st-pressure',badge(d.ppress));");
|
||||
s += F("setHtml('st-light',badge(d.plight));");
|
||||
s += F("setHtml('st-rain',badge(d.prain));");
|
||||
s += F("setHtml('st-compass',badge(d.pcomp));");
|
||||
s += F("setHtml('st-solar',badge(d.psolar));");
|
||||
|
||||
s += F("setText('v-wind-short',num(d.wind,1));");
|
||||
s += F("setText('v-beaufort-short',(d.beaufort<0)?'-':String(d.beaufort));");
|
||||
s += F("setText('v-dir8-short',(d.dir8<0)?'-':String(d.dir8));");
|
||||
s += F("setText('v-dirdeg-short',(d.dirdeg<0)?'-':String(d.dirdeg));");
|
||||
s += F("setText('v-hum-short',num(d.hum,1));");
|
||||
s += F("setText('v-temp-short',num(d.temp,1));");
|
||||
s += F("setText('v-noise-short',num(d.noise,1));");
|
||||
s += F("setText('v-air1-short',(d.air1<0?'-':String(d.air1)));");
|
||||
s += F("setText('v-air2-short',(d.air2<0?'-':String(d.air2)));");
|
||||
s += F("setText('v-pressure-short',num(d.press,1));");
|
||||
s += F("setText('v-luxh-short',String(d.lightHigh));");
|
||||
s += F("setText('v-luxl-short',String(d.lightLow));");
|
||||
s += F("setText('v-lux-short',String(d.light));");
|
||||
s += F("setText('v-rain-short',num(d.rain,1));");
|
||||
s += F("setText('v-compass-short',num(d.compass,2));");
|
||||
s += F("setText('v-solar-short',(d.solar<0)?'-':String(d.solar));");
|
||||
s += F("setText('data-age',String(d.age)+' '+L.seconds);");
|
||||
|
||||
s += F("setHtml('mb-state',d.mbOk?\"<span class='ok'>\"+L.ok+\"</span>\":\"<span class='bad'>\"+L.err+\"</span>\");");
|
||||
s += F("setText('mb-action',d.mbAction||'-');");
|
||||
s += F("setText('mb-dur',String(d.mbDuration)+' ms');");
|
||||
s += F("setText('mb-stats',String(d.mbOkCount)+' / '+String(d.mbErrCount));");
|
||||
s += F("setText('mb-err',d.mbError||'-');");
|
||||
s += F("setText('mb-tx',d.mbTx||'');");
|
||||
s += F("setText('mb-rx',d.mbRx||'');");
|
||||
s += F("if(Array.isArray(d.raw)){setText('raw-regs',d.raw.map((v,i)=>'R'+(500+i)+' = '+v).join('\\n'));}");
|
||||
|
||||
s += F("}catch(e){}");
|
||||
s += F("}");
|
||||
s += F("window.addEventListener('load',function(){tick();setInterval(tick,2000);});");
|
||||
s += F("</script>");
|
||||
return s;
|
||||
}
|
||||
|
||||
static String buildManualCommandScript() {
|
||||
String s;
|
||||
s.reserve(2400);
|
||||
s += F("<script>");
|
||||
s += F("function wsCrc16(bytes){let crc=0xFFFF;for(let i=0;i<bytes.length;i++){crc^=bytes[i];for(let j=0;j<8;j++){if(crc&1){crc=(crc>>1)^0xA001;}else{crc>>=1;}}}return crc&0xFFFF;}");
|
||||
s += F("function wsHexByte(v){return Number(v).toString(16).toUpperCase().padStart(2,'0');}");
|
||||
s += F("function wsHexWordFromInput(id,defv){let s=(document.getElementById(id).value||defv).trim();s=s.replace(/^0x/i,'');let v=parseInt(s,16);if(Number.isNaN(v))v=parseInt(defv,16);if(Number.isNaN(v))v=0;return Math.max(0,Math.min(65535,v));}");
|
||||
s += F("function wsUpdateManualPreview(){");
|
||||
s += F("const a=Math.max(1,Math.min(247,parseInt(document.getElementById('manual-addr').value||'1',10)));");
|
||||
s += F("const r=wsHexWordFromInput('manual-reg','6000');");
|
||||
s += F("const v=wsHexWordFromInput('manual-val','0000');");
|
||||
s += F("const frame=[a,0x06,(r>>8)&0xFF,r&0xFF,(v>>8)&0xFF,v&0xFF];");
|
||||
s += F("const crc=wsCrc16(frame);frame.push(crc&0xFF);frame.push((crc>>8)&0xFF);");
|
||||
s += F("const el=document.getElementById('manual-preview');if(el){el.textContent=frame.map(wsHexByte).join(' ');}}");
|
||||
s += F("window.addEventListener('load',function(){['manual-addr','manual-reg','manual-val'].forEach(function(id){const e=document.getElementById(id);if(e){e.addEventListener('input',wsUpdateManualPreview);e.addEventListener('change',wsUpdateManualPreview);}});wsUpdateManualPreview();});");
|
||||
s += F("</script>");
|
||||
return s;
|
||||
}
|
||||
|
||||
String buildMainPage(UiLang lang, const WeatherStation& ws, bool ethUp, const String& ip, const String& mac) {
|
||||
const auto& t = T(lang);
|
||||
String html;
|
||||
html.reserve(24000);
|
||||
html += F("<!DOCTYPE html><html><head><meta charset='utf-8'><meta name='viewport' content='width=device-width,initial-scale=1'><title>");
|
||||
html += t.appTitle;
|
||||
html += F("</title>");
|
||||
html += buildStyle(t, lang);
|
||||
html += F("</head><body><div class='wrap'>");
|
||||
appendTop(html, lang, t, "main");
|
||||
appendMainCards(html, t, ws, ethUp, ip, mac);
|
||||
html += buildMainScript(lang, t);
|
||||
html += F("</div></body></html>");
|
||||
return html;
|
||||
}
|
||||
|
||||
String buildConfigPage(UiLang lang, const WeatherStation& ws, const String& flashMsg) {
|
||||
const auto& t = T(lang);
|
||||
String html;
|
||||
html.reserve(24000);
|
||||
|
||||
(void)flashMsg;
|
||||
|
||||
html += F("<!DOCTYPE html><html><head><meta charset='utf-8'><meta name='viewport' content='width=device-width,initial-scale=1'><title>");
|
||||
html += t.tabConfig;
|
||||
html += F("</title>");
|
||||
html += buildStyle(t, lang);
|
||||
html += F("</head><body><div class='wrap'>");
|
||||
appendTop(html, lang, t, "config");
|
||||
|
||||
html += F("<div class='grid'>");
|
||||
html += buildConfigHistoryBox(t, ws);
|
||||
|
||||
html += F("<div class='card card-wide'><h2>");
|
||||
html += t.manualCommand;
|
||||
html += F("</h2><div class='note'>");
|
||||
html += t.manualNote;
|
||||
html += F("</div>");
|
||||
|
||||
html += F("<form method='POST' action='/cmd-manual?lang=");
|
||||
html += langCode(lang);
|
||||
html += F("'>");
|
||||
|
||||
html += F("<div class='row2'>");
|
||||
|
||||
html += F("<div><label>");
|
||||
html += t.manualAddress;
|
||||
html += F("</label><input type='number' id='manual-addr' name='address' min='1' max='247' value='");
|
||||
html += String(ws.config().address);
|
||||
html += F("'></div>");
|
||||
|
||||
html += F("<div><label>");
|
||||
html += t.manualRegisterHex;
|
||||
html += F("</label><input type='text' id='manual-reg' name='reg' value='6000' placeholder='6000'></div>");
|
||||
|
||||
html += F("<div><label>");
|
||||
html += t.manualValueHex;
|
||||
html += F("</label><input type='text' id='manual-val' name='value' value='0000' placeholder='0000'></div>");
|
||||
|
||||
html += F("<div><label>");
|
||||
html += t.manualPreview;
|
||||
html += F("</label><div class='mono' id='manual-preview'>-</div></div>");
|
||||
|
||||
html += F("</div><button type='submit'>");
|
||||
html += t.manualSend;
|
||||
html += F("</button></form>");
|
||||
|
||||
html += F("<hr style='margin:16px 0;border:none;border-top:1px solid #ddd'>");
|
||||
|
||||
html += F("<h2>");
|
||||
html += t.rawHexTitle;
|
||||
html += F("</h2><div class='note'>");
|
||||
html += t.rawHexNote;
|
||||
html += F("</div>");
|
||||
|
||||
html += F("<form method='POST' action='/cmd-rawhex?lang=");
|
||||
html += langCode(lang);
|
||||
html += F("'>");
|
||||
html += F("<label>");
|
||||
html += t.rawHexInput;
|
||||
html += F("</label><textarea name='rawhex' placeholder='010660000001560A'></textarea>");
|
||||
html += F("<button type='submit'>");
|
||||
html += t.rawHexSend;
|
||||
html += F("</button></form></div>");
|
||||
|
||||
html += F("<div class='card card-wide'><h2>");
|
||||
html += t.configTitle;
|
||||
html += F("</h2>");
|
||||
|
||||
html += F("<table class='cfg-table'>");
|
||||
html += F("<tr><th>");
|
||||
html += t.tableItem;
|
||||
html += F("</th><th>");
|
||||
html += t.tableSetting;
|
||||
html += F("</th><th>");
|
||||
html += t.tableNote;
|
||||
html += F("</th></tr>");
|
||||
|
||||
html += F("<tr><td>");
|
||||
html += t.address;
|
||||
html += F("</td><td>");
|
||||
html += F("<form class='cfg-inline-form' method='POST' action='/config-save?lang=");
|
||||
html += langCode(lang);
|
||||
html += F("'>");
|
||||
html += F("<input type='hidden' name='baudrate' value='");
|
||||
html += String(ws.config().baudrate);
|
||||
html += F("'>");
|
||||
html += F("<input type='hidden' name='windOffset' value='");
|
||||
html += hex16(ws.config().windOffset);
|
||||
html += F("'>");
|
||||
html += F("<input type='hidden' name='rainSensitivity' value='");
|
||||
html += hex16(ws.config().rainSensitivity);
|
||||
html += F("'>");
|
||||
html += F("<input type='number' name='address' min='1' max='247' value='");
|
||||
html += String(ws.config().address);
|
||||
html += F("'> <button type='submit'>");
|
||||
html += t.save;
|
||||
html += F("</button></form></td><td>");
|
||||
html += t.noteAddress;
|
||||
html += F("</td></tr>");
|
||||
|
||||
html += F("<tr><td>");
|
||||
html += t.baudrate;
|
||||
html += F("</td><td>");
|
||||
html += F("<form class='cfg-inline-form' method='POST' action='/config-save?lang=");
|
||||
html += langCode(lang);
|
||||
html += F("'>");
|
||||
html += F("<input type='hidden' name='address' value='");
|
||||
html += String(ws.config().address);
|
||||
html += F("'>");
|
||||
html += F("<input type='hidden' name='windOffset' value='");
|
||||
html += hex16(ws.config().windOffset);
|
||||
html += F("'>");
|
||||
html += F("<input type='hidden' name='rainSensitivity' value='");
|
||||
html += hex16(ws.config().rainSensitivity);
|
||||
html += F("'>");
|
||||
html += F("<select name='baudrate'>");
|
||||
const uint32_t baudrates[] = {1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200};
|
||||
for (uint8_t i = 0; i < sizeof(baudrates) / sizeof(baudrates[0]); i++) {
|
||||
html += F("<option value='");
|
||||
html += String(baudrates[i]);
|
||||
html += F("'");
|
||||
if (baudrates[i] == ws.config().baudrate) html += F(" selected");
|
||||
html += F(">");
|
||||
html += String(baudrates[i]);
|
||||
html += F("</option>");
|
||||
}
|
||||
html += F("</select> <button type='submit'>");
|
||||
html += t.save;
|
||||
html += F("</button></form></td><td>");
|
||||
html += t.noteBaudrate;
|
||||
html += F("</td></tr>");
|
||||
|
||||
html += F("<tr><td>");
|
||||
html += t.windOffset;
|
||||
html += F("</td><td>");
|
||||
html += F("<form class='cfg-inline-form' method='POST' action='/config-save?lang=");
|
||||
html += langCode(lang);
|
||||
html += F("'>");
|
||||
html += F("<input type='hidden' name='address' value='");
|
||||
html += String(ws.config().address);
|
||||
html += F("'>");
|
||||
html += F("<input type='hidden' name='baudrate' value='");
|
||||
html += String(ws.config().baudrate);
|
||||
html += F("'>");
|
||||
html += F("<input type='hidden' name='rainSensitivity' value='");
|
||||
html += hex16(ws.config().rainSensitivity);
|
||||
html += F("'>");
|
||||
html += F("<input type='text' name='windOffset' value='");
|
||||
html += hex16(ws.config().windOffset);
|
||||
html += F("' placeholder='0000'> <button type='submit'>");
|
||||
html += t.save;
|
||||
html += F("</button></form></td><td>");
|
||||
html += t.noteWindOffset;
|
||||
html += F("</td></tr>");
|
||||
|
||||
html += F("<tr><td>");
|
||||
html += t.rainSensitivity;
|
||||
html += F("</td><td>");
|
||||
html += F("<form class='cfg-inline-form' method='POST' action='/config-save?lang=");
|
||||
html += langCode(lang);
|
||||
html += F("'>");
|
||||
html += F("<input type='hidden' name='address' value='");
|
||||
html += String(ws.config().address);
|
||||
html += F("'>");
|
||||
html += F("<input type='hidden' name='baudrate' value='");
|
||||
html += String(ws.config().baudrate);
|
||||
html += F("'>");
|
||||
html += F("<input type='hidden' name='windOffset' value='");
|
||||
html += hex16(ws.config().windOffset);
|
||||
html += F("'>");
|
||||
html += F("<input type='text' name='rainSensitivity' value='");
|
||||
html += hex16(ws.config().rainSensitivity);
|
||||
html += F("' placeholder='0011'> <button type='submit'>");
|
||||
html += t.save;
|
||||
html += F("</button></form></td><td>");
|
||||
html += t.noteRainSensitivity;
|
||||
html += F("</td></tr>");
|
||||
|
||||
html += F("<tr><td>");
|
||||
html += t.commandWindZero;
|
||||
html += F("</td><td><form class='cfg-inline-form' method='POST' action='/cmd-wind-zero?lang=");
|
||||
html += langCode(lang);
|
||||
html += F("'><button type='submit'>");
|
||||
html += t.execute;
|
||||
html += F("</button></form></td><td>");
|
||||
html += t.noteWindZero;
|
||||
html += F("</td></tr>");
|
||||
|
||||
html += F("<tr><td>");
|
||||
html += t.commandRainZero;
|
||||
html += F("</td><td><form class='cfg-inline-form' method='POST' action='/cmd-rain-zero?lang=");
|
||||
html += langCode(lang);
|
||||
html += F("'><button type='submit'>");
|
||||
html += t.execute;
|
||||
html += F("</button></form></td><td>");
|
||||
html += t.noteRainZero;
|
||||
html += F("</td></tr>");
|
||||
|
||||
html += F("</table></div>");
|
||||
|
||||
html += F("</div>");
|
||||
html += buildManualCommandScript();
|
||||
html += F("</div></body></html>");
|
||||
return html;
|
||||
}
|
||||
|
||||
String buildMainDataJson(const WeatherStation& ws, bool ethUp, const String& ip, const String& mac) {
|
||||
const auto& v = ws.values();
|
||||
const auto& p = ws.presence();
|
||||
const auto& c = ws.commLog();
|
||||
|
||||
String json;
|
||||
json.reserve(2400);
|
||||
|
||||
json += F("{");
|
||||
json += F("\"eth\":"); json += ethUp ? F("true") : F("false");
|
||||
json += F(",\"ip\":\""); json += jsonString(ip); json += F("\"");
|
||||
json += F(",\"mac\":\""); json += jsonString(mac); json += F("\"");
|
||||
json += F(",\"age\":"); json += String((millis() - v.lastReadMs) / 1000UL);
|
||||
|
||||
json += F(",\"wind\":"); json += jsonFloat(v.windSpeed);
|
||||
json += F(",\"beaufort\":"); json += (v.windForce >= 0 ? String(v.windForce) : F("-1"));
|
||||
json += F(",\"dir8\":"); json += (v.windDir8 >= 0 ? String(v.windDir8) : F("-1"));
|
||||
json += F(",\"dirdeg\":"); json += (v.windDirDeg >= 0 ? String(v.windDirDeg) : F("-1"));
|
||||
json += F(",\"temp\":"); json += jsonFloat(v.temperature);
|
||||
json += F(",\"hum\":"); json += jsonFloat(v.humidity);
|
||||
json += F(",\"noise\":"); json += jsonFloat(v.noise);
|
||||
json += F(",\"air1\":"); json += String(v.air1);
|
||||
json += F(",\"air2\":"); json += String(v.air2);
|
||||
json += F(",\"press\":"); json += jsonFloat(v.pressureKpa);
|
||||
json += F(",\"rain\":"); json += jsonFloat(v.rain);
|
||||
json += F(",\"solar\":"); json += String(v.solarRadiation);
|
||||
json += F(",\"light\":"); json += String(v.lightLux);
|
||||
json += F(",\"lightHigh\":"); json += String(v.lightHigh);
|
||||
json += F(",\"lightLow\":"); json += String(v.lightLow);
|
||||
json += F(",\"compass\":"); json += jsonFloat(v.compassDeg, 2);
|
||||
|
||||
json += F(",\"pwind\":"); json += p.wind ? F("true") : F("false");
|
||||
json += F(",\"pth\":"); json += p.humidityTemp ? F("true") : F("false");
|
||||
json += F(",\"pnoise\":"); json += p.noise ? F("true") : F("false");
|
||||
json += F(",\"pair\":"); json += p.air ? F("true") : F("false");
|
||||
json += F(",\"ppress\":"); json += p.pressure ? F("true") : F("false");
|
||||
json += F(",\"plight\":"); json += p.light ? F("true") : F("false");
|
||||
json += F(",\"prain\":"); json += p.rain ? F("true") : F("false");
|
||||
json += F(",\"pcomp\":"); json += p.compass ? F("true") : F("false");
|
||||
json += F(",\"psolar\":"); json += p.solar ? F("true") : F("false");
|
||||
|
||||
json += F(",\"mbOk\":"); json += c.lastOk ? F("true") : F("false");
|
||||
json += F(",\"mbDuration\":"); json += String(c.lastDurationMs);
|
||||
json += F(",\"mbOkCount\":"); json += String(c.successCount);
|
||||
json += F(",\"mbErrCount\":"); json += String(c.errorCount);
|
||||
json += F(",\"mbAction\":\""); json += jsonString(c.lastAction); json += F("\"");
|
||||
json += F(",\"mbError\":\""); json += jsonString(c.lastError); json += F("\"");
|
||||
json += F(",\"mbTx\":\""); json += jsonString(c.lastRequestHex); json += F("\"");
|
||||
json += F(",\"mbRx\":\""); json += jsonString(c.lastResponseHex); json += F("\"");
|
||||
|
||||
json += F(",\"raw\":[");
|
||||
for (uint8_t i = 0; i < REG_DATA_COUNT; i++) {
|
||||
if (i) json += ',';
|
||||
json += String(v.raw[i]);
|
||||
}
|
||||
json += F("]}");
|
||||
|
||||
return json;
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <WebServer.h>
|
||||
#include "Lang.h"
|
||||
#include "WeatherStation.h"
|
||||
|
||||
String htmlEscape(const String& in);
|
||||
String fmtFloat(float v, uint8_t decimals = 1);
|
||||
String buildMainPage(UiLang lang, const WeatherStation& ws, bool ethUp, const String& ip, const String& mac);
|
||||
String buildConfigPage(UiLang lang, const WeatherStation& ws, const String& flashMsg);
|
||||
String buildMainDataJson(const WeatherStation& ws, bool ethUp, const String& ip, const String& mac);
|
||||
String buildStyle(const Texts& t, UiLang lang);
|
||||
|
|
@ -0,0 +1,455 @@
|
|||
#include <Arduino.h>
|
||||
#include <WiFi.h>
|
||||
#include <ETH.h>
|
||||
#include <Preferences.h>
|
||||
#include <WebServer.h>
|
||||
#include <stdlib.h>
|
||||
#include "Config.h"
|
||||
#include "Lang.h"
|
||||
#include "WeatherStation.h"
|
||||
#include "WebUi.h"
|
||||
#include "logo_web.h"
|
||||
|
||||
Preferences prefs;
|
||||
WebServer server(80);
|
||||
HardwareSerial RS485Serial(2);
|
||||
WeatherStation station(RS485Serial);
|
||||
|
||||
bool ethConnected = false;
|
||||
bool ethGotIp = false;
|
||||
unsigned long lastPollMs = 0;
|
||||
unsigned long lastDetectRecheckMs = 0;
|
||||
bool uiOnConfigPage = false;
|
||||
String flashMessage;
|
||||
|
||||
static void fwLog(const String& msg) {
|
||||
Serial.println(String(F("[FW] ")) + msg);
|
||||
}
|
||||
|
||||
|
||||
static void sendNoCacheHeaders() {
|
||||
server.sendHeader(F("Cache-Control"), F("no-store, no-cache, must-revalidate, max-age=0"));
|
||||
server.sendHeader(F("Pragma"), F("no-cache"));
|
||||
server.sendHeader(F("Expires"), F("0"));
|
||||
}
|
||||
|
||||
static void loadPreferences() {
|
||||
prefs.begin("meteo", true);
|
||||
station.config().address = prefs.getUChar("addr", DEFAULT_MODBUS_ADDR);
|
||||
station.config().baudrate = prefs.getUInt("baud", DEFAULT_MODBUS_BAUD);
|
||||
station.config().airMode = static_cast<AirQualityMode>(prefs.getUChar("airMode", 0));
|
||||
prefs.end();
|
||||
}
|
||||
|
||||
static void savePreferences() {
|
||||
prefs.begin("meteo", false);
|
||||
prefs.putUChar("addr", station.config().address);
|
||||
prefs.putUInt("baud", station.config().baudrate);
|
||||
prefs.putUChar("airMode", static_cast<uint8_t>(station.config().airMode));
|
||||
prefs.end();
|
||||
}
|
||||
|
||||
void WiFiEvent(WiFiEvent_t event) {
|
||||
switch (event) {
|
||||
case ARDUINO_EVENT_ETH_START:
|
||||
ETH.setHostname("esplan-weather");
|
||||
break;
|
||||
case ARDUINO_EVENT_ETH_CONNECTED:
|
||||
ethConnected = true;
|
||||
fwLog(F("ETH link connected"));
|
||||
break;
|
||||
case ARDUINO_EVENT_ETH_GOT_IP:
|
||||
ethConnected = true;
|
||||
ethGotIp = true;
|
||||
fwLog(String(F("ETH IP acquired: ")) + ETH.localIP().toString());
|
||||
break;
|
||||
case ARDUINO_EVENT_ETH_DISCONNECTED:
|
||||
ethConnected = false;
|
||||
ethGotIp = false;
|
||||
fwLog(F("ETH link disconnected"));
|
||||
break;
|
||||
case ARDUINO_EVENT_ETH_STOP:
|
||||
ethConnected = false;
|
||||
ethGotIp = false;
|
||||
fwLog(F("ETH stopped"));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static UiLang currentLang() {
|
||||
if (server.hasArg("lang")) return parseLang(server.arg("lang"));
|
||||
return UiLang::CZ;
|
||||
}
|
||||
|
||||
static String currentIp() {
|
||||
return ethGotIp ? ETH.localIP().toString() : String("0.0.0.0");
|
||||
}
|
||||
|
||||
static String currentMac() {
|
||||
return ETH.macAddress();
|
||||
}
|
||||
|
||||
static void redirectWithMessage(const String& url, UiLang lang, const String& msg) {
|
||||
flashMessage = msg;
|
||||
const String target = url + (url.indexOf('?') >= 0 ? '&' : '?') + String(F("lang=")) + langCode(lang);
|
||||
server.sendHeader("Location", target, true);
|
||||
server.send(302, "text/plain", "");
|
||||
}
|
||||
|
||||
static String buildSimpleMessage(UiLang lang, const String& title, const String& detail, bool ok) {
|
||||
const auto& t = T(lang);
|
||||
String msg;
|
||||
msg.reserve(320);
|
||||
msg += F("<div><strong>");
|
||||
msg += htmlEscape(title);
|
||||
msg += F(":</strong> ");
|
||||
msg += ok ? String(F("<span class='ok'>")) + t.statusOkShort + F("</span>") : String(F("<span class='bad'>")) + t.statusErrorShort + F("</span>");
|
||||
if (detail.length()) {
|
||||
msg += F("<br>");
|
||||
msg += htmlEscape(detail);
|
||||
}
|
||||
msg += F("</div>");
|
||||
return msg;
|
||||
}
|
||||
|
||||
static String buildConfigResultMessage(UiLang lang, const WeatherStation& ws, const String& title) {
|
||||
const auto& t = T(lang);
|
||||
const auto& c = ws.commLog();
|
||||
|
||||
String msg;
|
||||
msg.reserve(900);
|
||||
msg += F("<div><strong>");
|
||||
msg += htmlEscape(title);
|
||||
msg += F(":</strong> ");
|
||||
msg += c.lastOk ? String(F("<span class='ok'>")) + t.statusOkShort + F("</span>") : String(F("<span class='bad'>")) + t.statusErrorShort + F("</span>");
|
||||
msg += F("<br>");
|
||||
msg += htmlEscape(t.modbusAction);
|
||||
msg += F(": ");
|
||||
msg += htmlEscape(c.lastAction.length() ? c.lastAction : String("-"));
|
||||
msg += F("<br>");
|
||||
msg += htmlEscape(t.modbusDuration);
|
||||
msg += F(": ");
|
||||
msg += String(c.lastDurationMs);
|
||||
msg += F(" ms");
|
||||
msg += F("<br>");
|
||||
msg += htmlEscape(t.modbusError);
|
||||
msg += F(": ");
|
||||
msg += (c.lastError.length() ? htmlEscape(c.lastError) : F("-"));
|
||||
msg += F("</div>");
|
||||
return msg;
|
||||
}
|
||||
|
||||
static bool parseHex16(const String& s, uint16_t& out) {
|
||||
String v = s;
|
||||
v.trim();
|
||||
v.replace("0x", "");
|
||||
v.replace("0X", "");
|
||||
if (v.length() == 0 || v.length() > 4) return false;
|
||||
char* endptr = nullptr;
|
||||
unsigned long n = strtoul(v.c_str(), &endptr, 16);
|
||||
if (*endptr != '\0' || n > 0xFFFFUL) return false;
|
||||
out = static_cast<uint16_t>(n);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parseUint32Strict(const String& s, uint32_t& out) {
|
||||
String v = s;
|
||||
v.trim();
|
||||
if (v.length() == 0) return false;
|
||||
char* endptr = nullptr;
|
||||
unsigned long n = strtoul(v.c_str(), &endptr, 10);
|
||||
if (*endptr != '\0') return false;
|
||||
out = static_cast<uint32_t>(n);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parseHexBytesLoose(const String& input, uint8_t* out, size_t& outLen, size_t maxLen) {
|
||||
String s = input;
|
||||
s.trim();
|
||||
s.replace(" ", "");
|
||||
s.replace("\t", "");
|
||||
s.replace("\r", "");
|
||||
s.replace("\n", "");
|
||||
if (s.length() == 0 || (s.length() % 2) != 0) {
|
||||
outLen = 0;
|
||||
return false;
|
||||
}
|
||||
size_t bytes = s.length() / 2;
|
||||
if (bytes > maxLen) {
|
||||
outLen = 0;
|
||||
return false;
|
||||
}
|
||||
outLen = 0;
|
||||
for (size_t i = 0; i < bytes; i++) {
|
||||
String tok = s.substring(i * 2, i * 2 + 2);
|
||||
char* endptr = nullptr;
|
||||
unsigned long v = strtoul(tok.c_str(), &endptr, 16);
|
||||
if (*endptr != '\0' || v > 0xFFUL) {
|
||||
outLen = 0;
|
||||
return false;
|
||||
}
|
||||
out[outLen++] = static_cast<uint8_t>(v);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool writeRegisterToAddress(uint8_t slaveAddr, uint16_t reg, uint16_t value) {
|
||||
const uint8_t oldAddr = station.config().address;
|
||||
station.config().address = slaveAddr;
|
||||
const bool ok = station.writeRegister(reg, value);
|
||||
station.config().address = oldAddr;
|
||||
return ok;
|
||||
}
|
||||
|
||||
static void handleRoot() {
|
||||
uiOnConfigPage = false;
|
||||
UiLang lang = currentLang();
|
||||
sendNoCacheHeaders();
|
||||
server.send(200, "text/html; charset=utf-8", buildMainPage(lang, station, ethConnected && ethGotIp, currentIp(), currentMac()));
|
||||
}
|
||||
|
||||
static void handleConfig() {
|
||||
uiOnConfigPage = true;
|
||||
UiLang lang = currentLang();
|
||||
const String msg = flashMessage;
|
||||
flashMessage = String();
|
||||
sendNoCacheHeaders();
|
||||
server.send(200, "text/html; charset=utf-8", buildConfigPage(lang, station, msg));
|
||||
}
|
||||
|
||||
static void handleLogo() {
|
||||
server.send_P(200, "image/png", reinterpret_cast<PGM_P>(logo_web_png), logo_web_png_len);
|
||||
}
|
||||
|
||||
static void handleJson() {
|
||||
sendNoCacheHeaders();
|
||||
server.send(200, "application/json; charset=utf-8", buildMainDataJson(station, ethConnected && ethGotIp, currentIp(), currentMac()));
|
||||
}
|
||||
|
||||
static bool applyRuntimeComm(UiLang lang, String& errorText, bool& changed) {
|
||||
changed = false;
|
||||
|
||||
if (server.hasArg("address")) {
|
||||
uint32_t addr = 0;
|
||||
if (!parseUint32Strict(server.arg("address"), addr) || addr < 1 || addr > 247) {
|
||||
errorText = T(lang).address;
|
||||
return false;
|
||||
}
|
||||
if (station.config().address != static_cast<uint8_t>(addr)) {
|
||||
station.config().address = static_cast<uint8_t>(addr);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (server.hasArg("baudrate")) {
|
||||
uint32_t baud = 0;
|
||||
if (!parseUint32Strict(server.arg("baudrate"), baud)) {
|
||||
errorText = T(lang).baudrate;
|
||||
return false;
|
||||
}
|
||||
switch (baud) {
|
||||
case 1200:
|
||||
case 2400:
|
||||
case 4800:
|
||||
case 9600:
|
||||
case 19200:
|
||||
case 38400:
|
||||
case 57600:
|
||||
case 115200:
|
||||
if (station.config().baudrate != baud) {
|
||||
station.setBaudrate(baud);
|
||||
changed = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
errorText = T(lang).baudrate;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) savePreferences();
|
||||
return true;
|
||||
}
|
||||
|
||||
static void handleConfigSave() {
|
||||
UiLang lang = currentLang();
|
||||
const auto& t = T(lang);
|
||||
|
||||
String runtimeError;
|
||||
bool runtimeChanged = false;
|
||||
if (!applyRuntimeComm(lang, runtimeError, runtimeChanged)) {
|
||||
redirectWithMessage("/config", lang, buildSimpleMessage(lang, t.save, runtimeError, false));
|
||||
return;
|
||||
}
|
||||
|
||||
bool didWrite = false;
|
||||
bool ok = true;
|
||||
String firstValidationError;
|
||||
|
||||
const bool hasWindOffset = server.hasArg("windOffset") && server.arg("windOffset").length() > 0;
|
||||
const bool hasRainSensitivity = server.hasArg("rainSensitivity") && server.arg("rainSensitivity").length() > 0;
|
||||
|
||||
if (hasWindOffset) {
|
||||
uint16_t v = 0;
|
||||
if (!parseHex16(server.arg("windOffset"), v)) {
|
||||
ok = false;
|
||||
firstValidationError = t.windOffset;
|
||||
} else {
|
||||
ok = station.writeRegister(REG_CFG_WIND_DIR_OFFSET, v) && ok;
|
||||
station.pushConfigLog();
|
||||
didWrite = true;
|
||||
if (ok) station.config().windOffset = v;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasRainSensitivity) {
|
||||
uint16_t v = 0;
|
||||
if (!parseHex16(server.arg("rainSensitivity"), v)) {
|
||||
ok = false;
|
||||
if (!firstValidationError.length()) firstValidationError = t.rainSensitivity;
|
||||
} else {
|
||||
ok = station.writeRegister(REG_CFG_RAIN_SENSITIVITY, v) && ok;
|
||||
station.pushConfigLog();
|
||||
didWrite = true;
|
||||
if (ok) station.config().rainSensitivity = v;
|
||||
}
|
||||
}
|
||||
|
||||
if (!didWrite) {
|
||||
const String detail = runtimeChanged ? String() : firstValidationError;
|
||||
redirectWithMessage("/config", lang, buildSimpleMessage(lang, t.save, detail, runtimeChanged || ok));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ok && firstValidationError.length()) {
|
||||
String msg = buildConfigResultMessage(lang, station, t.save);
|
||||
msg += F("<div style='margin-top:8px'>");
|
||||
msg += htmlEscape(firstValidationError);
|
||||
msg += F("</div>");
|
||||
redirectWithMessage("/config", lang, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
redirectWithMessage("/config", lang, buildConfigResultMessage(lang, station, t.save));
|
||||
}
|
||||
|
||||
static void handleCmdWindZero() {
|
||||
UiLang lang = currentLang();
|
||||
station.commandZeroWind();
|
||||
station.pushConfigLog();
|
||||
redirectWithMessage("/config", lang, buildConfigResultMessage(lang, station, T(lang).commandWindZero));
|
||||
}
|
||||
|
||||
static void handleCmdRainZero() {
|
||||
UiLang lang = currentLang();
|
||||
station.commandZeroRain();
|
||||
station.pushConfigLog();
|
||||
redirectWithMessage("/config", lang, buildConfigResultMessage(lang, station, T(lang).commandRainZero));
|
||||
}
|
||||
|
||||
static void handleCmdManual() {
|
||||
UiLang lang = currentLang();
|
||||
const auto& t = T(lang);
|
||||
if (!server.hasArg("address") || !server.hasArg("reg") || !server.hasArg("value")) {
|
||||
redirectWithMessage("/config", lang, buildSimpleMessage(lang, t.manualCommand, t.writeFail, false));
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t addrParsed = 0;
|
||||
uint16_t regIn = 0;
|
||||
uint16_t valIn = 0;
|
||||
if (!parseUint32Strict(server.arg("address"), addrParsed) || addrParsed < 1 || addrParsed > 247 ||
|
||||
!parseHex16(server.arg("reg"), regIn) || !parseHex16(server.arg("value"), valIn)) {
|
||||
redirectWithMessage("/config", lang, buildSimpleMessage(lang, t.manualCommand, t.writeFail, false));
|
||||
return;
|
||||
}
|
||||
|
||||
writeRegisterToAddress(static_cast<uint8_t>(addrParsed), regIn, valIn);
|
||||
station.pushConfigLog();
|
||||
redirectWithMessage("/config", lang, buildConfigResultMessage(lang, station, t.manualCommand));
|
||||
}
|
||||
|
||||
static void handleCmdRawHex() {
|
||||
UiLang lang = currentLang();
|
||||
const auto& t = T(lang);
|
||||
if (!server.hasArg("rawhex")) {
|
||||
redirectWithMessage("/config", lang, buildSimpleMessage(lang, t.rawHexTitle, t.writeFail, false));
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t frame[128];
|
||||
size_t frameLen = 0;
|
||||
if (!parseHexBytesLoose(server.arg("rawhex"), frame, frameLen, sizeof(frame))) {
|
||||
redirectWithMessage("/config", lang, buildSimpleMessage(lang, t.rawHexTitle, t.writeFail, false));
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t resp[128] = {0};
|
||||
station.sendRawFrame(frame, frameLen, resp, sizeof(resp), 300, String(t.rawHexTitle));
|
||||
station.pushConfigLog();
|
||||
redirectWithMessage("/config", lang, buildConfigResultMessage(lang, station, t.rawHexTitle));
|
||||
}
|
||||
|
||||
static void handleNotFound() {
|
||||
sendNoCacheHeaders();
|
||||
server.send(404, "text/plain; charset=utf-8", "404 Not Found");
|
||||
}
|
||||
|
||||
static void beginEthernet() {
|
||||
WiFi.onEvent(WiFiEvent);
|
||||
ETH.begin(ETH_PHY_TYPE, ETH_PHY_ADDR, ETH_PHY_MDC, ETH_PHY_MDIO, ETH_PHY_POWER, ETH_CLK_MODE);
|
||||
}
|
||||
|
||||
static void beginWeb() {
|
||||
server.on("/", HTTP_GET, handleRoot);
|
||||
server.on("/config", HTTP_GET, handleConfig);
|
||||
server.on("/data.json", HTTP_GET, handleJson);
|
||||
server.on("/logo.png", HTTP_GET, handleLogo);
|
||||
server.on("/config-save", HTTP_POST, handleConfigSave);
|
||||
server.on("/cmd-wind-zero", HTTP_POST, handleCmdWindZero);
|
||||
server.on("/cmd-rain-zero", HTTP_POST, handleCmdRainZero);
|
||||
server.on("/cmd-manual", HTTP_POST, handleCmdManual);
|
||||
server.on("/cmd-rawhex", HTTP_POST, handleCmdRawHex);
|
||||
server.onNotFound(handleNotFound);
|
||||
server.begin();
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(300);
|
||||
Serial.println();
|
||||
Serial.println("ESPlan Weather Station start");
|
||||
fwLog(F("Boot"));
|
||||
|
||||
loadPreferences();
|
||||
station.begin();
|
||||
station.readSensorConfig();
|
||||
station.readAll();
|
||||
|
||||
beginEthernet();
|
||||
beginWeb();
|
||||
fwLog(F("HTTP server started"));
|
||||
}
|
||||
|
||||
void loop() {
|
||||
server.handleClient();
|
||||
|
||||
const unsigned long now = millis();
|
||||
if (!uiOnConfigPage && (now - lastPollMs >= SENSOR_POLL_MS)) {
|
||||
lastPollMs = now;
|
||||
const bool ok = station.readAll();
|
||||
if (!ok) {
|
||||
fwLog(String(F("Modbus read failed: ")) + station.commLog().lastError);
|
||||
}
|
||||
}
|
||||
|
||||
if (!uiOnConfigPage && (now - lastDetectRecheckMs >= DETECT_RECHECK_MS)) {
|
||||
lastDetectRecheckMs = now;
|
||||
const bool ok = station.readSensorConfig();
|
||||
if (!ok) {
|
||||
fwLog(String(F("Sensor config refresh failed: ")) + station.commLog().lastError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,936 @@
|
|||
#include "logo_web.h"
|
||||
#include <pgmspace.h>
|
||||
#include <stddef.h>
|
||||
|
||||
const uint8_t logo_web_png[] PROGMEM = {
|
||||
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D,
|
||||
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x01, 0x90, 0x00, 0x00, 0x00, 0x66,
|
||||
0x08, 0x06, 0x00, 0x00, 0x00, 0xE5, 0x03, 0xC7, 0x7C, 0x00, 0x00, 0x00,
|
||||
0x01, 0x73, 0x52, 0x47, 0x42, 0x01, 0xD9, 0xC9, 0x2C, 0x7F, 0x00, 0x00,
|
||||
0x00, 0x04, 0x67, 0x41, 0x4D, 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC,
|
||||
0x61, 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4D, 0x00, 0x00,
|
||||
0x7A, 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xFA, 0x00, 0x00, 0x00,
|
||||
0x80, 0xE8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xEA, 0x60, 0x00, 0x00,
|
||||
0x3A, 0x98, 0x00, 0x00, 0x17, 0x70, 0x9C, 0xBA, 0x51, 0x3C, 0x00, 0x00,
|
||||
0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x2C, 0x4B, 0x00, 0x00,
|
||||
0x2C, 0x4B, 0x01, 0xA5, 0x3D, 0x96, 0xA9, 0x00, 0x00, 0x20, 0x00, 0x49,
|
||||
0x44, 0x41, 0x54, 0x78, 0xDA, 0xED, 0x9D, 0x79, 0x98, 0x14, 0xC5, 0xF9,
|
||||
0xC7, 0x3F, 0x35, 0xBB, 0x0B, 0x28, 0x82, 0x88, 0x12, 0x4F, 0xBC, 0xEF,
|
||||
0xA8, 0xA8, 0x98, 0xA8, 0xC9, 0xA0, 0x02, 0x2A, 0x06, 0xD4, 0x78, 0xD1,
|
||||
0x6A, 0x34, 0xDE, 0x6D, 0xBC, 0x30, 0xC6, 0xC4, 0xC4, 0xF1, 0xF8, 0x99,
|
||||
0x78, 0x0D, 0x78, 0xDF, 0x1A, 0x6B, 0xA3, 0x46, 0x45, 0x4D, 0x71, 0x28,
|
||||
0x06, 0x24, 0x9A, 0xC4, 0x73, 0x8C, 0x07, 0x2A, 0x5E, 0xA8, 0xC8, 0x65,
|
||||
0xF0, 0x8A, 0x72, 0xDF, 0xC7, 0xEE, 0x4E, 0xFD, 0xFE, 0xA8, 0x1A, 0x76,
|
||||
0x58, 0x66, 0x76, 0xBB, 0x7B, 0x66, 0x76, 0x66, 0x77, 0xEB, 0xFB, 0x3C,
|
||||
0x3C, 0xC0, 0x6E, 0x77, 0x75, 0x75, 0x55, 0xF5, 0xFB, 0xAD, 0xF7, 0xAD,
|
||||
0xF7, 0x10, 0x94, 0x18, 0x42, 0xAA, 0xAE, 0x1A, 0x76, 0x02, 0x76, 0x04,
|
||||
0x7A, 0x01, 0xEB, 0x03, 0x31, 0xFB, 0xEB, 0xE5, 0xC0, 0x7C, 0x60, 0x96,
|
||||
0x80, 0xCF, 0xB5, 0xEF, 0xCD, 0xA7, 0x1D, 0x42, 0x48, 0xD5, 0x43, 0xC3,
|
||||
0xCE, 0xC0, 0xF6, 0xC0, 0xC6, 0x76, 0x0C, 0x00, 0x34, 0xB0, 0x0C, 0x98,
|
||||
0x0B, 0xCC, 0xB0, 0x63, 0xB0, 0x14, 0x07, 0x07, 0x07, 0x87, 0xB6, 0x20,
|
||||
0xDB, 0x4A, 0x20, 0x2C, 0x37, 0xD0, 0x70, 0x18, 0x30, 0x08, 0xE8, 0x07,
|
||||
0xEC, 0x02, 0x54, 0x05, 0xB8, 0x35, 0x0D, 0x7C, 0x09, 0xBC, 0x0E, 0xBC,
|
||||
0x00, 0x4C, 0xC4, 0xF7, 0xBE, 0x6F, 0xA3, 0x84, 0xB1, 0x89, 0x86, 0x23,
|
||||
0x80, 0xC3, 0x81, 0x38, 0xB0, 0x4D, 0x16, 0x69, 0x36, 0x87, 0x06, 0x60,
|
||||
0x1A, 0x90, 0x02, 0xFE, 0x21, 0xE0, 0x05, 0xED, 0x7B, 0x4B, 0xDC, 0x32,
|
||||
0x75, 0x70, 0x70, 0x68, 0xB7, 0x04, 0xD2, 0xB3, 0x76, 0x94, 0x98, 0xAF,
|
||||
0x75, 0x1C, 0xF8, 0x15, 0x70, 0x0C, 0xD0, 0xB5, 0x08, 0xCD, 0xD6, 0x03,
|
||||
0xFF, 0x02, 0x6A, 0xAB, 0x60, 0x5C, 0x83, 0xEF, 0xD5, 0x57, 0xF2, 0x40,
|
||||
0x56, 0x4B, 0x55, 0x55, 0x0F, 0x47, 0x02, 0x3E, 0x86, 0x40, 0x3B, 0x15,
|
||||
0xA1, 0xD9, 0xE5, 0xC0, 0xB3, 0xC0, 0x83, 0xDD, 0x85, 0x78, 0x79, 0xF1,
|
||||
0x39, 0x43, 0xB5, 0x5B, 0xB2, 0x0E, 0x0E, 0x0E, 0x19, 0xE8, 0x64, 0x7C,
|
||||
0xB0, 0x95, 0xBB, 0xB9, 0xF0, 0x85, 0x48, 0xA4, 0x7E, 0x5D, 0xD9, 0x04,
|
||||
0x22, 0xD5, 0x60, 0xE0, 0x1A, 0xE0, 0xC7, 0x25, 0xEC, 0xE7, 0x2C, 0x60,
|
||||
0x44, 0x15, 0x3C, 0xD4, 0xE0, 0x7B, 0x75, 0x15, 0x48, 0x1C, 0xA7, 0x03,
|
||||
0x09, 0x8C, 0x99, 0xAE, 0x54, 0x98, 0x0C, 0x5C, 0xDB, 0x4D, 0x88, 0x71,
|
||||
0x4B, 0x1C, 0x91, 0x38, 0x38, 0x38, 0x18, 0x02, 0xB9, 0x00, 0xB8, 0x37,
|
||||
0xCF, 0xAF, 0x3F, 0x12, 0x89, 0xD4, 0x5E, 0xA5, 0x7C, 0x7E, 0x2C, 0xF2,
|
||||
0x9D, 0x52, 0xED, 0x8E, 0x54, 0xFF, 0x06, 0x26, 0x94, 0x98, 0x3C, 0x00,
|
||||
0xB6, 0x03, 0x1E, 0x68, 0x80, 0x0F, 0x91, 0x6A, 0x50, 0xC5, 0xCC, 0x9E,
|
||||
0x54, 0xFD, 0xEB, 0xE1, 0x7D, 0xE0, 0x2F, 0x25, 0x26, 0x0F, 0x80, 0x7D,
|
||||
0x80, 0xA7, 0x97, 0x68, 0xFD, 0x0A, 0x52, 0xF5, 0x71, 0x9F, 0x8E, 0x83,
|
||||
0x83, 0x43, 0xD9, 0x37, 0xD0, 0x61, 0x6F, 0xA8, 0x91, 0xAA, 0xAA, 0x0E,
|
||||
0xFE, 0x00, 0xFC, 0x1F, 0xD0, 0xB9, 0x95, 0xFB, 0xBB, 0x2B, 0xF0, 0x0F,
|
||||
0xA4, 0x7A, 0x44, 0xC0, 0xAF, 0xB5, 0xEF, 0x2D, 0x2E, 0xC7, 0xA0, 0xD9,
|
||||
0x73, 0x9E, 0x5B, 0x31, 0xE6, 0x2A, 0xD1, 0xCA, 0x8F, 0xEF, 0x07, 0x4C,
|
||||
0x42, 0xAA, 0x1B, 0xAB, 0xE0, 0xFA, 0x4A, 0x37, 0xED, 0x39, 0x38, 0x38,
|
||||
0xB4, 0x5F, 0x84, 0xD2, 0x40, 0x84, 0x54, 0xBD, 0xEA, 0xE0, 0x79, 0xE0,
|
||||
0x86, 0x32, 0x90, 0x47, 0x36, 0xCE, 0xD0, 0xF0, 0x2E, 0x52, 0xED, 0xD5,
|
||||
0xEA, 0x4F, 0x96, 0x6A, 0x37, 0x0D, 0x6F, 0x03, 0xE7, 0x96, 0x81, 0x3C,
|
||||
0xD6, 0xF0, 0x38, 0x70, 0x4D, 0x03, 0xBC, 0x88, 0x54, 0x9B, 0xB9, 0x65,
|
||||
0xEC, 0xE0, 0xE0, 0x50, 0x96, 0xCD, 0x74, 0x08, 0xC1, 0xB9, 0x2B, 0xC6,
|
||||
0x5C, 0xB5, 0x7D, 0x05, 0xF5, 0x7F, 0x29, 0x70, 0x22, 0xBE, 0xF7, 0x5C,
|
||||
0x2B, 0x91, 0xC7, 0xA1, 0xC0, 0x68, 0x60, 0xC3, 0x0A, 0x1A, 0x83, 0x2F,
|
||||
0x81, 0x21, 0xF8, 0xDE, 0x47, 0x6E, 0x39, 0x3B, 0x38, 0xB4, 0x5F, 0xE8,
|
||||
0x64, 0xFC, 0xA7, 0x40, 0xF7, 0x26, 0x3F, 0x3E, 0x12, 0xB8, 0x20, 0xCF,
|
||||
0x2D, 0x5F, 0xE4, 0xF9, 0xDD, 0x1B, 0x22, 0x91, 0x5A, 0xD8, 0x7A, 0x04,
|
||||
0x62, 0x6C, 0xEE, 0xFF, 0xC4, 0xC4, 0x71, 0x54, 0x1A, 0xEA, 0x80, 0xD3,
|
||||
0xF1, 0xBD, 0x27, 0x4B, 0x4C, 0x1E, 0xC7, 0x01, 0x4F, 0x94, 0x59, 0xF3,
|
||||
0xCA, 0x87, 0xF9, 0xC0, 0x60, 0x7C, 0xEF, 0x2D, 0xF7, 0x99, 0x39, 0x38,
|
||||
0xB4, 0x5B, 0x02, 0x99, 0x0C, 0xEC, 0x5D, 0x84, 0xA6, 0x0E, 0x14, 0x89,
|
||||
0xD4, 0x9B, 0xC5, 0xE8, 0x53, 0xCB, 0x26, 0x2C, 0xA9, 0x76, 0xAF, 0x60,
|
||||
0xF2, 0x00, 0x63, 0xCE, 0x79, 0x14, 0xA9, 0x4E, 0x2A, 0x21, 0x79, 0x1C,
|
||||
0x03, 0x3C, 0x55, 0xA1, 0xE4, 0x01, 0xD0, 0x13, 0x73, 0x36, 0xB4, 0xB7,
|
||||
0xFB, 0xCC, 0x1C, 0x1C, 0x1C, 0x5A, 0x0B, 0xB1, 0x16, 0x04, 0xE7, 0x66,
|
||||
0xC0, 0xC4, 0x0A, 0x26, 0x8F, 0x0C, 0xAA, 0x81, 0xC7, 0x4A, 0x42, 0x22,
|
||||
0x52, 0x1D, 0x69, 0xC9, 0xA3, 0xA6, 0xC2, 0xC7, 0xA0, 0x07, 0xF0, 0x1C,
|
||||
0x52, 0xF5, 0x76, 0xCB, 0xDA, 0xC1, 0xC1, 0xA1, 0xB5, 0x04, 0x6F, 0x6E,
|
||||
0x66, 0x91, 0xAA, 0x53, 0xDA, 0xD8, 0xFB, 0xB7, 0x2E, 0xC2, 0x73, 0xA6,
|
||||
0x03, 0xEF, 0x00, 0x9F, 0x02, 0x73, 0x80, 0xD5, 0x98, 0xE8, 0xF4, 0x8D,
|
||||
0x80, 0x1D, 0x80, 0xBE, 0xC0, 0x5E, 0x44, 0xF0, 0x0A, 0xCB, 0x41, 0x22,
|
||||
0x1A, 0xDF, 0xFB, 0x5B, 0x91, 0xC8, 0x63, 0x08, 0x66, 0x0C, 0x0A, 0xD5,
|
||||
0x3C, 0xD2, 0xC0, 0x47, 0x76, 0x0C, 0xA6, 0x63, 0x4C, 0x4E, 0x0D, 0x96,
|
||||
0x94, 0x7A, 0x61, 0xBC, 0xCB, 0xF6, 0xC3, 0xA4, 0x3B, 0x29, 0x04, 0x9B,
|
||||
0x03, 0x63, 0x63, 0x52, 0xF5, 0x4B, 0xFB, 0xDE, 0x4A, 0xB7, 0xBC, 0x73,
|
||||
0xCE, 0xE9, 0xCD, 0xC0, 0xA6, 0x45, 0x68, 0xE9, 0x0F, 0xF8, 0xDE, 0xB7,
|
||||
0x6E, 0x40, 0x1D, 0x1C, 0x81, 0xE4, 0x96, 0x78, 0x7F, 0x02, 0x7E, 0x5A,
|
||||
0x40, 0xDB, 0xB3, 0x00, 0x09, 0x28, 0x7C, 0x6F, 0x46, 0x4B, 0x17, 0x0B,
|
||||
0xA9, 0x36, 0xD6, 0x70, 0x34, 0x70, 0x0E, 0xF0, 0x93, 0x02, 0xDE, 0xE7,
|
||||
0x71, 0x4B, 0x22, 0xAA, 0x08, 0xE4, 0x31, 0xA6, 0x40, 0xF2, 0x78, 0x1B,
|
||||
0xA8, 0x15, 0x30, 0x4E, 0x07, 0x49, 0xCB, 0x22, 0xD5, 0xB6, 0x80, 0x87,
|
||||
0x71, 0x0F, 0x8E, 0x1A, 0x57, 0xB2, 0x5F, 0x1A, 0x86, 0x03, 0x97, 0xB8,
|
||||
0xE5, 0x9D, 0x13, 0x3F, 0xC7, 0xE4, 0x66, 0x2B, 0x14, 0x37, 0x02, 0x8E,
|
||||
0x40, 0x1C, 0x3A, 0x34, 0x44, 0x1E, 0x41, 0xB6, 0x3F, 0x26, 0x27, 0x55,
|
||||
0x55, 0x84, 0x36, 0xBF, 0x02, 0xAE, 0xAE, 0x82, 0xC7, 0x23, 0xC7, 0x28,
|
||||
0x48, 0xD5, 0x0F, 0xB8, 0x19, 0xD8, 0x3F, 0xE2, 0x7B, 0xD5, 0x03, 0xA7,
|
||||
0x44, 0x26, 0x11, 0x23, 0xC8, 0x3F, 0x05, 0xBA, 0x44, 0x7C, 0xFE, 0x7B,
|
||||
0xC0, 0x65, 0x9B, 0x08, 0xF1, 0xD2, 0xDC, 0x08, 0x51, 0xE3, 0x36, 0xD6,
|
||||
0xC6, 0x03, 0x92, 0x98, 0x3C, 0x5A, 0x51, 0x34, 0x9E, 0x01, 0xF8, 0xDE,
|
||||
0x2B, 0x6E, 0x89, 0xAF, 0x33, 0xB7, 0x9F, 0x17, 0x89, 0x40, 0x76, 0xC3,
|
||||
0xF7, 0x3E, 0x73, 0x03, 0xEA, 0xD0, 0x5A, 0xA8, 0xC4, 0x43, 0xF4, 0x75,
|
||||
0x08, 0xC4, 0xA6, 0xE6, 0x98, 0x84, 0x89, 0x7C, 0x0E, 0x8B, 0x5A, 0x01,
|
||||
0x97, 0x16, 0x23, 0x01, 0x60, 0x27, 0xA9, 0x62, 0xAB, 0xE1, 0x42, 0xE0,
|
||||
0xA6, 0x88, 0x82, 0xBC, 0xCE, 0x92, 0xC8, 0xA8, 0x88, 0x82, 0xE6, 0xB7,
|
||||
0x96, 0xC4, 0xC2, 0xC4, 0x7A, 0xAC, 0x06, 0xAE, 0xAC, 0x86, 0xDB, 0xEB,
|
||||
0x7D, 0xAF, 0xA1, 0xE0, 0xC9, 0x31, 0x99, 0x8C, 0x47, 0x60, 0x5C, 0xF1,
|
||||
0xC2, 0xC6, 0x9C, 0x7C, 0x1A, 0x83, 0x3E, 0xE9, 0x0A, 0x4A, 0xFD, 0xA2,
|
||||
0x93, 0xF1, 0x0D, 0x03, 0xBE, 0x47, 0x5A, 0x24, 0x52, 0xA5, 0x09, 0x12,
|
||||
0x6D, 0xC7, 0x04, 0xA2, 0x93, 0xF1, 0xEE, 0x04, 0x8B, 0xED, 0xD2, 0x22,
|
||||
0x91, 0x5A, 0xD4, 0xA1, 0x77, 0xCE, 0x52, 0xF5, 0x08, 0xBA, 0x19, 0x2B,
|
||||
0x57, 0xC0, 0x72, 0x8E, 0xF9, 0x7D, 0x03, 0x63, 0xEA, 0x6F, 0x6A, 0x75,
|
||||
0xE9, 0xD4, 0xCC, 0x46, 0x32, 0x97, 0x29, 0xBB, 0xBF, 0x48, 0xA4, 0xDE,
|
||||
0x2E, 0x46, 0x9F, 0xAA, 0x73, 0x6C, 0xDD, 0x4F, 0x8B, 0x40, 0x1E, 0xAB,
|
||||
0x81, 0xF3, 0xF0, 0xBD, 0x87, 0x8B, 0x95, 0xA4, 0x69, 0xB5, 0xEF, 0xA5,
|
||||
0x81, 0xBB, 0x91, 0xEA, 0x0D, 0x4C, 0x42, 0xC1, 0xCD, 0xC3, 0x6E, 0xE4,
|
||||
0x81, 0x27, 0x90, 0x8A, 0x48, 0x24, 0xE2, 0x7B, 0xB7, 0x22, 0x95, 0xB0,
|
||||
0x24, 0x12, 0x04, 0xDF, 0x03, 0xC7, 0xE1, 0x7B, 0xAF, 0x17, 0x2B, 0x34,
|
||||
0x5C, 0xFB, 0xDE, 0x32, 0xE0, 0x22, 0xA4, 0xFA, 0x0F, 0xF0, 0x10, 0xE1,
|
||||
0xCC, 0x69, 0xBB, 0xA5, 0x8D, 0x29, 0xEC, 0xBE, 0x0A, 0xFA, 0x6E, 0xBF,
|
||||
0x01, 0xD6, 0x0B, 0x70, 0xDD, 0x4C, 0x4A, 0x9F, 0x1A, 0xA6, 0x3D, 0xE2,
|
||||
0x63, 0x60, 0xAB, 0x00, 0xD7, 0x2D, 0xD1, 0xC3, 0xFB, 0x6D, 0x24, 0x2E,
|
||||
0x7F, 0x2D, 0xDD, 0x61, 0x77, 0xF3, 0xE6, 0x1C, 0x92, 0xB6, 0xB5, 0x16,
|
||||
0xC5, 0x4F, 0xD7, 0xDD, 0x80, 0xE9, 0xF3, 0x81, 0xBB, 0xF3, 0xDC, 0x30,
|
||||
0x05, 0xC4, 0xBA, 0xB2, 0x5C, 0x54, 0x15, 0x6D, 0xDE, 0xD7, 0x22, 0x90,
|
||||
0x2A, 0xA9, 0xAA, 0x1B, 0xE0, 0xEA, 0x08, 0xE4, 0x71, 0x3C, 0xBE, 0x37,
|
||||
0xBE, 0x24, 0x63, 0xE6, 0x7B, 0xEF, 0x58, 0x93, 0xD6, 0x4B, 0x40, 0xEF,
|
||||
0x08, 0xEF, 0x37, 0xD2, 0x9E, 0x89, 0x8C, 0x8E, 0xF0, 0xEC, 0x5B, 0x90,
|
||||
0x8A, 0x00, 0x24, 0xF2, 0x35, 0x30, 0x10, 0xDF, 0x9B, 0x5A, 0xA2, 0x31,
|
||||
0x78, 0x02, 0xA9, 0xE6, 0x00, 0xE3, 0x02, 0x0A, 0xE0, 0x0C, 0xAE, 0x8C,
|
||||
0x49, 0xF5, 0x97, 0xB4, 0xEF, 0xAD, 0xAA, 0x90, 0xEF, 0x36, 0x16, 0x50,
|
||||
0x03, 0x89, 0xE1, 0x10, 0xD5, 0xA2, 0xE0, 0xC6, 0x37, 0xA2, 0xF5, 0xA5,
|
||||
0xC0, 0xEB, 0x4A, 0xDF, 0xE1, 0xC4, 0xBA, 0x84, 0xAF, 0x93, 0xF1, 0x74,
|
||||
0x0B, 0xF7, 0x34, 0x94, 0xFA, 0x83, 0x5E, 0x83, 0x06, 0x38, 0x01, 0x93,
|
||||
0xB8, 0x30, 0x04, 0x91, 0x73, 0x66, 0xC9, 0xC8, 0xA3, 0x51, 0x80, 0xCE,
|
||||
0x00, 0xFA, 0x63, 0xA2, 0xAE, 0xC3, 0x22, 0xA3, 0x89, 0x9C, 0x10, 0xF1,
|
||||
0xD9, 0xB7, 0x00, 0xBF, 0x6F, 0x61, 0x57, 0x3D, 0xA0, 0x64, 0xE4, 0xD1,
|
||||
0xD8, 0x8F, 0x7F, 0x02, 0xA7, 0x5A, 0xB5, 0x34, 0x28, 0xB6, 0x48, 0x9B,
|
||||
0x7B, 0x1C, 0x1C, 0x1C, 0x1C, 0x8A, 0x8E, 0xA6, 0x26, 0xAC, 0xF3, 0x43,
|
||||
0xDE, 0x7F, 0x3B, 0xBE, 0xF7, 0x44, 0xAB, 0xF4, 0xD4, 0xF7, 0x66, 0x20,
|
||||
0xD5, 0x00, 0xE0, 0xC5, 0x08, 0x9A, 0x48, 0x86, 0x44, 0x34, 0xBE, 0x37,
|
||||
0x26, 0xC2, 0xB3, 0x6F, 0xB6, 0xE6, 0xAC, 0x11, 0x79, 0xC8, 0xE3, 0xF3,
|
||||
0x56, 0x1A, 0x83, 0xB1, 0x48, 0x75, 0x23, 0x70, 0x55, 0x88, 0xBB, 0xCE,
|
||||
0xC3, 0x64, 0x0B, 0x76, 0x30, 0x78, 0x94, 0xE2, 0xC4, 0x35, 0x2D, 0x70,
|
||||
0x43, 0xE9, 0xE0, 0x08, 0x24, 0x03, 0xA9, 0xB6, 0xC3, 0x64, 0x7A, 0x0D,
|
||||
0x8A, 0x4F, 0x63, 0x70, 0x65, 0xAB, 0x1A, 0x51, 0x7D, 0x6F, 0xBA, 0x25,
|
||||
0x91, 0x97, 0x08, 0x66, 0xEB, 0x6D, 0x4A, 0x22, 0x4F, 0x22, 0xD5, 0xC9,
|
||||
0x11, 0x49, 0xE4, 0x26, 0x6B, 0xCE, 0x1A, 0x6E, 0xD5, 0xDA, 0xD6, 0xD1,
|
||||
0x3C, 0x9A, 0xA0, 0x0A, 0xAE, 0x6D, 0x80, 0xC1, 0xC0, 0xBE, 0x01, 0x6F,
|
||||
0xE9, 0x8B, 0x54, 0xBB, 0xE3, 0x7B, 0x9F, 0xB8, 0xE5, 0x0E, 0xF8, 0xDE,
|
||||
0xF5, 0x6E, 0x10, 0x1C, 0x1C, 0x8A, 0xAF, 0x81, 0x9C, 0x40, 0x38, 0x7B,
|
||||
0xDF, 0x6F, 0xCA, 0x12, 0xAC, 0x66, 0x48, 0xA4, 0x7F, 0x81, 0x24, 0x72,
|
||||
0x12, 0xBE, 0x37, 0x36, 0x22, 0x89, 0x08, 0xE0, 0xE2, 0x72, 0x90, 0x07,
|
||||
0x40, 0x83, 0xEF, 0xD5, 0x21, 0xD5, 0x25, 0xC0, 0x2B, 0x01, 0xE7, 0x4B,
|
||||
0x00, 0xC7, 0x03, 0x8E, 0x40, 0x1C, 0x1C, 0xDA, 0x1F, 0x5E, 0x02, 0xCE,
|
||||
0x0E, 0xA4, 0x25, 0x4B, 0x75, 0x16, 0x30, 0x20, 0x80, 0xC0, 0xB8, 0x54,
|
||||
0x07, 0x2C, 0x27, 0x9E, 0x4D, 0x20, 0x47, 0x84, 0xE8, 0xF4, 0x1B, 0xF8,
|
||||
0xDE, 0xF3, 0x65, 0xDC, 0x45, 0x4E, 0xCF, 0x32, 0x67, 0x15, 0xA2, 0x89,
|
||||
0x44, 0x21, 0x91, 0x11, 0x42, 0x2A, 0xA9, 0x7D, 0x6F, 0x7E, 0x19, 0xDF,
|
||||
0xFF, 0x35, 0x5B, 0xCC, 0xEB, 0xD0, 0x80, 0x77, 0x0C, 0x06, 0xAE, 0x73,
|
||||
0xDF, 0x9A, 0x83, 0x43, 0xFB, 0x82, 0x48, 0xA4, 0x3E, 0xC5, 0xC4, 0xAC,
|
||||
0x05, 0xC1, 0xFE, 0xC0, 0x29, 0x2D, 0x5D, 0xA4, 0x4D, 0xAD, 0xA7, 0x40,
|
||||
0x04, 0x12, 0x03, 0x88, 0x49, 0x55, 0x03, 0x1C, 0x10, 0xA2, 0xDF, 0x77,
|
||||
0x57, 0x80, 0x29, 0x62, 0x9A, 0x65, 0xD3, 0xAF, 0x23, 0xDC, 0xDD, 0x09,
|
||||
0x78, 0x0A, 0xA9, 0x8E, 0x8D, 0xF2, 0xE8, 0xB2, 0x92, 0x47, 0xB4, 0x39,
|
||||
0xE8, 0x2B, 0xA4, 0xEA, 0xEA, 0x3E, 0x37, 0x07, 0x07, 0x87, 0x62, 0x22,
|
||||
0x06, 0x90, 0x36, 0xC1, 0x29, 0xEB, 0x07, 0xBC, 0x67, 0xA9, 0x80, 0x67,
|
||||
0x2A, 0xA2, 0xF7, 0x86, 0x44, 0xFA, 0x47, 0x24, 0x91, 0x9A, 0x42, 0x48,
|
||||
0xA4, 0xDC, 0xA8, 0x32, 0x49, 0x2E, 0x83, 0x12, 0x59, 0x8D, 0x06, 0x57,
|
||||
0x06, 0xD7, 0xC1, 0xC1, 0xA1, 0xF8, 0x04, 0x82, 0x49, 0xE6, 0x17, 0x14,
|
||||
0xAF, 0x68, 0xDF, 0x5B, 0x51, 0x31, 0x6F, 0x50, 0x1C, 0x4D, 0xE4, 0x98,
|
||||
0xB6, 0x36, 0x71, 0x0D, 0x26, 0xC2, 0xFC, 0x9F, 0x21, 0x6E, 0xD9, 0xC3,
|
||||
0x2D, 0x77, 0x07, 0x07, 0x87, 0x52, 0x10, 0x48, 0x98, 0xD4, 0x0E, 0xFF,
|
||||
0xA9, 0xB8, 0xB7, 0x30, 0x6E, 0xB4, 0x03, 0x30, 0x9E, 0x51, 0x51, 0x48,
|
||||
0xE4, 0x6F, 0x6D, 0x91, 0x44, 0x80, 0x30, 0x05, 0xA4, 0x76, 0x72, 0xCB,
|
||||
0xDD, 0xC1, 0xC1, 0xA1, 0x98, 0xC8, 0x1C, 0xA2, 0x6F, 0x11, 0xE2, 0x9E,
|
||||
0x29, 0x15, 0xF9, 0x26, 0xBE, 0xF7, 0x79, 0xD6, 0xC1, 0xFA, 0x16, 0x21,
|
||||
0xEF, 0xCE, 0x90, 0x88, 0x87, 0xEF, 0x8D, 0x6B, 0x43, 0xF3, 0xF7, 0x61,
|
||||
0x88, 0x6B, 0x7F, 0xD0, 0xD1, 0x16, 0xB7, 0x4E, 0xC6, 0xBB, 0x61, 0x62,
|
||||
0x3E, 0x7A, 0x60, 0xD2, 0xC0, 0xD4, 0x03, 0xAB, 0x80, 0x79, 0xC0, 0x5C,
|
||||
0x91, 0x48, 0xAD, 0x2A, 0x43, 0x9F, 0xBA, 0xDB, 0x3E, 0x6D, 0x88, 0xC9,
|
||||
0xF1, 0x56, 0x87, 0xC9, 0x57, 0x34, 0x1F, 0x98, 0x27, 0x12, 0xA9, 0x0E,
|
||||
0x9B, 0x86, 0x5F, 0x27, 0xE3, 0x5D, 0x80, 0x4D, 0x80, 0x8D, 0xED, 0xD8,
|
||||
0xC4, 0xEC, 0xD8, 0x2C, 0xB0, 0xF3, 0xB5, 0xD4, 0x89, 0xEC, 0xCA, 0x24,
|
||||
0x90, 0xEE, 0x21, 0xEE, 0x99, 0x5D, 0xB1, 0x6F, 0xE3, 0x7B, 0x53, 0x0B,
|
||||
0x24, 0x11, 0xD5, 0xC6, 0x48, 0x24, 0x4C, 0x3A, 0xF1, 0xEE, 0xED, 0x79,
|
||||
0x21, 0xEB, 0x64, 0xBC, 0x07, 0x70, 0xB0, 0xFD, 0xB3, 0x37, 0xB0, 0x27,
|
||||
0xA6, 0x52, 0x63, 0xBE, 0xB4, 0x1D, 0x75, 0x3A, 0x19, 0x9F, 0x01, 0xBC,
|
||||
0x8B, 0x31, 0x05, 0x4E, 0x10, 0x89, 0xD4, 0xDC, 0xA2, 0xF6, 0x69, 0xC4,
|
||||
0x21, 0x82, 0x74, 0xFD, 0xBE, 0xC0, 0x10, 0x4C, 0x89, 0x82, 0x7D, 0xAD,
|
||||
0x70, 0xCC, 0xD7, 0xA7, 0x7A, 0x9D, 0x8C, 0xFF, 0x0F, 0x53, 0x3B, 0xE6,
|
||||
0x03, 0xE0, 0x35, 0xE0, 0xD5, 0x72, 0x0A, 0x4E, 0x9D, 0x8C, 0x1F, 0x82,
|
||||
0xA9, 0xD7, 0x13, 0x06, 0xE3, 0x44, 0x22, 0x35, 0xBD, 0xF9, 0x76, 0xFB,
|
||||
0xD5, 0x80, 0x3E, 0x10, 0xC8, 0xB4, 0xDF, 0x07, 0xD8, 0x92, 0xFC, 0x25,
|
||||
0x26, 0x1A, 0x74, 0x32, 0xFE, 0x9D, 0x9D, 0xAF, 0x57, 0x81, 0xBF, 0x8B,
|
||||
0x44, 0x6A, 0x6A, 0x45, 0x2D, 0x42, 0x53, 0x7C, 0x6E, 0x97, 0x90, 0x77,
|
||||
0x8D, 0xC4, 0xF7, 0xFE, 0xD7, 0xA4, 0x9D, 0xCD, 0x08, 0xE0, 0x2D, 0x65,
|
||||
0xF1, 0x09, 0xBE, 0x37, 0x31, 0x4F, 0x7F, 0x9A, 0xB6, 0xB3, 0x57, 0xC0,
|
||||
0x36, 0xCF, 0x41, 0xAA, 0x79, 0xB9, 0x7E, 0x21, 0xE0, 0xB1, 0x6C, 0x17,
|
||||
0xDF, 0xEA, 0x26, 0x7F, 0x07, 0x41, 0x65, 0xEF, 0x02, 0x8A, 0x43, 0x22,
|
||||
0x43, 0xF1, 0xBD, 0x67, 0xDB, 0x80, 0xDC, 0x0C, 0x73, 0x16, 0xD5, 0xEE,
|
||||
0xBC, 0xB0, 0x74, 0x32, 0xDE, 0x19, 0x38, 0x16, 0x93, 0x00, 0x74, 0x20,
|
||||
0xF9, 0xB3, 0x92, 0xE6, 0x42, 0x0D, 0xE6, 0xEC, 0x6F, 0x57, 0xFB, 0x91,
|
||||
0xAD, 0xD2, 0xC9, 0xF8, 0x68, 0xE0, 0x7A, 0x91, 0x48, 0x7D, 0x56, 0x60,
|
||||
0xBF, 0x6A, 0x80, 0x33, 0x49, 0xD7, 0xFF, 0x1A, 0xD8, 0x3D, 0xE4, 0x86,
|
||||
0x6E, 0x2B, 0xFB, 0xE7, 0x67, 0xC0, 0xE5, 0xC0, 0x0A, 0x9D, 0x8C, 0x3F,
|
||||
0x0F, 0x3C, 0x0C, 0x62, 0x42, 0xA9, 0x73, 0x1B, 0x35, 0x79, 0x8F, 0x13,
|
||||
0x80, 0x91, 0x21, 0xC7, 0xF5, 0x21, 0x44, 0xEC, 0xF6, 0x66, 0xDA, 0x8C,
|
||||
0x03, 0x67, 0x81, 0x3E, 0x06, 0x53, 0x50, 0x2E, 0x28, 0xAA, 0xEC, 0xF7,
|
||||
0xBC, 0x05, 0x70, 0x14, 0x70, 0x93, 0x4E, 0xC6, 0x53, 0xC0, 0x8D, 0x22,
|
||||
0x91, 0xFA, 0x47, 0x05, 0x90, 0xC7, 0x05, 0x18, 0xCF, 0xC8, 0x30, 0x79,
|
||||
0xC6, 0x6E, 0x58, 0x87, 0x3C, 0x0C, 0x7A, 0x03, 0xB7, 0x04, 0x6C, 0xE3,
|
||||
0x31, 0x8C, 0x43, 0x4D, 0x2E, 0x6C, 0x1D, 0xA2, 0x9D, 0x6C, 0x24, 0xF2,
|
||||
0xCE, 0x9F, 0x91, 0xAB, 0x6B, 0x08, 0x24, 0x4A, 0x52, 0xB5, 0xCA, 0x4F,
|
||||
0xC4, 0x66, 0x02, 0xFC, 0x06, 0x12, 0xAD, 0xE0, 0x4F, 0x86, 0x44, 0x8E,
|
||||
0x6E, 0x03, 0x32, 0x34, 0x4C, 0xBD, 0x96, 0x06, 0xDA, 0x09, 0x74, 0x32,
|
||||
0x5E, 0xA3, 0x93, 0xF1, 0x8B, 0x30, 0xD5, 0x1D, 0x9F, 0xB4, 0xC2, 0xB6,
|
||||
0x53, 0x81, 0xCD, 0x76, 0xB6, 0x44, 0xF2, 0xA1, 0x4E, 0xC6, 0xAF, 0xD5,
|
||||
0xC9, 0x7E, 0xD5, 0x11, 0xFB, 0xB6, 0x3F, 0xC6, 0xB4, 0xF8, 0xE7, 0x90,
|
||||
0xE4, 0x91, 0x0F, 0xEB, 0x01, 0xC7, 0x00, 0xE3, 0x40, 0xFF, 0xA3, 0x15,
|
||||
0xC7, 0xF8, 0x44, 0xE0, 0x89, 0x90, 0xE3, 0xFA, 0x04, 0x88, 0x73, 0xC5,
|
||||
0xE5, 0xAF, 0xE6, 0x4A, 0xFA, 0x77, 0x98, 0x4E, 0xC6, 0xDF, 0xB6, 0x5A,
|
||||
0xD5, 0x99, 0x21, 0xC9, 0x23, 0xCF, 0x66, 0x98, 0x7E, 0xC0, 0x44, 0x9D,
|
||||
0x8C, 0x8F, 0xD3, 0xC9, 0x78, 0xF9, 0xCA, 0x6E, 0x4B, 0x75, 0x31, 0x70,
|
||||
0x4F, 0x48, 0xD9, 0x78, 0x6B, 0xAF, 0x98, 0xB8, 0xBA, 0xAD, 0x7F, 0x8B,
|
||||
0x99, 0x17, 0x0E, 0x63, 0x0B, 0xDE, 0xB0, 0x4D, 0xBC, 0x99, 0xA9, 0xD5,
|
||||
0x30, 0x20, 0x22, 0x89, 0x74, 0x06, 0x46, 0x21, 0xD5, 0x51, 0x15, 0xFE,
|
||||
0x96, 0x61, 0xCC, 0x52, 0xCB, 0xDA, 0x91, 0xF2, 0x51, 0x6B, 0x77, 0x7B,
|
||||
0x5B, 0x95, 0xA0, 0xED, 0x1A, 0xE0, 0x6A, 0xD0, 0xCF, 0x58, 0x9B, 0x7C,
|
||||
0x18, 0xA1, 0x7B, 0x8A, 0x35, 0xAF, 0xEC, 0x5A, 0xA2, 0xF7, 0x7E, 0xB9,
|
||||
0x95, 0xC8, 0xE3, 0x14, 0xAB, 0x79, 0xD4, 0x84, 0xB8, 0x6D, 0x0C, 0x88,
|
||||
0xD3, 0x73, 0x69, 0x48, 0xB6, 0xBD, 0x17, 0x80, 0x1F, 0x95, 0xA8, 0xCB,
|
||||
0x47, 0x03, 0x6F, 0xE9, 0x64, 0xBC, 0xF5, 0x1D, 0x45, 0xA4, 0xBA, 0x14,
|
||||
0xB8, 0x83, 0x70, 0x59, 0x3C, 0xEE, 0x5B, 0x4F, 0x88, 0xCB, 0xE6, 0x9C,
|
||||
0x3D, 0x54, 0xB7, 0xF5, 0x0F, 0x31, 0x43, 0x20, 0x61, 0x8A, 0xCB, 0x6C,
|
||||
0xD7, 0x66, 0xDE, 0xCE, 0x90, 0x48, 0x21, 0x9A, 0x48, 0xA5, 0x93, 0x48,
|
||||
0x98, 0x7A, 0xF5, 0x0B, 0xDB, 0x11, 0x81, 0xB4, 0x46, 0x02, 0xCF, 0x21,
|
||||
0xC0, 0xE3, 0x7A, 0xF8, 0x41, 0x81, 0x04, 0x83, 0x4E, 0xC6, 0x8F, 0x06,
|
||||
0xFE, 0x5A, 0x04, 0x4D, 0x28, 0x1F, 0x56, 0x58, 0xAD, 0xA6, 0xD4, 0xE4,
|
||||
0x71, 0x06, 0x26, 0xE1, 0x64, 0x18, 0xED, 0x76, 0x3C, 0x70, 0x8A, 0x48,
|
||||
0xBC, 0x96, 0xAF, 0x14, 0xCE, 0x84, 0x56, 0x58, 0x7F, 0xDB, 0x01, 0xCF,
|
||||
0xB7, 0xAA, 0x26, 0x22, 0xD5, 0x15, 0xC0, 0xAD, 0x21, 0xC9, 0xE3, 0xA1,
|
||||
0x4E, 0x30, 0x6C, 0xC5, 0x39, 0x6D, 0x9F, 0x3C, 0xB2, 0x09, 0x24, 0xCC,
|
||||
0xC1, 0xF8, 0x9E, 0x6D, 0xEA, 0x0D, 0x7D, 0xEF, 0x53, 0x4B, 0x22, 0xFF,
|
||||
0x2B, 0x40, 0x13, 0x39, 0xB2, 0x42, 0xDF, 0x2E, 0x4C, 0x70, 0xE0, 0x37,
|
||||
0xB4, 0x13, 0x88, 0x44, 0xEA, 0x79, 0x4C, 0xBD, 0xF9, 0x52, 0xE3, 0x78,
|
||||
0x74, 0xFA, 0xBC, 0x00, 0x42, 0xB7, 0x17, 0xA6, 0xE0, 0x57, 0x55, 0x09,
|
||||
0xFB, 0xF2, 0x58, 0xB1, 0x0F, 0xF9, 0x73, 0xBC, 0xC7, 0xB9, 0x56, 0xBB,
|
||||
0x0B, 0x63, 0x8A, 0xF9, 0x27, 0xE0, 0x35, 0xE7, 0xD1, 0x26, 0x12, 0xA9,
|
||||
0x85, 0xC0, 0xBD, 0xAD, 0x30, 0x5F, 0xDB, 0x01, 0x0F, 0xB6, 0x12, 0x79,
|
||||
0x5C, 0x03, 0xDC, 0x10, 0x76, 0xE3, 0x53, 0x0D, 0xE7, 0xDA, 0x62, 0x79,
|
||||
0xED, 0x02, 0x99, 0x85, 0x12, 0xC6, 0x9B, 0xE1, 0xA0, 0x36, 0xF7, 0x96,
|
||||
0x86, 0x44, 0x06, 0x14, 0x40, 0x22, 0xA3, 0x2B, 0x94, 0x44, 0xE2, 0x21,
|
||||
0xAE, 0x6D, 0x6F, 0xF5, 0xBB, 0xAF, 0x6D, 0xA5, 0xE7, 0x5C, 0x6F, 0x3D,
|
||||
0xBC, 0x9A, 0xC3, 0xEF, 0x30, 0xDE, 0x55, 0xA5, 0x42, 0x1A, 0xB8, 0xB3,
|
||||
0xC4, 0xE4, 0x71, 0x21, 0xF0, 0x40, 0x48, 0x12, 0x7C, 0x05, 0x38, 0x56,
|
||||
0x24, 0x52, 0x41, 0x9C, 0x39, 0x6E, 0x07, 0x5A, 0xA3, 0x34, 0xEC, 0x31,
|
||||
0x3A, 0x19, 0x1F, 0x58, 0x62, 0xF2, 0xB8, 0x0E, 0xF8, 0x63, 0xC8, 0xBB,
|
||||
0xC6, 0xC4, 0xE0, 0x8C, 0x62, 0x94, 0xBA, 0xAE, 0x44, 0x02, 0x09, 0x13,
|
||||
0xDB, 0x71, 0x80, 0x90, 0x6A, 0x93, 0x36, 0x4A, 0x22, 0x85, 0x68, 0x22,
|
||||
0xA3, 0x91, 0x6A, 0x48, 0xC5, 0xEC, 0xC2, 0xA5, 0xEA, 0x1E, 0x92, 0x40,
|
||||
0x3E, 0x6E, 0x57, 0xF4, 0x21, 0x62, 0xCF, 0x01, 0xEF, 0x04, 0x95, 0x8F,
|
||||
0x05, 0x3C, 0xA9, 0x27, 0x70, 0x56, 0xDE, 0x86, 0x87, 0xF7, 0x8B, 0x11,
|
||||
0xAE, 0x68, 0xD7, 0x3C, 0x4C, 0x89, 0xE6, 0xBB, 0x2C, 0x09, 0xDE, 0x00,
|
||||
0xDC, 0x0F, 0xFC, 0x1D, 0x98, 0x95, 0xA7, 0xAF, 0x2F, 0x88, 0x44, 0xAA,
|
||||
0x64, 0xD9, 0x94, 0x75, 0x32, 0xFE, 0x6B, 0xCC, 0x99, 0x52, 0x18, 0x53,
|
||||
0xCC, 0x1B, 0xC0, 0xD1, 0x22, 0x91, 0x0A, 0x74, 0xB6, 0x26, 0x12, 0xA9,
|
||||
0x79, 0x21, 0xB4, 0x90, 0x42, 0xCD, 0x3B, 0xBF, 0x2B, 0xC5, 0x38, 0x6D,
|
||||
0x52, 0x3B, 0x4A, 0x20, 0xD5, 0x70, 0xC2, 0xD5, 0xE3, 0x01, 0x18, 0x1F,
|
||||
0x83, 0x53, 0xD2, 0x26, 0x7B, 0x44, 0xBB, 0x42, 0x35, 0xC0, 0xFA, 0x42,
|
||||
0x4C, 0x5B, 0xAE, 0xF5, 0x5C, 0x4C, 0x10, 0x4F, 0x4B, 0xA8, 0xD1, 0xF0,
|
||||
0x0B, 0xFB, 0x01, 0xB4, 0x35, 0x12, 0xF9, 0x04, 0xA9, 0x06, 0x02, 0xFF,
|
||||
0x06, 0x36, 0x8B, 0x40, 0x22, 0x63, 0x90, 0xEA, 0x78, 0x7C, 0x6F, 0x42,
|
||||
0xB9, 0x5F, 0x45, 0x83, 0x87, 0x09, 0xB6, 0x0A, 0x82, 0x45, 0xD5, 0x30,
|
||||
0xA5, 0xBE, 0x1D, 0x2D, 0x5C, 0x71, 0xF9, 0xAB, 0x5A, 0x27, 0xE3, 0x7F,
|
||||
0xB2, 0x82, 0x37, 0x1B, 0x33, 0x30, 0x36, 0xF9, 0x37, 0xED, 0xC6, 0x68,
|
||||
0x2E, 0x26, 0x80, 0xB0, 0x3B, 0xE6, 0x70, 0xFB, 0x70, 0xE0, 0x74, 0xC2,
|
||||
0x39, 0x83, 0x9C, 0x02, 0xDC, 0x96, 0x7B, 0x22, 0xF4, 0x0E, 0x04, 0x77,
|
||||
0x17, 0xBF, 0x01, 0xB8, 0xAE, 0x39, 0x73, 0x8F, 0x4E, 0xC6, 0xB7, 0xC4,
|
||||
0x9C, 0xBF, 0x9C, 0x82, 0xF1, 0x32, 0x12, 0x98, 0x43, 0xDA, 0x52, 0x91,
|
||||
0xC7, 0x65, 0xC0, 0x4D, 0x21, 0x6F, 0x7B, 0x17, 0x18, 0x22, 0x12, 0xA9,
|
||||
0xB0, 0x1A, 0xC5, 0xAD, 0xC0, 0x45, 0x40, 0xB7, 0xAC, 0x9F, 0x2D, 0x00,
|
||||
0x9E, 0xC3, 0x78, 0x67, 0xBD, 0x8F, 0x31, 0xB5, 0x2E, 0xC7, 0xB8, 0x9D,
|
||||
0xF7, 0xC6, 0xC4, 0xF5, 0x9C, 0x05, 0xEC, 0x10, 0xE2, 0x39, 0x87, 0xE9,
|
||||
0x64, 0x7C, 0x53, 0x91, 0x48, 0x7D, 0x57, 0xAC, 0x71, 0xEA, 0x5E, 0x3B,
|
||||
0x4A, 0xCC, 0xD5, 0xFA, 0x36, 0xE0, 0x92, 0x90, 0xB7, 0xFE, 0x53, 0x80,
|
||||
0x57, 0xA6, 0xB2, 0xD2, 0xF3, 0x80, 0xA7, 0xB2, 0xFE, 0xFF, 0xA3, 0x80,
|
||||
0xE3, 0x38, 0x9E, 0xFC, 0xE1, 0x1A, 0x6B, 0xA5, 0x88, 0x17, 0x59, 0x6A,
|
||||
0xD9, 0x28, 0x4C, 0x4D, 0x90, 0x20, 0x98, 0x56, 0x05, 0xBB, 0x37, 0xF8,
|
||||
0x5E, 0xDB, 0x94, 0x49, 0x52, 0xED, 0x8E, 0xF1, 0x67, 0xDE, 0x34, 0xC2,
|
||||
0xDD, 0x2B, 0x31, 0x35, 0xE0, 0x9F, 0x2B, 0x57, 0xF7, 0x3B, 0x4B, 0x15,
|
||||
0x5B, 0x65, 0x3E, 0xB6, 0xA0, 0xE7, 0x51, 0xE3, 0xF1, 0xBD, 0xB2, 0x3B,
|
||||
0x03, 0xE8, 0x64, 0x7C, 0x45, 0x40, 0xD2, 0x9B, 0x25, 0x12, 0xA9, 0xED,
|
||||
0x5B, 0x6C, 0x6F, 0x44, 0x7F, 0x41, 0xBA, 0x6E, 0x12, 0x26, 0x40, 0x6F,
|
||||
0x22, 0x30, 0x1C, 0x51, 0x95, 0x12, 0x97, 0xBF, 0xA2, 0x5B, 0xE8, 0xC7,
|
||||
0x66, 0xC0, 0x68, 0xE0, 0xA7, 0x21, 0x4C, 0x48, 0x9B, 0x89, 0x44, 0x6A,
|
||||
0x4E, 0x8E, 0xB6, 0x0E, 0x26, 0x98, 0x77, 0xD4, 0x1C, 0x44, 0xF5, 0xA6,
|
||||
0xE2, 0xF2, 0x97, 0x75, 0x88, 0xF1, 0xDA, 0x1B, 0x38, 0x03, 0x11, 0xBB,
|
||||
0x34, 0x97, 0x6B, 0x6C, 0x8E, 0xEB, 0xBF, 0x24, 0x98, 0x67, 0xDA, 0x52,
|
||||
0x84, 0xD8, 0x10, 0xAD, 0x13, 0x40, 0xD8, 0x02, 0x5B, 0x1F, 0x01, 0x03,
|
||||
0xA2, 0x9E, 0xC7, 0xE8, 0x64, 0x7C, 0x04, 0xA6, 0x44, 0xF4, 0x27, 0xC0,
|
||||
0x8D, 0xC0, 0xE8, 0x96, 0x32, 0x02, 0xE8, 0x64, 0xBC, 0x13, 0x70, 0x33,
|
||||
0xA6, 0x0E, 0x4F, 0x60, 0xD2, 0x17, 0x89, 0xD4, 0x13, 0xCD, 0xC8, 0x80,
|
||||
0xA0, 0xF3, 0x30, 0x73, 0x03, 0x21, 0x76, 0x5C, 0xAA, 0xF5, 0x5D, 0x96,
|
||||
0xFC, 0xC2, 0xE0, 0x55, 0x01, 0x43, 0xB4, 0xEF, 0x2D, 0x0D, 0x29, 0x9F,
|
||||
0x7E, 0x44, 0xF0, 0x33, 0xBE, 0xC7, 0xF0, 0xBD, 0xD3, 0x02, 0xB6, 0xFB,
|
||||
0x67, 0xE0, 0xDC, 0x00, 0x57, 0xEE, 0x80, 0xEF, 0xCD, 0x0C, 0x63, 0xC2,
|
||||
0xC2, 0xEE, 0x02, 0x82, 0x62, 0xA7, 0x06, 0x38, 0xA3, 0xCD, 0x6E, 0x5F,
|
||||
0x4D, 0x75, 0xBE, 0x01, 0x40, 0x94, 0x1D, 0x4A, 0x17, 0x60, 0x2C, 0x52,
|
||||
0xFD, 0xAC, 0x5C, 0xDD, 0x5F, 0x05, 0x27, 0x12, 0xCE, 0x99, 0x61, 0x3C,
|
||||
0xED, 0x10, 0xE2, 0x0F, 0x2F, 0x69, 0xE0, 0x4A, 0xE0, 0x28, 0x91, 0x48,
|
||||
0x0D, 0x11, 0x89, 0xD4, 0x6B, 0x2D, 0x91, 0x87, 0x35, 0xA7, 0xFC, 0x0F,
|
||||
0x13, 0x5B, 0x11, 0x54, 0x08, 0xC6, 0x80, 0xFD, 0xF2, 0xFC, 0x2E, 0xE8,
|
||||
0x99, 0xC1, 0xC6, 0xE8, 0xFA, 0xC3, 0x43, 0xBD, 0x5F, 0x22, 0xF5, 0xBE,
|
||||
0x48, 0xA4, 0x2E, 0x09, 0x42, 0x1E, 0xE1, 0x25, 0xB9, 0xFE, 0x63, 0x04,
|
||||
0xF2, 0xF8, 0x0C, 0x18, 0x54, 0xE0, 0x61, 0xFE, 0xAD, 0xC0, 0xE5, 0x20,
|
||||
0xFA, 0x88, 0x44, 0x6A, 0x64, 0x90, 0x74, 0x32, 0x22, 0x91, 0x5A, 0x8D,
|
||||
0xA8, 0xBA, 0x04, 0x08, 0x53, 0x83, 0x68, 0xDF, 0x22, 0x8D, 0x54, 0x6C,
|
||||
0xA9, 0xD6, 0xF7, 0x45, 0x20, 0x8F, 0x37, 0x05, 0x1C, 0x15, 0x9A, 0x3C,
|
||||
0xDA, 0x18, 0x62, 0x59, 0xAA, 0xC8, 0x38, 0xC2, 0xC5, 0x83, 0xDC, 0x28,
|
||||
0xA4, 0xEA, 0xD5, 0x66, 0xDF, 0xDC, 0x90, 0xC8, 0xC0, 0x88, 0x24, 0xD2,
|
||||
0xB9, 0x5C, 0x24, 0x22, 0xA4, 0xDA, 0x88, 0x70, 0xD1, 0xA5, 0x75, 0x02,
|
||||
0xC6, 0xB6, 0xD7, 0x05, 0x2C, 0x12, 0xA9, 0xE7, 0x45, 0x22, 0x35, 0x21,
|
||||
0xC2, 0x7D, 0x73, 0x31, 0x9E, 0x53, 0x41, 0x91, 0xCF, 0x7D, 0x3D, 0x0C,
|
||||
0x09, 0x4D, 0xD4, 0xC9, 0xF8, 0xCB, 0x3A, 0x19, 0xFF, 0x83, 0x4E, 0xC6,
|
||||
0x07, 0xE9, 0x64, 0x7C, 0x0B, 0x9D, 0xEC, 0x57, 0x55, 0x86, 0x61, 0xDB,
|
||||
0x00, 0x08, 0x1B, 0xC4, 0x36, 0x03, 0x38, 0x4C, 0x24, 0x52, 0xDF, 0x16,
|
||||
0x38, 0x5F, 0xDF, 0x8B, 0x44, 0x6A, 0x44, 0x33, 0x2E, 0xBF, 0xB9, 0xEF,
|
||||
0x33, 0x1B, 0x83, 0x5B, 0x43, 0xDC, 0xB2, 0x4B, 0x91, 0xC6, 0x6A, 0x5B,
|
||||
0xE0, 0xBC, 0x90, 0xF7, 0xBC, 0x67, 0x35, 0x8F, 0xC5, 0xB4, 0x73, 0xAC,
|
||||
0x89, 0xB6, 0xD5, 0xBE, 0x37, 0x1F, 0xA9, 0xC6, 0x61, 0x6C, 0xEB, 0x41,
|
||||
0xD0, 0x4B, 0xC3, 0x5F, 0xD6, 0xAB, 0x55, 0x3F, 0x5F, 0x71, 0x8E, 0xD7,
|
||||
0x36, 0x7D, 0x9A, 0x7D, 0x6F, 0x8A, 0x3D, 0x13, 0x79, 0x91, 0xF0, 0xC9,
|
||||
0x06, 0x33, 0x9A, 0xC8, 0xB1, 0xF8, 0x5E, 0xAB, 0x44, 0x08, 0x77, 0xAF,
|
||||
0x1D, 0x25, 0x16, 0x6B, 0xFD, 0x00, 0xE1, 0x52, 0xB4, 0x8C, 0xD7, 0xBE,
|
||||
0x37, 0x87, 0x0E, 0x08, 0x3D, 0xFC, 0x20, 0x81, 0x4E, 0x77, 0x26, 0x7F,
|
||||
0xAA, 0x9E, 0x30, 0xCE, 0x23, 0x5B, 0xE6, 0xF9, 0xF9, 0x34, 0x8C, 0x59,
|
||||
0x33, 0x88, 0x69, 0x4E, 0xD0, 0x98, 0xAF, 0x2B, 0xD3, 0xCB, 0x65, 0x3A,
|
||||
0x19, 0x9F, 0x66, 0x77, 0xF7, 0x53, 0x80, 0x49, 0xC0, 0x9B, 0x22, 0x91,
|
||||
0x5A, 0x54, 0x41, 0x43, 0x39, 0xDB, 0x92, 0xC7, 0x57, 0xAD, 0x30, 0x5F,
|
||||
0xD5, 0x76, 0x83, 0x96, 0x0B, 0x61, 0x92, 0x87, 0x6E, 0x5E, 0xA6, 0xB1,
|
||||
0xFA, 0x48, 0xC0, 0x11, 0x15, 0x52, 0x74, 0xAE, 0xF5, 0x08, 0xC4, 0xE2,
|
||||
0xEE, 0x10, 0x04, 0x02, 0x70, 0xD4, 0x0A, 0xCD, 0x0D, 0xC0, 0x15, 0x6D,
|
||||
0x58, 0x13, 0x99, 0x92, 0x75, 0xB0, 0x1E, 0x85, 0x44, 0x9E, 0x6E, 0x2D,
|
||||
0x12, 0x59, 0xAC, 0xF5, 0x95, 0x21, 0xE7, 0x27, 0x33, 0xA7, 0xED, 0x9F,
|
||||
0x2C, 0x92, 0xF1, 0xDD, 0x30, 0x07, 0xE4, 0xFB, 0x01, 0x3F, 0x04, 0x36,
|
||||
0x47, 0xA7, 0x37, 0x26, 0x5C, 0x34, 0x75, 0xB3, 0xFC, 0x9D, 0x67, 0x47,
|
||||
0xBD, 0x42, 0x27, 0xE3, 0x13, 0x31, 0x39, 0xB9, 0xA2, 0xA0, 0x2B, 0x26,
|
||||
0xF9, 0xE3, 0xDE, 0xD9, 0x5A, 0xA3, 0x4E, 0xC6, 0x5F, 0xC7, 0x44, 0x83,
|
||||
0x3F, 0x21, 0x12, 0xA9, 0xE5, 0x65, 0x1E, 0xDE, 0x53, 0x45, 0x22, 0x35,
|
||||
0xAB, 0xC8, 0xF3, 0xB5, 0x29, 0x30, 0x08, 0x53, 0x66, 0xB5, 0x0F, 0xD0,
|
||||
0x1B, 0x9D, 0xDE, 0x84, 0xE0, 0x85, 0xED, 0x82, 0x7C, 0x9B, 0xAD, 0x8D,
|
||||
0x34, 0x70, 0x7C, 0x47, 0xDA, 0xB0, 0xAD, 0x15, 0x30, 0xB4, 0xB1, 0x10,
|
||||
0xAF, 0x03, 0xAF, 0x87, 0x6C, 0x23, 0x81, 0x54, 0xBF, 0x6F, 0xD3, 0xA3,
|
||||
0xE0, 0x7B, 0x1F, 0x63, 0xCC, 0x59, 0x73, 0x23, 0x2E, 0xD4, 0xB1, 0x25,
|
||||
0x77, 0xF1, 0x35, 0x29, 0x13, 0xC2, 0xC6, 0x3E, 0xBC, 0xD5, 0x53, 0x88,
|
||||
0x97, 0xDB, 0x2F, 0x69, 0xF4, 0xAB, 0xD2, 0xC9, 0xF8, 0x99, 0x3A, 0x19,
|
||||
0xFF, 0x00, 0x73, 0x28, 0x7B, 0x07, 0xC6, 0xA5, 0x76, 0x1F, 0x8C, 0x97,
|
||||
0x5D, 0x4D, 0x11, 0x1F, 0xD7, 0x9C, 0x8B, 0xEB, 0x70, 0x2B, 0x3C, 0x8A,
|
||||
0x85, 0x1A, 0x4C, 0x96, 0x5A, 0x09, 0xCC, 0xD0, 0xC9, 0xF8, 0xE9, 0x65,
|
||||
0x1E, 0xEA, 0xC8, 0xB9, 0xC1, 0x72, 0x10, 0x47, 0x3F, 0x9D, 0x8C, 0x4F,
|
||||
0xC0, 0x14, 0x80, 0xFB, 0x2B, 0x70, 0x01, 0xC6, 0x99, 0x61, 0xEB, 0x22,
|
||||
0x92, 0x47, 0x39, 0xE5, 0xE9, 0x75, 0x3D, 0x6A, 0x47, 0x09, 0x3A, 0x08,
|
||||
0xD6, 0x22, 0x90, 0x79, 0x26, 0xBC, 0xFE, 0xAA, 0x08, 0xED, 0x0C, 0x47,
|
||||
0xAA, 0xCB, 0xDA, 0x01, 0x89, 0x1C, 0x4E, 0xF0, 0x32, 0xB1, 0xD9, 0x58,
|
||||
0xCF, 0x6A, 0x22, 0xE7, 0x15, 0xBB, 0x5B, 0x55, 0x52, 0x55, 0x23, 0xD5,
|
||||
0xAD, 0x98, 0x73, 0x8F, 0xB0, 0x0B, 0xF3, 0xBA, 0xF9, 0xED, 0x24, 0x65,
|
||||
0x42, 0x0E, 0x41, 0xB4, 0x23, 0xE8, 0xB7, 0x30, 0xE7, 0x18, 0x7B, 0x95,
|
||||
0xB3, 0x2F, 0x22, 0x91, 0x7A, 0x1B, 0xB8, 0xAE, 0x44, 0xCD, 0x6F, 0x06,
|
||||
0x3C, 0xA2, 0x93, 0x71, 0x59, 0xA6, 0xF3, 0x12, 0x0C, 0x99, 0xE9, 0x11,
|
||||
0x05, 0xCE, 0x57, 0x57, 0x9D, 0x8C, 0x3F, 0x82, 0x09, 0x3E, 0x1C, 0x4C,
|
||||
0x69, 0xA3, 0xF6, 0xCB, 0x89, 0x13, 0x17, 0x6A, 0xFD, 0x9B, 0x0E, 0x49,
|
||||
0x20, 0x56, 0x90, 0xBE, 0x0C, 0x8C, 0x89, 0xB0, 0x3B, 0x1B, 0x81, 0x54,
|
||||
0xBF, 0x6B, 0xD3, 0xA3, 0xE1, 0x7B, 0x93, 0x81, 0xC3, 0x22, 0x92, 0x48,
|
||||
0x0D, 0x70, 0x3F, 0x52, 0x3D, 0x25, 0xA4, 0x2A, 0x4E, 0xF1, 0x26, 0xA9,
|
||||
0x76, 0x69, 0x30, 0x2E, 0xA2, 0x97, 0x46, 0x20, 0x8F, 0x7F, 0x55, 0x42,
|
||||
0xBC, 0x4A, 0x89, 0xC8, 0x63, 0x37, 0x4C, 0x20, 0x5B, 0xDF, 0x4A, 0xE9,
|
||||
0x93, 0x48, 0xA4, 0xFE, 0x88, 0x39, 0x98, 0x2E, 0x55, 0xA4, 0xF1, 0x39,
|
||||
0xA0, 0xAF, 0x2B, 0xE3, 0x2B, 0xFE, 0xC6, 0x66, 0xE8, 0x8D, 0x32, 0x5F,
|
||||
0xEB, 0x63, 0xDC, 0xAC, 0x4F, 0x8F, 0xB0, 0x8E, 0xDB, 0x22, 0x46, 0x20,
|
||||
0xD5, 0x21, 0x1D, 0x93, 0x40, 0x0C, 0x2E, 0x21, 0x7C, 0xF2, 0x33, 0x01,
|
||||
0xDC, 0xD4, 0x0E, 0x48, 0xE4, 0xBD, 0x02, 0x48, 0x04, 0xE0, 0x44, 0x0D,
|
||||
0x9F, 0x21, 0xD5, 0xEF, 0x6D, 0xB4, 0x78, 0x14, 0xE2, 0xD8, 0xDC, 0x6A,
|
||||
0x1D, 0x1F, 0x10, 0x3C, 0x56, 0x21, 0x1B, 0x2B, 0x08, 0xEF, 0x76, 0xD8,
|
||||
0x56, 0xC8, 0xA3, 0x13, 0x26, 0x86, 0xA3, 0xE2, 0xB2, 0x21, 0x88, 0x44,
|
||||
0xEA, 0x7A, 0xE0, 0x40, 0x4C, 0x7E, 0xA8, 0x52, 0x68, 0x7E, 0xBF, 0xB7,
|
||||
0xE4, 0x59, 0x96, 0xD7, 0x03, 0x6A, 0x75, 0x32, 0xBE, 0x47, 0x84, 0x7B,
|
||||
0x6F, 0xC1, 0x04, 0x45, 0x76, 0x14, 0x54, 0x03, 0x4F, 0x21, 0xD5, 0x56,
|
||||
0x1D, 0xE1, 0x45, 0x73, 0x09, 0xD1, 0xAF, 0x90, 0xEA, 0x22, 0xE0, 0xF1,
|
||||
0x88, 0x24, 0xA2, 0xF1, 0xBD, 0x5B, 0xDB, 0xEC, 0xA8, 0xF8, 0xDE, 0x7B,
|
||||
0x48, 0x75, 0x38, 0x26, 0x05, 0x75, 0xCF, 0x08, 0x2D, 0x6C, 0x04, 0x8C,
|
||||
0xD0, 0x70, 0x05, 0x52, 0xFD, 0x0D, 0x18, 0x2B, 0xE0, 0x35, 0xED, 0x7B,
|
||||
0x79, 0x0F, 0x43, 0x85, 0x54, 0x1B, 0x69, 0x73, 0x0E, 0xE3, 0x61, 0xD2,
|
||||
0x53, 0x77, 0x2E, 0xE0, 0x0D, 0x12, 0xB6, 0x26, 0x4A, 0x7B, 0xC4, 0x99,
|
||||
0x84, 0xAB, 0xB3, 0xB1, 0x18, 0xE3, 0xD9, 0xF4, 0x55, 0x0E, 0xED, 0xA0,
|
||||
0xB7, 0xDD, 0x2C, 0x14, 0x93, 0x44, 0x26, 0x01, 0x87, 0xEB, 0x64, 0x7C,
|
||||
0x17, 0x3B, 0x97, 0x87, 0x5B, 0x4D, 0x69, 0xBD, 0x22, 0x34, 0x5F, 0x85,
|
||||
0x71, 0x29, 0xFD, 0x75, 0x99, 0xC6, 0x7E, 0x03, 0x60, 0xB4, 0x4E, 0xC6,
|
||||
0xF7, 0x0F, 0xEA, 0x25, 0x66, 0x4C, 0x8D, 0x81, 0x82, 0xD7, 0x32, 0xA8,
|
||||
0x03, 0x26, 0x63, 0x6A, 0xBD, 0xAC, 0xCC, 0x21, 0x5F, 0x4E, 0xA7, 0x2D,
|
||||
0xD4, 0x24, 0x32, 0x41, 0xCA, 0xA3, 0x62, 0x52, 0x1D, 0x9C, 0xF6, 0xBD,
|
||||
0xD5, 0x1D, 0x8B, 0x40, 0x8C, 0x10, 0x1D, 0x89, 0x54, 0x07, 0x85, 0x9C,
|
||||
0xFC, 0xCC, 0x24, 0xDF, 0x6C, 0x49, 0xE4, 0xB6, 0x36, 0x4C, 0x22, 0xEF,
|
||||
0x5A, 0x12, 0xF9, 0x27, 0xD1, 0x8B, 0xDF, 0x6C, 0x68, 0xC7, 0xEF, 0x5C,
|
||||
0x0D, 0x75, 0x48, 0xF5, 0x89, 0xFD, 0x30, 0x16, 0x58, 0x61, 0x56, 0x63,
|
||||
0x77, 0xD2, 0xBB, 0x6A, 0x93, 0x62, 0xA0, 0x18, 0x76, 0xE1, 0xA7, 0x37,
|
||||
0x14, 0xE2, 0xAE, 0x45, 0xB4, 0x5B, 0x9C, 0x16, 0xF0, 0xBA, 0x34, 0xC6,
|
||||
0x3B, 0xF0, 0x8E, 0x7C, 0xC1, 0x6A, 0x3A, 0x19, 0x1F, 0x52, 0x6C, 0x02,
|
||||
0xC9, 0x22, 0x92, 0xA9, 0x98, 0x73, 0x91, 0xEB, 0x6C, 0x85, 0xC2, 0xDD,
|
||||
0x2C, 0xF1, 0x6D, 0x0F, 0xEC, 0x8C, 0x89, 0x2B, 0xD9, 0x05, 0xE3, 0xF9,
|
||||
0x17, 0xC6, 0xAC, 0x73, 0x78, 0x99, 0xC7, 0x7F, 0x17, 0xE0, 0x11, 0x3D,
|
||||
0xFC, 0xA0, 0xE3, 0x03, 0x06, 0x38, 0x9E, 0x1A, 0x62, 0x5D, 0x8F, 0x02,
|
||||
0x86, 0xE5, 0x4B, 0x41, 0x62, 0xCE, 0x80, 0xF4, 0xA9, 0x6D, 0x84, 0x40,
|
||||
0x00, 0x0E, 0x48, 0x1B, 0xC7, 0x8E, 0x0B, 0x3A, 0x1E, 0x81, 0x98, 0x59,
|
||||
0x1A, 0x96, 0x36, 0x8B, 0xFD, 0x90, 0x08, 0x24, 0x72, 0x0B, 0x52, 0xD1,
|
||||
0x0E, 0x48, 0xE4, 0xB0, 0x02, 0x49, 0x24, 0x83, 0x1A, 0x8C, 0xBB, 0x62,
|
||||
0x9F, 0x12, 0xF6, 0xF8, 0x7D, 0x01, 0xA7, 0x2D, 0x6A, 0xBF, 0x07, 0xE7,
|
||||
0x9D, 0x09, 0x5E, 0x94, 0xE8, 0x71, 0x91, 0x48, 0x8D, 0xA8, 0x84, 0x7E,
|
||||
0x8B, 0x44, 0xAA, 0x0E, 0x13, 0xC3, 0xF0, 0x61, 0x8E, 0x77, 0xEA, 0x0D,
|
||||
0x1C, 0x61, 0xC9, 0x6E, 0xDB, 0x00, 0xCD, 0x6D, 0xA3, 0x93, 0xFD, 0xAA,
|
||||
0xC3, 0x06, 0xE2, 0x35, 0x83, 0xAF, 0x31, 0xF5, 0x72, 0xF6, 0x0B, 0x71,
|
||||
0xCF, 0x31, 0xE8, 0xF4, 0xE5, 0x98, 0x54, 0x24, 0x2D, 0xE1, 0xC0, 0x80,
|
||||
0x6D, 0xCE, 0xC6, 0xB8, 0x0B, 0x57, 0xF2, 0x6E, 0xFD, 0x33, 0x4B, 0x5E,
|
||||
0x3B, 0x87, 0xB8, 0xE7, 0x7C, 0xA4, 0x7A, 0x1B, 0xDF, 0x7B, 0xA4, 0x0D,
|
||||
0x7D, 0x6A, 0x81, 0xF3, 0xC4, 0x35, 0xCB, 0xE4, 0x69, 0xDF, 0x5B, 0x2D,
|
||||
0x8C, 0x7F, 0xFB, 0x7B, 0x51, 0xBE, 0x1B, 0x4B, 0x22, 0x6D, 0xDB, 0x23,
|
||||
0xC1, 0xF7, 0xDE, 0xB5, 0xBB, 0xBE, 0x05, 0x15, 0xDE, 0xD3, 0xE9, 0xC0,
|
||||
0xE0, 0x76, 0x9E, 0x3A, 0xE1, 0x07, 0x04, 0x77, 0xCD, 0x7D, 0x29, 0xC0,
|
||||
0x35, 0x9B, 0x15, 0xAB, 0x63, 0x7A, 0xC4, 0x21, 0x42, 0x27, 0xE3, 0x23,
|
||||
0x75, 0x32, 0x3E, 0x50, 0x8F, 0x38, 0x24, 0xB0, 0x46, 0x21, 0x12, 0xA9,
|
||||
0x2F, 0x45, 0x22, 0x25, 0x31, 0x09, 0x14, 0x83, 0xA0, 0x33, 0xE8, 0x62,
|
||||
0x79, 0x30, 0x7D, 0x87, 0x49, 0xE9, 0x73, 0x0C, 0xE1, 0xB3, 0x54, 0x5F,
|
||||
0xAB, 0x93, 0xF1, 0x20, 0xDA, 0x50, 0xD0, 0xA2, 0x67, 0x6F, 0xB6, 0x4C,
|
||||
0x1E, 0x7A, 0x73, 0xCA, 0xE7, 0xBD, 0x35, 0xDD, 0x8E, 0xD5, 0x71, 0xC0,
|
||||
0x92, 0x90, 0xF7, 0xDE, 0x87, 0x54, 0xFB, 0x56, 0xC0, 0xF7, 0xB3, 0x32,
|
||||
0xE0, 0x75, 0x41, 0x73, 0x22, 0xB6, 0xAC, 0x0A, 0x6A, 0xDF, 0x5B, 0x28,
|
||||
0x4C, 0xC0, 0xCF, 0x07, 0x11, 0x49, 0xE4, 0xD6, 0x76, 0x40, 0x22, 0xEF,
|
||||
0x10, 0xDD, 0xC5, 0xB7, 0xB5, 0x76, 0x46, 0x03, 0xF1, 0xBD, 0x6F, 0x69,
|
||||
0xDF, 0x08, 0x23, 0x3C, 0x36, 0x6F, 0x41, 0x9B, 0x59, 0x1F, 0x28, 0x9E,
|
||||
0xEB, 0x79, 0xBA, 0xFE, 0x50, 0x4C, 0x96, 0xEA, 0x7F, 0x91, 0xAE, 0x9F,
|
||||
0xA4, 0x93, 0xF1, 0x5F, 0x85, 0xAC, 0x8E, 0xD7, 0x23, 0xE0, 0x75, 0xAB,
|
||||
0x41, 0x14, 0xC3, 0xD3, 0xEB, 0x7B, 0x60, 0xA0, 0x48, 0xA4, 0x3E, 0x17,
|
||||
0x89, 0xD4, 0xD7, 0xC0, 0x50, 0xD3, 0x76, 0xA8, 0xB9, 0x78, 0x42, 0x27,
|
||||
0xE3, 0x2D, 0x69, 0x4D, 0x41, 0x2B, 0x34, 0x06, 0x49, 0x6C, 0xFA, 0x47,
|
||||
0xCA, 0x63, 0xBE, 0x9A, 0x01, 0x0C, 0xC0, 0xF7, 0xBE, 0xC5, 0xF7, 0xA6,
|
||||
0x60, 0xF2, 0x00, 0x86, 0xD1, 0xF2, 0xD7, 0x03, 0x46, 0x0B, 0xA9, 0x36,
|
||||
0x2E, 0xF3, 0xF7, 0x13, 0xB4, 0xA8, 0xDC, 0xEF, 0x90, 0xEA, 0x17, 0xD9,
|
||||
0x3F, 0xA8, 0x96, 0xAA, 0x0A, 0xA9, 0xBC, 0xA6, 0xA5, 0x3C, 0x02, 0x4D,
|
||||
0x86, 0xF6, 0xBD, 0xB9, 0xC2, 0xD8, 0x8A, 0x3F, 0x8C, 0xD0, 0xE9, 0x0C,
|
||||
0x89, 0x5C, 0x42, 0x5B, 0x86, 0x21, 0x91, 0x7E, 0x98, 0x9A, 0x0D, 0x95,
|
||||
0x84, 0x37, 0x04, 0x1C, 0x84, 0xEF, 0xCD, 0xA6, 0xFD, 0x63, 0x61, 0x88,
|
||||
0x0F, 0xF7, 0x02, 0x9B, 0x75, 0x37, 0x17, 0x79, 0x74, 0x03, 0xFE, 0x46,
|
||||
0xF1, 0xF2, 0x25, 0xC1, 0xDA, 0x69, 0xBE, 0xFB, 0x62, 0x8A, 0x33, 0x7D,
|
||||
0xAB, 0x93, 0xF1, 0x37, 0x75, 0x32, 0x7E, 0xB3, 0x4E, 0xC6, 0x4F, 0xD5,
|
||||
0xC9, 0xF8, 0xFE, 0x3A, 0x19, 0xDF, 0x5C, 0x27, 0xE3, 0x1B, 0xD8, 0xB8,
|
||||
0x88, 0x5E, 0xF6, 0x67, 0xBF, 0x07, 0x9E, 0x09, 0x2A, 0xCC, 0x8A, 0x60,
|
||||
0xBE, 0xAA, 0x03, 0x0E, 0x15, 0x89, 0xD4, 0x94, 0x2C, 0x4D, 0x28, 0x45,
|
||||
0xF8, 0x54, 0xE5, 0x1B, 0x63, 0x0E, 0xD5, 0x9B, 0x73, 0x10, 0x08, 0x1A,
|
||||
0x95, 0xDD, 0x2F, 0x5F, 0x21, 0x28, 0x3D, 0xFC, 0x20, 0xA1, 0x93, 0xF1,
|
||||
0x2B, 0x80, 0xB3, 0xCB, 0xB0, 0xE6, 0x16, 0x5B, 0xF2, 0xF8, 0x32, 0x4B,
|
||||
0x16, 0x8C, 0x05, 0x92, 0x21, 0xDB, 0xD9, 0x4E, 0xC3, 0xC8, 0x1A, 0xA9,
|
||||
0xCA, 0x19, 0xFF, 0x12, 0x34, 0x75, 0x4F, 0x27, 0x60, 0x24, 0x52, 0x7D,
|
||||
0x8A, 0x54, 0x63, 0x90, 0x6A, 0x62, 0xBD, 0x31, 0x75, 0xFE, 0x4D, 0x37,
|
||||
0xC9, 0x84, 0x11, 0x38, 0xBA, 0x54, 0xFB, 0xDE, 0x1C, 0x21, 0xD5, 0xA1,
|
||||
0x1A, 0xFE, 0x45, 0xF8, 0xC0, 0x2D, 0x01, 0xDC, 0x66, 0x0F, 0xD6, 0xEF,
|
||||
0x6C, 0xB3, 0xE2, 0xCB, 0xF7, 0x3E, 0x11, 0x52, 0xFD, 0x58, 0x1B, 0xEF,
|
||||
0xB4, 0x41, 0x15, 0xD0, 0x23, 0x19, 0x83, 0x61, 0x65, 0xAA, 0x35, 0xD0,
|
||||
0xEA, 0x10, 0x89, 0xD4, 0x42, 0x9D, 0x8C, 0xCF, 0xC2, 0x1C, 0x44, 0xB7,
|
||||
0x84, 0xAD, 0x80, 0x77, 0x74, 0x32, 0x7E, 0x0B, 0x90, 0xC2, 0xD4, 0x37,
|
||||
0xE8, 0x09, 0xF4, 0xC7, 0x78, 0x32, 0x15, 0xCD, 0xC5, 0xD2, 0x7A, 0x5C,
|
||||
0x1D, 0x91, 0x67, 0x97, 0xBE, 0xBF, 0xFD, 0xB3, 0xD6, 0x2D, 0xF6, 0x4F,
|
||||
0x94, 0xDD, 0x74, 0x31, 0x62, 0x7B, 0x56, 0x21, 0xC4, 0x94, 0x1C, 0xE3,
|
||||
0x7B, 0xBF, 0x4E, 0xC6, 0xFB, 0x86, 0x14, 0xD4, 0x7D, 0x81, 0x7B, 0x9A,
|
||||
0xB9, 0x67, 0x72, 0x8E, 0xF7, 0xCF, 0x67, 0x0D, 0x99, 0xA0, 0x93, 0xF1,
|
||||
0x7B, 0x31, 0x89, 0x5D, 0xBF, 0xB7, 0x3B, 0xF7, 0x7D, 0xD1, 0xE9, 0x73,
|
||||
0x81, 0x1F, 0x97, 0x69, 0xD9, 0xCD, 0xCD, 0xB5, 0x39, 0xAB, 0x81, 0xAB,
|
||||
0xEB, 0x4C, 0xFA, 0x99, 0xC1, 0x21, 0xDA, 0x1A, 0x54, 0x67, 0xB4, 0xA8,
|
||||
0xAB, 0xCB, 0xF2, 0xFD, 0xC0, 0xDB, 0xDA, 0x38, 0x97, 0x04, 0x5D, 0x77,
|
||||
0xBB, 0xDA, 0x3F, 0xD9, 0xF8, 0x05, 0x70, 0x5F, 0x28, 0x0D, 0x64, 0x2D,
|
||||
0x12, 0x81, 0x43, 0x31, 0x35, 0x01, 0xA2, 0x68, 0x22, 0xB7, 0x23, 0xD5,
|
||||
0xC5, 0x6D, 0x59, 0x88, 0x69, 0xDF, 0x9B, 0xDB, 0xD9, 0x2C, 0x9A, 0xDF,
|
||||
0x00, 0xCB, 0xCA, 0xD4, 0x8D, 0x39, 0x80, 0x87, 0xEF, 0x9D, 0xDB, 0x51,
|
||||
0xC8, 0x23, 0x0B, 0x7F, 0x0F, 0x71, 0xED, 0x96, 0x98, 0x52, 0xAA, 0x93,
|
||||
0x80, 0x4F, 0x31, 0x69, 0x7A, 0xAE, 0x2F, 0x26, 0x79, 0x58, 0x5C, 0x1C,
|
||||
0xF2, 0x5B, 0x12, 0x11, 0xC9, 0x63, 0x15, 0xA6, 0x7A, 0x61, 0x29, 0x71,
|
||||
0x11, 0xE1, 0xEB, 0xCD, 0x9F, 0xA5, 0x93, 0xF1, 0x5F, 0x15, 0x61, 0xBE,
|
||||
0x3A, 0x63, 0x82, 0x66, 0x5F, 0xB1, 0xF3, 0xF5, 0x1E, 0xA6, 0x46, 0xFB,
|
||||
0x8F, 0x2B, 0x6D, 0x11, 0xD6, 0xF9, 0x5E, 0x5A, 0x18, 0x0F, 0xB3, 0xE9,
|
||||
0x21, 0x6F, 0xBD, 0x02, 0xA9, 0x8E, 0x2E, 0x93, 0xEC, 0xFA, 0xDE, 0x6E,
|
||||
0xA6, 0x0A, 0xC1, 0x4F, 0x90, 0x6A, 0xDB, 0x48, 0x04, 0x52, 0x24, 0x12,
|
||||
0xB9, 0xA3, 0xAD, 0x93, 0xC8, 0x2A, 0xDF, 0x4B, 0xE3, 0x7B, 0x77, 0x60,
|
||||
0x6A, 0x72, 0x8C, 0xA1, 0x34, 0x41, 0x63, 0xB9, 0xD0, 0x00, 0x3C, 0x20,
|
||||
0x60, 0x77, 0x7C, 0x6F, 0x14, 0x1D, 0x13, 0xF7, 0x5A, 0x13, 0x4C, 0x65,
|
||||
0x6C, 0x28, 0x92, 0xF1, 0x8D, 0x08, 0xEE, 0x5A, 0x5C, 0x28, 0x6E, 0x10,
|
||||
0x89, 0xD4, 0x17, 0x25, 0xD6, 0xF2, 0x4C, 0xC1, 0xB4, 0xF0, 0x87, 0xEA,
|
||||
0x77, 0xEA, 0x64, 0x3C, 0x87, 0xA6, 0x21, 0x9E, 0xB7, 0x64, 0xD0, 0xEE,
|
||||
0xA0, 0x7D, 0x6F, 0x01, 0xC6, 0xC9, 0x28, 0x8C, 0xE3, 0x4A, 0x0C, 0xF8,
|
||||
0x2B, 0x52, 0xED, 0x5C, 0xA6, 0x6E, 0x17, 0x5A, 0x49, 0x56, 0x00, 0x27,
|
||||
0x47, 0x26, 0x90, 0x0C, 0x93, 0x15, 0x81, 0x44, 0x86, 0xB5, 0xF9, 0x15,
|
||||
0xE4, 0x7B, 0xB3, 0xF0, 0xBD, 0x13, 0x30, 0xAE, 0x8A, 0xE3, 0x29, 0x6E,
|
||||
0x42, 0xBD, 0xB5, 0x36, 0x3C, 0x98, 0xCC, 0xAC, 0x7B, 0xE2, 0x7B, 0xE7,
|
||||
0x6B, 0xDF, 0x9B, 0x4B, 0x07, 0x85, 0x48, 0xA4, 0xA6, 0x11, 0xDE, 0xFE,
|
||||
0xDC, 0x1C, 0x66, 0x14, 0x78, 0xFF, 0x39, 0x98, 0x00, 0xBB, 0x52, 0x43,
|
||||
0x81, 0xB8, 0xB1, 0x95, 0xC6, 0xF8, 0x2B, 0x4C, 0xD1, 0xB2, 0x30, 0x44,
|
||||
0xDD, 0x19, 0x18, 0xA5, 0x93, 0xF1, 0x1F, 0xAC, 0xDD, 0xD6, 0x6B, 0x0D,
|
||||
0xC0, 0xF9, 0x14, 0x2F, 0xC5, 0xCB, 0xCC, 0x0A, 0x93, 0x01, 0x1F, 0x63,
|
||||
0x4A, 0xEE, 0x86, 0xD9, 0x44, 0xF6, 0xC0, 0x1C, 0xAA, 0x77, 0x6D, 0xED,
|
||||
0xEE, 0x76, 0x11, 0x3C, 0x4D, 0xB0, 0x0A, 0x9A, 0xCD, 0xA1, 0x30, 0x02,
|
||||
0xC9, 0x52, 0x87, 0x0E, 0x05, 0x3E, 0x8E, 0x48, 0x22, 0x77, 0xDA, 0x68,
|
||||
0xF7, 0xB6, 0x0F, 0xDF, 0x7B, 0xCB, 0x96, 0x8C, 0xDD, 0x0D, 0x18, 0x81,
|
||||
0xF1, 0x69, 0x2F, 0x06, 0xA6, 0x02, 0xFF, 0x07, 0x6C, 0x8F, 0xEF, 0x9D,
|
||||
0x8A, 0xEF, 0xB5, 0xCB, 0x9D, 0x5C, 0x84, 0xE5, 0x73, 0x2D, 0x6B, 0xD7,
|
||||
0x7A, 0x8E, 0x8A, 0xD1, 0xC0, 0xD3, 0x05, 0xB6, 0x71, 0x40, 0xA9, 0x37,
|
||||
0xBA, 0xC0, 0xED, 0x20, 0x4E, 0xB1, 0xC2, 0xB8, 0xB5, 0x88, 0xFA, 0x55,
|
||||
0x8C, 0x39, 0x29, 0x0C, 0x7A, 0x03, 0x4F, 0x35, 0xCD, 0xDC, 0x2B, 0x12,
|
||||
0xA9, 0x57, 0x80, 0x0B, 0x8B, 0xB0, 0xC1, 0xFA, 0x82, 0x4A, 0x2C, 0x1D,
|
||||
0x61, 0xAC, 0x01, 0x61, 0x63, 0x8E, 0xF6, 0xD4, 0x50, 0xBB, 0x49, 0x2B,
|
||||
0x67, 0xEE, 0x5D, 0x79, 0x8E, 0x97, 0x06, 0x4E, 0xB1, 0x63, 0x19, 0x15,
|
||||
0x7B, 0x22, 0xD5, 0x9E, 0x05, 0x11, 0x88, 0x1D, 0xB8, 0xEF, 0x31, 0xE9,
|
||||
0x37, 0xA2, 0x92, 0xC8, 0x5D, 0xED, 0x86, 0x44, 0xCC, 0x78, 0x7C, 0x8E,
|
||||
0xEF, 0x5D, 0xDE, 0xD9, 0x44, 0x19, 0xF7, 0x05, 0x2E, 0xC7, 0x1C, 0x7A,
|
||||
0x7E, 0x15, 0x50, 0x50, 0xCC, 0xB2, 0x02, 0xED, 0x37, 0xC0, 0x0F, 0x7B,
|
||||
0x0A, 0xB1, 0x1B, 0xBE, 0x77, 0x1D, 0xBE, 0xF7, 0x15, 0x0E, 0x4D, 0x76,
|
||||
0xB5, 0xE2, 0x54, 0xE0, 0x06, 0x20, 0xAA, 0x47, 0xD2, 0x18, 0xE0, 0x97,
|
||||
0x14, 0x6A, 0x7E, 0x14, 0xB1, 0xA1, 0xC0, 0xCF, 0x31, 0x45, 0xC9, 0x8A,
|
||||
0xAD, 0x81, 0xBE, 0x8B, 0xA9, 0x3F, 0x7E, 0x69, 0x11, 0x03, 0x07, 0xC3,
|
||||
0x90, 0xC8, 0x3D, 0xC0, 0x23, 0x21, 0x6F, 0xEB, 0x0F, 0x3A, 0x99, 0xA3,
|
||||
0xAD, 0x3F, 0x63, 0x4C, 0x63, 0xF3, 0x0A, 0xD8, 0x4C, 0x1D, 0x56, 0xC0,
|
||||
0xFD, 0x25, 0x45, 0xB5, 0xC9, 0x62, 0xFE, 0x7C, 0xC8, 0xDB, 0x4E, 0x9A,
|
||||
0xAB, 0x75, 0xEB, 0xA7, 0xA5, 0xF1, 0xBD, 0x6F, 0x30, 0x45, 0xCD, 0xDE,
|
||||
0x2E, 0xA0, 0x95, 0x5F, 0x14, 0x4E, 0x20, 0x6B, 0x93, 0xC8, 0x94, 0x28,
|
||||
0x6B, 0xD4, 0x92, 0xC8, 0x85, 0xED, 0x49, 0xC0, 0xD9, 0x33, 0x92, 0xF7,
|
||||
0xF0, 0xBD, 0x11, 0xF8, 0xDE, 0x91, 0xF8, 0x5E, 0x6F, 0x61, 0xD4, 0xD6,
|
||||
0x3E, 0x98, 0xA8, 0xFE, 0xA3, 0x30, 0x7E, 0xF7, 0x47, 0x02, 0x07, 0x01,
|
||||
0x7B, 0x08, 0xE8, 0x86, 0xEF, 0x6D, 0x8F, 0xEF, 0x1D, 0x87, 0xEF, 0xDD,
|
||||
0x81, 0xEF, 0x7D, 0xD2, 0x5E, 0x53, 0xB1, 0x17, 0x8B, 0x44, 0x44, 0x22,
|
||||
0x75, 0x15, 0xA6, 0xF6, 0xC7, 0x93, 0x04, 0x2F, 0xC7, 0x3C, 0x15, 0x38,
|
||||
0x0D, 0x51, 0x35, 0xD4, 0xDA, 0xFB, 0x0B, 0xEB, 0xC7, 0xE5, 0xAF, 0xA6,
|
||||
0x45, 0x22, 0xF5, 0xAC, 0x48, 0xA4, 0x06, 0x62, 0xBC, 0xC3, 0x2E, 0xC1,
|
||||
0x98, 0x33, 0xA3, 0x66, 0x93, 0x99, 0x07, 0x3C, 0x0A, 0x0C, 0x44, 0x54,
|
||||
0xFF, 0x48, 0x24, 0x52, 0x2F, 0x97, 0x79, 0xA8, 0xCF, 0xC7, 0x38, 0x21,
|
||||
0x84, 0xC1, 0x6F, 0x75, 0x32, 0x3E, 0x34, 0x07, 0x89, 0x3C, 0x83, 0x71,
|
||||
0x9D, 0x1E, 0x4E, 0x70, 0xF7, 0xDE, 0x05, 0x98, 0x94, 0x30, 0x7D, 0x45,
|
||||
0x22, 0x35, 0xBD, 0x52, 0xD7, 0x63, 0xBD, 0xEF, 0x35, 0x08, 0x23, 0x54,
|
||||
0xC3, 0x9A, 0x44, 0x6F, 0x42, 0xAA, 0x83, 0xCB, 0x40, 0x22, 0xB3, 0xAB,
|
||||
0x4C, 0xA2, 0xD6, 0x73, 0x09, 0x77, 0x46, 0xB5, 0x04, 0xE3, 0xD8, 0xF0,
|
||||
0x60, 0x46, 0x80, 0x17, 0x07, 0x52, 0x6D, 0x8A, 0xA9, 0xEA, 0xF7, 0xC3,
|
||||
0x88, 0x6A, 0xFA, 0x30, 0x7C, 0xEF, 0x5E, 0x27, 0x1A, 0xDB, 0x2F, 0x74,
|
||||
0x32, 0x7E, 0x60, 0xC0, 0x4D, 0xCB, 0x4A, 0x91, 0x48, 0xBD, 0x1B, 0xB2,
|
||||
0xED, 0xEE, 0x76, 0x23, 0xB3, 0x2F, 0x26, 0xD5, 0x44, 0xA6, 0x1A, 0xE1,
|
||||
0x0A, 0xCC, 0x81, 0xF0, 0x47, 0xC0, 0x6B, 0x88, 0xD8, 0x3B, 0xD9, 0x39,
|
||||
0x9C, 0x6C, 0x20, 0xDC, 0x96, 0x01, 0x1E, 0xF1, 0xAD, 0x48, 0xA4, 0x66,
|
||||
0x06, 0xEF, 0x4F, 0xBF, 0x2A, 0xD0, 0x3B, 0xD8, 0x4D, 0xC3, 0x76, 0x98,
|
||||
0x34, 0x25, 0x3F, 0xC0, 0x54, 0x36, 0xEC, 0x6C, 0xB5, 0x95, 0xE5, 0x96,
|
||||
0x30, 0x66, 0x63, 0x4A, 0xE3, 0x4E, 0x06, 0x31, 0x25, 0xAA, 0xA9, 0x4A,
|
||||
0x27, 0xE3, 0xFB, 0x11, 0x2C, 0x09, 0x67, 0x83, 0x48, 0xA4, 0xDE, 0x0C,
|
||||
0xD1, 0xEE, 0x26, 0x84, 0x8F, 0x99, 0x59, 0x26, 0x12, 0xA9, 0xF7, 0x9B,
|
||||
0x19, 0x9F, 0x1A, 0xD0, 0x3F, 0xC1, 0xB8, 0xF8, 0xEE, 0x8E, 0x09, 0x24,
|
||||
0x5C, 0x1F, 0x73, 0xEE, 0x32, 0x17, 0x13, 0x1C, 0xFB, 0x36, 0xF0, 0x62,
|
||||
0x36, 0xD1, 0xEB, 0x64, 0xBC, 0x47, 0x40, 0x19, 0xB3, 0x5C, 0x24, 0x52,
|
||||
0x93, 0x9B, 0x91, 0x57, 0x41, 0xB3, 0x5C, 0xAF, 0xB4, 0xD9, 0x28, 0x82,
|
||||
0xCA, 0xC1, 0x2D, 0xEC, 0x7C, 0x87, 0xC1, 0xFC, 0x6C, 0xF3, 0xB4, 0x90,
|
||||
0x6A, 0x03, 0x1D, 0x3C, 0xE5, 0xD1, 0xF7, 0xF8, 0xDE, 0xB4, 0x42, 0xBE,
|
||||
0xCB, 0x6E, 0xB5, 0xA3, 0xC4, 0x12, 0xAD, 0x7F, 0x08, 0xC4, 0x81, 0x3D,
|
||||
0x30, 0xA6, 0xC8, 0x6E, 0xF6, 0x5B, 0x5D, 0x6E, 0xBF, 0x9F, 0xCF, 0x80,
|
||||
0xC9, 0x02, 0x52, 0xDA, 0xF7, 0x56, 0x64, 0x6B, 0x00, 0xC5, 0x43, 0xE1,
|
||||
0x24, 0x72, 0x11, 0xBE, 0x77, 0x9F, 0x13, 0xB5, 0x0E, 0x0E, 0x0E, 0x0E,
|
||||
0x6D, 0xC0, 0x12, 0x50, 0xF4, 0x16, 0x0D, 0x89, 0xBC, 0x48, 0xB8, 0x94,
|
||||
0xDB, 0xD9, 0x24, 0x72, 0x21, 0xBE, 0x77, 0xBF, 0x9B, 0x1A, 0x07, 0x07,
|
||||
0x07, 0x87, 0xCA, 0x46, 0xF1, 0xF3, 0xCA, 0xF8, 0xDE, 0x77, 0xD6, 0x94,
|
||||
0xF0, 0x49, 0x44, 0x42, 0xBB, 0x17, 0xA9, 0xCE, 0x77, 0x53, 0xE3, 0xE0,
|
||||
0xE0, 0xE0, 0xD0, 0xD1, 0x34, 0x90, 0x46, 0x4D, 0x64, 0x33, 0xAB, 0x89,
|
||||
0x44, 0xA9, 0xA0, 0xA6, 0x81, 0x0B, 0xF0, 0xBD, 0x07, 0xDC, 0x14, 0x39,
|
||||
0x38, 0x38, 0x38, 0x74, 0x34, 0x02, 0x71, 0x24, 0xE2, 0xE0, 0xE0, 0xE0,
|
||||
0xE0, 0x08, 0xA4, 0x8C, 0x24, 0x92, 0xB6, 0x24, 0xF2, 0x67, 0x37, 0x55,
|
||||
0x0E, 0x0E, 0x0E, 0x0E, 0x1D, 0x8D, 0x40, 0x0C, 0x89, 0x6C, 0x6E, 0x49,
|
||||
0x64, 0x57, 0x47, 0x22, 0x0E, 0x0E, 0x0E, 0x0E, 0x8E, 0x40, 0x5A, 0x9B,
|
||||
0x44, 0xCE, 0xC7, 0xF7, 0x1E, 0xAC, 0xC8, 0x51, 0x94, 0xEA, 0x2C, 0x4C,
|
||||
0xF4, 0xF8, 0xB3, 0xC0, 0xF3, 0x31, 0x78, 0x3B, 0xED, 0x7B, 0x2B, 0xDD,
|
||||
0xF2, 0x72, 0x70, 0x70, 0x70, 0x04, 0x52, 0x5C, 0x12, 0x79, 0x89, 0x68,
|
||||
0x85, 0x7C, 0xD2, 0xC0, 0x79, 0xF8, 0x9E, 0xAC, 0x30, 0xF2, 0x38, 0x13,
|
||||
0x13, 0x99, 0x99, 0xED, 0xD1, 0xB6, 0x12, 0x78, 0x07, 0x53, 0xC5, 0xF1,
|
||||
0x03, 0x4C, 0xDE, 0x99, 0xD9, 0x02, 0xBE, 0x8E, 0xC1, 0xCA, 0x2A, 0x48,
|
||||
0xC7, 0x04, 0x54, 0x23, 0xF4, 0x52, 0x17, 0x6D, 0xEE, 0xE0, 0xE0, 0xE0,
|
||||
0x08, 0x24, 0xB0, 0xC0, 0xDD, 0xC2, 0x6A, 0x22, 0x6D, 0x9F, 0x44, 0x72,
|
||||
0x93, 0x47, 0x4B, 0x58, 0x85, 0x29, 0x1D, 0x3A, 0x15, 0x38, 0xD2, 0xBA,
|
||||
0x3D, 0x3B, 0x38, 0x38, 0x38, 0x38, 0x02, 0x69, 0x25, 0x12, 0xF9, 0x15,
|
||||
0xBE, 0x57, 0x5B, 0x66, 0xF2, 0x38, 0xC3, 0x92, 0x47, 0x94, 0x12, 0x95,
|
||||
0xD3, 0x81, 0xFE, 0x2E, 0x49, 0xA2, 0x83, 0x83, 0x83, 0x23, 0x90, 0xE8,
|
||||
0x24, 0xF2, 0x12, 0x26, 0x6F, 0x51, 0xDB, 0x22, 0x11, 0x53, 0x70, 0xFE,
|
||||
0x31, 0xA2, 0x05, 0x62, 0x4E, 0xA7, 0x69, 0x8D, 0x65, 0x07, 0x07, 0x07,
|
||||
0x87, 0x36, 0x88, 0x58, 0xD9, 0x9E, 0x6C, 0x52, 0x0A, 0xF7, 0x07, 0x3E,
|
||||
0x8F, 0xD8, 0xEF, 0x3F, 0x23, 0xD5, 0xD9, 0xAD, 0xDE, 0x6F, 0xA9, 0x4E,
|
||||
0x02, 0xFE, 0x1A, 0x71, 0xEC, 0x66, 0x38, 0xF2, 0x70, 0x68, 0x6F, 0xA8,
|
||||
0x92, 0xAA, 0x7A, 0xE3, 0x56, 0xAE, 0x6B, 0xE1, 0xD0, 0xD1, 0x35, 0x90,
|
||||
0x46, 0x81, 0xBC, 0x25, 0xC6, 0x9C, 0x15, 0x55, 0x13, 0xF1, 0xF1, 0xBD,
|
||||
0x87, 0x5A, 0xA9, 0xAF, 0x27, 0x02, 0x8F, 0x03, 0xD5, 0x11, 0xC9, 0xA3,
|
||||
0x7F, 0x87, 0x26, 0x0F, 0xA9, 0x3E, 0xC4, 0x64, 0x8B, 0x7D, 0x0A, 0xDF,
|
||||
0xBB, 0xA6, 0x03, 0xBE, 0xFF, 0x79, 0x18, 0x6F, 0x3D, 0x11, 0x83, 0x3D,
|
||||
0xD2, 0xBE, 0xB7, 0xBA, 0xCD, 0xEE, 0x3C, 0xA5, 0xEA, 0x94, 0x36, 0x35,
|
||||
0x30, 0x4E, 0x07, 0x36, 0xC7, 0x94, 0x75, 0x7D, 0x14, 0xDF, 0xBB, 0xA4,
|
||||
0x03, 0xCE, 0x6B, 0x3F, 0x8C, 0x39, 0x1B, 0xE0, 0x64, 0x7C, 0xEF, 0x3D,
|
||||
0xA7, 0x81, 0xB4, 0x9E, 0x26, 0xF2, 0x35, 0x30, 0xA0, 0x00, 0x4D, 0x44,
|
||||
0x5A, 0x37, 0x5A, 0x47, 0x1E, 0x95, 0x8F, 0x9D, 0xEC, 0x46, 0x61, 0xD3,
|
||||
0x0E, 0xFA, 0xFE, 0x3D, 0xED, 0xFB, 0xEF, 0x54, 0x11, 0x9B, 0xB7, 0x02,
|
||||
0x90, 0x36, 0xB5, 0xE9, 0xAF, 0x06, 0xB6, 0xC6, 0xA4, 0xCD, 0xDF, 0x88,
|
||||
0x68, 0xE7, 0x81, 0xED, 0x01, 0x5D, 0xED, 0xBC, 0xEE, 0x0C, 0x74, 0xE9,
|
||||
0x48, 0x2F, 0x1E, 0xAB, 0x88, 0x5E, 0x34, 0x92, 0xC8, 0xB4, 0x88, 0xEF,
|
||||
0x20, 0xAD, 0x47, 0x54, 0xA9, 0xC8, 0xC3, 0x2B, 0x80, 0x3C, 0x66, 0xE2,
|
||||
0xCC, 0x56, 0x0E, 0xED, 0xC9, 0x6C, 0x21, 0x55, 0x4F, 0xE0, 0x0C, 0xFB,
|
||||
0xDF, 0x31, 0x98, 0x7A, 0x2A, 0x7D, 0x81, 0x3B, 0xDD, 0xE8, 0x74, 0x2C,
|
||||
0xC4, 0x2A, 0xA6, 0x27, 0x85, 0x93, 0x48, 0x6D, 0x49, 0x48, 0xC4, 0x90,
|
||||
0xC7, 0xC8, 0x02, 0xC8, 0xA3, 0x3F, 0xBE, 0x37, 0xDB, 0x2D, 0x35, 0x87,
|
||||
0xF6, 0x02, 0x0D, 0x3B, 0x66, 0x7D, 0x0F, 0x0F, 0xE0, 0x7B, 0xDF, 0xD8,
|
||||
0x0A, 0x9C, 0xD3, 0xDD, 0xE8, 0x74, 0x2C, 0x54, 0x57, 0x54, 0x6F, 0x7C,
|
||||
0xEF, 0x2B, 0xA4, 0x1A, 0x80, 0x39, 0x13, 0xD9, 0x29, 0x22, 0x89, 0x68,
|
||||
0x7C, 0xEF, 0x91, 0x22, 0x91, 0xC7, 0xD0, 0x02, 0x35, 0x0F, 0x47, 0x1E,
|
||||
0xF9, 0xC7, 0x76, 0x0F, 0xE0, 0x02, 0x60, 0x6F, 0x8C, 0x39, 0xE7, 0x53,
|
||||
0x60, 0x24, 0xBE, 0xF7, 0xEF, 0xAC, 0x6B, 0xEE, 0x03, 0x7A, 0x01, 0x53,
|
||||
0xF1, 0xBD, 0xAB, 0xF2, 0xB4, 0x73, 0x13, 0xA6, 0x02, 0x5C, 0x0A, 0xDF,
|
||||
0xBB, 0xB3, 0x99, 0xE7, 0xDD, 0x85, 0xB1, 0xD5, 0xFF, 0x03, 0x78, 0xDD,
|
||||
0x3E, 0xBB, 0xAF, 0x5D, 0x37, 0x1F, 0x03, 0xF7, 0xE1, 0x7B, 0x93, 0x63,
|
||||
0x52, 0xD5, 0xA4, 0xE1, 0x54, 0x4C, 0x9D, 0xF3, 0x2D, 0x80, 0x65, 0xC0,
|
||||
0xCB, 0x02, 0xEE, 0xD6, 0xBE, 0x37, 0x7F, 0xAD, 0x05, 0x67, 0xAE, 0x3D,
|
||||
0x1A, 0x18, 0x84, 0xC9, 0xB0, 0xB0, 0x1E, 0xA6, 0x94, 0xED, 0x1B, 0xC0,
|
||||
0x83, 0xA1, 0xB4, 0x4E, 0xA9, 0xB6, 0x07, 0x6E, 0xC4, 0x98, 0x81, 0xE6,
|
||||
0x08, 0xF8, 0x6D, 0xA6, 0xF2, 0x9B, 0x90, 0xAA, 0x9B, 0x36, 0x3B, 0xFE,
|
||||
0x41, 0x18, 0xF3, 0xDF, 0x62, 0xE0, 0x55, 0xFB, 0x8C, 0x6F, 0x9B, 0xB4,
|
||||
0x33, 0x18, 0x38, 0x13, 0x58, 0x19, 0x83, 0xB3, 0xD3, 0x70, 0x1A, 0xA6,
|
||||
0x8F, 0x73, 0xF1, 0xBD, 0xB3, 0x00, 0x6A, 0xA4, 0xAA, 0xAA, 0x83, 0xE3,
|
||||
0x80, 0x63, 0x30, 0x65, 0x78, 0x63, 0x98, 0x12, 0xB3, 0x93, 0x80, 0x67,
|
||||
0xF0, 0xBD, 0x0F, 0x72, 0x75, 0x71, 0xA3, 0xDA, 0x51, 0x62, 0x81, 0xD6,
|
||||
0xF7, 0xD8, 0x71, 0xC9, 0x60, 0x98, 0xFD, 0x4E, 0x00, 0xAE, 0xCB, 0xB8,
|
||||
0xA6, 0x57, 0x49, 0x55, 0xD3, 0x00, 0x9E, 0x1D, 0xC7, 0x6D, 0x80, 0x06,
|
||||
0xE0, 0x43, 0xCC, 0xF9, 0xD7, 0xCB, 0x39, 0xDE, 0x5F, 0x62, 0xCA, 0x3E,
|
||||
0x3F, 0x6D, 0xFB, 0x71, 0x1E, 0xF0, 0x23, 0xE0, 0x2A, 0x7C, 0xEF, 0xD5,
|
||||
0x66, 0xC6, 0xED, 0x12, 0x4C, 0x69, 0xD6, 0xA9, 0x02, 0xEE, 0xD2, 0x70,
|
||||
0x21, 0xA6, 0xDE, 0xF7, 0xFA, 0xC0, 0x2C, 0xE0, 0x11, 0x7C, 0x6F, 0x62,
|
||||
0xCF, 0xDA, 0x51, 0x62, 0xBE, 0xD6, 0x3F, 0xC3, 0x94, 0x9D, 0xDD, 0xD1,
|
||||
0xF6, 0x67, 0x12, 0x70, 0x4F, 0x53, 0xE2, 0xB3, 0x15, 0xFA, 0x0E, 0xB6,
|
||||
0xE3, 0xD6, 0x07, 0x53, 0x45, 0x72, 0x05, 0xF0, 0x3E, 0xF0, 0x30, 0xBE,
|
||||
0x37, 0x39, 0x84, 0xB6, 0xD6, 0x4D, 0xC3, 0x2D, 0x18, 0xF3, 0x65, 0x1D,
|
||||
0x70, 0x99, 0xDD, 0x2C, 0x53, 0x25, 0x55, 0x75, 0x83, 0x29, 0x6D, 0x7D,
|
||||
0xAC, 0x1D, 0xA3, 0xD5, 0x98, 0x00, 0xE4, 0x87, 0xF0, 0xBD, 0x8F, 0x9A,
|
||||
0xBC, 0xE7, 0xAE, 0x98, 0xD2, 0xBE, 0x60, 0xCA, 0x26, 0xEF, 0x63, 0xDF,
|
||||
0x65, 0xCB, 0x1A, 0xE8, 0x5F, 0xE7, 0x7B, 0x69, 0x7B, 0xDD, 0xC1, 0xC0,
|
||||
0xC9, 0x98, 0xA2, 0x7E, 0x5D, 0x80, 0x85, 0x98, 0x60, 0xE6, 0x89, 0xEB,
|
||||
0x09, 0xF1, 0xE2, 0x8A, 0x22, 0x07, 0x2E, 0x8B, 0x0A, 0x15, 0x2E, 0x5B,
|
||||
0x61, 0x5C, 0x7C, 0x77, 0x8C, 0x70, 0x77, 0x1A, 0x38, 0xBB, 0x60, 0x12,
|
||||
0x91, 0xEA, 0x04, 0x4C, 0xAD, 0xED, 0x28, 0xE4, 0x31, 0xCB, 0x92, 0xC7,
|
||||
0x7F, 0x1D, 0x53, 0xAC, 0x35, 0xA6, 0x2B, 0xEC, 0xA2, 0xFE, 0x1C, 0x53,
|
||||
0xE2, 0xB5, 0x53, 0x8E, 0xAB, 0x1E, 0xAF, 0x82, 0xB3, 0x1A, 0x7C, 0xAF,
|
||||
0x0E, 0xA9, 0xAE, 0x07, 0xAE, 0xB4, 0x1F, 0xFB, 0x2E, 0xF8, 0xDE, 0x8C,
|
||||
0x26, 0xED, 0xED, 0x6E, 0x85, 0xBF, 0x00, 0x06, 0xE3, 0x7B, 0x13, 0x9B,
|
||||
0x79, 0xF6, 0x54, 0x8C, 0x8D, 0xFA, 0x23, 0xBB, 0x39, 0x69, 0x6A, 0xAB,
|
||||
0xAE, 0xC3, 0xD4, 0xFF, 0x3E, 0x0F, 0xD8, 0x2F, 0x47, 0x0B, 0xFF, 0x05,
|
||||
0x7E, 0x62, 0xBD, 0x07, 0x89, 0x49, 0xD5, 0x39, 0x0D, 0x93, 0xC9, 0x9F,
|
||||
0x24, 0x74, 0x31, 0x26, 0x50, 0xF4, 0xB5, 0xAC, 0x3E, 0x5C, 0x01, 0xDC,
|
||||
0x60, 0x77, 0x3B, 0x5D, 0xD2, 0xBE, 0xB7, 0xCA, 0xFE, 0x7C, 0x4F, 0x4B,
|
||||
0x6C, 0x5B, 0x58, 0x41, 0x3E, 0x70, 0x8D, 0x00, 0x91, 0x6A, 0x1F, 0xE0,
|
||||
0x19, 0xCC, 0x59, 0x43, 0xAE, 0x67, 0xFC, 0x02, 0xDF, 0x9B, 0x90, 0xF5,
|
||||
0x8C, 0x8B, 0xAD, 0x29, 0x69, 0xB9, 0x25, 0xB2, 0x81, 0xF6, 0x37, 0x6F,
|
||||
0xE2, 0x7B, 0x07, 0xC6, 0xA4, 0xEA, 0x92, 0x36, 0x29, 0x77, 0x0E, 0xCB,
|
||||
0xD3, 0xEF, 0xFF, 0xC5, 0x60, 0xDB, 0x35, 0x7D, 0xCB, 0x42, 0xD7, 0xDA,
|
||||
0x51, 0x62, 0x99, 0xD6, 0x2B, 0xC8, 0x5F, 0x36, 0xB7, 0x0F, 0xBE, 0xF7,
|
||||
0x21, 0x52, 0x6D, 0x6B, 0xFB, 0x9C, 0xAF, 0x2C, 0xEB, 0x53, 0x02, 0xCE,
|
||||
0xD4, 0xD9, 0xE9, 0x7E, 0xA4, 0xFA, 0x16, 0xD8, 0x0C, 0x78, 0xD9, 0x12,
|
||||
0x47, 0x57, 0xFB, 0x9B, 0x9F, 0xE3, 0x7B, 0xCF, 0x36, 0x33, 0xAF, 0x4F,
|
||||
0x02, 0x27, 0xD9, 0xF9, 0xE9, 0x6C, 0xDB, 0x68, 0x8A, 0xEB, 0xED, 0x9C,
|
||||
0x9F, 0x98, 0xE3, 0x77, 0x4B, 0x81, 0x41, 0xF8, 0xDE, 0x7F, 0xB2, 0xDA,
|
||||
0x54, 0x18, 0xC1, 0x9E, 0x0B, 0x0D, 0x98, 0xDC, 0x7C, 0x0F, 0x66, 0x5D,
|
||||
0x7F, 0x04, 0x90, 0x59, 0x7B, 0x3F, 0xCD, 0xB4, 0x25, 0xA4, 0xDA, 0x44,
|
||||
0xC3, 0x73, 0xF6, 0x7D, 0x56, 0x03, 0x27, 0xE2, 0x7B, 0xCF, 0xD8, 0x7B,
|
||||
0x36, 0x05, 0xC6, 0x61, 0x4A, 0xFA, 0xE6, 0x7A, 0x46, 0x02, 0xDF, 0xBB,
|
||||
0x39, 0xEB, 0x19, 0x71, 0x20, 0xB3, 0x96, 0x9E, 0xB5, 0xE4, 0x06, 0xB0,
|
||||
0xA2, 0x1A, 0xBA, 0xD5, 0xFB, 0x5E, 0x03, 0x52, 0xDD, 0x6E, 0xC9, 0x25,
|
||||
0x5F, 0xBF, 0x7F, 0x88, 0xEF, 0x4D, 0x6D, 0x9F, 0x26, 0xAC, 0xA6, 0x9A,
|
||||
0x88, 0x71, 0xF1, 0x9D, 0x1E, 0xF1, 0x9D, 0x6A, 0x6D, 0xA0, 0x5F, 0x21,
|
||||
0xE4, 0xF1, 0x84, 0x23, 0x8F, 0x92, 0x61, 0x67, 0x2B, 0xF4, 0x25, 0x70,
|
||||
0x0E, 0x90, 0xC0, 0x38, 0x1A, 0x00, 0x9C, 0xDA, 0x60, 0x85, 0x2C, 0x70,
|
||||
0xBF, 0xFD, 0xF0, 0xAA, 0xAC, 0x70, 0x6F, 0x8A, 0x8B, 0x6C, 0x3B, 0x53,
|
||||
0x3B, 0xC1, 0xF3, 0x01, 0x9F, 0xBD, 0xA7, 0xB1, 0xC2, 0x70, 0x3F, 0xC6,
|
||||
0x23, 0xEA, 0x71, 0xFB, 0xFF, 0x1A, 0x8C, 0x27, 0xCD, 0x7E, 0x98, 0x1A,
|
||||
0xE5, 0xD7, 0x02, 0xBF, 0x07, 0x32, 0xB5, 0xC3, 0xB7, 0xB1, 0x1A, 0x82,
|
||||
0xD9, 0xA5, 0x18, 0x01, 0xFB, 0x1F, 0x4C, 0x4D, 0xF3, 0xBB, 0x30, 0xDE,
|
||||
0x48, 0x27, 0x03, 0xF7, 0x01, 0xF5, 0x76, 0xD7, 0xFA, 0x70, 0x8D, 0x54,
|
||||
0xB1, 0x16, 0xD6, 0xDA, 0x81, 0x56, 0x68, 0x66, 0xC8, 0xE3, 0xD0, 0x0C,
|
||||
0x79, 0x08, 0xA9, 0x7A, 0x61, 0x04, 0xD0, 0xD6, 0xC0, 0xF7, 0xC0, 0xA5,
|
||||
0x76, 0x77, 0x7D, 0xA6, 0x25, 0xCE, 0xEE, 0xC0, 0x28, 0xBB, 0x3B, 0x6D,
|
||||
0x8A, 0xF5, 0x2D, 0x79, 0xCC, 0x01, 0x1E, 0xC1, 0x9C, 0x55, 0x90, 0x36,
|
||||
0xE3, 0x7D, 0x58, 0xD6, 0xF8, 0x1E, 0x69, 0xFF, 0x3F, 0xCC, 0xF6, 0xE3,
|
||||
0x96, 0x5C, 0xE4, 0x01, 0xB0, 0xBE, 0xD9, 0x6E, 0x26, 0x80, 0xBB, 0xB3,
|
||||
0x09, 0x1F, 0xB8, 0x0C, 0xB8, 0x4C, 0xC0, 0xB7, 0x42, 0xAA, 0xF5, 0x6C,
|
||||
0x9F, 0xFB, 0xD8, 0x71, 0x1D, 0x0D, 0xFC, 0xCA, 0xF6, 0x7D, 0x92, 0xBD,
|
||||
0xE7, 0x24, 0x6D, 0x0E, 0xE1, 0x73, 0xE1, 0x10, 0x4B, 0x1E, 0xFF, 0xC1,
|
||||
0x5C, 0xF3, 0x45, 0xC0, 0x79, 0xDD, 0x06, 0x53, 0x73, 0x5E, 0xD9, 0x67,
|
||||
0x65, 0x48, 0x14, 0x8C, 0xB7, 0xD8, 0x89, 0x96, 0x70, 0x6F, 0xB3, 0xBF,
|
||||
0x7F, 0xC6, 0xFE, 0x6E, 0x03, 0xE0, 0x81, 0x0D, 0xD6, 0x76, 0x43, 0x7E,
|
||||
0x09, 0x93, 0x8E, 0xE8, 0x31, 0xDB, 0xF7, 0xA1, 0x76, 0x3D, 0x2C, 0xB2,
|
||||
0x6B, 0xF1, 0x2E, 0x1B, 0xC7, 0xD6, 0xDC, 0xBC, 0xF6, 0xD6, 0xF0, 0x8A,
|
||||
0x25, 0x8F, 0xBA, 0x6C, 0xF2, 0xB0, 0x6B, 0x62, 0xAC, 0x25, 0x8F, 0xD9,
|
||||
0x83, 0x5D, 0x9A, 0x00, 0x00, 0x0A, 0xDD, 0x49, 0x44, 0x41, 0x54, 0x55,
|
||||
0xC0, 0x70, 0x3B, 0x57, 0xC7, 0x03, 0x2F, 0xD8, 0x67, 0x8C, 0x40, 0xAA,
|
||||
0xE3, 0xF2, 0xB4, 0x7E, 0xB4, 0xD5, 0x88, 0x14, 0xF0, 0xE7, 0x2A, 0xD0,
|
||||
0x48, 0x75, 0x40, 0x16, 0x79, 0x4C, 0x00, 0x4E, 0xC0, 0x1C, 0x09, 0x9C,
|
||||
0x05, 0x8C, 0x02, 0x9E, 0x28, 0x36, 0x79, 0x54, 0x9E, 0x09, 0x2B, 0xB7,
|
||||
0x39, 0xEB, 0x25, 0x60, 0x87, 0x90, 0x77, 0x57, 0x65, 0x99, 0xB3, 0xFE,
|
||||
0x1A, 0x92, 0x3C, 0x8E, 0xB7, 0xE4, 0x51, 0x13, 0xA1, 0xD7, 0x5F, 0x38,
|
||||
0xF2, 0x08, 0x04, 0x0D, 0x1C, 0x83, 0xEF, 0x3D, 0x97, 0xA5, 0xEA, 0xDF,
|
||||
0xA7, 0xCD, 0x0E, 0x6B, 0x2F, 0xE0, 0x62, 0x21, 0xD5, 0x4D, 0xDA, 0xF7,
|
||||
0xBE, 0x46, 0xAA, 0x31, 0x56, 0x30, 0x9F, 0x29, 0xA4, 0xBA, 0x46, 0xFB,
|
||||
0xDE, 0x32, 0x7B, 0x7D, 0x0F, 0x0D, 0xBF, 0xB4, 0xB7, 0xDF, 0xBD, 0x3A,
|
||||
0xA3, 0xC2, 0x07, 0xC3, 0xB1, 0xF8, 0xDE, 0xF3, 0x59, 0x73, 0x3E, 0xC7,
|
||||
0x92, 0x09, 0xC0, 0x37, 0x02, 0xFA, 0x6A, 0xDF, 0x9B, 0x6B, 0x35, 0x8D,
|
||||
0x3B, 0xAD, 0xA6, 0xB1, 0x3B, 0x70, 0xD4, 0x46, 0xB5, 0xA3, 0xC4, 0x82,
|
||||
0x46, 0x33, 0xC0, 0x95, 0x02, 0x2E, 0xD3, 0xBE, 0xB7, 0x20, 0x7B, 0x77,
|
||||
0x8D, 0x54, 0xDF, 0x03, 0x7F, 0x04, 0x76, 0xA8, 0x33, 0x84, 0xF5, 0x41,
|
||||
0x9E, 0xB5, 0x76, 0xB8, 0x15, 0xB0, 0xDD, 0xB2, 0xC8, 0xE3, 0xC3, 0xAC,
|
||||
0x41, 0xBA, 0xD4, 0xEE, 0xA8, 0x57, 0x00, 0x07, 0xE3, 0x7B, 0x9F, 0xD9,
|
||||
0x5F, 0xBD, 0x2A, 0xA4, 0x1A, 0xAB, 0xE1, 0x5D, 0xAB, 0xA5, 0x5F, 0x4E,
|
||||
0xE3, 0xA1, 0x76, 0x36, 0x26, 0x0B, 0x18, 0xA0, 0x7D, 0x6F, 0x61, 0xD6,
|
||||
0xCF, 0xF6, 0xB6, 0x7F, 0x7F, 0xD7, 0x5D, 0x88, 0x0B, 0x17, 0x37, 0xBE,
|
||||
0xCB, 0xBF, 0x80, 0x7B, 0x3A, 0x4B, 0x15, 0x5B, 0x95, 0x67, 0xD0, 0xE6,
|
||||
0x9C, 0x3D, 0x54, 0x03, 0xB7, 0x23, 0xD5, 0xFE, 0x96, 0x70, 0x00, 0xFE,
|
||||
0x8E, 0xEF, 0xA9, 0xCC, 0xA4, 0x22, 0xD5, 0x45, 0x59, 0x5A, 0xD9, 0xEF,
|
||||
0xF0, 0xBD, 0xDB, 0xD6, 0x7C, 0x94, 0x52, 0xDD, 0xDD, 0x60, 0x88, 0xEC,
|
||||
0x68, 0xE0, 0x4C, 0xA4, 0xBA, 0x0D, 0xDF, 0x9B, 0x92, 0xE3, 0x51, 0xC3,
|
||||
0xF0, 0xBD, 0x7B, 0x22, 0xAC, 0xAB, 0xAB, 0xF1, 0xBD, 0x1B, 0xB3, 0xC6,
|
||||
0xF7, 0x6D, 0xCC, 0xF9, 0x25, 0x96, 0xD4, 0xFB, 0x67, 0xB9, 0xD8, 0xDE,
|
||||
0x8E, 0x54, 0x4F, 0x59, 0x62, 0xD9, 0x73, 0xA9, 0xD6, 0xDB, 0x67, 0x36,
|
||||
0x31, 0x31, 0xF8, 0x4B, 0x1A, 0x5E, 0x68, 0xA2, 0xF1, 0x8E, 0x46, 0xAA,
|
||||
0x49, 0xC0, 0xDF, 0xAD, 0xA6, 0x73, 0x04, 0xF0, 0x50, 0x9E, 0x79, 0xDD,
|
||||
0xC9, 0x12, 0xC1, 0xB6, 0xF6, 0xB9, 0x27, 0xAF, 0xD1, 0x3C, 0x0C, 0x9B,
|
||||
0x1C, 0x03, 0xFC, 0xC4, 0xFE, 0xF7, 0x14, 0x7C, 0x6F, 0x4C, 0xE6, 0x77,
|
||||
0x5D, 0x6A, 0xD5, 0x33, 0x2B, 0x35, 0xCF, 0x02, 0x43, 0xAC, 0xC9, 0x6A,
|
||||
0x6C, 0x8E, 0x27, 0xCC, 0xB5, 0x9A, 0xCE, 0xE7, 0x58, 0x06, 0x42, 0xAA,
|
||||
0x7D, 0xB3, 0x7E, 0x7F, 0x41, 0x13, 0xD3, 0xF9, 0xC3, 0x9D, 0xA4, 0x8A,
|
||||
0x95, 0xC2, 0x67, 0xBC, 0xBA, 0xA2, 0xC5, 0x8C, 0xEF, 0x7D, 0x89, 0x54,
|
||||
0xFD, 0x0B, 0x20, 0x91, 0xBF, 0x58, 0x12, 0x79, 0x34, 0x04, 0x79, 0x3C,
|
||||
0xE9, 0xC8, 0xA3, 0xE4, 0x78, 0x31, 0x9B, 0x3C, 0x00, 0xB4, 0xEF, 0x2D,
|
||||
0x46, 0xAA, 0xEB, 0xEC, 0x6E, 0xA9, 0xB3, 0x36, 0x1A, 0xE8, 0x28, 0xBB,
|
||||
0x93, 0x3C, 0x19, 0xE8, 0xA9, 0x8D, 0xCD, 0x57, 0x5A, 0x61, 0x75, 0xA6,
|
||||
0xDD, 0x3D, 0x2E, 0x12, 0xF0, 0x68, 0x08, 0xC3, 0xEE, 0x94, 0xB5, 0xC8,
|
||||
0x23, 0x23, 0xF4, 0x1B, 0x09, 0xE4, 0xAF, 0x19, 0xF2, 0xB0, 0x9A, 0xC6,
|
||||
0x6A, 0xA4, 0x7A, 0xDA, 0x12, 0x48, 0xCF, 0x85, 0x5A, 0x6F, 0x68, 0xED,
|
||||
0xCA, 0xE0, 0x7B, 0xDF, 0x59, 0xA1, 0xB9, 0x85, 0x15, 0xF4, 0x19, 0x6D,
|
||||
0x23, 0x3B, 0x45, 0x4D, 0xEF, 0x5C, 0x04, 0x92, 0x36, 0x3B, 0xC4, 0xBF,
|
||||
0x58, 0x61, 0xB4, 0xB8, 0x29, 0x79, 0x58, 0x0C, 0xB6, 0x7F, 0xFF, 0x07,
|
||||
0xA8, 0xB6, 0xE7, 0x46, 0x6B, 0x18, 0xD8, 0xEE, 0xF4, 0x2F, 0x06, 0x7E,
|
||||
0xD6, 0xB5, 0x76, 0x94, 0x58, 0xB6, 0xAE, 0x7D, 0xFB, 0xEA, 0x26, 0xE4,
|
||||
0x41, 0xD6, 0x8E, 0x7E, 0xD3, 0xC5, 0x5A, 0x4F, 0x44, 0xAA, 0x67, 0x2C,
|
||||
0xD1, 0x7C, 0xAA, 0x7D, 0x6F, 0xF1, 0xAA, 0x70, 0x44, 0x9C, 0x6F, 0x77,
|
||||
0x0C, 0xF0, 0x4D, 0x35, 0xDC, 0x59, 0x9F, 0x6D, 0x43, 0xF1, 0xBD, 0x7A,
|
||||
0xA4, 0x4A, 0xD8, 0x6B, 0x84, 0x7D, 0xBF, 0xA6, 0x04, 0x32, 0x75, 0x63,
|
||||
0x21, 0xEE, 0x9D, 0x17, 0xFE, 0xB9, 0xF5, 0xF6, 0x0C, 0x64, 0x0D, 0x04,
|
||||
0x8C, 0xD5, 0x46, 0x83, 0xED, 0x64, 0xD7, 0xDC, 0x7B, 0x39, 0xE6, 0x3D,
|
||||
0x63, 0xD6, 0x5A, 0x43, 0x20, 0x36, 0x3E, 0x67, 0x86, 0x90, 0x6A, 0x23,
|
||||
0xDD, 0xE8, 0xA6, 0x0C, 0x30, 0xDF, 0x0E, 0xBD, 0xB0, 0xF3, 0x9A, 0x0B,
|
||||
0xFB, 0x60, 0xDC, 0x9B, 0x33, 0xAE, 0xEA, 0x67, 0x64, 0x13, 0x84, 0xC5,
|
||||
0x91, 0xF6, 0xEF, 0x6F, 0x81, 0xCF, 0xB3, 0xE7, 0x75, 0xA5, 0x5E, 0x63,
|
||||
0xA2, 0x1A, 0x02, 0xEC, 0x8E, 0x54, 0x5B, 0xE7, 0x38, 0x47, 0xBD, 0x27,
|
||||
0x43, 0x1E, 0x59, 0x98, 0x99, 0xF5, 0xEF, 0x71, 0x48, 0x35, 0x12, 0x73,
|
||||
0x9E, 0xF2, 0x09, 0xBE, 0xF7, 0xFD, 0xEA, 0xC2, 0xE7, 0xB5, 0x0D, 0x12,
|
||||
0x48, 0x71, 0x48, 0xE4, 0x21, 0xA4, 0xA2, 0x45, 0x12, 0x31, 0xEA, 0x62,
|
||||
0xA1, 0xE4, 0xF1, 0x05, 0x0E, 0x41, 0xF0, 0x49, 0x5E, 0xE1, 0xDE, 0x88,
|
||||
0x2D, 0xED, 0xFC, 0xBF, 0x85, 0x54, 0x6F, 0x02, 0x07, 0x00, 0x17, 0xF5,
|
||||
0xAC, 0x1D, 0x55, 0xBB, 0x54, 0x6B, 0xB1, 0xDA, 0x1C, 0x96, 0x02, 0x3C,
|
||||
0xA4, 0x7D, 0x6F, 0x49, 0x88, 0x67, 0xCF, 0xCC, 0xF1, 0xB3, 0xC5, 0x4D,
|
||||
0x4C, 0x90, 0x4D, 0x91, 0xAD, 0x61, 0xD4, 0x64, 0xAD, 0x99, 0x83, 0xAC,
|
||||
0xF9, 0xAA, 0x4F, 0x33, 0xCF, 0xCB, 0xB7, 0x9E, 0x1E, 0xCD, 0x22, 0x9C,
|
||||
0x6E, 0x76, 0xB7, 0xDA, 0x94, 0x40, 0xB6, 0xB4, 0x7F, 0x0F, 0xC4, 0x9C,
|
||||
0xDD, 0xE4, 0x43, 0xCF, 0x15, 0x5A, 0xD7, 0x58, 0x73, 0x5F, 0x36, 0xDE,
|
||||
0x6D, 0x7A, 0xA1, 0x80, 0xFB, 0xB4, 0x39, 0x40, 0xDF, 0x07, 0x73, 0x28,
|
||||
0x3F, 0xC8, 0x12, 0x52, 0x03, 0x52, 0xA5, 0x30, 0x87, 0xD6, 0xA9, 0x02,
|
||||
0xE6, 0x36, 0x63, 0xDA, 0xF9, 0xA8, 0xDE, 0xF7, 0x1A, 0x72, 0x08, 0x9C,
|
||||
0xA9, 0xF5, 0x46, 0xA3, 0x5A, 0xCF, 0xBE, 0x73, 0x53, 0x7C, 0x30, 0x2F,
|
||||
0xDA, 0x41, 0xEF, 0x1C, 0xED, 0x7B, 0x4B, 0x9B, 0x0C, 0xFC, 0xEA, 0xD5,
|
||||
0x8D, 0x04, 0x92, 0x6B, 0x5E, 0x17, 0x35, 0x91, 0x15, 0x99, 0x79, 0xDD,
|
||||
0x01, 0x33, 0x4E, 0x87, 0x92, 0xDF, 0xCC, 0x9F, 0x4F, 0x76, 0xDE, 0xD5,
|
||||
0xE4, 0x9E, 0x5C, 0x01, 0xD2, 0x99, 0x79, 0xDD, 0x3C, 0xC7, 0x9C, 0x37,
|
||||
0xC5, 0xA6, 0xD6, 0xA4, 0xDA, 0xEC, 0xBC, 0xD6, 0xC0, 0x0B, 0x75, 0x66,
|
||||
0xC3, 0x35, 0xD4, 0x6A, 0x99, 0x7B, 0xAF, 0xD9, 0x6B, 0x48, 0xF5, 0x31,
|
||||
0x30, 0x02, 0xDF, 0x1B, 0xD9, 0xF1, 0x08, 0xA4, 0x91, 0x44, 0x32, 0xE6,
|
||||
0xAC, 0xED, 0x23, 0x92, 0x88, 0xC6, 0xF7, 0x1E, 0x6B, 0x86, 0x3C, 0x9E,
|
||||
0x72, 0xE4, 0xD1, 0x6A, 0xE8, 0x91, 0xE7, 0xE7, 0x1B, 0x65, 0xFD, 0x7B,
|
||||
0x59, 0x93, 0x8F, 0xF2, 0x00, 0x60, 0xAF, 0xF9, 0x5A, 0xF7, 0xB3, 0x02,
|
||||
0x77, 0x07, 0xB3, 0x91, 0x27, 0xAC, 0xA9, 0xA3, 0xA1, 0x85, 0xDF, 0x07,
|
||||
0xDB, 0xA9, 0x49, 0xD5, 0xDB, 0x6A, 0x00, 0x5D, 0xAD, 0x70, 0xFA, 0x9B,
|
||||
0xDD, 0xA1, 0x02, 0x6C, 0x65, 0x35, 0x83, 0xE6, 0x10, 0xB3, 0xC2, 0x63,
|
||||
0x3B, 0xFB, 0x3E, 0x8F, 0x22, 0xD5, 0x8F, 0x9B, 0xEC, 0x2C, 0x97, 0x02,
|
||||
0x1B, 0x63, 0x3C, 0xD4, 0xC6, 0x35, 0xD7, 0xE7, 0x18, 0x34, 0xA4, 0xD7,
|
||||
0x25, 0x8B, 0xBA, 0xA6, 0x92, 0x58, 0xFB, 0xDE, 0xFC, 0x2A, 0xA9, 0xF6,
|
||||
0x6F, 0x80, 0xA3, 0x30, 0x36, 0xF2, 0x3E, 0x18, 0x0F, 0xB2, 0x4D, 0x30,
|
||||
0xE7, 0x2B, 0xFF, 0x42, 0xAA, 0xBD, 0x72, 0xEC, 0x70, 0x83, 0x22, 0x33,
|
||||
0x6F, 0xBD, 0xF2, 0x0C, 0x7E, 0x37, 0x1A, 0x0F, 0xE1, 0x17, 0xE5, 0xB8,
|
||||
0x64, 0x55, 0xC4, 0xE7, 0xD6, 0x15, 0x63, 0x5E, 0xAD, 0x67, 0xD4, 0x73,
|
||||
0x56, 0xF0, 0x2F, 0xC0, 0x9C, 0xF1, 0x7C, 0x65, 0x35, 0x8F, 0x2A, 0xCC,
|
||||
0xF9, 0x5C, 0xAC, 0x85, 0x79, 0xFD, 0x0E, 0x58, 0x62, 0xCD, 0x8B, 0x57,
|
||||
0x21, 0xD5, 0x24, 0x7C, 0x6F, 0x7C, 0xD6, 0x35, 0x99, 0x0D, 0xCF, 0x42,
|
||||
0xA0, 0xA5, 0x92, 0xDD, 0xDF, 0xE4, 0xF8, 0xD9, 0x3A, 0xD6, 0xA8, 0x3A,
|
||||
0xDF, 0x4B, 0xF7, 0xA8, 0x1D, 0x75, 0xE2, 0x42, 0xAD, 0xEF, 0xB5, 0x9A,
|
||||
0x5D, 0x5F, 0xFB, 0x0E, 0xBD, 0x31, 0x66, 0xD4, 0xC7, 0x91, 0x6A, 0x65,
|
||||
0x0E, 0x6D, 0xA8, 0x03, 0x10, 0x88, 0x21, 0x91, 0xD9, 0x59, 0x9A, 0x48,
|
||||
0x14, 0x12, 0x79, 0xD8, 0x6A, 0x22, 0x8F, 0x35, 0x11, 0x04, 0xC7, 0x3A,
|
||||
0xCD, 0xA3, 0xD5, 0x31, 0x44, 0x48, 0xB5, 0x49, 0xB6, 0xA9, 0xC8, 0xE2,
|
||||
0xF4, 0xAC, 0x7F, 0xBF, 0x9D, 0xF5, 0x45, 0x8E, 0x4E, 0xC3, 0xCD, 0x76,
|
||||
0xE7, 0x36, 0xCC, 0x0A, 0x5C, 0x30, 0xF6, 0xF7, 0x99, 0x65, 0x7A, 0x87,
|
||||
0xC1, 0x34, 0x7A, 0x0A, 0x0D, 0xC2, 0xF7, 0xA6, 0x65, 0xAD, 0xA9, 0x9F,
|
||||
0x04, 0x20, 0x90, 0xD7, 0x05, 0x0C, 0xB1, 0xA6, 0xBA, 0x31, 0xC0, 0x86,
|
||||
0xC0, 0x18, 0x21, 0xD5, 0x81, 0x59, 0x3B, 0xE9, 0x49, 0x98, 0xC3, 0xE1,
|
||||
0x5E, 0x02, 0x6E, 0xD1, 0xBE, 0xB7, 0x96, 0x65, 0xA7, 0x5A, 0xAA, 0xAA,
|
||||
0x2E, 0x42, 0xA4, 0x97, 0x9E, 0x33, 0x54, 0xD7, 0x87, 0x61, 0x50, 0xDF,
|
||||
0xAB, 0xC3, 0xD8, 0xD6, 0xC7, 0xC2, 0x1A, 0xEF, 0xAA, 0xA3, 0x30, 0x07,
|
||||
0xCB, 0x9D, 0xED, 0xBB, 0x45, 0x25, 0x90, 0x37, 0x81, 0x1F, 0x03, 0x7B,
|
||||
0x5B, 0x22, 0x5A, 0x6B, 0x87, 0xAD, 0xCD, 0x1C, 0xC7, 0x9A, 0xCE, 0x71,
|
||||
0xA5, 0xA0, 0xC1, 0x10, 0x6A, 0x46, 0x6B, 0xB8, 0x10, 0xDF, 0x7B, 0x72,
|
||||
0x0D, 0x21, 0x4B, 0xD5, 0x55, 0x1B, 0x8F, 0xAE, 0xE6, 0x30, 0x1B, 0xE3,
|
||||
0x94, 0x50, 0x65, 0xC7, 0xA2, 0x3B, 0xF0, 0x18, 0x52, 0xED, 0x97, 0x75,
|
||||
0xA6, 0x32, 0x09, 0x73, 0x60, 0xBE, 0x21, 0x30, 0x16, 0xDF, 0x9B, 0x94,
|
||||
0x93, 0xC8, 0x7C, 0x2F, 0xCC, 0xB4, 0xB2, 0xD0, 0x68, 0x6E, 0xAF, 0xD8,
|
||||
0x3F, 0x99, 0xB5, 0xB8, 0x27, 0xC6, 0x39, 0xA2, 0x27, 0xC6, 0x5D, 0xB8,
|
||||
0x83, 0x12, 0x48, 0xF1, 0x48, 0x44, 0xE3, 0x7B, 0x8F, 0xDB, 0xC1, 0x1D,
|
||||
0x6C, 0xC9, 0xA3, 0x53, 0x84, 0xDE, 0xFC, 0x17, 0x13, 0x61, 0xEE, 0xC8,
|
||||
0x23, 0x3C, 0x7A, 0x6A, 0x98, 0x88, 0x54, 0xE7, 0x75, 0x11, 0x4C, 0x5E,
|
||||
0xA5, 0xE9, 0xA1, 0xCD, 0x19, 0x84, 0xBF, 0x46, 0x08, 0x65, 0xC5, 0x22,
|
||||
0xA4, 0x8D, 0x4B, 0xEF, 0xFD, 0x98, 0x8F, 0xF7, 0xB8, 0x26, 0x9A, 0x49,
|
||||
0xB9, 0x90, 0xBD, 0xA3, 0xDD, 0x0A, 0x1B, 0x00, 0x2B, 0xA4, 0xDA, 0x40,
|
||||
0xC3, 0x9F, 0x5A, 0xBA, 0x59, 0xC0, 0x91, 0xDA, 0xF7, 0x16, 0x01, 0xCF,
|
||||
0xD8, 0xB3, 0x9F, 0x6B, 0x80, 0x3D, 0xB4, 0x39, 0xE3, 0x39, 0x39, 0xEB,
|
||||
0xFD, 0x8E, 0x07, 0x36, 0xD1, 0x46, 0x33, 0x18, 0x56, 0x03, 0x6F, 0x54,
|
||||
0x09, 0xF4, 0x4A, 0xCD, 0x5E, 0xF5, 0x30, 0x62, 0xA9, 0xD6, 0xAF, 0x63,
|
||||
0x3C, 0x84, 0x82, 0xC1, 0x1C, 0xB6, 0x5E, 0x01, 0xDC, 0x13, 0x83, 0xD7,
|
||||
0xD3, 0xBE, 0x57, 0xB7, 0xEC, 0x9C, 0xA1, 0xDA, 0xBA, 0x58, 0xE7, 0xD2,
|
||||
0xFE, 0xC2, 0xE2, 0x7E, 0x8C, 0x2B, 0x74, 0x27, 0xE0, 0x59, 0xA4, 0xF2,
|
||||
0xAB, 0xE1, 0xC5, 0x06, 0xE8, 0xA2, 0x4D, 0x4C, 0xCA, 0x70, 0x7B, 0xDD,
|
||||
0xB4, 0x18, 0x4C, 0x48, 0x57, 0xDE, 0xDA, 0x6C, 0x3A, 0xAF, 0xC6, 0x44,
|
||||
0x64, 0x62, 0x67, 0x6E, 0xA4, 0xE5, 0x74, 0x2D, 0x67, 0xAF, 0xD1, 0xDE,
|
||||
0xA4, 0xFA, 0x25, 0x26, 0xAE, 0xA5, 0x07, 0x30, 0xD6, 0x6E, 0x0E, 0x96,
|
||||
0x0B, 0x78, 0x58, 0x1B, 0x6F, 0xB6, 0x0D, 0x31, 0xE7, 0x15, 0xC3, 0x62,
|
||||
0x30, 0xBE, 0x8B, 0x10, 0xAB, 0x97, 0x6B, 0xBD, 0x0D, 0xF0, 0x87, 0x06,
|
||||
0xD8, 0xB4, 0x46, 0xAA, 0xA1, 0x75, 0x39, 0xCC, 0x80, 0x39, 0xD7, 0x93,
|
||||
0x71, 0x2A, 0x79, 0x02, 0xA8, 0x15, 0xF0, 0x42, 0xD6, 0x26, 0x64, 0x59,
|
||||
0x91, 0xE6, 0x35, 0xAF, 0xBA, 0xD5, 0xB6, 0x60, 0x0E, 0x94, 0xFA, 0x93,
|
||||
0xDB, 0x96, 0x1D, 0x84, 0x44, 0x1E, 0x41, 0xAA, 0x53, 0x2D, 0x79, 0x8C,
|
||||
0x21, 0xBF, 0x4F, 0x7B, 0x4B, 0xE4, 0xD1, 0x1F, 0xDF, 0x9B, 0xE5, 0xB8,
|
||||
0x20, 0x12, 0x56, 0x60, 0xDC, 0x65, 0xDF, 0x59, 0xA9, 0x59, 0xA2, 0x8D,
|
||||
0x57, 0xC9, 0x55, 0x46, 0xAE, 0x32, 0x17, 0xE3, 0x7A, 0xD8, 0x54, 0xE0,
|
||||
0x3E, 0x68, 0xEF, 0x8B, 0xD9, 0x3F, 0x1F, 0x75, 0x15, 0xE2, 0xA5, 0x32,
|
||||
0xBE, 0xC3, 0xB3, 0x59, 0x26, 0x98, 0x09, 0x48, 0x35, 0x01, 0xA9, 0x46,
|
||||
0xEB, 0x4C, 0x00, 0x69, 0xCB, 0x04, 0xB2, 0x46, 0x60, 0x77, 0x36, 0x04,
|
||||
0x90, 0x31, 0x51, 0x9D, 0x64, 0x83, 0xE3, 0xB0, 0x31, 0x24, 0x57, 0x5B,
|
||||
0xF3, 0xC9, 0xDE, 0xC0, 0x6B, 0x75, 0xB0, 0x74, 0xA5, 0x66, 0x09, 0xC6,
|
||||
0x33, 0xEC, 0x70, 0xE0, 0x0A, 0xA4, 0xDA, 0x3A, 0x44, 0xBF, 0xFF, 0x68,
|
||||
0x49, 0xE9, 0xA5, 0x34, 0x2C, 0x42, 0xAA, 0x99, 0x36, 0x06, 0xE3, 0x05,
|
||||
0x3B, 0xFE, 0x5F, 0x8B, 0xDC, 0x9E, 0x3F, 0x41, 0xBF, 0xCF, 0xCF, 0x30,
|
||||
0xE7, 0x53, 0x69, 0xAB, 0x3D, 0xBD, 0x50, 0x0F, 0xCB, 0xB4, 0x19, 0xAB,
|
||||
0xFB, 0x30, 0xF1, 0x37, 0xF3, 0x81, 0x93, 0xD2, 0x46, 0x13, 0xAA, 0x28,
|
||||
0x74, 0x32, 0x0E, 0x0F, 0x99, 0xF3, 0xA6, 0xE1, 0x48, 0xF5, 0x32, 0x52,
|
||||
0x3D, 0x59, 0x67, 0x34, 0xB2, 0x8B, 0x03, 0x98, 0xC2, 0x96, 0x67, 0x8D,
|
||||
0xC5, 0xB3, 0x34, 0x6E, 0x26, 0xF6, 0xD2, 0x66, 0x0D, 0xA3, 0x7D, 0xEF,
|
||||
0x7B, 0x4C, 0xB0, 0xEA, 0x2A, 0xCC, 0x39, 0xC8, 0xE8, 0x34, 0x2C, 0x59,
|
||||
0xAE, 0xF5, 0x22, 0x6B, 0x0E, 0x3D, 0x0F, 0x38, 0xB6, 0x0E, 0x7E, 0x16,
|
||||
0xB4, 0xDF, 0x1A, 0x7E, 0x8D, 0xB9, 0x7E, 0x8C, 0x86, 0x05, 0x48, 0xF5,
|
||||
0x5F, 0xA4, 0xFA, 0xAF, 0xDD, 0xD8, 0xF4, 0xB4, 0xCF, 0x2A, 0x7A, 0x49,
|
||||
0xF0, 0x58, 0x9B, 0x14, 0x3F, 0x8D, 0x24, 0x12, 0x45, 0x80, 0x1B, 0x12,
|
||||
0x31, 0xE4, 0x11, 0x25, 0xF1, 0xD9, 0x6C, 0x47, 0x1E, 0x05, 0x63, 0xB8,
|
||||
0x15, 0x26, 0xAB, 0x30, 0xF1, 0x0A, 0x02, 0x63, 0xC3, 0x36, 0xBE, 0xF1,
|
||||
0xBE, 0xF7, 0xE9, 0x3A, 0x1F, 0x88, 0xEF, 0xCD, 0xB1, 0xDA, 0x62, 0x06,
|
||||
0x77, 0x2F, 0x2B, 0x67, 0x39, 0x60, 0x53, 0x49, 0xF2, 0x08, 0xCC, 0x39,
|
||||
0xC6, 0x7A, 0xD6, 0xEC, 0x73, 0xBC, 0x15, 0x20, 0xE7, 0x86, 0x69, 0x6A,
|
||||
0x95, 0xEF, 0xA5, 0x85, 0xD9, 0x9D, 0x67, 0x9C, 0x0B, 0x6E, 0xB6, 0x11,
|
||||
0xC5, 0xE0, 0x7B, 0x37, 0x60, 0xBC, 0x96, 0x26, 0x59, 0x22, 0xE9, 0x62,
|
||||
0xC7, 0x2C, 0x8D, 0x71, 0x7B, 0x1E, 0x10, 0x32, 0xDB, 0xC1, 0x3D, 0x18,
|
||||
0x1B, 0xFF, 0x4A, 0xDB, 0xEF, 0xED, 0x30, 0x1E, 0x64, 0xAB, 0xED, 0xF8,
|
||||
0xF7, 0x6B, 0x6A, 0x2A, 0x8B, 0x30, 0x36, 0xB5, 0xD6, 0x8C, 0xF3, 0xA6,
|
||||
0xED, 0x73, 0x67, 0xFB, 0xDD, 0xAD, 0xC6, 0x1C, 0xF4, 0xFE, 0xA8, 0x52,
|
||||
0x33, 0xD6, 0x5A, 0x6F, 0xA5, 0x21, 0x96, 0x50, 0xC1, 0x9C, 0x0B, 0x9D,
|
||||
0x64, 0x85, 0xF0, 0x25, 0x18, 0xCF, 0xA9, 0xC0, 0x58, 0x5F, 0x88, 0xEB,
|
||||
0xAC, 0x16, 0x02, 0x70, 0x0A, 0x52, 0x0D, 0xB3, 0x63, 0x34, 0x1E, 0x73,
|
||||
0xAE, 0xF7, 0x1C, 0xC6, 0xD5, 0xB7, 0x06, 0x63, 0x9A, 0xD5, 0x98, 0x33,
|
||||
0xAF, 0x93, 0x9B, 0x9C, 0x9B, 0xB4, 0x84, 0xB1, 0x98, 0xB8, 0x95, 0x05,
|
||||
0xD6, 0xB2, 0xB4, 0x35, 0x8D, 0xC1, 0xA7, 0x29, 0xBB, 0x4E, 0xDE, 0x2D,
|
||||
0xF6, 0x78, 0x55, 0xB7, 0x59, 0x11, 0xB4, 0xB6, 0x39, 0x6B, 0xBB, 0x08,
|
||||
0x24, 0x12, 0x25, 0x73, 0xA8, 0x23, 0x8F, 0x02, 0x20, 0x1A, 0x17, 0xF4,
|
||||
0x32, 0xED, 0x7B, 0xCB, 0x85, 0x54, 0x7F, 0xB0, 0x79, 0x95, 0x10, 0x30,
|
||||
0x53, 0xFB, 0xDE, 0xE2, 0x16, 0x9A, 0xC8, 0x9C, 0x99, 0xCC, 0x13, 0x30,
|
||||
0x52, 0x87, 0x7B, 0xF6, 0x81, 0x19, 0x21, 0xA6, 0xD7, 0xFD, 0x08, 0xA6,
|
||||
0x35, 0x98, 0x20, 0x34, 0x80, 0x25, 0x7A, 0xDD, 0x7B, 0xEF, 0xC7, 0x78,
|
||||
0x4D, 0xD1, 0x09, 0xE6, 0xAD, 0x6A, 0x5C, 0x83, 0x6F, 0x02, 0x7D, 0xAC,
|
||||
0x06, 0xB0, 0x29, 0xB0, 0xA0, 0x06, 0x66, 0xC5, 0x40, 0xAF, 0x36, 0xF1,
|
||||
0x02, 0x08, 0x58, 0x9C, 0x6E, 0x6C, 0xE7, 0x0E, 0xAC, 0x1B, 0xF2, 0x46,
|
||||
0x42, 0xAC, 0x9E, 0xB7, 0x36, 0x41, 0x2E, 0x16, 0x52, 0x65, 0x47, 0x60,
|
||||
0xAF, 0xD2, 0x8D, 0xCF, 0x19, 0x0F, 0x8C, 0xB7, 0x91, 0xCD, 0xBD, 0x6D,
|
||||
0x5B, 0xB3, 0x73, 0x09, 0x7A, 0x61, 0xDA, 0x7F, 0x12, 0xA0, 0xB3, 0x60,
|
||||
0xC1, 0xCA, 0x75, 0xBF, 0x9B, 0x17, 0x80, 0x17, 0x6C, 0x24, 0xFD, 0xD6,
|
||||
0x18, 0xC7, 0x85, 0x65, 0x02, 0xBE, 0xC8, 0xC4, 0xD8, 0x04, 0xF8, 0x78,
|
||||
0xDE, 0x4B, 0xDB, 0xF1, 0xCA, 0x7E, 0xBF, 0x26, 0xCF, 0x79, 0x11, 0x38,
|
||||
0x50, 0x48, 0xD5, 0xCB, 0xBA, 0xC2, 0xD6, 0x09, 0x98, 0x91, 0xEF, 0x19,
|
||||
0x02, 0xF6, 0xB0, 0x1B, 0xDA, 0x55, 0x21, 0xE7, 0xF5, 0x57, 0x19, 0xCD,
|
||||
0x40, 0xE7, 0x20, 0x03, 0x21, 0xD5, 0x76, 0x76, 0x83, 0xB2, 0x52, 0xAF,
|
||||
0xBB, 0x7B, 0x4E, 0xE9, 0xC6, 0xF7, 0x58, 0x94, 0x6E, 0xEC, 0xFB, 0x97,
|
||||
0xC0, 0x20, 0xA4, 0xFA, 0x81, 0x15, 0xC2, 0x2B, 0x62, 0x30, 0x3D, 0xED,
|
||||
0x7B, 0xAB, 0x84, 0x54, 0x8F, 0xDB, 0x7E, 0x2E, 0xD7, 0x8D, 0xED, 0xBC,
|
||||
0x98, 0x69, 0x27, 0x06, 0x0B, 0xB3, 0x6D, 0x4E, 0xCB, 0xCF, 0x19, 0xAA,
|
||||
0x63, 0x52, 0x9D, 0xA4, 0x8D, 0xB9, 0x0A, 0xA0, 0x21, 0x6B, 0x5E, 0xDF,
|
||||
0xC7, 0x9C, 0x07, 0x76, 0xD3, 0x46, 0x86, 0x75, 0x02, 0xBE, 0xCD, 0xA4,
|
||||
0x3A, 0x69, 0x32, 0xE6, 0x6F, 0xA5, 0x73, 0xF5, 0xB5, 0xB1, 0xAD, 0x8F,
|
||||
0x80, 0xD3, 0xAA, 0xA5, 0xAA, 0xAA, 0x37, 0xA6, 0xB7, 0x5E, 0x76, 0xCC,
|
||||
0x67, 0x37, 0x89, 0x53, 0x2A, 0xF6, 0x37, 0xDD, 0xC6, 0x21, 0xD5, 0x36,
|
||||
0x11, 0x49, 0x24, 0x2A, 0x79, 0xCC, 0xC4, 0xA1, 0xB5, 0xE6, 0xF6, 0x38,
|
||||
0x2B, 0xDC, 0x5E, 0xD1, 0x10, 0xB7, 0x66, 0x9E, 0xF5, 0x81, 0x1B, 0xF1,
|
||||
0xBD, 0x2B, 0xDD, 0x00, 0x39, 0x38, 0x94, 0x7D, 0x53, 0xD8, 0x2E, 0x04,
|
||||
0xCD, 0xB6, 0x96, 0x44, 0xB6, 0x2D, 0xD1, 0x13, 0xBE, 0xB4, 0xE4, 0x31,
|
||||
0xC3, 0x2D, 0x99, 0x56, 0x5A, 0x98, 0x52, 0xAD, 0xAF, 0x61, 0x2A, 0x66,
|
||||
0x37, 0x55, 0x9F, 0xA5, 0x2D, 0xCF, 0x14, 0xB0, 0x4F, 0x00, 0x6D, 0xC5,
|
||||
0xC1, 0xC1, 0xA1, 0xC4, 0x88, 0xB5, 0x8B, 0xB7, 0x30, 0x9E, 0x50, 0xFD,
|
||||
0x09, 0x9E, 0x37, 0xC7, 0x91, 0x47, 0xE5, 0xA3, 0x1A, 0x93, 0x5E, 0x63,
|
||||
0x99, 0xFD, 0x77, 0x03, 0xC6, 0x2E, 0x3D, 0xD0, 0x91, 0x87, 0x83, 0x83,
|
||||
0xD3, 0x40, 0xDA, 0x82, 0x26, 0xE2, 0xC8, 0xA3, 0xCC, 0xB0, 0x69, 0xC1,
|
||||
0x7B, 0x09, 0x58, 0x14, 0xD4, 0x46, 0xEF, 0xE0, 0xE0, 0xE0, 0x08, 0x24,
|
||||
0x2A, 0x89, 0x6C, 0x67, 0x49, 0x64, 0x9B, 0x22, 0x90, 0xC7, 0x00, 0x57,
|
||||
0x24, 0xC7, 0xC1, 0xC1, 0xC1, 0xA1, 0xA3, 0x10, 0x48, 0x71, 0x48, 0xE4,
|
||||
0x2B, 0xAB, 0x79, 0x38, 0xF2, 0x70, 0x70, 0x70, 0x70, 0xE8, 0x50, 0x04,
|
||||
0x52, 0x18, 0x89, 0x38, 0xF2, 0x70, 0x70, 0x70, 0x70, 0xE8, 0xD0, 0x04,
|
||||
0x12, 0x8D, 0x44, 0x1C, 0x79, 0x38, 0x38, 0x38, 0x38, 0x38, 0x02, 0x59,
|
||||
0x43, 0x22, 0xDB, 0x5B, 0x12, 0x69, 0x29, 0xDD, 0xC3, 0xD7, 0x96, 0x3C,
|
||||
0xA6, 0xB9, 0x65, 0xE1, 0xE0, 0xE0, 0xE0, 0xE0, 0x08, 0x24, 0x28, 0x89,
|
||||
0x38, 0xF2, 0x70, 0x70, 0x70, 0x70, 0x70, 0x04, 0x12, 0x9A, 0x44, 0x1C,
|
||||
0x79, 0x38, 0x38, 0x38, 0x38, 0x44, 0x40, 0xAC, 0xC3, 0xBC, 0xA9, 0x49,
|
||||
0x41, 0x32, 0x00, 0xE3, 0x9E, 0x9B, 0x4D, 0x1E, 0x03, 0x1C, 0x79, 0x38,
|
||||
0x38, 0x38, 0x38, 0x38, 0x0D, 0x24, 0x88, 0x26, 0xB2, 0x83, 0xD5, 0x44,
|
||||
0x62, 0x96, 0x3C, 0x3E, 0x77, 0xCB, 0xC0, 0xC1, 0xC1, 0xC1, 0xC1, 0x21,
|
||||
0x28, 0x89, 0xEC, 0x88, 0x54, 0x3B, 0xBB, 0x81, 0x70, 0x70, 0x70, 0x70,
|
||||
0x88, 0x8E, 0xFF, 0x07, 0x02, 0x8E, 0xE9, 0xCF, 0xD4, 0x3B, 0x89, 0x6F,
|
||||
0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82
|
||||
};
|
||||
|
||||
const unsigned int logo_web_png_len = 11136;
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
#include <Arduino.h>
|
||||
#include <pgmspace.h>
|
||||
#include <stddef.h>
|
||||
|
||||
extern const uint8_t logo_web_png[];
|
||||
extern const size_t logo_web_png_len;
|
||||
|
|
@ -1,27 +1,21 @@
|
|||
/* Test for LaskaKit ESPlan V2 ESP32 LAN8720A RS485 PoE
|
||||
* ESP32 + LAN8720 + WebServer + SD + RS485 + SHT40 + BMP280 + NeoPixel
|
||||
*
|
||||
* Funkce:
|
||||
* - web rozhrani pres Ethernet
|
||||
* - stav ETH, SD, SHT40, BMP280, RS485
|
||||
* - ovladani NeoPixel LED
|
||||
* - odesilani textu pres RS485
|
||||
* - prijem dat z RS485
|
||||
* - prochazeni adresaru na SD
|
||||
* - upload / stahnout / smazat souboru na SD
|
||||
* - vytvareni a mazani adresaru na SD
|
||||
* - automaticka reakce na vyndani / vlozeni SD karty
|
||||
* - po vlozeni se SD karta ihned znovu nacte
|
||||
* - SD panel se na webu obnovi jen pri zmene stavu SD karty
|
||||
* - periodicky debug do seriove konzole
|
||||
* - volba jazyka CZ / ENG
|
||||
/*
|
||||
ESP32 + LAN8720 + WebServer + SD + RS485 + SHT40 + BMP280 + NeoPixel
|
||||
|
||||
* Board: kaKit ESPlan V2 https://www.laskakit.cz/laskakit-esplan-esp32-lan8720a-max485-poe/
|
||||
*
|
||||
*
|
||||
* Email:podpora@laskakit.cz
|
||||
* Web:laskakit.cz
|
||||
*/
|
||||
Funkce:
|
||||
- web rozhrani pres Ethernet
|
||||
- stav ETH, SD, SHT40, BMP280, RS485
|
||||
- ovladani NeoPixel LED
|
||||
- odesilani textu pres RS485
|
||||
- prijem dat z RS485
|
||||
- prochazeni adresaru na SD
|
||||
- upload / stahnout / smazat souboru na SD
|
||||
- vytvareni a mazani adresaru na SD
|
||||
- automaticka reakce na vyndani / vlozeni SD karty
|
||||
- po vlozeni se SD karta ihned znovu nacte
|
||||
- SD panel se na webu obnovi jen pri zmene stavu SD karty
|
||||
- periodicky debug do seriove konzole
|
||||
- volba jazyka CZ / ENG
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <WiFi.h>
|
||||
|
|
@ -2129,11 +2123,6 @@ void setup() {
|
|||
addLogEntry(LOG_HEAP_FREE, String(ESP.getFreeHeap()), String(getFreeHeapPercent(), 1));
|
||||
|
||||
initI2CDevices();
|
||||
|
||||
lastSdDetectRaw = isSdCardPresent();
|
||||
lastSdDetectStable = lastSdDetectRaw;
|
||||
lastSdDetectChangeMs = millis();
|
||||
|
||||
initSDCard();
|
||||
initRS485();
|
||||
initEthernet();
|
||||
|
|
|
|||
Loading…
Reference in New Issue