diff --git a/devices/sh_core_esp8266/src/REST_API.cpp b/devices/sh_core_esp8266/src/REST_API.cpp index e0964bd..9d9a5a2 100755 --- a/devices/sh_core_esp8266/src/REST_API.cpp +++ b/devices/sh_core_esp8266/src/REST_API.cpp @@ -438,7 +438,7 @@ return; } - uint8_t tmp[32]; + uint8_t tmp[CHANNEL_SCHEMA_DATA_LEN]; String err; if (!parseByteArray32(arr, tmp, err)) { String json = "{\"status\":\"error\",\"error\":\"IllegalActionOrParams\",\"message\":\"" + err + "\"}"; @@ -446,7 +446,7 @@ return; } - for (uint8_t i = 0; i < 32; i++) { + for (uint8_t i = 0; i < CHANNEL_SCHEMA_DATA_LEN; i++) { channels_schema[i] = (char)tmp[i]; } @@ -455,7 +455,7 @@ String json = F("{\"status\":\"ok\",\"message\":\"Channels schema updated\"}"); sendJson(200, json); - delay(800); + delay(200); ESP.restart(); } @@ -476,9 +476,9 @@ json += "\"status\":\"ok\","; json += "\"schema\":["; - for (uint8_t i = 0; i < CHANNEL_SCHEMA_MAX_LEN; i++) { + for (uint8_t i = 0; i < CHANNEL_SCHEMA_DATA_LEN; i++) { json += String((uint8_t)channels_schema[i]); - if (i < CHANNEL_SCHEMA_MAX_LEN - 1) json += ","; + if (i < CHANNEL_SCHEMA_DATA_LEN - 1) json += ","; } json += "]"; diff --git a/devices/sh_core_esp8266/src/sh_core.cpp b/devices/sh_core_esp8266/src/sh_core.cpp index 1065bcc..29b20ea 100644 --- a/devices/sh_core_esp8266/src/sh_core.cpp +++ b/devices/sh_core_esp8266/src/sh_core.cpp @@ -24,7 +24,7 @@ static uint32_t sta_pause_until = 0; -char channels_schema[CHANNEL_SCHEMA_MAX_LEN] = {0}; +char channels_schema[CHANNEL_SCHEMA_DATA_LEN] = {0}; // -------------------- core "online" event state -------------------- static bool sta_was_connected = false; @@ -89,33 +89,43 @@ } static uint8_t crc8_simple(const uint8_t* data, uint16_t len) { - // простой CRC8 (xor), не крипто, но хорошо ловит мусор/битые записи uint8_t crc = 0; for (uint16_t i = 0; i < len; i++) crc ^= data[i]; return crc; } bool is_channels_schema_valid() { + EEPROM.begin(EEPROM_SIZE); + uint8_t m0 = EEPROM.read(CHANNEL_SCHEMA_META_ADDR + 0); uint8_t m1 = EEPROM.read(CHANNEL_SCHEMA_META_ADDR + 1); uint8_t ver = EEPROM.read(CHANNEL_SCHEMA_META_ADDR + 2); uint8_t crc_stored = EEPROM.read(CHANNEL_SCHEMA_META_ADDR + 3); - if (m0 != CHANNEL_SCHEMA_MAGIC_0 || m1 != CHANNEL_SCHEMA_MAGIC_1) return false; - if (ver != CHANNEL_SCHEMA_VERSION) return false; + if (m0 != CHANNEL_SCHEMA_MAGIC_0 || m1 != CHANNEL_SCHEMA_MAGIC_1) { + EEPROM.end(); + return false; + } + if (ver != CHANNEL_SCHEMA_VERSION) { + EEPROM.end(); + return false; + } - uint8_t tmp[CHANNEL_SCHEMA_MAX_LEN]; - for (uint16_t i = 0; i < CHANNEL_SCHEMA_MAX_LEN; i++) { + uint8_t tmp[CHANNEL_SCHEMA_DATA_LEN]; + for (uint16_t i = 0; i < CHANNEL_SCHEMA_DATA_LEN; i++) { tmp[i] = EEPROM.read(CHANNEL_SCHEMA_DATA_ADDR + i); } - uint8_t crc_calc = crc8_simple(tmp, CHANNEL_SCHEMA_MAX_LEN); + EEPROM.end(); + + uint8_t crc_calc = crc8_simple(tmp, CHANNEL_SCHEMA_DATA_LEN); return (crc_calc == crc_stored); } void load_channels_schema() { EEPROM.begin(EEPROM_SIZE); - for (uint16_t i = 0; i < CHANNEL_SCHEMA_MAX_LEN; i++) { + + for (uint16_t i = 0; i < CHANNEL_SCHEMA_DATA_LEN; i++) { channels_schema[i] = (char)EEPROM.read(CHANNEL_SCHEMA_DATA_ADDR + i); } @@ -124,23 +134,25 @@ void write_channels_schema() { EEPROM.begin(EEPROM_SIZE); - // пишем данные - for (uint16_t i = 0; i < CHANNEL_SCHEMA_MAX_LEN; i++) { + + // data (32) + for (uint16_t i = 0; i < CHANNEL_SCHEMA_DATA_LEN; i++) { EEPROM.write(CHANNEL_SCHEMA_DATA_ADDR + i, (uint8_t)channels_schema[i]); } - // пишем header + // meta (4) EEPROM.write(CHANNEL_SCHEMA_META_ADDR + 0, CHANNEL_SCHEMA_MAGIC_0); EEPROM.write(CHANNEL_SCHEMA_META_ADDR + 1, CHANNEL_SCHEMA_MAGIC_1); EEPROM.write(CHANNEL_SCHEMA_META_ADDR + 2, CHANNEL_SCHEMA_VERSION); - uint8_t crc = crc8_simple((const uint8_t*)channels_schema, CHANNEL_SCHEMA_MAX_LEN); + uint8_t crc = crc8_simple((const uint8_t*)channels_schema, CHANNEL_SCHEMA_DATA_LEN); EEPROM.write(CHANNEL_SCHEMA_META_ADDR + 3, crc); EEPROM.commit(); EEPROM.end(); } + void saveWiFiConfig(const String &ssid, const String &pass) { EEPROM.begin(EEPROM_SIZE); writeStringToEEPROM(SSID_ADDR, ssid, SSID_MAX_LEN); @@ -384,35 +396,40 @@ } void init_default_channels_schema() { - for (uint8_t i = 0; i < CHANNEL_SCHEMA_MAX_LEN; i++) { - channels_schema[i] = SH_PIN_UNUSED; + for (uint8_t i = 0; i < CHANNEL_SCHEMA_DATA_LEN; i++) { + channels_schema[i] = (char)SH_PIN_UNUSED; } - // Дефолтные пины для первых 4 каналов const uint8_t default_pins[4] = {14, 12, 13, 15}; for (uint8_t ch = 0; ch < 4; ch++) { uint8_t base = ch * CHANNEL_BYTES; - - channels_schema[base + 0] = default_pins[ch]; // pin - channels_schema[base + 1] = ch; // indicator (0,1,2,3) - channels_schema[base + 2] = SH_PIN_UNUSED; // feedback + channels_schema[base + 0] = (char)default_pins[ch]; // pin + channels_schema[base + 1] = (char)ch; // indicator + channels_schema[base + 2] = (char)SH_PIN_UNUSED; // feedback + channels_schema[base + 3] = (char)SH_PIN_UNUSED; // reserved } } + uint8_t sh_channel_get_u8(uint8_t ch, ShChannelField field) { + if (ch >= CHANNEL_MAX) return SH_PIN_UNUSED; + uint16_t idx = (uint16_t)ch * CHANNEL_BYTES + (uint8_t)field; - if (idx >= CHANNEL_MAX) return SH_PIN_UNUSED; + if (idx >= CHANNEL_SCHEMA_DATA_LEN) return SH_PIN_UNUSED; + return (uint8_t)channels_schema[idx]; } void sh_channel_set_u8(uint8_t ch, ShChannelField field, uint8_t v) { + if (ch >= CHANNEL_MAX) return; + uint16_t idx = (uint16_t)ch * CHANNEL_BYTES + (uint8_t)field; - if (idx >= CHANNEL_MAX) return; + if (idx >= CHANNEL_SCHEMA_DATA_LEN) return; + channels_schema[idx] = (char)v; } -// convenience uint8_t sh_channel_pin(uint8_t ch) { return sh_channel_get_u8(ch, SH_CH_PIN); } @@ -426,6 +443,7 @@ } + // -------------------- Core setup / loop -------------------- void coreSetup() { Serial.begin(115200); diff --git a/devices/sh_core_esp8266/src/sh_core.h b/devices/sh_core_esp8266/src/sh_core.h index 19df068..124cef0 100755 --- a/devices/sh_core_esp8266/src/sh_core.h +++ b/devices/sh_core_esp8266/src/sh_core.h @@ -9,12 +9,12 @@ // -------------------- compile-time defaults -------------------- extern const char* DEVICE_TYPE; extern const char* FW_VERSION; + static constexpr uint8_t SH_PIN_UNUSED = 0xFF; + extern const uint8_t CHANNEL_NUM; - // -------------------- EEPROM layout (ядро) -------------------- - constexpr uint16_t SSID_ADDR = 0; constexpr uint16_t SSID_MAX_LEN = 32; @@ -27,23 +27,29 @@ constexpr uint16_t DEVICE_NAME_MAX_LEN = 64; // 97..160 constexpr uint16_t AUTH_TOKEN_ADDR = DEVICE_NAME_ADDR + DEVICE_NAME_MAX_LEN; -constexpr uint16_t AUTH_TOKEN_MAX_LEN = 64; +constexpr uint16_t AUTH_TOKEN_MAX_LEN = 64; constexpr uint16_t SERVER_ADDR = AUTH_TOKEN_ADDR + AUTH_TOKEN_MAX_LEN; -constexpr uint16_t SERVER_MAX_LEN = 32; +constexpr uint16_t SERVER_MAX_LEN = 32; -constexpr uint16_t CHANNEL_SCHEMA_ADDR = SERVER_ADDR + SERVER_MAX_LEN; -constexpr uint16_t CHANNEL_SCHEMA_MAX_LEN = 36; +// ---- channels schema (EEPROM) ---- +// data = 8 каналов * 4 байта = 32 +constexpr uint16_t CHANNEL_SCHEMA_DATA_LEN = 32; +constexpr uint16_t CHANNEL_SCHEMA_META_LEN = 4; +constexpr uint16_t CHANNEL_SCHEMA_TOTAL_LEN = CHANNEL_SCHEMA_META_LEN + CHANNEL_SCHEMA_DATA_LEN; -constexpr uint8_t CHANNEL_SCHEMA_MAGIC_0 = 0xA5; -constexpr uint8_t CHANNEL_SCHEMA_MAGIC_1 = 0x5A; -constexpr uint8_t CHANNEL_SCHEMA_VERSION = 1; +constexpr uint16_t CHANNEL_SCHEMA_ADDR = SERVER_ADDR + SERVER_MAX_LEN; +constexpr uint16_t CHANNEL_SCHEMA_MAX_LEN = CHANNEL_SCHEMA_DATA_LEN; // ВАЖНО: размер RAM-буфера = 32 -constexpr uint16_t CHANNEL_SCHEMA_META_ADDR = CHANNEL_SCHEMA_ADDR; -constexpr uint16_t CHANNEL_SCHEMA_DATA_ADDR = CHANNEL_SCHEMA_ADDR + 4; +constexpr uint8_t CHANNEL_SCHEMA_MAGIC_0 = 0xA5; +constexpr uint8_t CHANNEL_SCHEMA_MAGIC_1 = 0x5A; +constexpr uint8_t CHANNEL_SCHEMA_VERSION = 1; -// Конец блока ядра -constexpr uint16_t CORE_EEPROM_END = CHANNEL_SCHEMA_ADDR + CHANNEL_SCHEMA_MAX_LEN; +constexpr uint16_t CHANNEL_SCHEMA_META_ADDR = CHANNEL_SCHEMA_ADDR; // +0..+3 +constexpr uint16_t CHANNEL_SCHEMA_DATA_ADDR = CHANNEL_SCHEMA_ADDR + 4; // +4..+35 + +// Конец блока ядра +constexpr uint16_t CORE_EEPROM_END = CHANNEL_SCHEMA_ADDR + CHANNEL_SCHEMA_TOTAL_LEN; // Общий размер EEPROM constexpr uint16_t EEPROM_SIZE = 1024; @@ -52,7 +58,7 @@ constexpr uint16_t DEVICE_EEPROM_START = 512; constexpr uint16_t DEVICE_EEPROM_SIZE = EEPROM_SIZE - DEVICE_EEPROM_START; - +// ---- channel fields ---- constexpr uint8_t CHANNEL_BYTES = 4; constexpr uint8_t CHANNEL_MAX = 8; @@ -81,13 +87,14 @@ extern String deviceName; extern String serverBaseUrl; extern String authToken; -extern char channels_schema[CHANNEL_SCHEMA_MAX_LEN]; + +// RAM-буфер схемы: ТОЛЬКО 32 байта data +extern char channels_schema[CHANNEL_SCHEMA_DATA_LEN]; // -------------------- pages -------------------- extern const char* wifi_setup_page; extern const char* update_page; - // -------------------- core API -------------------- uint16_t getDeviceEepromStart(); uint16_t getDeviceEepromSize(); @@ -95,15 +102,20 @@ String readStringFromEEPROM(uint16_t addr, uint16_t maxLen); void writeStringToEEPROM(uint16_t addr, const String &str, uint16_t maxLen); +// channels schema +bool is_channels_schema_valid(); +void init_default_channels_schema(); void write_channels_schema(); void load_channels_schema(); -uint8_t sh_channel_get_u8(uint8_t ch, uint8_t field); -void sh_channel_set_u8(uint8_t ch, ShChannelField field, uint8_t v); + +uint8_t sh_channel_get_u8(uint8_t ch, ShChannelField field); +void sh_channel_set_u8(uint8_t ch, ShChannelField field, uint8_t v); + uint8_t sh_channel_pin(uint8_t ch); uint8_t sh_channel_indicator(uint8_t ch); uint8_t sh_channel_feedback_pin(uint8_t ch); - +// wifi/device config void saveWiFiConfig(const String &ssid, const String &pass); void loadWiFiConfig();