From 11e5953ccdfd5037d925989ed6edb95394348f86 Mon Sep 17 00:00:00 2001 From: Noah Metz Date: Mon, 1 Jun 2026 14:35:42 -0600 Subject: [PATCH] Initial commit --- .clangd | 3 + .gitignore | 2 + CMakeLists.txt | 7 + Makefile | 62 ++ case/case.py | 61 ++ case/requirements.txt | 4 + icons.py | 152 +++ main/CMakeLists.txt | 7 + main/ble.c | 216 ++++ main/ble.h | 41 + main/config.h | 89 ++ main/draw.c | 294 ++++++ main/draw.h | 19 + main/font.h | 86 ++ main/game.c | 97 ++ main/game.h | 12 + main/main.c | 464 +++++++++ main/state.h | 33 + pcb/commeownder.kicad_pcb | 2 + pcb/commeownder.kicad_pro | 1 + pcb/commeownder.kicad_sch | 14 + sdkconfig | 2010 +++++++++++++++++++++++++++++++++++++ sdkconfig.defaults | 3 + simulator/CMakeLists.txt | 33 + simulator/main.c | 283 ++++++ simulator/test_ble.c | 1015 +++++++++++++++++++ 26 files changed, 5010 insertions(+) create mode 100644 .clangd create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 Makefile create mode 100644 case/case.py create mode 100644 case/requirements.txt create mode 100755 icons.py create mode 100644 main/CMakeLists.txt create mode 100644 main/ble.c create mode 100644 main/ble.h create mode 100644 main/config.h create mode 100644 main/draw.c create mode 100644 main/draw.h create mode 100644 main/font.h create mode 100644 main/game.c create mode 100644 main/game.h create mode 100644 main/main.c create mode 100644 main/state.h create mode 100644 pcb/commeownder.kicad_pcb create mode 100644 pcb/commeownder.kicad_pro create mode 100644 pcb/commeownder.kicad_sch create mode 100644 sdkconfig create mode 100644 sdkconfig.defaults create mode 100644 simulator/CMakeLists.txt create mode 100644 simulator/main.c create mode 100644 simulator/test_ble.c diff --git a/.clangd b/.clangd new file mode 100644 index 0000000..8f7a9b3 --- /dev/null +++ b/.clangd @@ -0,0 +1,3 @@ +CompileFlags: + CompilationDatabase: build + Remove: [-mlongcalls, -fstrict-volatile-bitfields, -fno-tree-switch-conversion] diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..36f60a5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +case/venv/ +case/output/*.stl diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..d8e11fc --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.16) +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(commeownder) + +if(DEBUG) + add_compile_definitions(DEBUG) +endif() diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c84477f --- /dev/null +++ b/Makefile @@ -0,0 +1,62 @@ +SHELL := /bin/bash +.ONESHELL: + +ESP_ENV := . ~/scripts/esp_env.sh +SIM_BUILD := simulator/build +PORT ?= /dev/ttyUSB0 + +# All firmware targets build with DEBUG=1 so serial commands and DBG lines +# are always available for testing and monitoring. +IDF := $(ESP_ENV) && idf.py -DDEBUG=1 + +.PHONY: all firmware sim test flash monitor flash-monitor clean firmware-clean sim-clean case case_live case_clean + +all: firmware sim + +firmware: + $(IDF) build + +flash: + $(IDF) flash + +monitor: + $(IDF) monitor + +flash-monitor: + $(IDF) flash monitor + +sim: + cmake --build $(SIM_BUILD) --parallel + +test: sim flash + sleep 5 + $(SIM_BUILD)/test_ble --port $(PORT) + +clean: firmware-clean sim-clean case_clean + +firmware-clean: + $(IDF) fullclean + +sim-clean: + cmake --build $(SIM_BUILD) --target clean + +# --- case (build123d) --- +CASE_VENV := case/venv +CASE_PYTHON := $(CASE_VENV)/bin/python +CASE_PIP := $(CASE_VENV)/bin/pip +CASE_FW := $(CASE_VENV)/bin/fw123d + +$(CASE_VENV)/.installed: case/requirements.txt + python3.13 -m venv $(CASE_VENV) + $(CASE_PIP) install --upgrade pip + $(CASE_PIP) install -r case/requirements.txt + touch $@ + +case: $(CASE_VENV)/.installed + $(CASE_PYTHON) case/case.py + +case_live: $(CASE_VENV)/.installed + $(CASE_FW) case/case.py + +case_clean: + rm -rf $(CASE_VENV) case/output/*.stl diff --git a/case/case.py b/case/case.py new file mode 100644 index 0000000..2fc52b4 --- /dev/null +++ b/case/case.py @@ -0,0 +1,61 @@ +from build123d import * + +# --- Facade panel --- +PANEL = 1.6 # plate thickness (Cherry MX standard ~1.5 mm) + +# --- Component footprints --- +SW_SIZE = 14.0 # Cherry MX plate cutout (square) +SW_PITCH = 19.0 # switch centre-to-centre +N_SW = 3 + +OLED_W = 25.0 # 0.96" SSD1306 visible window width +OLED_H = 13.0 # visible window height + +# --- OLED alignment pegs (solid 2 mm, 24 mm square pattern) --- +POST_D = 2.0 # peg diameter +POST_SPACING = 24.0 # hole centre-to-centre +POST_H = 12.0 # peg length behind panel + +# --- Layout --- +# MARGIN_Y=7 and OLED_SW_GAP=9 push outer_h to 50 mm, giving the top pegs +# 1.5 mm clearance from the panel edge and the bottom pegs 2.5 mm clearance +# above the switch cutout tops. +MARGIN_X = 3.0 +MARGIN_Y = 7.0 +OLED_SW_GAP = 9.0 + +outer_w = (N_SW - 1) * SW_PITCH + SW_SIZE + 2 * MARGIN_X # 58 mm +outer_h = 2 * MARGIN_Y + OLED_H + OLED_SW_GAP + SW_SIZE # 50 mm + +oled_cy = outer_h / 2 - MARGIN_Y - OLED_H / 2 # 11.5 mm +sw_cy = -outer_h / 2 + MARGIN_Y + SW_SIZE / 2 # -11.0 mm + +with BuildPart() as case: + Box(outer_w, outer_h, PANEL) + + with BuildSketch(Plane.XY.offset(PANEL / 2)): + with Locations((0, oled_cy)): + Rectangle(OLED_W, OLED_H) + with Locations((-SW_PITCH, sw_cy), (0, sw_cy), (SW_PITCH, sw_cy)): + RectangleRounded(SW_SIZE, SW_SIZE, 0.3) + extrude(amount=-PANEL, mode=Mode.SUBTRACT) + + # Solid 2 mm alignment pegs extending from the back face + half_s = POST_SPACING / 2 + post_z = -PANEL / 2 - POST_H / 2 + post_xy = [ + (-half_s, oled_cy - half_s), + ( half_s, oled_cy - half_s), + (-half_s, oled_cy + half_s), + ( half_s, oled_cy + half_s), + ] + with Locations([(x, y, post_z) for x, y in post_xy]): + Cylinder(POST_D / 2, POST_H) + +export_stl(case.part, "case/output/case.stl") + +try: + from ocp_vscode import show + show(case) +except Exception: + pass diff --git a/case/requirements.txt b/case/requirements.txt new file mode 100644 index 0000000..21f9e82 --- /dev/null +++ b/case/requirements.txt @@ -0,0 +1,4 @@ +build123d>=0.10.0 +cadquery-ocp>=7.8,<7.9 +ocp-vscode +git+https://github.com/jdegenstein/filewatcher123d diff --git a/icons.py b/icons.py new file mode 100755 index 0000000..23e49dc --- /dev/null +++ b/icons.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python3 +"""Display SSD1306 vertical-byte glyph/icon arrays as console text. + +Handles two array shapes found in C headers: + + Single-page glyphs uint8_t name[][W] + Each row is one glyph: W columns × 8 rows. + Displayed side-by-side in a grid. + + Two-page icons uint8_t name[...][2][W] or name[2][W] + Each pair of rows is one icon: W columns × 16 rows. + Outer 1-pixel border trimmed → 14×14 display. + +Usage: + python3 icons.py [FILE] show all glyphs and icons (default: main/font.h) +""" + +import re +import sys + +# ── Glyph display (single page, arbitrary W×8) ─────────────────────────────── + +def decode_glyph(data): + """data: list of W ints → 8×W bitmap.""" + w = len(data) + return [[(data[col] >> row) & 1 for col in range(w)] for row in range(8)] + + +def show_glyphs(entries, per_row=10): + """entries: list of (label, data) — print glyphs side by side.""" + if not entries: + return + glyph_w = len(entries[0][1]) + col_w = max(glyph_w, max(len(label) for label, _ in entries)) + sep = " " + + for i in range(0, len(entries), per_row): + chunk = entries[i : i + per_row] + grids = [decode_glyph(data) for _, data in chunk] + labels = [label for label, _ in chunk] + + print(sep.join(f"{lbl:^{col_w}}" for lbl in labels)) + for row in range(8): + parts = ["".join("x" if grids[g][row][c] else " " for c in range(glyph_w)) + for g in range(len(chunk))] + print(sep.join(f"{p:^{col_w}}" for p in parts)) + print() + + +# ── Icon display (two pages, W×16 → trimmed 14×14) ─────────────────────────── + +def decode_icon(data): + """data: [[W ints page0], [W ints page1]] → 14×14 list-of-lists.""" + w = len(data[0]) + rows = [[(data[page][col] >> bit) & 1 + for col in range(w)] + for page in range(2) + for bit in range(8)] + return [r[1:-1] for r in rows[1:-1]] + + +def show_icon(grid, name=""): + if name: + print(f"── {name} ──") + for row in grid: + print("".join("x" if p else " " for p in row)) + print() + + +# ── C file parser ───────────────────────────────────────────────────────────── + +def _hex_row(raw): + return [int(x, 16) for x in re.findall(r"0x[0-9A-Fa-f]+", raw)] + + +def parse_file(path): + """ + Parse all uint8_t byte arrays from a C header. + + Returns: + glyphs: dict of array_name → list of (label, [W bytes]) + icons: dict of name → [[W page0 bytes], [W page1 bytes]] + """ + text = open(path).read() + glyphs = {} + icons = {} + + # ── Two-page icon arrays ────────────────────────────────────────────────── + # Matches: uint8_t name[...][2][W] = { ... }; + # Also: uint8_t name[2][W] = { ... }; + for m in re.finditer( + r"uint8_t\s+(\w+)\s*(?:\[[^\]]*\])*\[2\]\[([^\]]+)\]\s*=\s*\{(.*?)\}\s*;", + text, re.DOTALL, + ): + array_name = m.group(1) + body = m.group(3) + + # Pull each { {top}, {bot} } pair, with an optional // comment before it + pairs = re.findall( + r"(?://\s*(.+?)\n)?\s*\{\s*\{([^}]+)\}\s*,\s*\{([^}]+)\}\s*\}", + body, + ) + if pairs: + for i, (comment, raw0, raw1) in enumerate(pairs): + label = comment.strip() if comment.strip() else f"{array_name}[{i}]" + icons[label] = [_hex_row(raw0), _hex_row(raw1)] + else: + # Standalone name[2][W] — whole array is one icon + rows = re.findall(r"\{([^}]+)\}", body) + if len(rows) == 2: + icons[array_name] = [_hex_row(rows[0]), _hex_row(rows[1])] + + # ── Single-page glyph arrays ────────────────────────────────────────────── + # Matches: uint8_t name[][W] = { {bytes}, // label \n ... }; + for m in re.finditer( + r"uint8_t\s+(\w+)\s*\[\]\s*\[([^\]]+)\]\s*=\s*\{(.*?)\}\s*;", + text, re.DOTALL, + ): + array_name = m.group(1) + body = m.group(3) + + entries = [] + for em in re.finditer(r"\{([^}]+)\}\s*(?:,\s*)?(?://\s*(.+))?", body): + data = _hex_row(em.group(1)) + comment = (em.group(2) or "").strip().strip("'\"") + label = comment if comment else str(len(entries)) + entries.append((label, data)) + + if entries: + glyphs[array_name] = entries + + return glyphs, icons + + +# ── Entry point ─────────────────────────────────────────────────────────────── + +if __name__ == "__main__": + path = next((a for a in sys.argv[1:] if not a.startswith("--")), "main/font.h") + + glyphs, icons = parse_file(path) + + if not glyphs and not icons: + sys.exit(f"no glyph or icon arrays found in {path}") + + for array_name, entries in glyphs.items(): + print(f"{'═' * 60}") + print(f" {array_name} ({len(entries)} glyphs)") + print(f"{'═' * 60}\n") + show_glyphs(entries) + + for name, data in icons.items(): + show_icon(decode_icon(data), name) diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt new file mode 100644 index 0000000..f2bbb68 --- /dev/null +++ b/main/CMakeLists.txt @@ -0,0 +1,7 @@ +idf_component_register(SRCS "main.c" "draw.c" "ble.c" "game.c" + INCLUDE_DIRS "." + PRIV_REQUIRES driver nvs_flash bt vfs) + +if(DEBUG) + target_compile_definitions(${COMPONENT_LIB} PUBLIC DEBUG) +endif() diff --git a/main/ble.c b/main/ble.c new file mode 100644 index 0000000..42f49c9 --- /dev/null +++ b/main/ble.c @@ -0,0 +1,216 @@ +#include "ble.h" +#include "state.h" +#include "nimble/nimble_port.h" +#include "nimble/nimble_port_freertos.h" +#include "services/gap/ble_svc_gap.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include +#include + +volatile int g_ble_scanning; +volatile int g_ble_initialized; +uint8_t g_own_addr_type; +uint8_t g_own_addr[6]; +uint8_t g_player_id = 0xFF; +volatile int g_reset_requested; +int g_reset_cmd_ticks; + +static int ble_gap_event_handler(struct ble_gap_event *event, void *arg); + +static void ble_adv_start_internal(void) +{ + ble_payload_t payload; + payload.magic[0] = BLE_MFR_MAGIC_0; + payload.magic[1] = BLE_MFR_MAGIC_1; + payload.game_id[0] = g_game_id[0]; + payload.game_id[1] = g_game_id[1]; + memcpy(payload.name, g_player_name, PLAYER_NAME_LEN); + payload.life = (int16_t)g_life; + payload.poison = (uint8_t)g_counters[0]; + payload.eliminated = (uint8_t)g_eliminated; + payload.player_id = g_player_id; + payload.reset_cmd = (g_reset_cmd_ticks > 0) ? 1 : 0; + for (int i = 0; i < MAX_OPPONENTS; i++) + payload.cmdr_dmg[i] = (uint8_t)g_cmdr_damage[i]; + + static uint8_t mfr[2 + sizeof(ble_payload_t)]; + mfr[0] = 0xFF; mfr[1] = 0xFF; + memcpy(mfr + 2, &payload, sizeof(payload)); + + struct ble_hs_adv_fields fields = {0}; + fields.mfg_data = mfr; + fields.mfg_data_len = sizeof(mfr); + ble_gap_adv_set_fields(&fields); + + struct ble_gap_adv_params params = {0}; + params.conn_mode = BLE_GAP_CONN_MODE_NON; + params.disc_mode = BLE_GAP_DISC_MODE_NON; + params.itvl_min = 0x0320; // 500ms + params.itvl_max = 0x0320; + ble_gap_adv_start(g_own_addr_type, NULL, BLE_HS_FOREVER, ¶ms, ble_gap_event_handler, NULL); + +#ifdef DEBUG + printf("DBG ADV_TX name=%-8.8s life=%d poison=%u game_id=%02X%02X eliminated=%u pid=%u reset=%u\n", + payload.name, (int)payload.life, (unsigned)payload.poison, + payload.game_id[0], payload.game_id[1], (unsigned)payload.eliminated, + (unsigned)payload.player_id, (unsigned)payload.reset_cmd); + fflush(stdout); +#endif +} + +void ble_adv_update(void) +{ + if (!g_ble_initialized || g_ble_scanning) return; + ble_gap_adv_stop(); + if (g_ble_enabled) ble_adv_start_internal(); +} + +static void ble_update_peer(const ble_addr_t *addr, const ble_payload_t *p) +{ + if (p->game_id[0] != g_game_id[0] || p->game_id[1] != g_game_id[1]) return; + + int slot = -1; + for (int i = 0; i < MAX_BLE_PEERS; i++) { + if (g_peers[i].active && memcmp(&g_peers[i].addr, addr, sizeof(ble_addr_t)) == 0) { + slot = i; break; + } + } + if (slot < 0) { + for (int i = 0; i < MAX_BLE_PEERS; i++) { + if (!g_peers[i].active) { slot = i; break; } + } + if (slot < 0) { + slot = 0; + for (int i = 1; i < MAX_BLE_PEERS; i++) + if (g_peers[i].last_seen < g_peers[slot].last_seen) slot = i; + } + } + uint8_t prev_reset_cmd = g_peers[slot].reset_cmd; + g_peers[slot].addr = *addr; + g_peers[slot].life = p->life; + g_peers[slot].poison = p->poison; + g_peers[slot].eliminated = p->eliminated; + g_peers[slot].player_id = p->player_id; + g_peers[slot].reset_cmd = p->reset_cmd; + memcpy(g_peers[slot].cmdr_dmg, p->cmdr_dmg, MAX_OPPONENTS); + g_peers[slot].last_seen = g_tick; + g_peers[slot].active = 1; + memcpy(g_peers[slot].name, p->name, PLAYER_NAME_LEN); + g_peers[slot].name[PLAYER_NAME_LEN] = '\0'; + if (p->reset_cmd && !prev_reset_cmd) g_reset_requested = 1; + +#ifdef DEBUG + printf("DBG PEER_RX slot=%d addr=%02X:%02X:%02X:%02X:%02X:%02X name=%-8.8s life=%d poison=%u game_id=%02X%02X eliminated=%u pid=%u reset=%u cmdr=[%u,%u,%u,%u]\n", + slot, + addr->val[5], addr->val[4], addr->val[3], + addr->val[2], addr->val[1], addr->val[0], + p->name, (int)p->life, (unsigned)p->poison, + p->game_id[0], p->game_id[1], (unsigned)p->eliminated, + (unsigned)p->player_id, (unsigned)p->reset_cmd, + (unsigned)p->cmdr_dmg[0], (unsigned)p->cmdr_dmg[1], + (unsigned)p->cmdr_dmg[2], (unsigned)p->cmdr_dmg[3]); + fflush(stdout); +#endif +} + +static int ble_gap_event_handler(struct ble_gap_event *event, void *arg) +{ + if (event->type == BLE_GAP_EVENT_DISC) { + const uint8_t *adv_data = event->disc.data; + int len = event->disc.length_data; + int i = 0; + while (i < len) { + uint8_t adlen = adv_data[i]; + if (adlen == 0 || i + adlen >= len) break; + uint8_t adtype = adv_data[i+1]; + if (adtype == 0xFF && adlen >= 1 + 2 + (int)sizeof(ble_payload_t)) { + const uint8_t *payload_ptr = adv_data + i + 4; + if (payload_ptr[0] == BLE_MFR_MAGIC_0 && payload_ptr[1] == BLE_MFR_MAGIC_1) { + ble_update_peer(&event->disc.addr, (const ble_payload_t *)payload_ptr); + } + } + i += 1 + adlen; + } + } else if (event->type == BLE_GAP_EVENT_DISC_COMPLETE) { + g_ble_scanning = 0; + if (g_ble_enabled) ble_adv_start_internal(); + } + return 0; +} + +static void ble_on_sync(void) +{ + ble_hs_id_infer_auto(0, &g_own_addr_type); + ble_hs_id_copy_addr(g_own_addr_type, g_own_addr, NULL); + if (g_player_id == 0xFF) g_player_id = 0; + g_ble_initialized = 1; + if (g_ble_enabled) ble_adv_start_internal(); +} + +static void ble_on_reset(int reason) { (void)reason; } + +static void ble_host_task(void *arg) +{ + nimble_port_run(); + nimble_port_freertos_deinit(); +} + +static void ble_manager_task(void *arg) +{ + while (!g_ble_initialized) vTaskDelay(pdMS_TO_TICKS(100)); + while (1) { + vTaskDelay(pdMS_TO_TICKS(10000)); + if (!g_ble_enabled || g_ble_scanning) continue; + + g_ble_scanning = 1; + ble_gap_adv_stop(); + + struct ble_gap_disc_params disc_params = {0}; + disc_params.itvl = 0x0100; disc_params.window = 0x0080; disc_params.passive = 1; + int rc = ble_gap_disc(g_own_addr_type, 5000, &disc_params, ble_gap_event_handler, NULL); + if (rc != 0) { + g_ble_scanning = 0; + if (g_ble_enabled) ble_adv_start_internal(); + } + vTaskDelay(pdMS_TO_TICKS(6000)); + if (g_ble_scanning) { + ble_gap_disc_cancel(); + g_ble_scanning = 0; + if (g_ble_enabled) ble_adv_start_internal(); + } + } +} + +void player_id_resolve(void) +{ + if (!g_ble_initialized || !g_ble_enabled) return; + for (int i = 0; i < MAX_BLE_PEERS; i++) { + if (!g_peers[i].active || g_peers[i].player_id != g_player_id) continue; + int we_lose = 0; + for (int b = 5; b >= 0; b--) { + if (g_peers[i].addr.val[b] < g_own_addr[b]) { we_lose = 1; break; } + if (g_peers[i].addr.val[b] > g_own_addr[b]) break; + } + if (!we_lose) continue; + uint8_t used[BLE_MAX_PLAYERS] = {0}; + for (int j = 0; j < MAX_BLE_PEERS; j++) + if (g_peers[j].active && g_peers[j].player_id < BLE_MAX_PLAYERS) + used[g_peers[j].player_id] = 1; + for (int id = 0; id < BLE_MAX_PLAYERS; id++) { + if (!used[id]) { g_player_id = (uint8_t)id; break; } + } + ble_adv_update(); + break; + } +} + +void ble_init(void) +{ + nimble_port_init(); + ble_hs_cfg.sync_cb = ble_on_sync; + ble_hs_cfg.reset_cb = ble_on_reset; + ble_svc_gap_init(); + nimble_port_freertos_init(ble_host_task); + xTaskCreate(ble_manager_task, "ble_mgr", 4096, NULL, 5, NULL); +} diff --git a/main/ble.h b/main/ble.h new file mode 100644 index 0000000..22315dc --- /dev/null +++ b/main/ble.h @@ -0,0 +1,41 @@ +#pragma once +#include +#include "config.h" +#include "host/ble_hs.h" + +typedef struct __attribute__((packed)) { + uint8_t magic[2]; + uint8_t game_id[2]; + char name[PLAYER_NAME_LEN]; + int16_t life; + uint8_t poison; + uint8_t eliminated; + uint8_t player_id; + uint8_t reset_cmd; + uint8_t cmdr_dmg[MAX_OPPONENTS]; +} ble_payload_t; + +typedef struct { + ble_addr_t addr; + char name[PLAYER_NAME_LEN + 1]; + int16_t life; + uint8_t poison; + uint8_t eliminated; + uint8_t player_id; + uint8_t reset_cmd; + uint8_t cmdr_dmg[MAX_OPPONENTS]; + uint32_t last_seen; + int active; +} ble_peer_t; + +extern volatile int g_ble_scanning; +extern volatile int g_ble_initialized; +extern uint8_t g_own_addr_type; +extern uint8_t g_own_addr[6]; +extern uint8_t g_player_id; +extern volatile int g_reset_requested; +extern int g_reset_cmd_ticks; + +void ble_init(void); +void ble_adv_update(void); +void player_id_resolve(void); diff --git a/main/config.h b/main/config.h new file mode 100644 index 0000000..dd0ea9c --- /dev/null +++ b/main/config.h @@ -0,0 +1,89 @@ +#pragma once + +// ── Buttons ─────────────────────────────────────────────────────────────────── +#define BTN_RIGHT_GPIO 23 +#define BTN_LEFT_GPIO 4 +#define BTN_MID_GPIO 5 + +// ── RGB LED ─────────────────────────────────────────────────────────────────── +#define LED_R_GPIO 13 +#define LED_G_GPIO 14 +#define LED_B_GPIO 27 + +// ── I2C / OLED ──────────────────────────────────────────────────────────────── +#define I2C_PORT I2C_NUM_0 +#define I2C_SDA_GPIO 21 +#define I2C_SCL_GPIO 22 +#define I2C_FREQ_HZ 400000 +#define OLED_ADDR 0x3C +#define OLED_WIDTH 128 +#define OLED_PAGES 8 +#define HEADER_PAGES 2 + +// ── Button timing ───────────────────────────────────────────────────────────── +#define HOLD_DELAY 50 +#define HOLD_REPEAT 10 +#define MID_HOLD_MENU 15 +#define MID_HOLD_SETTINGS 100 + +// ── BLE ─────────────────────────────────────────────────────────────────────── +#define BLE_MFR_MAGIC_0 0xC0 +#define BLE_MFR_MAGIC_1 0xDE +#define BLE_GAME_ID_0 0x42 +#define BLE_GAME_ID_1 0x42 +#define BLE_MAX_PLAYERS 5 +#define MAX_BLE_PEERS 4 +#define BLE_PEER_TIMEOUT 3000 + +// ── Menus ───────────────────────────────────────────────────────────────────── +#define NUM_MENUS 4 +#define MENU_LIFE 0 +#define MENU_CMDR 1 +#define MENU_COUNTERS 2 +#define MENU_SETTINGS 3 + +extern const int menu_slot[NUM_MENUS]; + +// ── Settings ────────────────────────────────────────────────────────────────── +#define NUM_SETTINGS 8 +#define SET_BRIGHTNESS 0 +#define SET_START_LIFE 1 +#define SET_NUM_OPP 2 +#define SET_BLE 3 +#define SET_RESET 4 +#define SET_RESET_ALL 5 +#define SET_PLAYER_NAME 7 +#define SET_GAME_ID 6 +#define BRIGHTNESS_MIN 1 +#define BRIGHTNESS_MAX 100 +#define PLAYER_NAME_LEN 8 +#define GAME_ID_DIGITS 4 + +extern const char *setting_names[NUM_SETTINGS]; +extern const int start_life_opts[]; +#define NUM_LIFE_OPTS 3 + +extern const char NAME_CHARS[]; +#define NUM_NAME_CHARS 37 +#define NUM_HEX_CHARS 16 + +// ── Counters ────────────────────────────────────────────────────────────────── +#define NUM_COUNTERS 4 +extern const char *counter_names[NUM_COUNTERS]; + +// ── Opponents ───────────────────────────────────────────────────────────────── +#define MAX_OPPONENTS 4 + +// ── Font / display ──────────────────────────────────────────────────────────── +#define SCALE 5 +#define CHAR_WIDTH (5 * SCALE + SCALE) +#define CHAR_PAGES 5 +#define START_PAGE (HEADER_PAGES + (OLED_PAGES - HEADER_PAGES - CHAR_PAGES + 1) / 2) +#define SEG_W 16 +#define ICON_W 16 +#define FONT_BASE 0x20 +#define FONT_MAX 0x5A + +// ── NVS ─────────────────────────────────────────────────────────────────────── +#define NVS_NS "settings" +#define SAVE_DELAY 300 diff --git a/main/draw.c b/main/draw.c new file mode 100644 index 0000000..f85bbd0 --- /dev/null +++ b/main/draw.c @@ -0,0 +1,294 @@ +#include "draw.h" +#include "config.h" +#include "game.h" +#include "font.h" +#include "state.h" +#include "driver/ledc.h" +#include "driver/i2c.h" +#include "freertos/FreeRTOS.h" +#include +#include + +const int menu_slot[NUM_MENUS] = {0, 1, 2, 7}; +const char *setting_names[NUM_SETTINGS] = { + "LED BRIGHTNESS", "STARTING LIFE", "NUM OPPONENTS", "BLE", + "RESET", "RESET ALL", "GAME ID", "PLAYER NAME", +}; + +#define LEDC_TIMER_SEL LEDC_TIMER_0 +#define LEDC_MODE_ LEDC_LOW_SPEED_MODE +#define LEDC_DUTY_RES_ LEDC_TIMER_8_BIT +#define LEDC_FREQ_HZ_ 5000 + +// ── LED ─────────────────────────────────────────────────────────────────────── +void led_init(void) +{ + ledc_timer_config_t timer = { + .speed_mode = LEDC_MODE_, + .timer_num = LEDC_TIMER_SEL, + .duty_resolution = LEDC_DUTY_RES_, + .freq_hz = LEDC_FREQ_HZ_, + .clk_cfg = LEDC_AUTO_CLK, + }; + ledc_timer_config(&timer); + ledc_channel_config_t ch[] = { + {.gpio_num=LED_R_GPIO,.speed_mode=LEDC_MODE_,.channel=LEDC_CHANNEL_0,.timer_sel=LEDC_TIMER_SEL,.duty=0,.hpoint=0}, + {.gpio_num=LED_G_GPIO,.speed_mode=LEDC_MODE_,.channel=LEDC_CHANNEL_1,.timer_sel=LEDC_TIMER_SEL,.duty=0,.hpoint=0}, + {.gpio_num=LED_B_GPIO,.speed_mode=LEDC_MODE_,.channel=LEDC_CHANNEL_2,.timer_sel=LEDC_TIMER_SEL,.duty=0,.hpoint=0}, + }; + for (int i = 0; i < 3; i++) ledc_channel_config(&ch[i]); +} + +void led_update_for_count(int count, uint8_t scale) +{ + int c = count < 0 ? 0 : count > 80 ? 80 : count; + uint8_t r, g, b; + if (c <= 40) { + int cc = c < 10 ? 10 : c; + r = (uint8_t)((uint32_t)(40-cc)*scale*g_led_max/30/255); + g = (uint8_t)((uint32_t)(cc-10)*scale*g_led_max/30/255); + b = 0; + } else { + r = 0; + g = (uint8_t)((uint32_t)(80-c)*g_led_max/40); + b = (uint8_t)((uint32_t)(c-40)*g_led_max/40); + } + ledc_set_duty(LEDC_MODE_, LEDC_CHANNEL_0, r); ledc_update_duty(LEDC_MODE_, LEDC_CHANNEL_0); + ledc_set_duty(LEDC_MODE_, LEDC_CHANNEL_1, g); ledc_update_duty(LEDC_MODE_, LEDC_CHANNEL_1); + ledc_set_duty(LEDC_MODE_, LEDC_CHANNEL_2, b); ledc_update_duty(LEDC_MODE_, LEDC_CHANNEL_2); +} + +// ── OLED ────────────────────────────────────────────────────────────────────── +static void oled_write(const uint8_t *buf, size_t len) +{ + i2c_master_write_to_device(I2C_PORT, OLED_ADDR, buf, len, pdMS_TO_TICKS(100)); +} +static void oled_cmd(uint8_t c) { uint8_t b[2]={0x00,c}; oled_write(b,2); } +static void oled_write_page(int p, const uint8_t *row); + +void oled_init(void) +{ + static const uint8_t seq[] = { + 0xAE,0xD5,0x80,0xA8,0x3F,0xD3,0x00,0x40,0x8D,0x14,0x20,0x00, + 0xA1,0xC8,0xDA,0x12,0x81,0xCF,0xD9,0xF1,0xDB,0x40,0xA4,0xA6,0xAF, + }; + for (int i = 0; i < (int)sizeof(seq); i++) oled_cmd(seq[i]); +} + +void oled_clear(void) +{ + uint8_t row[OLED_WIDTH]; memset(row, 0, sizeof(row)); + for (int p = 0; p < OLED_PAGES; p++) oled_write_page(p, row); +} + +static void oled_write_page(int p, const uint8_t *row) +{ + oled_cmd(0x21); oled_cmd(0); oled_cmd(127); + oled_cmd(0x22); oled_cmd(p); oled_cmd(p); + uint8_t buf[OLED_WIDTH+1]; buf[0]=0x40; + memcpy(buf+1, row, OLED_WIDTH); oled_write(buf, sizeof(buf)); +} + +void oled_draw_header(void) +{ + uint8_t pages[HEADER_PAGES][OLED_WIDTH]; + memset(pages, 0, sizeof(pages)); + for (int seg = 0; seg < NUM_MENUS; seg++) { + uint8_t bg = (seg == g_active_menu) ? 0x00 : 0xFF; + int sx = menu_slot[seg] * SEG_W; + const uint8_t (*icon)[ICON_W] = (seg == MENU_CMDR && g_ble_enabled) ? icon_net : icons[seg]; + for (int col = 0; col < ICON_W; col++) { + pages[0][sx+col] = bg ^ icon[0][col]; + pages[1][sx+col] = bg ^ icon[1][col]; + } + } + for (int p = 0; p < HEADER_PAGES; p++) oled_write_page(p, pages[p]); +} + +void oled_draw_centered(const char *str) +{ + int len = strlen(str); + int start = (OLED_WIDTH - len * CHAR_WIDTH) / 2; + if (start < 0) start = 0; + for (int p = HEADER_PAGES; p < OLED_PAGES; p++) { + uint8_t row[OLED_WIDTH]; memset(row, 0, sizeof(row)); + if (p >= START_PAGE && p < START_PAGE + CHAR_PAGES) { + int char_page = p - START_PAGE; + for (int i = 0; i < len; i++) { + char c = str[i]; + if (c < FONT_BASE || c > FONT_MAX) c = ' '; + const uint8_t *glyph = font5x8[(uint8_t)c - FONT_BASE]; + int col = start + i * CHAR_WIDTH; + for (int sc = 0; sc < 5*SCALE; sc++) { + int x = col + sc; + if (x < 0 || x >= OLED_WIDTH) continue; + uint8_t font_col = glyph[sc/SCALE]; + uint8_t pixel_byte = 0; + for (int b = 0; b < 8; b++) { + int src_row = (char_page*8+b)/SCALE; + if (src_row < 8 && ((font_col >> src_row) & 1)) pixel_byte |= (1<= base && 8*p+r < base+h) mask |= (1< FONT_MAX) c = ' '; + const uint8_t *glyph = font5x8[c - FONT_BASE]; + for (int sc = 0; sc < 5; sc++, x++) { + for (int g = 0; g < 8; g++) { + if ((glyph[sc] >> g) & 1) { + int row = base + 1 + g; + if (row < content_h) { + if (inv) pages[row/8][x] &= ~(1 << (row%8)); + else pages[row/8][x] |= (1 << (row%8)); + } + } + } + } + x++; + } + return x; +} + +// ── Core list renderer ──────────────────────────────────────────────────────── + +void oled_draw_rows(const oled_row_t *rows, int count, int active) +{ + const int content_h = (OLED_PAGES - HEADER_PAGES) * 8; + const int entry_h = 9; + const int max_full = content_h / entry_h; + + int start = active - max_full / 2; + if (start < 0) start = 0; + if (start + max_full > count) start = count - max_full; + if (start < 0) start = 0; + + uint8_t pages[OLED_PAGES - HEADER_PAGES][OLED_WIDTH]; + memset(pages, 0, sizeof(pages)); + + for (int ei = 0; ei < max_full+1 && (start+ei) < count; ei++) { + int entry = start + ei; + int inv = (entry == active); + int base = ei * entry_h; + + if (inv) pxbuf_fill(pages, content_h, base, entry_h); + + if (rows[entry].label && rows[entry].label[0]) + pxbuf_str(pages, content_h, base, 2, rows[entry].label, inv); + + if (rows[entry].value[0]) { + int vlen = (int)strlen(rows[entry].value); + int rx = OLED_WIDTH - 2 - vlen*6; + if (rx < 0) rx = 0; + pxbuf_str(pages, content_h, base, rx, rows[entry].value, inv); + + if (inv && rows[entry].cursor >= 0 && rows[entry].cursor < vlen) { + int cursor_x = rx + rows[entry].cursor * 6; + for (int p = base/8; p <= (base+entry_h-1)/8 && p < content_h/8; p++) { + uint8_t mask = row_mask(p, base, entry_h); + for (int j = 0; j < 6 && cursor_x+j < OLED_WIDTH; j++) + pages[p][cursor_x+j] &= ~mask; + } + char one[2] = { rows[entry].value[rows[entry].cursor], 0 }; + pxbuf_str(pages, content_h, base, cursor_x, one, 0); + } + } + } + + for (int p = 0; p < OLED_PAGES - HEADER_PAGES; p++) + oled_write_page(HEADER_PAGES + p, pages[p]); +} + +// ── Menu draw functions (thin wrappers that build rows and call oled_draw_rows) ── + +void oled_draw_list(const char **labels, const int *values, int count, int active) +{ + oled_row_t rows[8]; + int n = count < 8 ? count : 8; + for (int i = 0; i < n; i++) { + rows[i].label = labels[i]; + rows[i].cursor = -1; + snprintf(rows[i].value, sizeof(rows[i].value), "%d", values[i]); + } + oled_draw_rows(rows, n, active); +} + +void oled_draw_players(void) +{ + int total = MAX_BLE_PEERS + 1 + (!g_ble_enabled ? 1 : 0); + oled_row_t rows[MAX_BLE_PEERS + 2]; + + rows[0].label = g_player_name; + rows[0].cursor = -1; + snprintf(rows[0].value, sizeof(rows[0].value), + g_eliminated ? "ELIM" : "%d/%d", g_life, g_counters[0]); + + for (int pi = 0; pi < MAX_BLE_PEERS; pi++) { + rows[pi+1].cursor = -1; + if (g_peers[pi].active) { + rows[pi+1].label = g_peers[pi].name; + snprintf(rows[pi+1].value, sizeof(rows[pi+1].value), + g_peers[pi].eliminated ? "ELIM" : "%d/%d/%d", + g_peers[pi].life, g_peers[pi].poison, g_cmdr_damage[pi]); + } else { + rows[pi+1].label = ""; + rows[pi+1].value[0] = 0; + } + } + + if (!g_ble_enabled) { + rows[MAX_BLE_PEERS+1].label = "BLE OFF"; + rows[MAX_BLE_PEERS+1].value[0] = 0; + rows[MAX_BLE_PEERS+1].cursor = -1; + } + + oled_draw_rows(rows, total, g_active_player); +} + +void oled_draw_settings(void) +{ + oled_row_t rows[NUM_SETTINGS]; + for (int i = 0; i < NUM_SETTINGS; i++) { + rows[i].label = setting_names[i]; + rows[i].cursor = -1; + } + snprintf(rows[SET_BRIGHTNESS].value, sizeof(rows[0].value), "%d%%", g_brightness_pct); + snprintf(rows[SET_START_LIFE].value, sizeof(rows[0].value), "%d", start_life_opts[g_start_life_index]); + snprintf(rows[SET_NUM_OPP].value, sizeof(rows[0].value), "%d", g_num_opponents); + memcpy(rows[SET_PLAYER_NAME].value, g_player_name, PLAYER_NAME_LEN); + rows[SET_PLAYER_NAME].value[PLAYER_NAME_LEN] = 0; + rows[SET_PLAYER_NAME].cursor = g_name_cursor; + snprintf(rows[SET_BLE].value, sizeof(rows[0].value), "%s", g_ble_enabled ? "ON" : "OFF"); + snprintf(rows[SET_GAME_ID].value, sizeof(rows[0].value), "%02X%02X", g_game_id[0], g_game_id[1]); + rows[SET_GAME_ID].cursor = g_game_id_cursor; + snprintf(rows[SET_RESET].value, sizeof(rows[0].value), "---"); + snprintf(rows[SET_RESET_ALL].value, sizeof(rows[0].value), "---"); + oled_draw_rows(rows, NUM_SETTINGS, g_active_setting); +} diff --git a/main/draw.h b/main/draw.h new file mode 100644 index 0000000..5a4f359 --- /dev/null +++ b/main/draw.h @@ -0,0 +1,19 @@ +#pragma once +#include + +typedef struct { + const char *label; // left-aligned; NULL or empty = blank row + char value[16]; // right-aligned formatted string; empty = omit + int cursor; // index into value for edit cursor indicator; -1 = none +} oled_row_t; + +void led_init(void); +void led_update_for_count(int count, uint8_t scale); +void oled_init(void); +void oled_clear(void); +void oled_draw_header(void); +void oled_draw_centered(const char *str); +void oled_draw_rows(const oled_row_t *rows, int count, int active); +void oled_draw_list(const char **labels, const int *values, int count, int active); +void oled_draw_players(void); +void oled_draw_settings(void); diff --git a/main/font.h b/main/font.h new file mode 100644 index 0000000..31821d9 --- /dev/null +++ b/main/font.h @@ -0,0 +1,86 @@ +#pragma once +#include +#include "config.h" + +static const uint8_t font5x8[][5] = { + {0x00,0x00,0x00,0x00,0x00}, // ' ' + {0x00,0x00,0x5F,0x00,0x00}, // '!' + {0x00,0x07,0x00,0x07,0x00}, // '"' + {0x14,0x7F,0x14,0x7F,0x14}, // '#' + {0x24,0x2A,0x7F,0x2A,0x12}, // '$' + {0x23,0x13,0x08,0x64,0x62}, // '%' + {0x36,0x49,0x55,0x22,0x50}, // '&' + {0x00,0x05,0x03,0x00,0x00}, // '\'' + {0x00,0x1C,0x22,0x41,0x00}, // '(' + {0x00,0x41,0x22,0x1C,0x00}, // ')' + {0x14,0x08,0x3E,0x08,0x14}, // '*' + {0x08,0x08,0x3E,0x08,0x08}, // '+' + {0x00,0x50,0x30,0x00,0x00}, // ',' + {0x08,0x08,0x08,0x08,0x08}, // '-' + {0x00,0x60,0x60,0x00,0x00}, // '.' + {0x20,0x10,0x08,0x04,0x02}, // '/' + {0x3E,0x51,0x49,0x45,0x3E}, // '0' + {0x00,0x42,0x7F,0x40,0x00}, // '1' + {0x72,0x49,0x49,0x49,0x46}, // '2' + {0x21,0x41,0x49,0x4D,0x33}, // '3' + {0x18,0x14,0x12,0x7F,0x10}, // '4' + {0x27,0x45,0x45,0x45,0x39}, // '5' + {0x3C,0x4A,0x49,0x49,0x31}, // '6' + {0x41,0x21,0x11,0x09,0x07}, // '7' + {0x36,0x49,0x49,0x49,0x36}, // '8' + {0x46,0x49,0x49,0x29,0x1E}, // '9' + {0x00,0x36,0x36,0x00,0x00}, // ':' + {0x00,0x56,0x36,0x00,0x00}, // ';' + {0x08,0x14,0x22,0x41,0x00}, // '<' + {0x14,0x14,0x14,0x14,0x14}, // '=' + {0x00,0x41,0x22,0x14,0x08}, // '>' + {0x02,0x01,0x51,0x09,0x06}, // '?' + {0x32,0x49,0x79,0x41,0x3E}, // '@' + {0x7E,0x11,0x11,0x11,0x7E}, // 'A' + {0x7F,0x49,0x49,0x49,0x36}, // 'B' + {0x3E,0x41,0x41,0x41,0x22}, // 'C' + {0x7F,0x41,0x41,0x22,0x1C}, // 'D' + {0x7F,0x49,0x49,0x49,0x41}, // 'E' + {0x7F,0x09,0x09,0x09,0x01}, // 'F' + {0x3E,0x41,0x49,0x49,0x7A}, // 'G' + {0x7F,0x08,0x08,0x08,0x7F}, // 'H' + {0x00,0x41,0x7F,0x41,0x00}, // 'I' + {0x20,0x40,0x41,0x3F,0x01}, // 'J' + {0x7F,0x08,0x14,0x22,0x41}, // 'K' + {0x7F,0x40,0x40,0x40,0x40}, // 'L' + {0x7F,0x02,0x04,0x02,0x7F}, // 'M' + {0x7F,0x04,0x08,0x10,0x7F}, // 'N' + {0x3E,0x41,0x41,0x41,0x3E}, // 'O' + {0x7F,0x09,0x09,0x09,0x06}, // 'P' + {0x3E,0x41,0x51,0x21,0x5E}, // 'Q' + {0x7F,0x09,0x19,0x29,0x46}, // 'R' + {0x46,0x49,0x49,0x49,0x31}, // 'S' + {0x01,0x01,0x7F,0x01,0x01}, // 'T' + {0x3F,0x40,0x40,0x40,0x3F}, // 'U' + {0x1F,0x20,0x40,0x20,0x1F}, // 'V' + {0x3F,0x40,0x38,0x40,0x3F}, // 'W' + {0x63,0x14,0x08,0x14,0x63}, // 'X' + {0x07,0x08,0x70,0x08,0x07}, // 'Y' + {0x61,0x51,0x49,0x45,0x43}, // 'Z' +}; + +static const uint8_t icons[NUM_MENUS][2][ICON_W] = { + // Heart (life) + { {0x00,0x70,0xF8,0xFC,0xFC,0xFC,0xF8,0xF0,0xF0,0xF8,0xFC,0xFC,0xFC,0xF8,0x70,0x00}, + {0x00,0x00,0x00,0x01,0x03,0x07,0x0F,0x3F,0x3F,0x0F,0x07,0x03,0x01,0x00,0x00,0x00} }, + // Shield (commander damage) + { {0x00,0xFC,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFC,0x00,0x00}, + {0x00,0x07,0x0F,0x1F,0x3F,0x3F,0x3F,0x7F,0x7F,0x3F,0x3F,0x1F,0x0F,0x07,0x00,0x00} }, + // Plus (counters) + { {0x00,0x00,0x00,0xC0,0xC0,0xC0,0xF8,0xF8,0xF8,0xF8,0xC0,0xC0,0xC0,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x03,0x03,0x03,0x1F,0x1F,0x1F,0x1F,0x03,0x03,0x03,0x00,0x00,0x00} }, + // Cog (settings) + { {0x00,0x80,0xDC,0xFC,0xFC,0xB8,0x9C,0xFE,0xFE,0x9C,0xB8,0xFC,0xFC,0xDC,0x80,0x00}, + {0x00,0x01,0x3B,0x3F,0x3F,0x1D,0x39,0x7F,0x7F,0x39,0x1D,0x3F,0x3F,0x3B,0x01,0x00} }, +}; + +// Signal bars shown on MENU_CMDR slot when BLE is enabled +static const uint8_t icon_net[2][ICON_W] = { + {0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x00,0xF8,0xF8,0x00,0xFE,0xFE,0x00,0x00}, + {0x00,0x00,0x00,0x38,0x38,0x00,0x3F,0x3F,0x00,0x3F,0x3F,0x00,0x3F,0x3F,0x00,0x00}, +}; diff --git a/main/game.c b/main/game.c new file mode 100644 index 0000000..f8e7ead --- /dev/null +++ b/main/game.c @@ -0,0 +1,97 @@ +#include "game.h" +#include "config.h" +#include "state.h" +#include "ble.h" +#include "nvs.h" +#include "esp_err.h" +#include +#include + +const int start_life_opts[] = {20, 30, 40}; +const char NAME_CHARS[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; +const char *counter_names[NUM_COUNTERS] = {"POISON", "EXPERIENCE", "ENERGY", "LORE"}; + +void settings_reset_defaults(void) +{ + g_brightness_pct = 10; + g_start_life_index = 2; + g_num_opponents = 3; + strncpy(g_player_name, "PLAYER 1", PLAYER_NAME_LEN); + g_player_name[PLAYER_NAME_LEN] = '\0'; + g_ble_enabled = 0; + g_led_max = 26; + g_game_id[0] = BLE_GAME_ID_0; + g_game_id[1] = BLE_GAME_ID_1; +} + +void game_reset(void) +{ + g_life = start_life_opts[g_start_life_index]; + g_eliminated = 0; + memset(g_cmdr_damage, 0, sizeof(g_cmdr_damage)); + memset(g_counters, 0, sizeof(g_counters)); +} + +void check_elimination(void) +{ + if (g_eliminated) return; + if (g_life <= 0 || g_counters[0] >= 10) { g_eliminated = 1; return; } + for (int i = 0; i < g_num_opponents; i++) + if (g_cmdr_damage[i] >= 21) { g_eliminated = 1; return; } +} + +void settings_load(void) +{ + nvs_handle_t nvs; + if (nvs_open(NVS_NS, NVS_READONLY, &nvs) != ESP_OK) return; + int32_t val; + if (nvs_get_i32(nvs, "brightness", &val) == ESP_OK) g_brightness_pct = (int)val; + if (nvs_get_i32(nvs, "start_life", &val) == ESP_OK) g_start_life_index = (int)val; + if (nvs_get_i32(nvs, "num_opp", &val) == ESP_OK) g_num_opponents = (int)val; + if (nvs_get_i32(nvs, "ble_en", &val) == ESP_OK) g_ble_enabled = (int)val; + if (nvs_get_i32(nvs, "game_id", &val) == ESP_OK) { + g_game_id[0] = (uint8_t)((val >> 8) & 0xFF); + g_game_id[1] = (uint8_t)(val & 0xFF); + } + size_t len = sizeof(g_player_name); + nvs_get_str(nvs, "pname", g_player_name, &len); + if (nvs_get_i32(nvs, "player_id", &val) == ESP_OK) g_player_id = (uint8_t)val; + if (nvs_get_i32(nvs, "life", &val) == ESP_OK) g_life = (int)val; + if (nvs_get_i32(nvs, "elim", &val) == ESP_OK) g_eliminated = (int)val; + char key[8]; + for (int i = 0; i < MAX_OPPONENTS; i++) { + snprintf(key, sizeof(key), "cmdr%d", i); + if (nvs_get_i32(nvs, key, &val) == ESP_OK) g_cmdr_damage[i] = (int)val; + } + for (int i = 0; i < NUM_COUNTERS; i++) { + snprintf(key, sizeof(key), "cnt%d", i); + if (nvs_get_i32(nvs, key, &val) == ESP_OK) g_counters[i] = (int)val; + } + nvs_close(nvs); +} + +void settings_save(void) +{ + nvs_handle_t nvs; + if (nvs_open(NVS_NS, NVS_READWRITE, &nvs) != ESP_OK) return; + nvs_set_i32(nvs, "brightness", (int32_t)g_brightness_pct); + nvs_set_i32(nvs, "start_life", (int32_t)g_start_life_index); + nvs_set_i32(nvs, "num_opp", (int32_t)g_num_opponents); + nvs_set_i32(nvs, "ble_en", (int32_t)g_ble_enabled); + nvs_set_i32(nvs, "game_id", (int32_t)((g_game_id[0] << 8) | g_game_id[1])); + nvs_set_str(nvs, "pname", g_player_name); + nvs_set_i32(nvs, "player_id", (int32_t)g_player_id); + nvs_set_i32(nvs, "life", (int32_t)g_life); + nvs_set_i32(nvs, "elim", (int32_t)g_eliminated); + char key[8]; + for (int i = 0; i < MAX_OPPONENTS; i++) { + snprintf(key, sizeof(key), "cmdr%d", i); + nvs_set_i32(nvs, key, (int32_t)g_cmdr_damage[i]); + } + for (int i = 0; i < NUM_COUNTERS; i++) { + snprintf(key, sizeof(key), "cnt%d", i); + nvs_set_i32(nvs, key, (int32_t)g_counters[i]); + } + nvs_commit(nvs); + nvs_close(nvs); +} diff --git a/main/game.h b/main/game.h new file mode 100644 index 0000000..f68a44e --- /dev/null +++ b/main/game.h @@ -0,0 +1,12 @@ +#pragma once +#include "config.h" + +extern const int start_life_opts[]; +extern const char NAME_CHARS[]; +extern const char *counter_names[NUM_COUNTERS]; + +void settings_reset_defaults(void); +void game_reset(void); +void check_elimination(void); +void settings_load(void); +void settings_save(void); diff --git a/main/main.c b/main/main.c new file mode 100644 index 0000000..0136d03 --- /dev/null +++ b/main/main.c @@ -0,0 +1,464 @@ +#include "config.h" +#include "state.h" +#include "game.h" +#include "draw.h" +#include "ble.h" +#include "driver/gpio.h" +#include "driver/i2c.h" +#include "driver/uart.h" +#include "esp_vfs_dev.h" +#include "nvs_flash.h" +#include "nvs.h" +#include "esp_err.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include +#include +#include + +// ── Global state ────────────────────────────────────────────────────────────── +// Game +int g_life; +int g_cmdr_damage[MAX_OPPONENTS]; +int g_counters[NUM_COUNTERS]; +int g_eliminated; + +// UI +int g_active_menu; +int g_active_opponent; +int g_active_counter; +int g_active_player; +int g_active_setting; +int g_name_cursor; + +// Settings +int g_brightness_pct = 10; +int g_start_life_index = 2; // 40 +int g_num_opponents = 3; +char g_player_name[PLAYER_NAME_LEN + 1] = "PLAYER 1"; +int g_ble_enabled = 0; +uint8_t g_led_max = 26; +int g_game_id_cursor = 0; +uint8_t g_game_id[2] = {BLE_GAME_ID_0, BLE_GAME_ID_1}; + +// Peers +ble_peer_t g_peers[MAX_BLE_PEERS]; + +// Timing +uint32_t g_tick; + +// ── Serial command task ─────────────────────────────────────────────────────── +static void serial_print_state(void) +{ + printf("DBG STATE life=%d poison=%u cmdr=[%d,%d,%d,%d] counters=[%d,%d,%d] menu=%d ble=%d pid=%u eliminated=%d\n", + g_life, (unsigned)g_counters[0], + g_cmdr_damage[0], g_cmdr_damage[1], g_cmdr_damage[2], g_cmdr_damage[3], + g_counters[0], g_counters[1], g_counters[2], + g_active_menu, g_ble_enabled, (unsigned)g_player_id, g_eliminated); + fflush(stdout); +} + +static void serial_cmd_task(void *arg) +{ + (void)arg; + char buf[64]; + int pos = 0; + for (;;) { + int c = fgetc(stdin); + if (c < 0) { vTaskDelay(pdMS_TO_TICKS(10)); continue; } + if (c == '\n' || c == '\r') { + if (pos > 0) { + buf[pos] = '\0'; + pos = 0; + int val = 0; + if (strncmp(buf, "SET ", 4) == 0) { + const char *kv = buf + 4; + if (sscanf(kv, "life=%d", &val) == 1) { + g_life = val; check_elimination(); + } + if (sscanf(kv, "ble=%d", &val) == 1) { + g_ble_enabled = val ? 1 : 0; + } + { + char fmt[14]; + for (int i = 0; i < MAX_OPPONENTS; i++) { + snprintf(fmt, sizeof(fmt), "cmdr%d=%%d", i); + if (sscanf(kv, fmt, &val) == 1) { + g_cmdr_damage[i] = val < 0 ? 0 : val; check_elimination(); break; + } + } + for (int i = 0; i < NUM_COUNTERS; i++) { + snprintf(fmt, sizeof(fmt), "counter%d=%%d", i); + if (sscanf(kv, fmt, &val) == 1) { + g_counters[i] = val < 0 ? 0 : val; check_elimination(); break; + } + } + } + ble_adv_update(); + serial_print_state(); + } else if (strcmp(buf, "RESET") == 0) { + game_reset(); + ble_adv_update(); + serial_print_state(); + } else if (strcmp(buf, "CLEARNVS") == 0) { + nvs_handle_t nvs; + if (nvs_open(NVS_NS, NVS_READWRITE, &nvs) == ESP_OK) { + nvs_erase_all(nvs); + nvs_commit(nvs); + nvs_close(nvs); + } + settings_reset_defaults(); + game_reset(); + ble_adv_update(); + serial_print_state(); + } else if (strcmp(buf, "STATE") == 0) { + serial_print_state(); + } + } + } else if (pos < (int)sizeof(buf) - 1) { + buf[pos++] = (char)c; + } + } +} + +// ── app_main ────────────────────────────────────────────────────────────────── +void app_main(void) +{ + led_init(); + + i2c_config_t i2c_cfg = { + .mode=I2C_MODE_MASTER, .sda_io_num=I2C_SDA_GPIO, .scl_io_num=I2C_SCL_GPIO, + .sda_pullup_en=GPIO_PULLUP_ENABLE, .scl_pullup_en=GPIO_PULLUP_ENABLE, + .master.clk_speed=I2C_FREQ_HZ, + }; + ESP_ERROR_CHECK(i2c_param_config(I2C_PORT, &i2c_cfg)); + ESP_ERROR_CHECK(i2c_driver_install(I2C_PORT, I2C_MODE_MASTER, 0, 0, 0)); + + esp_err_t nvs_err = nvs_flash_init(); + if (nvs_err == ESP_ERR_NVS_NO_FREE_PAGES || nvs_err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + nvs_flash_erase(); nvs_flash_init(); + } + g_life = start_life_opts[g_start_life_index]; + settings_load(); + g_led_max = (uint8_t)(255 * g_brightness_pct / 100); + + oled_init(); + oled_clear(); + + gpio_config_t gpio_cfg = { + .pin_bit_mask = (1ULL<= MID_HOLD_MENU) { + if (g_active_menu == MENU_SETTINGS) { + g_active_menu = 0; + } else { + g_active_menu = (g_active_menu + 1) % (NUM_MENUS - 1); + } + hold_right = hold_left = players_tick = 0; + oled_draw_header(); + changed = 1; + } else if (g_active_menu == MENU_SETTINGS) { + if (g_active_setting == SET_PLAYER_NAME) { + g_name_cursor++; + if (g_name_cursor >= PLAYER_NAME_LEN) { + g_name_cursor = 0; + g_active_setting = (g_active_setting + 1) % NUM_SETTINGS; + g_game_id_cursor = 0; + } + } else if (g_active_setting == SET_GAME_ID) { + g_game_id_cursor++; + if (g_game_id_cursor >= GAME_ID_DIGITS) { + g_game_id_cursor = 0; + g_active_setting = (g_active_setting + 1) % NUM_SETTINGS; + } + } else { + g_active_setting = (g_active_setting + 1) % NUM_SETTINGS; + g_name_cursor = 0; + g_game_id_cursor = 0; + } + changed = 1; + } else if (g_active_menu == MENU_CMDR) { + if (g_ble_enabled) { + int next = (g_active_player + 1) % (MAX_BLE_PEERS + 1); + while (next != g_active_player && next != 0 && !g_peers[next - 1].active) + next = (next + 1) % (MAX_BLE_PEERS + 1); + g_active_player = next; + } else { + g_active_opponent = (g_active_opponent + 1) % g_num_opponents; + } + changed = 1; + } else if (g_active_menu == MENU_COUNTERS) { + g_active_counter = (g_active_counter + 1) % NUM_COUNTERS; + changed = 1; + } + } + hold_mid = 0; mid_fired_hold = 0; + } + + // ── Left / Right ───────────────────────────────────────────────────── + int delta_r=0, delta_l=0; + if (right==0) { + if (prev_right==1) { + delta_r=1; hold_right=0; + hold_armed_r = (release_r >= 2); + release_r = 0; + } else if (hold_armed_r && ++hold_right>=HOLD_DELAY && (hold_right-HOLD_DELAY)%HOLD_REPEAT==0) { + delta_r=1; + } + } else { hold_right=0; if (release_r < 2) release_r++; } + if (left==0) { + if (prev_left==1) { + delta_l=1; hold_left=0; + hold_armed_l = (release_l >= 2); + release_l = 0; + } else if (hold_armed_l && ++hold_left>=HOLD_DELAY && (hold_left-HOLD_DELAY)%HOLD_REPEAT==0) { + delta_l=1; + } + } else { hold_left=0; if (release_l < 2) release_l++; } + + if (delta_r || delta_l) { + int d = delta_r - delta_l; + if (g_active_menu == MENU_LIFE) { + g_life += d; changed = 1; MARK_DIRTY(); check_elimination(); + } else if (g_active_menu == MENU_CMDR) { + if (g_ble_enabled) { + if (g_active_player == 0) { + g_life += d; check_elimination(); + } else { + int slot = g_active_player - 1; + g_cmdr_damage[slot] += d; + if (g_cmdr_damage[slot] < 0) g_cmdr_damage[slot] = 0; + check_elimination(); + } + } else { + g_cmdr_damage[g_active_opponent] += d; + if (g_cmdr_damage[g_active_opponent] < 0) g_cmdr_damage[g_active_opponent] = 0; + check_elimination(); + } + changed = 1; MARK_DIRTY(); + } else if (g_active_menu == MENU_COUNTERS) { + g_counters[g_active_counter] += d; + if (g_counters[g_active_counter] < 0) g_counters[g_active_counter] = 0; + changed = 1; MARK_DIRTY(); check_elimination(); + } else if (g_active_menu == MENU_SETTINGS) { + changed = 1; MARK_DIRTY(); + switch (g_active_setting) { + case SET_BRIGHTNESS: + g_brightness_pct += d; + if (g_brightness_pct < BRIGHTNESS_MIN) g_brightness_pct = BRIGHTNESS_MIN; + if (g_brightness_pct > BRIGHTNESS_MAX) g_brightness_pct = BRIGHTNESS_MAX; + g_led_max = (uint8_t)(255 * g_brightness_pct / 100); + break; + case SET_START_LIFE: + g_start_life_index += d; + if (g_start_life_index < 0) g_start_life_index = 0; + if (g_start_life_index >= NUM_LIFE_OPTS) g_start_life_index = NUM_LIFE_OPTS-1; + break; + case SET_NUM_OPP: + g_num_opponents += d; + if (g_num_opponents < 1) g_num_opponents = 1; + if (g_num_opponents > MAX_OPPONENTS) g_num_opponents = MAX_OPPONENTS; + if (g_active_opponent >= g_num_opponents) g_active_opponent = 0; + break; + case SET_PLAYER_NAME: { + char curr = g_player_name[g_name_cursor]; + const char *pos = strchr(NAME_CHARS, curr); + int idx = pos ? (int)(pos - NAME_CHARS) : 0; + idx = (idx + d + NUM_NAME_CHARS) % NUM_NAME_CHARS; + g_player_name[g_name_cursor] = NAME_CHARS[idx]; + break; + } + case SET_BLE: + g_ble_enabled += d; + if (g_ble_enabled < 0) g_ble_enabled = 0; + if (g_ble_enabled > 1) g_ble_enabled = 1; + ble_adv_update(); + oled_draw_header(); + break; + case SET_GAME_ID: { + int byte = g_game_id_cursor / 2; + int nibble = g_game_id_cursor % 2; + int val = nibble == 0 ? (g_game_id[byte] >> 4) & 0xF : g_game_id[byte] & 0xF; + val = (val + d + NUM_HEX_CHARS) % NUM_HEX_CHARS; + if (nibble == 0) + g_game_id[byte] = (g_game_id[byte] & 0x0F) | ((uint8_t)val << 4); + else + g_game_id[byte] = (g_game_id[byte] & 0xF0) | (uint8_t)val; + ble_adv_update(); + break; + } + case SET_RESET: + game_reset(); + ble_adv_update(); + break; + case SET_RESET_ALL: + game_reset(); + g_reset_cmd_ticks = 1500; + ble_adv_update(); + break; + } + } + } + + // ── Remote reset command ────────────────────────────────────────────── + if (g_reset_requested) { + g_reset_requested = 0; + game_reset(); + MARK_DIRTY(); + changed = 1; + ble_adv_update(); + } + + // ── reset_cmd broadcast countdown ──────────────────────────────────── + if (g_reset_cmd_ticks > 0 && --g_reset_cmd_ticks == 0) ble_adv_update(); + + // ── Peer expiry + player ID resolution ─────────────────────────────── + if (g_tick % 100 == 0) { + for (int i = 0; i < MAX_BLE_PEERS; i++) { + if (g_peers[i].active && g_tick - g_peers[i].last_seen > BLE_PEER_TIMEOUT) { +#ifdef DEBUG + printf("DBG PEER_EXPIRE slot=%d name=%-8.8s\n", i, g_peers[i].name); + fflush(stdout); +#endif + g_peers[i].active = 0; + } + } + player_id_resolve(); + } + + // ── Autosave settings ───────────────────────────────────────────────── + if (settings_dirty && ++settings_save_tick >= SAVE_DELAY) { + settings_save(); settings_dirty = 0; settings_save_tick = 0; + } + + // ── BLE adv update on game state change ─────────────────────────────── + if (changed && (g_active_menu==MENU_LIFE || g_active_menu==MENU_COUNTERS || + g_active_menu==MENU_CMDR)) { + ble_adv_update(); + } + + // ── Players periodic refresh ────────────────────────────────────────── + if (g_active_menu == MENU_CMDR && g_ble_enabled) { + if (++players_tick >= 100) { + players_tick = 0; oled_draw_players(); + } + } else { players_tick = 0; } + + // ── LED ─────────────────────────────────────────────────────────────── + if (g_life == 0) { + led_update_for_count(0, 255); + } else if (g_life < 10) { + float speed = 1.0f + (10.0f - g_life) / 9.0f * 2.0f; + breath_phase += 2.0f * 3.14159265f * speed / 200.0f; + uint8_t sc = (uint8_t)(127.5f + 127.5f * sinf(breath_phase)); + led_update_for_count(g_life, sc); + } else if (changed) { + led_update_for_count(g_life, 255); + } + + // ── Display dispatch ────────────────────────────────────────────────── + if (changed) { + switch (g_active_menu) { + case MENU_LIFE: + snprintf(nbuf, sizeof(nbuf), "%d", g_life); + oled_draw_centered(nbuf); + break; + case MENU_CMDR: + for (int i = 0; i < g_num_opponents; i++) { + int found = 0; + if (g_ble_enabled) { + for (int j = 0; j < MAX_BLE_PEERS; j++) { + if (g_peers[j].active && g_peers[j].player_id == (uint8_t)i) { + snprintf(opponent_labels[i], sizeof(opponent_labels[i]), "%.4s", g_peers[j].name); + found = 1; + break; + } + } + } + if (!found) + snprintf(opponent_labels[i], sizeof(opponent_labels[i]), "CMD %d", i+1); + opponent_label_ptrs[i] = opponent_labels[i]; + } + if (!g_ble_enabled) + oled_draw_list(opponent_label_ptrs, g_cmdr_damage, g_num_opponents, g_active_opponent); + else + oled_draw_players(); + break; + case MENU_COUNTERS: + oled_draw_list(counter_names, g_counters, NUM_COUNTERS, g_active_counter); + break; + case MENU_SETTINGS: + oled_draw_settings(); + break; + } + } + +#ifdef DEBUG + if (changed || g_tick % 1000 == 0) + serial_print_state(); +#endif + + prev_right = right; prev_left = left; prev_mid = mid; + vTaskDelay(pdMS_TO_TICKS(10)); + } +} diff --git a/main/state.h b/main/state.h new file mode 100644 index 0000000..4732762 --- /dev/null +++ b/main/state.h @@ -0,0 +1,33 @@ +#pragma once +#include "config.h" +#include "ble.h" + +// Game +extern int g_life; +extern int g_cmdr_damage[MAX_OPPONENTS]; +extern int g_counters[NUM_COUNTERS]; +extern int g_eliminated; + +// UI +extern int g_active_menu; +extern int g_active_opponent; +extern int g_active_counter; +extern int g_active_player; +extern int g_active_setting; +extern int g_name_cursor; + +// Settings +extern int g_brightness_pct; +extern int g_start_life_index; +extern int g_num_opponents; +extern char g_player_name[PLAYER_NAME_LEN + 1]; +extern int g_ble_enabled; +extern uint8_t g_led_max; +extern int g_game_id_cursor; +extern uint8_t g_game_id[2]; + +// Peers +extern ble_peer_t g_peers[MAX_BLE_PEERS]; + +// Timing +extern uint32_t g_tick; diff --git a/pcb/commeownder.kicad_pcb b/pcb/commeownder.kicad_pcb new file mode 100644 index 0000000..ccd82d6 --- /dev/null +++ b/pcb/commeownder.kicad_pcb @@ -0,0 +1,2 @@ +(kicad_pcb (version 20260206) (generator "pcbnew") (generator_version "10.0") +) \ No newline at end of file diff --git a/pcb/commeownder.kicad_pro b/pcb/commeownder.kicad_pro new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/pcb/commeownder.kicad_pro @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/pcb/commeownder.kicad_sch b/pcb/commeownder.kicad_sch new file mode 100644 index 0000000..b874060 --- /dev/null +++ b/pcb/commeownder.kicad_sch @@ -0,0 +1,14 @@ +(kicad_sch + (version 20260306) + (generator "eeschema") + (generator_version "10.0") + (uuid 4f1ddaab-5ed8-4280-ae9f-5da3efc5b3b5) + (paper "A4") + (lib_symbols) + (sheet_instances + (path "/" + (page "1") + ) + ) + (embedded_fonts no) +) \ No newline at end of file diff --git a/sdkconfig b/sdkconfig new file mode 100644 index 0000000..d83e06e --- /dev/null +++ b/sdkconfig @@ -0,0 +1,2010 @@ +# +# Automatically generated file. DO NOT EDIT. +# Espressif IoT Development Framework (ESP-IDF) 5.1.2 Project Configuration +# +CONFIG_SOC_BROWNOUT_RESET_SUPPORTED="Not determined" +CONFIG_SOC_TWAI_BRP_DIV_SUPPORTED="Not determined" +CONFIG_SOC_DPORT_WORKAROUND="Not determined" +CONFIG_SOC_CAPS_ECO_VER_MAX=301 +CONFIG_SOC_ADC_SUPPORTED=y +CONFIG_SOC_DAC_SUPPORTED=y +CONFIG_SOC_UART_SUPPORTED=y +CONFIG_SOC_MCPWM_SUPPORTED=y +CONFIG_SOC_GPTIMER_SUPPORTED=y +CONFIG_SOC_SDMMC_HOST_SUPPORTED=y +CONFIG_SOC_BT_SUPPORTED=y +CONFIG_SOC_PCNT_SUPPORTED=y +CONFIG_SOC_WIFI_SUPPORTED=y +CONFIG_SOC_SDIO_SLAVE_SUPPORTED=y +CONFIG_SOC_TWAI_SUPPORTED=y +CONFIG_SOC_EMAC_SUPPORTED=y +CONFIG_SOC_ULP_SUPPORTED=y +CONFIG_SOC_CCOMP_TIMER_SUPPORTED=y +CONFIG_SOC_RTC_FAST_MEM_SUPPORTED=y +CONFIG_SOC_RTC_SLOW_MEM_SUPPORTED=y +CONFIG_SOC_RTC_MEM_SUPPORTED=y +CONFIG_SOC_I2S_SUPPORTED=y +CONFIG_SOC_RMT_SUPPORTED=y +CONFIG_SOC_SDM_SUPPORTED=y +CONFIG_SOC_GPSPI_SUPPORTED=y +CONFIG_SOC_LEDC_SUPPORTED=y +CONFIG_SOC_I2C_SUPPORTED=y +CONFIG_SOC_SUPPORT_COEXISTENCE=y +CONFIG_SOC_AES_SUPPORTED=y +CONFIG_SOC_MPI_SUPPORTED=y +CONFIG_SOC_SHA_SUPPORTED=y +CONFIG_SOC_FLASH_ENC_SUPPORTED=y +CONFIG_SOC_SECURE_BOOT_SUPPORTED=y +CONFIG_SOC_TOUCH_SENSOR_SUPPORTED=y +CONFIG_SOC_BOD_SUPPORTED=y +CONFIG_SOC_ULP_FSM_SUPPORTED=y +CONFIG_SOC_DPORT_WORKAROUND_DIS_INTERRUPT_LVL=5 +CONFIG_SOC_XTAL_SUPPORT_26M=y +CONFIG_SOC_XTAL_SUPPORT_40M=y +CONFIG_SOC_XTAL_SUPPORT_AUTO_DETECT=y +CONFIG_SOC_ADC_RTC_CTRL_SUPPORTED=y +CONFIG_SOC_ADC_DIG_CTRL_SUPPORTED=y +CONFIG_SOC_ADC_DMA_SUPPORTED=y +CONFIG_SOC_ADC_PERIPH_NUM=2 +CONFIG_SOC_ADC_MAX_CHANNEL_NUM=10 +CONFIG_SOC_ADC_ATTEN_NUM=4 +CONFIG_SOC_ADC_DIGI_CONTROLLER_NUM=2 +CONFIG_SOC_ADC_PATT_LEN_MAX=16 +CONFIG_SOC_ADC_DIGI_MIN_BITWIDTH=9 +CONFIG_SOC_ADC_DIGI_MAX_BITWIDTH=12 +CONFIG_SOC_ADC_DIGI_RESULT_BYTES=2 +CONFIG_SOC_ADC_DIGI_DATA_BYTES_PER_CONV=4 +CONFIG_SOC_ADC_SAMPLE_FREQ_THRES_HIGH=2 +CONFIG_SOC_ADC_SAMPLE_FREQ_THRES_LOW=20 +CONFIG_SOC_ADC_RTC_MIN_BITWIDTH=9 +CONFIG_SOC_ADC_RTC_MAX_BITWIDTH=12 +CONFIG_SOC_SHARED_IDCACHE_SUPPORTED=y +CONFIG_SOC_IDCACHE_PER_CORE=y +CONFIG_SOC_CPU_CORES_NUM=2 +CONFIG_SOC_CPU_INTR_NUM=32 +CONFIG_SOC_CPU_HAS_FPU=y +CONFIG_SOC_CPU_BREAKPOINTS_NUM=2 +CONFIG_SOC_CPU_WATCHPOINTS_NUM=2 +CONFIG_SOC_CPU_WATCHPOINT_SIZE=64 +CONFIG_SOC_DAC_CHAN_NUM=2 +CONFIG_SOC_DAC_RESOLUTION=8 +CONFIG_SOC_DAC_DMA_16BIT_ALIGN=y +CONFIG_SOC_GPIO_PORT=1 +CONFIG_SOC_GPIO_PIN_COUNT=40 +CONFIG_SOC_GPIO_VALID_GPIO_MASK=0xFFFFFFFFFF +CONFIG_SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK=0xEF0FEA +CONFIG_SOC_I2C_NUM=2 +CONFIG_SOC_I2C_FIFO_LEN=32 +CONFIG_SOC_I2C_CMD_REG_NUM=16 +CONFIG_SOC_I2C_SUPPORT_SLAVE=y +CONFIG_SOC_I2C_SUPPORT_APB=y +CONFIG_SOC_I2S_NUM=2 +CONFIG_SOC_I2S_HW_VERSION_1=y +CONFIG_SOC_I2S_SUPPORTS_APLL=y +CONFIG_SOC_I2S_SUPPORTS_PLL_F160M=y +CONFIG_SOC_I2S_SUPPORTS_PDM=y +CONFIG_SOC_I2S_SUPPORTS_PDM_TX=y +CONFIG_SOC_I2S_PDM_MAX_TX_LINES=1 +CONFIG_SOC_I2S_SUPPORTS_PDM_RX=y +CONFIG_SOC_I2S_PDM_MAX_RX_LINES=1 +CONFIG_SOC_I2S_SUPPORTS_ADC_DAC=y +CONFIG_SOC_I2S_SUPPORTS_ADC=y +CONFIG_SOC_I2S_SUPPORTS_DAC=y +CONFIG_SOC_I2S_SUPPORTS_LCD_CAMERA=y +CONFIG_SOC_I2S_TRANS_SIZE_ALIGN_WORD=y +CONFIG_SOC_I2S_LCD_I80_VARIANT=y +CONFIG_SOC_LCD_I80_SUPPORTED=y +CONFIG_SOC_LCD_I80_BUSES=2 +CONFIG_SOC_LCD_I80_BUS_WIDTH=24 +CONFIG_SOC_LEDC_HAS_TIMER_SPECIFIC_MUX=y +CONFIG_SOC_LEDC_SUPPORT_APB_CLOCK=y +CONFIG_SOC_LEDC_SUPPORT_REF_TICK=y +CONFIG_SOC_LEDC_SUPPORT_HS_MODE=y +CONFIG_SOC_LEDC_CHANNEL_NUM=8 +CONFIG_SOC_LEDC_TIMER_BIT_WIDTH=20 +CONFIG_SOC_MCPWM_GROUPS=2 +CONFIG_SOC_MCPWM_TIMERS_PER_GROUP=3 +CONFIG_SOC_MCPWM_OPERATORS_PER_GROUP=3 +CONFIG_SOC_MCPWM_COMPARATORS_PER_OPERATOR=2 +CONFIG_SOC_MCPWM_GENERATORS_PER_OPERATOR=2 +CONFIG_SOC_MCPWM_TRIGGERS_PER_OPERATOR=2 +CONFIG_SOC_MCPWM_GPIO_FAULTS_PER_GROUP=3 +CONFIG_SOC_MCPWM_CAPTURE_TIMERS_PER_GROUP=y +CONFIG_SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER=3 +CONFIG_SOC_MCPWM_GPIO_SYNCHROS_PER_GROUP=3 +CONFIG_SOC_MMU_PERIPH_NUM=2 +CONFIG_SOC_MMU_LINEAR_ADDRESS_REGION_NUM=3 +CONFIG_SOC_MPU_MIN_REGION_SIZE=0x20000000 +CONFIG_SOC_MPU_REGIONS_MAX_NUM=8 +CONFIG_SOC_PCNT_GROUPS=1 +CONFIG_SOC_PCNT_UNITS_PER_GROUP=8 +CONFIG_SOC_PCNT_CHANNELS_PER_UNIT=2 +CONFIG_SOC_PCNT_THRES_POINT_PER_UNIT=2 +CONFIG_SOC_RMT_GROUPS=1 +CONFIG_SOC_RMT_TX_CANDIDATES_PER_GROUP=8 +CONFIG_SOC_RMT_RX_CANDIDATES_PER_GROUP=8 +CONFIG_SOC_RMT_CHANNELS_PER_GROUP=8 +CONFIG_SOC_RMT_MEM_WORDS_PER_CHANNEL=64 +CONFIG_SOC_RMT_SUPPORT_REF_TICK=y +CONFIG_SOC_RMT_SUPPORT_APB=y +CONFIG_SOC_RMT_CHANNEL_CLK_INDEPENDENT=y +CONFIG_SOC_RTCIO_PIN_COUNT=18 +CONFIG_SOC_RTCIO_INPUT_OUTPUT_SUPPORTED=y +CONFIG_SOC_RTCIO_HOLD_SUPPORTED=y +CONFIG_SOC_RTCIO_WAKE_SUPPORTED=y +CONFIG_SOC_SDM_GROUPS=1 +CONFIG_SOC_SDM_CHANNELS_PER_GROUP=8 +CONFIG_SOC_SDM_CLK_SUPPORT_APB=y +CONFIG_SOC_SPI_HD_BOTH_INOUT_SUPPORTED=y +CONFIG_SOC_SPI_AS_CS_SUPPORTED=y +CONFIG_SOC_SPI_PERIPH_NUM=3 +CONFIG_SOC_SPI_DMA_CHAN_NUM=2 +CONFIG_SOC_SPI_MAX_CS_NUM=3 +CONFIG_SOC_SPI_SUPPORT_CLK_APB=y +CONFIG_SOC_SPI_MAXIMUM_BUFFER_SIZE=64 +CONFIG_SOC_SPI_MAX_PRE_DIVIDER=8192 +CONFIG_SOC_MEMSPI_SRC_FREQ_80M_SUPPORTED=y +CONFIG_SOC_MEMSPI_SRC_FREQ_40M_SUPPORTED=y +CONFIG_SOC_MEMSPI_SRC_FREQ_26M_SUPPORTED=y +CONFIG_SOC_MEMSPI_SRC_FREQ_20M_SUPPORTED=y +CONFIG_SOC_TIMER_GROUPS=2 +CONFIG_SOC_TIMER_GROUP_TIMERS_PER_GROUP=2 +CONFIG_SOC_TIMER_GROUP_COUNTER_BIT_WIDTH=64 +CONFIG_SOC_TIMER_GROUP_TOTAL_TIMERS=4 +CONFIG_SOC_TIMER_GROUP_SUPPORT_APB=y +CONFIG_SOC_TOUCH_VERSION_1=y +CONFIG_SOC_TOUCH_SENSOR_NUM=10 +CONFIG_SOC_TOUCH_PAD_MEASURE_WAIT_MAX=0xFF +CONFIG_SOC_TWAI_CONTROLLER_NUM=1 +CONFIG_SOC_TWAI_BRP_MIN=2 +CONFIG_SOC_TWAI_CLK_SUPPORT_APB=y +CONFIG_SOC_TWAI_SUPPORT_MULTI_ADDRESS_LAYOUT=y +CONFIG_SOC_UART_NUM=3 +CONFIG_SOC_UART_SUPPORT_APB_CLK=y +CONFIG_SOC_UART_SUPPORT_REF_TICK=y +CONFIG_SOC_UART_FIFO_LEN=128 +CONFIG_SOC_UART_BITRATE_MAX=5000000 +CONFIG_SOC_SPIRAM_SUPPORTED=y +CONFIG_SOC_SPI_MEM_SUPPORT_CONFIG_GPIO_BY_EFUSE=y +CONFIG_SOC_SHA_SUPPORT_PARALLEL_ENG=y +CONFIG_SOC_SHA_SUPPORT_SHA1=y +CONFIG_SOC_SHA_SUPPORT_SHA256=y +CONFIG_SOC_SHA_SUPPORT_SHA384=y +CONFIG_SOC_SHA_SUPPORT_SHA512=y +CONFIG_SOC_RSA_MAX_BIT_LEN=4096 +CONFIG_SOC_AES_SUPPORT_AES_128=y +CONFIG_SOC_AES_SUPPORT_AES_192=y +CONFIG_SOC_AES_SUPPORT_AES_256=y +CONFIG_SOC_SECURE_BOOT_V1=y +CONFIG_SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS=y +CONFIG_SOC_FLASH_ENCRYPTED_XTS_AES_BLOCK_MAX=32 +CONFIG_SOC_PHY_DIG_REGS_MEM_SIZE=21 +CONFIG_SOC_PM_SUPPORT_EXT0_WAKEUP=y +CONFIG_SOC_PM_SUPPORT_EXT1_WAKEUP=y +CONFIG_SOC_PM_SUPPORT_EXT_WAKEUP=y +CONFIG_SOC_PM_SUPPORT_TOUCH_SENSOR_WAKEUP=y +CONFIG_SOC_PM_SUPPORT_RTC_PERIPH_PD=y +CONFIG_SOC_PM_SUPPORT_RTC_FAST_MEM_PD=y +CONFIG_SOC_PM_SUPPORT_RTC_SLOW_MEM_PD=y +CONFIG_SOC_PM_SUPPORT_RC_FAST_PD=y +CONFIG_SOC_PM_SUPPORT_VDDSDIO_PD=y +CONFIG_SOC_PM_SUPPORT_MODEM_PD=y +CONFIG_SOC_CONFIGURABLE_VDDSDIO_SUPPORTED=y +CONFIG_SOC_CLK_APLL_SUPPORTED=y +CONFIG_SOC_APLL_MULTIPLIER_OUT_MIN_HZ=350000000 +CONFIG_SOC_APLL_MULTIPLIER_OUT_MAX_HZ=500000000 +CONFIG_SOC_APLL_MIN_HZ=5303031 +CONFIG_SOC_APLL_MAX_HZ=125000000 +CONFIG_SOC_CLK_RC_FAST_D256_SUPPORTED=y +CONFIG_SOC_RTC_SLOW_CLK_SUPPORT_RC_FAST_D256=y +CONFIG_SOC_CLK_RC_FAST_SUPPORT_CALIBRATION=y +CONFIG_SOC_CLK_XTAL32K_SUPPORTED=y +CONFIG_SOC_SDMMC_USE_IOMUX=y +CONFIG_SOC_SDMMC_NUM_SLOTS=2 +CONFIG_SOC_WIFI_WAPI_SUPPORT=y +CONFIG_SOC_WIFI_CSI_SUPPORT=y +CONFIG_SOC_WIFI_MESH_SUPPORT=y +CONFIG_SOC_WIFI_SUPPORT_VARIABLE_BEACON_WINDOW=y +CONFIG_SOC_WIFI_NAN_SUPPORT=y +CONFIG_SOC_BLE_SUPPORTED=y +CONFIG_SOC_BLE_MESH_SUPPORTED=y +CONFIG_SOC_BT_CLASSIC_SUPPORTED=y +CONFIG_SOC_BLUFI_SUPPORTED=y +CONFIG_SOC_ULP_HAS_ADC=y +CONFIG_SOC_PHY_COMBO_MODULE=y +CONFIG_IDF_CMAKE=y +CONFIG_IDF_TARGET_ARCH_XTENSA=y +CONFIG_IDF_TARGET_ARCH="xtensa" +CONFIG_IDF_TARGET="esp32" +CONFIG_IDF_TARGET_ESP32=y +CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000 + +# +# Build type +# +CONFIG_APP_BUILD_TYPE_APP_2NDBOOT=y +# CONFIG_APP_BUILD_TYPE_RAM is not set +CONFIG_APP_BUILD_GENERATE_BINARIES=y +CONFIG_APP_BUILD_BOOTLOADER=y +CONFIG_APP_BUILD_USE_FLASH_SECTIONS=y +# CONFIG_APP_REPRODUCIBLE_BUILD is not set +# CONFIG_APP_NO_BLOBS is not set +# CONFIG_APP_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set +# CONFIG_APP_COMPATIBLE_PRE_V3_1_BOOTLOADERS is not set +# end of Build type + +# +# Bootloader config +# +CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x1000 +CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set +CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y +# CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set +CONFIG_BOOTLOADER_LOG_LEVEL=3 +# CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_8V is not set +CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y +# CONFIG_BOOTLOADER_FACTORY_RESET is not set +# CONFIG_BOOTLOADER_APP_TEST is not set +CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE=y +CONFIG_BOOTLOADER_WDT_ENABLE=y +# CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set +CONFIG_BOOTLOADER_WDT_TIME_MS=9000 +# CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS is not set +CONFIG_BOOTLOADER_RESERVE_RTC_SIZE=0 +# CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC is not set +CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT=y +# end of Bootloader config + +# +# Security features +# +CONFIG_SECURE_BOOT_V1_SUPPORTED=y +# CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT is not set +# CONFIG_SECURE_BOOT is not set +# CONFIG_SECURE_FLASH_ENC_ENABLED is not set +# end of Security features + +# +# Application manager +# +CONFIG_APP_COMPILE_TIME_DATE=y +# CONFIG_APP_EXCLUDE_PROJECT_VER_VAR is not set +# CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set +# CONFIG_APP_PROJECT_VER_FROM_CONFIG is not set +CONFIG_APP_RETRIEVE_LEN_ELF_SHA=16 +# end of Application manager + +CONFIG_ESP_ROM_HAS_CRC_LE=y +CONFIG_ESP_ROM_HAS_CRC_BE=y +CONFIG_ESP_ROM_HAS_MZ_CRC32=y +CONFIG_ESP_ROM_HAS_JPEG_DECODE=y +CONFIG_ESP_ROM_HAS_UART_BUF_SWITCH=y +CONFIG_ESP_ROM_NEEDS_SWSETUP_WORKAROUND=y +CONFIG_ESP_ROM_HAS_NEWLIB_NANO_FORMAT=y + +# +# Serial flasher config +# +# CONFIG_ESPTOOLPY_NO_STUB is not set +# CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set +# CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set +CONFIG_ESPTOOLPY_FLASHMODE_DIO=y +# CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set +CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR=y +CONFIG_ESPTOOLPY_FLASHMODE="dio" +# CONFIG_ESPTOOLPY_FLASHFREQ_80M is not set +CONFIG_ESPTOOLPY_FLASHFREQ_40M=y +# CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set +# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set +CONFIG_ESPTOOLPY_FLASHFREQ="40m" +# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y +# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE="2MB" +# CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE is not set +CONFIG_ESPTOOLPY_BEFORE_RESET=y +# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set +CONFIG_ESPTOOLPY_BEFORE="default_reset" +CONFIG_ESPTOOLPY_AFTER_RESET=y +# CONFIG_ESPTOOLPY_AFTER_NORESET is not set +CONFIG_ESPTOOLPY_AFTER="hard_reset" +CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 +# end of Serial flasher config + +# +# Partition Table +# +CONFIG_PARTITION_TABLE_SINGLE_APP=y +# CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set +# CONFIG_PARTITION_TABLE_TWO_OTA is not set +# CONFIG_PARTITION_TABLE_CUSTOM is not set +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv" +CONFIG_PARTITION_TABLE_OFFSET=0x8000 +CONFIG_PARTITION_TABLE_MD5=y +# end of Partition Table + +# +# Compiler options +# +CONFIG_COMPILER_OPTIMIZATION_DEFAULT=y +# CONFIG_COMPILER_OPTIMIZATION_SIZE is not set +# CONFIG_COMPILER_OPTIMIZATION_PERF is not set +# CONFIG_COMPILER_OPTIMIZATION_NONE is not set +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y +# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set +# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set +CONFIG_COMPILER_FLOAT_LIB_FROM_GCCLIB=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL=2 +# CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT is not set +CONFIG_COMPILER_HIDE_PATHS_MACROS=y +# CONFIG_COMPILER_CXX_EXCEPTIONS is not set +# CONFIG_COMPILER_CXX_RTTI is not set +CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y +# CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set +# CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set +# CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set +# CONFIG_COMPILER_WARN_WRITE_STRINGS is not set +# CONFIG_COMPILER_DISABLE_GCC12_WARNINGS is not set +# CONFIG_COMPILER_DUMP_RTL_FILES is not set +# end of Compiler options + +# +# Component config +# + +# +# Application Level Tracing +# +# CONFIG_APPTRACE_DEST_JTAG is not set +CONFIG_APPTRACE_DEST_NONE=y +# CONFIG_APPTRACE_DEST_UART1 is not set +# CONFIG_APPTRACE_DEST_UART2 is not set +CONFIG_APPTRACE_DEST_UART_NONE=y +CONFIG_APPTRACE_UART_TASK_PRIO=1 +CONFIG_APPTRACE_LOCK_ENABLE=y +# end of Application Level Tracing + +# +# Bluetooth +# +CONFIG_BT_ENABLED=y +# CONFIG_BT_BLUEDROID_ENABLED is not set +CONFIG_BT_NIMBLE_ENABLED=y +# CONFIG_BT_CONTROLLER_ONLY is not set +CONFIG_BT_CONTROLLER_ENABLED=y +# CONFIG_BT_CONTROLLER_DISABLED is not set + +# +# NimBLE Options +# +CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL=y +# CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_DEFAULT is not set +# CONFIG_BT_NIMBLE_LOG_LEVEL_NONE is not set +# CONFIG_BT_NIMBLE_LOG_LEVEL_ERROR is not set +# CONFIG_BT_NIMBLE_LOG_LEVEL_WARNING is not set +CONFIG_BT_NIMBLE_LOG_LEVEL_INFO=y +# CONFIG_BT_NIMBLE_LOG_LEVEL_DEBUG is not set +CONFIG_BT_NIMBLE_LOG_LEVEL=1 +CONFIG_BT_NIMBLE_MAX_CONNECTIONS=3 +CONFIG_BT_NIMBLE_MAX_BONDS=3 +CONFIG_BT_NIMBLE_MAX_CCCDS=8 +CONFIG_BT_NIMBLE_L2CAP_COC_MAX_NUM=0 +CONFIG_BT_NIMBLE_PINNED_TO_CORE_0=y +# CONFIG_BT_NIMBLE_PINNED_TO_CORE_1 is not set +CONFIG_BT_NIMBLE_PINNED_TO_CORE=0 +CONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=4096 +CONFIG_BT_NIMBLE_ROLE_CENTRAL=y +CONFIG_BT_NIMBLE_ROLE_PERIPHERAL=y +CONFIG_BT_NIMBLE_ROLE_BROADCASTER=y +CONFIG_BT_NIMBLE_ROLE_OBSERVER=y +# CONFIG_BT_NIMBLE_NVS_PERSIST is not set +CONFIG_BT_NIMBLE_SECURITY_ENABLE=y +CONFIG_BT_NIMBLE_SM_LEGACY=y +CONFIG_BT_NIMBLE_SM_SC=y +# CONFIG_BT_NIMBLE_SM_SC_DEBUG_KEYS is not set +CONFIG_BT_NIMBLE_LL_CFG_FEAT_LE_ENCRYPTION=y +# CONFIG_BT_NIMBLE_DEBUG is not set +# CONFIG_BT_NIMBLE_DYNAMIC_SERVICE is not set +CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME="nimble" +CONFIG_BT_NIMBLE_GAP_DEVICE_NAME_MAX_LEN=31 +CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU=256 +CONFIG_BT_NIMBLE_SVC_GAP_APPEARANCE=0 + +# +# Memory Settings +# +CONFIG_BT_NIMBLE_MSYS_1_BLOCK_COUNT=12 +CONFIG_BT_NIMBLE_MSYS_1_BLOCK_SIZE=256 +CONFIG_BT_NIMBLE_MSYS_2_BLOCK_COUNT=24 +CONFIG_BT_NIMBLE_MSYS_2_BLOCK_SIZE=320 +CONFIG_BT_NIMBLE_TRANSPORT_ACL_FROM_LL_COUNT=24 +CONFIG_BT_NIMBLE_TRANSPORT_ACL_SIZE=255 +CONFIG_BT_NIMBLE_TRANSPORT_EVT_SIZE=70 +CONFIG_BT_NIMBLE_TRANSPORT_EVT_COUNT=30 +CONFIG_BT_NIMBLE_TRANSPORT_EVT_DISCARD_COUNT=8 +# end of Memory Settings + +CONFIG_BT_NIMBLE_GATT_MAX_PROCS=4 +CONFIG_BT_NIMBLE_HS_FLOW_CTRL=y +CONFIG_BT_NIMBLE_HS_FLOW_CTRL_ITVL=1000 +CONFIG_BT_NIMBLE_HS_FLOW_CTRL_THRESH=2 +CONFIG_BT_NIMBLE_HS_FLOW_CTRL_TX_ON_DISCONNECT=y +CONFIG_BT_NIMBLE_RPA_TIMEOUT=900 +# CONFIG_BT_NIMBLE_MESH is not set +CONFIG_BT_NIMBLE_CRYPTO_STACK_MBEDTLS=y +CONFIG_BT_NIMBLE_HS_STOP_TIMEOUT_MS=2000 +# CONFIG_BT_NIMBLE_HOST_BASED_PRIVACY is not set +# CONFIG_BT_NIMBLE_ENABLE_CONN_REATTEMPT is not set +CONFIG_BT_NIMBLE_COEX_PHY_CODED_TX_RX_TLIM_EFF=0 +CONFIG_BT_NIMBLE_WHITELIST_SIZE=12 +# CONFIG_BT_NIMBLE_TEST_THROUGHPUT_TEST is not set +# CONFIG_BT_NIMBLE_BLUFI_ENABLE is not set +CONFIG_BT_NIMBLE_USE_ESP_TIMER=y +CONFIG_BT_NIMBLE_LEGACY_VHCI_ENABLE=y +# CONFIG_BT_NIMBLE_BLE_GATT_BLOB_TRANSFER is not set +# CONFIG_BT_NIMBLE_VS_SUPPORT is not set +# CONFIG_BT_NIMBLE_HIGH_DUTY_ADV_ITVL is not set +# CONFIG_BT_NIMBLE_HOST_QUEUE_CONG_CHECK is not set +# end of NimBLE Options + +# +# Controller Options +# +CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y +# CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY is not set +# CONFIG_BTDM_CTRL_MODE_BTDM is not set +CONFIG_BTDM_CTRL_BLE_MAX_CONN=3 +CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_EFF=0 +CONFIG_BTDM_CTRL_PCM_ROLE_EFF=0 +CONFIG_BTDM_CTRL_PCM_POLAR_EFF=0 +CONFIG_BTDM_CTRL_BLE_MAX_CONN_EFF=3 +CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN_EFF=0 +CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF=0 +CONFIG_BTDM_CTRL_PINNED_TO_CORE_0=y +# CONFIG_BTDM_CTRL_PINNED_TO_CORE_1 is not set +CONFIG_BTDM_CTRL_PINNED_TO_CORE=0 +CONFIG_BTDM_CTRL_HCI_MODE_VHCI=y +# CONFIG_BTDM_CTRL_HCI_MODE_UART_H4 is not set + +# +# MODEM SLEEP Options +# +CONFIG_BTDM_CTRL_MODEM_SLEEP=y +CONFIG_BTDM_CTRL_MODEM_SLEEP_MODE_ORIG=y +# CONFIG_BTDM_CTRL_MODEM_SLEEP_MODE_EVED is not set +CONFIG_BTDM_CTRL_LPCLK_SEL_MAIN_XTAL=y +# end of MODEM SLEEP Options + +CONFIG_BTDM_BLE_DEFAULT_SCA_250PPM=y +CONFIG_BTDM_BLE_SLEEP_CLOCK_ACCURACY_INDEX_EFF=1 +CONFIG_BTDM_BLE_SCAN_DUPL=y +CONFIG_BTDM_SCAN_DUPL_TYPE_DEVICE=y +# CONFIG_BTDM_SCAN_DUPL_TYPE_DATA is not set +# CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE is not set +CONFIG_BTDM_SCAN_DUPL_TYPE=0 +CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE=100 +CONFIG_BTDM_SCAN_DUPL_CACHE_REFRESH_PERIOD=0 +# CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN is not set +CONFIG_BTDM_CTRL_FULL_SCAN_SUPPORTED=y +CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP=y +CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_NUM=100 +CONFIG_BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD=20 +CONFIG_BTDM_RESERVE_DRAM=0xdb5c +CONFIG_BTDM_CTRL_HLI=y +# end of Controller Options +# end of Bluetooth + +# CONFIG_BLE_MESH is not set + +# +# Driver Configurations +# + +# +# Legacy ADC Configuration +# +CONFIG_ADC_DISABLE_DAC=y +# CONFIG_ADC_SUPPRESS_DEPRECATE_WARN is not set + +# +# Legacy ADC Calibration Configuration +# +CONFIG_ADC_CAL_EFUSE_TP_ENABLE=y +CONFIG_ADC_CAL_EFUSE_VREF_ENABLE=y +CONFIG_ADC_CAL_LUT_ENABLE=y +# CONFIG_ADC_CALI_SUPPRESS_DEPRECATE_WARN is not set +# end of Legacy ADC Calibration Configuration +# end of Legacy ADC Configuration + +# +# SPI Configuration +# +# CONFIG_SPI_MASTER_IN_IRAM is not set +CONFIG_SPI_MASTER_ISR_IN_IRAM=y +# CONFIG_SPI_SLAVE_IN_IRAM is not set +CONFIG_SPI_SLAVE_ISR_IN_IRAM=y +# end of SPI Configuration + +# +# TWAI Configuration +# +# CONFIG_TWAI_ISR_IN_IRAM is not set +CONFIG_TWAI_ERRATA_FIX_BUS_OFF_REC=y +CONFIG_TWAI_ERRATA_FIX_TX_INTR_LOST=y +CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID=y +CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT=y +CONFIG_TWAI_ERRATA_FIX_LISTEN_ONLY_DOM=y +# end of TWAI Configuration + +# +# UART Configuration +# +# CONFIG_UART_ISR_IN_IRAM is not set +# end of UART Configuration + +# +# GPIO Configuration +# +# CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL is not set +# CONFIG_GPIO_CTRL_FUNC_IN_IRAM is not set +# end of GPIO Configuration + +# +# Sigma Delta Modulator Configuration +# +# CONFIG_SDM_CTRL_FUNC_IN_IRAM is not set +# CONFIG_SDM_SUPPRESS_DEPRECATE_WARN is not set +# CONFIG_SDM_ENABLE_DEBUG_LOG is not set +# end of Sigma Delta Modulator Configuration + +# +# GPTimer Configuration +# +CONFIG_GPTIMER_ISR_HANDLER_IN_IRAM=y +# CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM is not set +# CONFIG_GPTIMER_ISR_IRAM_SAFE is not set +# CONFIG_GPTIMER_SUPPRESS_DEPRECATE_WARN is not set +# CONFIG_GPTIMER_ENABLE_DEBUG_LOG is not set +# end of GPTimer Configuration + +# +# PCNT Configuration +# +# CONFIG_PCNT_CTRL_FUNC_IN_IRAM is not set +# CONFIG_PCNT_ISR_IRAM_SAFE is not set +# CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN is not set +# CONFIG_PCNT_ENABLE_DEBUG_LOG is not set +# end of PCNT Configuration + +# +# RMT Configuration +# +# CONFIG_RMT_ISR_IRAM_SAFE is not set +# CONFIG_RMT_SUPPRESS_DEPRECATE_WARN is not set +# CONFIG_RMT_ENABLE_DEBUG_LOG is not set +# end of RMT Configuration + +# +# MCPWM Configuration +# +# CONFIG_MCPWM_ISR_IRAM_SAFE is not set +# CONFIG_MCPWM_CTRL_FUNC_IN_IRAM is not set +# CONFIG_MCPWM_SUPPRESS_DEPRECATE_WARN is not set +# CONFIG_MCPWM_ENABLE_DEBUG_LOG is not set +# end of MCPWM Configuration + +# +# I2S Configuration +# +# CONFIG_I2S_ISR_IRAM_SAFE is not set +# CONFIG_I2S_SUPPRESS_DEPRECATE_WARN is not set +# CONFIG_I2S_ENABLE_DEBUG_LOG is not set +# end of I2S Configuration + +# +# DAC Configuration +# +# CONFIG_DAC_CTRL_FUNC_IN_IRAM is not set +# CONFIG_DAC_ISR_IRAM_SAFE is not set +# CONFIG_DAC_SUPPRESS_DEPRECATE_WARN is not set +# CONFIG_DAC_ENABLE_DEBUG_LOG is not set +CONFIG_DAC_DMA_AUTO_16BIT_ALIGN=y +# end of DAC Configuration +# end of Driver Configurations + +# +# eFuse Bit Manager +# +# CONFIG_EFUSE_CUSTOM_TABLE is not set +# CONFIG_EFUSE_VIRTUAL is not set +# CONFIG_EFUSE_CODE_SCHEME_COMPAT_NONE is not set +CONFIG_EFUSE_CODE_SCHEME_COMPAT_3_4=y +# CONFIG_EFUSE_CODE_SCHEME_COMPAT_REPEAT is not set +CONFIG_EFUSE_MAX_BLK_LEN=192 +# end of eFuse Bit Manager + +# +# ESP-TLS +# +CONFIG_ESP_TLS_USING_MBEDTLS=y +# CONFIG_ESP_TLS_USE_SECURE_ELEMENT is not set +# CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS is not set +# CONFIG_ESP_TLS_SERVER is not set +# CONFIG_ESP_TLS_PSK_VERIFICATION is not set +# CONFIG_ESP_TLS_INSECURE is not set +# end of ESP-TLS + +# +# ADC and ADC Calibration +# +# CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM is not set +# CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE is not set + +# +# ADC Calibration Configurations +# +CONFIG_ADC_CALI_EFUSE_TP_ENABLE=y +CONFIG_ADC_CALI_EFUSE_VREF_ENABLE=y +CONFIG_ADC_CALI_LUT_ENABLE=y +# end of ADC Calibration Configurations + +CONFIG_ADC_DISABLE_DAC_OUTPUT=y +# end of ADC and ADC Calibration + +# +# Wireless Coexistence +# +CONFIG_ESP_COEX_SW_COEXIST_ENABLE=y +# end of Wireless Coexistence + +# +# Common ESP-related +# +CONFIG_ESP_ERR_TO_NAME_LOOKUP=y +# end of Common ESP-related + +# +# Ethernet +# +CONFIG_ETH_ENABLED=y +CONFIG_ETH_USE_ESP32_EMAC=y +CONFIG_ETH_PHY_INTERFACE_RMII=y +CONFIG_ETH_RMII_CLK_INPUT=y +# CONFIG_ETH_RMII_CLK_OUTPUT is not set +CONFIG_ETH_RMII_CLK_IN_GPIO=0 +CONFIG_ETH_DMA_BUFFER_SIZE=512 +CONFIG_ETH_DMA_RX_BUFFER_NUM=10 +CONFIG_ETH_DMA_TX_BUFFER_NUM=10 +# CONFIG_ETH_IRAM_OPTIMIZATION is not set +CONFIG_ETH_USE_SPI_ETHERNET=y +# CONFIG_ETH_SPI_ETHERNET_DM9051 is not set +# CONFIG_ETH_SPI_ETHERNET_W5500 is not set +# CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL is not set +# CONFIG_ETH_USE_OPENETH is not set +# CONFIG_ETH_TRANSMIT_MUTEX is not set +# end of Ethernet + +# +# Event Loop Library +# +# CONFIG_ESP_EVENT_LOOP_PROFILING is not set +CONFIG_ESP_EVENT_POST_FROM_ISR=y +CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y +# end of Event Loop Library + +# +# GDB Stub +# +# end of GDB Stub + +# +# ESP HTTP client +# +CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y +# CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set +# CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH is not set +# end of ESP HTTP client + +# +# HTTP Server +# +CONFIG_HTTPD_MAX_REQ_HDR_LEN=512 +CONFIG_HTTPD_MAX_URI_LEN=512 +CONFIG_HTTPD_ERR_RESP_NO_DELAY=y +CONFIG_HTTPD_PURGE_BUF_LEN=32 +# CONFIG_HTTPD_LOG_PURGE_DATA is not set +# CONFIG_HTTPD_WS_SUPPORT is not set +# CONFIG_HTTPD_QUEUE_WORK_BLOCKING is not set +# end of HTTP Server + +# +# ESP HTTPS OTA +# +# CONFIG_ESP_HTTPS_OTA_DECRYPT_CB is not set +# CONFIG_ESP_HTTPS_OTA_ALLOW_HTTP is not set +# end of ESP HTTPS OTA + +# +# ESP HTTPS server +# +# CONFIG_ESP_HTTPS_SERVER_ENABLE is not set +# end of ESP HTTPS server + +# +# Hardware Settings +# + +# +# Chip revision +# +CONFIG_ESP32_REV_MIN_0=y +# CONFIG_ESP32_REV_MIN_1 is not set +# CONFIG_ESP32_REV_MIN_1_1 is not set +# CONFIG_ESP32_REV_MIN_2 is not set +# CONFIG_ESP32_REV_MIN_3 is not set +# CONFIG_ESP32_REV_MIN_3_1 is not set +CONFIG_ESP32_REV_MIN=0 +CONFIG_ESP32_REV_MIN_FULL=0 +CONFIG_ESP_REV_MIN_FULL=0 + +# +# Maximum Supported ESP32 Revision (Rev v3.99) +# +CONFIG_ESP32_REV_MAX_FULL=399 +CONFIG_ESP_REV_MAX_FULL=399 +# end of Chip revision + +# +# MAC Config +# +CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_BT=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y +CONFIG_ESP_MAC_UNIVERSAL_MAC_ADDRESSES_FOUR=y +# CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_TWO is not set +CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR=y +CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES=4 +# CONFIG_ESP_MAC_IGNORE_MAC_CRC_ERROR is not set +# end of MAC Config + +# +# Sleep Config +# +# CONFIG_ESP_SLEEP_POWER_DOWN_FLASH is not set +CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND=y +# CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU is not set +CONFIG_ESP_SLEEP_RTC_BUS_ISO_WORKAROUND=y +# CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND is not set +CONFIG_ESP_SLEEP_DEEP_SLEEP_WAKEUP_DELAY=2000 +CONFIG_ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS=y +# end of Sleep Config + +# +# RTC Clock Config +# +CONFIG_RTC_CLK_SRC_INT_RC=y +# CONFIG_RTC_CLK_SRC_EXT_CRYS is not set +# CONFIG_RTC_CLK_SRC_EXT_OSC is not set +# CONFIG_RTC_CLK_SRC_INT_8MD256 is not set +CONFIG_RTC_CLK_CAL_CYCLES=1024 +# end of RTC Clock Config + +# +# Peripheral Control +# +CONFIG_PERIPH_CTRL_FUNC_IN_IRAM=y +# end of Peripheral Control + +# +# Main XTAL Config +# +# CONFIG_XTAL_FREQ_26 is not set +CONFIG_XTAL_FREQ_40=y +# CONFIG_XTAL_FREQ_AUTO is not set +CONFIG_XTAL_FREQ=40 +# end of Main XTAL Config +# end of Hardware Settings + +# +# LCD and Touch Panel +# + +# +# LCD Touch Drivers are maintained in the IDF Component Registry +# + +# +# LCD Peripheral Configuration +# +CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE=32 +# CONFIG_LCD_ENABLE_DEBUG_LOG is not set +# end of LCD Peripheral Configuration +# end of LCD and Touch Panel + +# +# ESP NETIF Adapter +# +CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL=120 +CONFIG_ESP_NETIF_TCPIP_LWIP=y +# CONFIG_ESP_NETIF_LOOPBACK is not set +CONFIG_ESP_NETIF_USES_TCPIP_WITH_BSD_API=y +# CONFIG_ESP_NETIF_RECEIVE_REPORT_ERRORS is not set +# CONFIG_ESP_NETIF_L2_TAP is not set +# CONFIG_ESP_NETIF_BRIDGE_EN is not set +# end of ESP NETIF Adapter + +# +# Partition API Configuration +# +# end of Partition API Configuration + +# +# PHY +# +CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y +# CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION is not set +CONFIG_ESP_PHY_MAX_WIFI_TX_POWER=20 +CONFIG_ESP_PHY_MAX_TX_POWER=20 +# CONFIG_ESP_PHY_REDUCE_TX_POWER is not set +CONFIG_ESP_PHY_RF_CAL_PARTIAL=y +# CONFIG_ESP_PHY_RF_CAL_NONE is not set +# CONFIG_ESP_PHY_RF_CAL_FULL is not set +CONFIG_ESP_PHY_CALIBRATION_MODE=0 +# end of PHY + +# +# Power Management +# +# CONFIG_PM_ENABLE is not set +# end of Power Management + +# +# ESP PSRAM +# +# CONFIG_SPIRAM is not set +# end of ESP PSRAM + +# +# ESP Ringbuf +# +# CONFIG_RINGBUF_PLACE_FUNCTIONS_INTO_FLASH is not set +# end of ESP Ringbuf + +# +# ESP System Settings +# +# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_80 is not set +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160=y +# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240 is not set +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=160 + +# +# Memory +# +# CONFIG_ESP32_USE_FIXED_STATIC_RAM_SIZE is not set + +# +# Non-backward compatible options +# +# CONFIG_ESP_SYSTEM_ESP32_SRAM1_REGION_AS_IRAM is not set +# end of Non-backward compatible options +# end of Memory + +# +# Trace memory +# +# CONFIG_ESP32_TRAX is not set +CONFIG_ESP32_TRACEMEM_RESERVE_DRAM=0x0 +# end of Trace memory + +# CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT is not set +CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y +# CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set +# CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set +# CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME is not set +CONFIG_ESP_SYSTEM_PANIC_REBOOT_DELAY_SECONDS=0 + +# +# Memory protection +# +# end of Memory protection + +CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32 +CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304 +CONFIG_ESP_MAIN_TASK_STACK_SIZE=3584 +CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y +# CONFIG_ESP_MAIN_TASK_AFFINITY_CPU1 is not set +# CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set +CONFIG_ESP_MAIN_TASK_AFFINITY=0x0 +CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048 +CONFIG_ESP_CONSOLE_UART_DEFAULT=y +# CONFIG_ESP_CONSOLE_UART_CUSTOM is not set +# CONFIG_ESP_CONSOLE_NONE is not set +CONFIG_ESP_CONSOLE_UART=y +CONFIG_ESP_CONSOLE_MULTIPLE_UART=y +CONFIG_ESP_CONSOLE_UART_NUM=0 +CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200 +CONFIG_ESP_INT_WDT=y +CONFIG_ESP_INT_WDT_TIMEOUT_MS=300 +CONFIG_ESP_INT_WDT_CHECK_CPU1=y +CONFIG_ESP_TASK_WDT_EN=y +CONFIG_ESP_TASK_WDT_INIT=y +# CONFIG_ESP_TASK_WDT_PANIC is not set +CONFIG_ESP_TASK_WDT_TIMEOUT_S=5 +CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=y +CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1=y +# CONFIG_ESP_PANIC_HANDLER_IRAM is not set +# CONFIG_ESP_DEBUG_STUBS_ENABLE is not set +CONFIG_ESP_DEBUG_OCDAWARE=y +CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5=y + +# +# Brownout Detector +# +CONFIG_ESP_BROWNOUT_DET=y +CONFIG_ESP_BROWNOUT_DET_LVL_SEL_0=y +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_1 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_2 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_7 is not set +CONFIG_ESP_BROWNOUT_DET_LVL=0 +# end of Brownout Detector + +# CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE is not set +CONFIG_ESP_SYSTEM_BROWNOUT_INTR=y +# end of ESP System Settings + +# +# IPC (Inter-Processor Call) +# +CONFIG_ESP_IPC_TASK_STACK_SIZE=1024 +CONFIG_ESP_IPC_USES_CALLERS_PRIORITY=y +CONFIG_ESP_IPC_ISR_ENABLE=y +# end of IPC (Inter-Processor Call) + +# +# High resolution timer (esp_timer) +# +# CONFIG_ESP_TIMER_PROFILING is not set +CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER=y +CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER=y +CONFIG_ESP_TIMER_TASK_STACK_SIZE=3584 +CONFIG_ESP_TIMER_INTERRUPT_LEVEL=1 +# CONFIG_ESP_TIMER_SHOW_EXPERIMENTAL is not set +CONFIG_ESP_TIMER_TASK_AFFINITY=0x0 +CONFIG_ESP_TIMER_TASK_AFFINITY_CPU0=y +CONFIG_ESP_TIMER_ISR_AFFINITY=0x1 +CONFIG_ESP_TIMER_ISR_AFFINITY_CPU0=y +# CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD is not set +CONFIG_ESP_TIMER_IMPL_TG0_LAC=y +# end of High resolution timer (esp_timer) + +# +# Wi-Fi +# +CONFIG_ESP_WIFI_ENABLED=y +CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=10 +CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=32 +# CONFIG_ESP_WIFI_STATIC_TX_BUFFER is not set +CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER=y +CONFIG_ESP_WIFI_TX_BUFFER_TYPE=1 +CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=32 +CONFIG_ESP_WIFI_STATIC_RX_MGMT_BUFFER=y +# CONFIG_ESP_WIFI_DYNAMIC_RX_MGMT_BUFFER is not set +CONFIG_ESP_WIFI_DYNAMIC_RX_MGMT_BUF=0 +CONFIG_ESP_WIFI_RX_MGMT_BUF_NUM_DEF=5 +# CONFIG_ESP_WIFI_CSI_ENABLED is not set +CONFIG_ESP_WIFI_AMPDU_TX_ENABLED=y +CONFIG_ESP_WIFI_TX_BA_WIN=6 +CONFIG_ESP_WIFI_AMPDU_RX_ENABLED=y +CONFIG_ESP_WIFI_RX_BA_WIN=6 +CONFIG_ESP_WIFI_NVS_ENABLED=y +CONFIG_ESP_WIFI_TASK_PINNED_TO_CORE_0=y +# CONFIG_ESP_WIFI_TASK_PINNED_TO_CORE_1 is not set +CONFIG_ESP_WIFI_SOFTAP_BEACON_MAX_LEN=752 +CONFIG_ESP_WIFI_MGMT_SBUF_NUM=32 +CONFIG_ESP_WIFI_IRAM_OPT=y +# CONFIG_ESP_WIFI_EXTRA_IRAM_OPT is not set +CONFIG_ESP_WIFI_RX_IRAM_OPT=y +CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y +CONFIG_ESP_WIFI_ENABLE_SAE_PK=y +CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT=y +CONFIG_ESP_WIFI_ENABLE_WPA3_OWE_STA=y +# CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set +CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE=y +# CONFIG_ESP_WIFI_GMAC_SUPPORT is not set +CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y +# CONFIG_ESP_WIFI_SLP_BEACON_LOST_OPT is not set +CONFIG_ESP_WIFI_ESPNOW_MAX_ENCRYPT_NUM=7 +# CONFIG_ESP_WIFI_NAN_ENABLE is not set +CONFIG_ESP_WIFI_MBEDTLS_CRYPTO=y +CONFIG_ESP_WIFI_MBEDTLS_TLS_CLIENT=y +# CONFIG_ESP_WIFI_WAPI_PSK is not set +# CONFIG_ESP_WIFI_11KV_SUPPORT is not set +# CONFIG_ESP_WIFI_MBO_SUPPORT is not set +# CONFIG_ESP_WIFI_DPP_SUPPORT is not set +# CONFIG_ESP_WIFI_11R_SUPPORT is not set +# CONFIG_ESP_WIFI_WPS_SOFTAP_REGISTRAR is not set + +# +# WPS Configuration Options +# +# CONFIG_ESP_WIFI_WPS_STRICT is not set +# CONFIG_ESP_WIFI_WPS_PASSPHRASE is not set +# end of WPS Configuration Options + +# CONFIG_ESP_WIFI_DEBUG_PRINT is not set +# CONFIG_ESP_WIFI_TESTING_OPTIONS is not set +CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT=y +# end of Wi-Fi + +# +# Core dump +# +# CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH is not set +# CONFIG_ESP_COREDUMP_ENABLE_TO_UART is not set +CONFIG_ESP_COREDUMP_ENABLE_TO_NONE=y +# end of Core dump + +# +# FAT Filesystem support +# +CONFIG_FATFS_VOLUME_COUNT=2 +CONFIG_FATFS_LFN_NONE=y +# CONFIG_FATFS_LFN_HEAP is not set +# CONFIG_FATFS_LFN_STACK is not set +# CONFIG_FATFS_SECTOR_512 is not set +CONFIG_FATFS_SECTOR_4096=y +# CONFIG_FATFS_CODEPAGE_DYNAMIC is not set +CONFIG_FATFS_CODEPAGE_437=y +# CONFIG_FATFS_CODEPAGE_720 is not set +# CONFIG_FATFS_CODEPAGE_737 is not set +# CONFIG_FATFS_CODEPAGE_771 is not set +# CONFIG_FATFS_CODEPAGE_775 is not set +# CONFIG_FATFS_CODEPAGE_850 is not set +# CONFIG_FATFS_CODEPAGE_852 is not set +# CONFIG_FATFS_CODEPAGE_855 is not set +# CONFIG_FATFS_CODEPAGE_857 is not set +# CONFIG_FATFS_CODEPAGE_860 is not set +# CONFIG_FATFS_CODEPAGE_861 is not set +# CONFIG_FATFS_CODEPAGE_862 is not set +# CONFIG_FATFS_CODEPAGE_863 is not set +# CONFIG_FATFS_CODEPAGE_864 is not set +# CONFIG_FATFS_CODEPAGE_865 is not set +# CONFIG_FATFS_CODEPAGE_866 is not set +# CONFIG_FATFS_CODEPAGE_869 is not set +# CONFIG_FATFS_CODEPAGE_932 is not set +# CONFIG_FATFS_CODEPAGE_936 is not set +# CONFIG_FATFS_CODEPAGE_949 is not set +# CONFIG_FATFS_CODEPAGE_950 is not set +CONFIG_FATFS_CODEPAGE=437 +CONFIG_FATFS_FS_LOCK=0 +CONFIG_FATFS_TIMEOUT_MS=10000 +CONFIG_FATFS_PER_FILE_CACHE=y +# CONFIG_FATFS_USE_FASTSEEK is not set +CONFIG_FATFS_VFS_FSTAT_BLKSIZE=0 +# end of FAT Filesystem support + +# +# FreeRTOS +# + +# +# Kernel +# +# CONFIG_FREERTOS_SMP is not set +# CONFIG_FREERTOS_UNICORE is not set +CONFIG_FREERTOS_HZ=100 +# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set +# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set +CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y +CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1 +CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536 +# CONFIG_FREERTOS_USE_IDLE_HOOK is not set +# CONFIG_FREERTOS_USE_TICK_HOOK is not set +CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16 +# CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY is not set +CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1 +CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2048 +CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10 +CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0 +CONFIG_FREERTOS_TASK_NOTIFICATION_ARRAY_ENTRIES=1 +# CONFIG_FREERTOS_USE_TRACE_FACILITY is not set +# CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set +# end of Kernel + +# +# Port +# +CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y +# CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set +CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS=y +# CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP is not set +CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y +CONFIG_FREERTOS_ISR_STACKSIZE=1536 +CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y +# CONFIG_FREERTOS_FPU_IN_ISR is not set +CONFIG_FREERTOS_TICK_SUPPORT_CORETIMER=y +CONFIG_FREERTOS_CORETIMER_0=y +# CONFIG_FREERTOS_CORETIMER_1 is not set +CONFIG_FREERTOS_SYSTICK_USES_CCOUNT=y +# CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH is not set +# CONFIG_FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH is not set +# CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set +CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT=y +# end of Port + +CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF +CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y +CONFIG_FREERTOS_DEBUG_OCDAWARE=y +# end of FreeRTOS + +# +# Hardware Abstraction Layer (HAL) and Low Level (LL) +# +CONFIG_HAL_ASSERTION_EQUALS_SYSTEM=y +# CONFIG_HAL_ASSERTION_DISABLE is not set +# CONFIG_HAL_ASSERTION_SILENT is not set +# CONFIG_HAL_ASSERTION_ENABLE is not set +CONFIG_HAL_DEFAULT_ASSERTION_LEVEL=2 +CONFIG_HAL_SPI_MASTER_FUNC_IN_IRAM=y +CONFIG_HAL_SPI_SLAVE_FUNC_IN_IRAM=y +# end of Hardware Abstraction Layer (HAL) and Low Level (LL) + +# +# Heap memory debugging +# +CONFIG_HEAP_POISONING_DISABLED=y +# CONFIG_HEAP_POISONING_LIGHT is not set +# CONFIG_HEAP_POISONING_COMPREHENSIVE is not set +CONFIG_HEAP_TRACING_OFF=y +# CONFIG_HEAP_TRACING_STANDALONE is not set +# CONFIG_HEAP_TRACING_TOHOST is not set +# CONFIG_HEAP_USE_HOOKS is not set +# CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS is not set +# CONFIG_HEAP_PLACE_FUNCTION_INTO_FLASH is not set +# end of Heap memory debugging + +CONFIG_IEEE802154_CCA_THRESHOLD=-60 +CONFIG_IEEE802154_PENDING_TABLE_SIZE=20 + +# +# Log output +# +# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set +# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set +# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set +CONFIG_LOG_DEFAULT_LEVEL_INFO=y +# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set +# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set +CONFIG_LOG_DEFAULT_LEVEL=3 +CONFIG_LOG_MAXIMUM_EQUALS_DEFAULT=y +# CONFIG_LOG_MAXIMUM_LEVEL_DEBUG is not set +# CONFIG_LOG_MAXIMUM_LEVEL_VERBOSE is not set +CONFIG_LOG_MAXIMUM_LEVEL=3 +CONFIG_LOG_COLORS=y +CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y +# CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set +# end of Log output + +# +# LWIP +# +CONFIG_LWIP_LOCAL_HOSTNAME="espressif" +# CONFIG_LWIP_NETIF_API is not set +CONFIG_LWIP_TCPIP_TASK_PRIO=18 +# CONFIG_LWIP_TCPIP_CORE_LOCKING is not set +# CONFIG_LWIP_CHECK_THREAD_SAFETY is not set +CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y +# CONFIG_LWIP_L2_TO_L3_COPY is not set +# CONFIG_LWIP_IRAM_OPTIMIZATION is not set +# CONFIG_LWIP_EXTRA_IRAM_OPTIMIZATION is not set +CONFIG_LWIP_TIMERS_ONDEMAND=y +CONFIG_LWIP_ND6=y +CONFIG_LWIP_MAX_SOCKETS=10 +# CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set +# CONFIG_LWIP_SO_LINGER is not set +CONFIG_LWIP_SO_REUSE=y +CONFIG_LWIP_SO_REUSE_RXTOALL=y +# CONFIG_LWIP_SO_RCVBUF is not set +# CONFIG_LWIP_NETBUF_RECVINFO is not set +CONFIG_LWIP_IP4_FRAG=y +CONFIG_LWIP_IP6_FRAG=y +# CONFIG_LWIP_IP4_REASSEMBLY is not set +# CONFIG_LWIP_IP6_REASSEMBLY is not set +CONFIG_LWIP_IP_REASS_MAX_PBUFS=10 +# CONFIG_LWIP_IP_FORWARD is not set +# CONFIG_LWIP_STATS is not set +CONFIG_LWIP_ESP_GRATUITOUS_ARP=y +CONFIG_LWIP_GARP_TMR_INTERVAL=60 +CONFIG_LWIP_ESP_MLDV6_REPORT=y +CONFIG_LWIP_MLDV6_TMR_INTERVAL=40 +CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32 +CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y +# CONFIG_LWIP_DHCP_DISABLE_CLIENT_ID is not set +CONFIG_LWIP_DHCP_DISABLE_VENDOR_CLASS_ID=y +# CONFIG_LWIP_DHCP_RESTORE_LAST_IP is not set +CONFIG_LWIP_DHCP_OPTIONS_LEN=68 +CONFIG_LWIP_NUM_NETIF_CLIENT_DATA=0 +CONFIG_LWIP_DHCP_COARSE_TIMER_SECS=1 + +# +# DHCP server +# +CONFIG_LWIP_DHCPS=y +CONFIG_LWIP_DHCPS_LEASE_UNIT=60 +CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8 +# end of DHCP server + +# CONFIG_LWIP_AUTOIP is not set +CONFIG_LWIP_IPV4=y +CONFIG_LWIP_IPV6=y +# CONFIG_LWIP_IPV6_AUTOCONFIG is not set +CONFIG_LWIP_IPV6_NUM_ADDRESSES=3 +# CONFIG_LWIP_IPV6_FORWARD is not set +# CONFIG_LWIP_NETIF_STATUS_CALLBACK is not set +CONFIG_LWIP_NETIF_LOOPBACK=y +CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8 + +# +# TCP +# +CONFIG_LWIP_MAX_ACTIVE_TCP=16 +CONFIG_LWIP_MAX_LISTENING_TCP=16 +CONFIG_LWIP_TCP_HIGH_SPEED_RETRANSMISSION=y +CONFIG_LWIP_TCP_MAXRTX=12 +CONFIG_LWIP_TCP_SYNMAXRTX=12 +CONFIG_LWIP_TCP_MSS=1440 +CONFIG_LWIP_TCP_TMR_INTERVAL=250 +CONFIG_LWIP_TCP_MSL=60000 +CONFIG_LWIP_TCP_FIN_WAIT_TIMEOUT=20000 +CONFIG_LWIP_TCP_SND_BUF_DEFAULT=5744 +CONFIG_LWIP_TCP_WND_DEFAULT=5744 +CONFIG_LWIP_TCP_RECVMBOX_SIZE=6 +CONFIG_LWIP_TCP_QUEUE_OOSEQ=y +# CONFIG_LWIP_TCP_SACK_OUT is not set +CONFIG_LWIP_TCP_OVERSIZE_MSS=y +# CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS is not set +# CONFIG_LWIP_TCP_OVERSIZE_DISABLE is not set +CONFIG_LWIP_TCP_RTO_TIME=1500 +# end of TCP + +# +# UDP +# +CONFIG_LWIP_MAX_UDP_PCBS=16 +CONFIG_LWIP_UDP_RECVMBOX_SIZE=6 +# end of UDP + +# +# Checksums +# +# CONFIG_LWIP_CHECKSUM_CHECK_IP is not set +# CONFIG_LWIP_CHECKSUM_CHECK_UDP is not set +CONFIG_LWIP_CHECKSUM_CHECK_ICMP=y +# end of Checksums + +CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=3072 +CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y +# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set +# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU1 is not set +CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF +# CONFIG_LWIP_PPP_SUPPORT is not set +CONFIG_LWIP_IPV6_MEMP_NUM_ND6_QUEUE=3 +CONFIG_LWIP_IPV6_ND6_NUM_NEIGHBORS=5 +# CONFIG_LWIP_SLIP_SUPPORT is not set + +# +# ICMP +# +CONFIG_LWIP_ICMP=y +# CONFIG_LWIP_MULTICAST_PING is not set +# CONFIG_LWIP_BROADCAST_PING is not set +# end of ICMP + +# +# LWIP RAW API +# +CONFIG_LWIP_MAX_RAW_PCBS=16 +# end of LWIP RAW API + +# +# SNTP +# +CONFIG_LWIP_SNTP_MAX_SERVERS=1 +# CONFIG_LWIP_DHCP_GET_NTP_SRV is not set +CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000 +# end of SNTP + +CONFIG_LWIP_BRIDGEIF_MAX_PORTS=7 +CONFIG_LWIP_ESP_LWIP_ASSERT=y + +# +# Hooks +# +# CONFIG_LWIP_HOOK_TCP_ISN_NONE is not set +CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT=y +# CONFIG_LWIP_HOOK_TCP_ISN_CUSTOM is not set +CONFIG_LWIP_HOOK_IP6_ROUTE_NONE=y +# CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT is not set +# CONFIG_LWIP_HOOK_IP6_ROUTE_CUSTOM is not set +CONFIG_LWIP_HOOK_ND6_GET_GW_NONE=y +# CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT is not set +# CONFIG_LWIP_HOOK_ND6_GET_GW_CUSTOM is not set +CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_NONE=y +# CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_DEFAULT is not set +# CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_CUSTOM is not set +CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y +# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_DEFAULT is not set +# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM is not set +CONFIG_LWIP_HOOK_IP6_INPUT_NONE=y +# CONFIG_LWIP_HOOK_IP6_INPUT_DEFAULT is not set +# CONFIG_LWIP_HOOK_IP6_INPUT_CUSTOM is not set +# end of Hooks + +# CONFIG_LWIP_DEBUG is not set +# end of LWIP + +# +# mbedTLS +# +CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y +# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set +# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set +CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y +CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384 +CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096 +# CONFIG_MBEDTLS_DYNAMIC_BUFFER is not set +# CONFIG_MBEDTLS_DEBUG is not set + +# +# mbedTLS v3.x related +# +# CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 is not set +# CONFIG_MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH is not set +CONFIG_MBEDTLS_ECDH_LEGACY_CONTEXT=y +# CONFIG_MBEDTLS_X509_TRUSTED_CERT_CALLBACK is not set +# CONFIG_MBEDTLS_SSL_CONTEXT_SERIALIZATION is not set +CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE=y +CONFIG_MBEDTLS_PKCS7_C=y +# end of mbedTLS v3.x related + +# +# Certificate Bundle +# +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=y +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set +# CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS=200 +# end of Certificate Bundle + +CONFIG_MBEDTLS_ECP_RESTARTABLE=y +CONFIG_MBEDTLS_CMAC_C=y +CONFIG_MBEDTLS_HARDWARE_AES=y +CONFIG_MBEDTLS_HARDWARE_MPI=y +CONFIG_MBEDTLS_HARDWARE_SHA=y +CONFIG_MBEDTLS_ROM_MD5=y +# CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN is not set +# CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY is not set +CONFIG_MBEDTLS_HAVE_TIME=y +# CONFIG_MBEDTLS_PLATFORM_TIME_ALT is not set +# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set +CONFIG_MBEDTLS_ECDSA_DETERMINISTIC=y +CONFIG_MBEDTLS_SHA512_C=y +CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y +# CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set +# CONFIG_MBEDTLS_TLS_CLIENT_ONLY is not set +# CONFIG_MBEDTLS_TLS_DISABLED is not set +CONFIG_MBEDTLS_TLS_SERVER=y +CONFIG_MBEDTLS_TLS_CLIENT=y +CONFIG_MBEDTLS_TLS_ENABLED=y + +# +# TLS Key Exchange Methods +# +# CONFIG_MBEDTLS_PSK_MODES is not set +CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y +# end of TLS Key Exchange Methods + +CONFIG_MBEDTLS_SSL_RENEGOTIATION=y +CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y +# CONFIG_MBEDTLS_SSL_PROTO_GMTSSL1_1 is not set +# CONFIG_MBEDTLS_SSL_PROTO_DTLS is not set +CONFIG_MBEDTLS_SSL_ALPN=y +CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS=y +CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS=y + +# +# Symmetric Ciphers +# +CONFIG_MBEDTLS_AES_C=y +# CONFIG_MBEDTLS_CAMELLIA_C is not set +# CONFIG_MBEDTLS_DES_C is not set +# CONFIG_MBEDTLS_BLOWFISH_C is not set +# CONFIG_MBEDTLS_XTEA_C is not set +CONFIG_MBEDTLS_CCM_C=y +CONFIG_MBEDTLS_GCM_C=y +# CONFIG_MBEDTLS_NIST_KW_C is not set +# end of Symmetric Ciphers + +# CONFIG_MBEDTLS_RIPEMD160_C is not set + +# +# Certificates +# +CONFIG_MBEDTLS_PEM_PARSE_C=y +CONFIG_MBEDTLS_PEM_WRITE_C=y +CONFIG_MBEDTLS_X509_CRL_PARSE_C=y +CONFIG_MBEDTLS_X509_CSR_PARSE_C=y +# end of Certificates + +CONFIG_MBEDTLS_ECP_C=y +# CONFIG_MBEDTLS_DHM_C is not set +CONFIG_MBEDTLS_ECDH_C=y +CONFIG_MBEDTLS_ECDSA_C=y +# CONFIG_MBEDTLS_ECJPAKE_C is not set +CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y +CONFIG_MBEDTLS_ECP_NIST_OPTIM=y +CONFIG_MBEDTLS_ECP_FIXED_POINT_OPTIM=y +# CONFIG_MBEDTLS_POLY1305_C is not set +# CONFIG_MBEDTLS_CHACHA20_C is not set +# CONFIG_MBEDTLS_HKDF_C is not set +# CONFIG_MBEDTLS_THREADING_C is not set +# CONFIG_MBEDTLS_LARGE_KEY_SOFTWARE_MPI is not set +# end of mbedTLS + +# +# ESP-MQTT Configurations +# +CONFIG_MQTT_PROTOCOL_311=y +# CONFIG_MQTT_PROTOCOL_5 is not set +CONFIG_MQTT_TRANSPORT_SSL=y +CONFIG_MQTT_TRANSPORT_WEBSOCKET=y +CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y +# CONFIG_MQTT_MSG_ID_INCREMENTAL is not set +# CONFIG_MQTT_SKIP_PUBLISH_IF_DISCONNECTED is not set +# CONFIG_MQTT_REPORT_DELETED_MESSAGES is not set +# CONFIG_MQTT_USE_CUSTOM_CONFIG is not set +# CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED is not set +# CONFIG_MQTT_CUSTOM_OUTBOX is not set +# end of ESP-MQTT Configurations + +# +# Newlib +# +CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y +# CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF is not set +# CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR is not set +# CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF is not set +# CONFIG_NEWLIB_STDIN_LINE_ENDING_LF is not set +CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y +# CONFIG_NEWLIB_NANO_FORMAT is not set +CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT=y +# CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC is not set +# CONFIG_NEWLIB_TIME_SYSCALL_USE_HRT is not set +# CONFIG_NEWLIB_TIME_SYSCALL_USE_NONE is not set +# end of Newlib + +# +# NVS +# +# CONFIG_NVS_ASSERT_ERROR_CHECK is not set +# end of NVS + +# +# OpenThread +# +# CONFIG_OPENTHREAD_ENABLED is not set + +# +# Thread Operational Dataset +# +CONFIG_OPENTHREAD_NETWORK_NAME="OpenThread-ESP" +CONFIG_OPENTHREAD_MESH_LOCAL_PREFIX="fd00:db8:a0:0::/64" +CONFIG_OPENTHREAD_NETWORK_CHANNEL=15 +CONFIG_OPENTHREAD_NETWORK_PANID=0x1234 +CONFIG_OPENTHREAD_NETWORK_EXTPANID="dead00beef00cafe" +CONFIG_OPENTHREAD_NETWORK_MASTERKEY="00112233445566778899aabbccddeeff" +CONFIG_OPENTHREAD_NETWORK_PSKC="104810e2315100afd6bc9215a6bfac53" +# end of Thread Operational Dataset + +CONFIG_OPENTHREAD_XTAL_ACCURACY=130 +# end of OpenThread + +# +# Protocomm +# +CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0=y +CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1=y +CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2=y +# end of Protocomm + +# +# PThreads +# +CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5 +CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 +CONFIG_PTHREAD_STACK_MIN=768 +CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY=y +# CONFIG_PTHREAD_DEFAULT_CORE_0 is not set +# CONFIG_PTHREAD_DEFAULT_CORE_1 is not set +CONFIG_PTHREAD_TASK_CORE_DEFAULT=-1 +CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread" +# end of PThreads + +# +# MMU Config +# +CONFIG_MMU_PAGE_SIZE_64KB=y +CONFIG_MMU_PAGE_MODE="64KB" +CONFIG_MMU_PAGE_SIZE=0x10000 +# end of MMU Config + +# +# SPI Flash driver +# +# CONFIG_SPI_FLASH_VERIFY_WRITE is not set +# CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set +CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y +CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y +# CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS is not set +# CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is not set +# CONFIG_SPI_FLASH_SHARE_SPI1_BUS is not set +# CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE is not set +CONFIG_SPI_FLASH_YIELD_DURING_ERASE=y +CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS=20 +CONFIG_SPI_FLASH_ERASE_YIELD_TICKS=1 +CONFIG_SPI_FLASH_WRITE_CHUNK_SIZE=8192 +# CONFIG_SPI_FLASH_SIZE_OVERRIDE is not set +# CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED is not set +# CONFIG_SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST is not set + +# +# SPI Flash behavior when brownout +# +CONFIG_SPI_FLASH_BROWNOUT_RESET_XMC=y +CONFIG_SPI_FLASH_BROWNOUT_RESET=y +# end of SPI Flash behavior when brownout + +# +# Auto-detect flash chips +# +CONFIG_SPI_FLASH_VENDOR_XMC_SUPPORTED=y +CONFIG_SPI_FLASH_VENDOR_GD_SUPPORTED=y +CONFIG_SPI_FLASH_VENDOR_ISSI_SUPPORTED=y +CONFIG_SPI_FLASH_VENDOR_MXIC_SUPPORTED=y +CONFIG_SPI_FLASH_VENDOR_WINBOND_SUPPORTED=y +CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_GD_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP=y +# CONFIG_SPI_FLASH_SUPPORT_BOYA_CHIP is not set +# CONFIG_SPI_FLASH_SUPPORT_TH_CHIP is not set +# end of Auto-detect flash chips + +CONFIG_SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE=y +# end of SPI Flash driver + +# +# SPIFFS Configuration +# +CONFIG_SPIFFS_MAX_PARTITIONS=3 + +# +# SPIFFS Cache Configuration +# +CONFIG_SPIFFS_CACHE=y +CONFIG_SPIFFS_CACHE_WR=y +# CONFIG_SPIFFS_CACHE_STATS is not set +# end of SPIFFS Cache Configuration + +CONFIG_SPIFFS_PAGE_CHECK=y +CONFIG_SPIFFS_GC_MAX_RUNS=10 +# CONFIG_SPIFFS_GC_STATS is not set +CONFIG_SPIFFS_PAGE_SIZE=256 +CONFIG_SPIFFS_OBJ_NAME_LEN=32 +# CONFIG_SPIFFS_FOLLOW_SYMLINKS is not set +CONFIG_SPIFFS_USE_MAGIC=y +CONFIG_SPIFFS_USE_MAGIC_LENGTH=y +CONFIG_SPIFFS_META_LENGTH=4 +CONFIG_SPIFFS_USE_MTIME=y + +# +# Debug Configuration +# +# CONFIG_SPIFFS_DBG is not set +# CONFIG_SPIFFS_API_DBG is not set +# CONFIG_SPIFFS_GC_DBG is not set +# CONFIG_SPIFFS_CACHE_DBG is not set +# CONFIG_SPIFFS_CHECK_DBG is not set +# CONFIG_SPIFFS_TEST_VISUALISATION is not set +# end of Debug Configuration +# end of SPIFFS Configuration + +# +# TCP Transport +# + +# +# Websocket +# +CONFIG_WS_TRANSPORT=y +CONFIG_WS_BUFFER_SIZE=1024 +# CONFIG_WS_DYNAMIC_BUFFER is not set +# end of Websocket +# end of TCP Transport + +# +# Ultra Low Power (ULP) Co-processor +# +# CONFIG_ULP_COPROC_ENABLED is not set +# end of Ultra Low Power (ULP) Co-processor + +# +# Unity unit testing library +# +CONFIG_UNITY_ENABLE_FLOAT=y +CONFIG_UNITY_ENABLE_DOUBLE=y +# CONFIG_UNITY_ENABLE_64BIT is not set +# CONFIG_UNITY_ENABLE_COLOR is not set +CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y +# CONFIG_UNITY_ENABLE_FIXTURE is not set +# CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL is not set +# end of Unity unit testing library + +# +# Root Hub configuration +# +# end of Root Hub configuration + +# +# Virtual file system +# +CONFIG_VFS_SUPPORT_IO=y +CONFIG_VFS_SUPPORT_DIR=y +CONFIG_VFS_SUPPORT_SELECT=y +CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y +CONFIG_VFS_SUPPORT_TERMIOS=y +CONFIG_VFS_MAX_COUNT=8 + +# +# Host File System I/O (Semihosting) +# +CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1 +# end of Host File System I/O (Semihosting) +# end of Virtual file system + +# +# Wear Levelling +# +# CONFIG_WL_SECTOR_SIZE_512 is not set +CONFIG_WL_SECTOR_SIZE_4096=y +CONFIG_WL_SECTOR_SIZE=4096 +# end of Wear Levelling + +# +# Wi-Fi Provisioning Manager +# +CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16 +CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30 +# CONFIG_WIFI_PROV_BLE_BONDING is not set +CONFIG_WIFI_PROV_BLE_SEC_CONN=y +# CONFIG_WIFI_PROV_BLE_FORCE_ENCRYPTION is not set +# CONFIG_WIFI_PROV_KEEP_BLE_ON_AFTER_PROV is not set +CONFIG_WIFI_PROV_STA_ALL_CHANNEL_SCAN=y +# CONFIG_WIFI_PROV_STA_FAST_SCAN is not set +# end of Wi-Fi Provisioning Manager +# end of Component config + +# CONFIG_IDF_EXPERIMENTAL_FEATURES is not set + +# Deprecated options for backward compatibility +# CONFIG_APP_BUILD_TYPE_ELF_RAM is not set +# CONFIG_NO_BLOBS is not set +# CONFIG_ESP32_NO_BLOBS is not set +# CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set +# CONFIG_ESP32_COMPATIBLE_PRE_V3_1_BOOTLOADERS is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_WARN is not set +CONFIG_LOG_BOOTLOADER_LEVEL_INFO=y +# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set +CONFIG_LOG_BOOTLOADER_LEVEL=3 +# CONFIG_APP_ROLLBACK_ENABLE is not set +# CONFIG_FLASH_ENCRYPTION_ENABLED is not set +# CONFIG_FLASHMODE_QIO is not set +# CONFIG_FLASHMODE_QOUT is not set +CONFIG_FLASHMODE_DIO=y +# CONFIG_FLASHMODE_DOUT is not set +CONFIG_MONITOR_BAUD=115200 +CONFIG_OPTIMIZATION_LEVEL_DEBUG=y +CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG=y +# CONFIG_OPTIMIZATION_LEVEL_RELEASE is not set +# CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is not set +CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y +# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set +# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set +CONFIG_OPTIMIZATION_ASSERTION_LEVEL=2 +# CONFIG_CXX_EXCEPTIONS is not set +CONFIG_STACK_CHECK_NONE=y +# CONFIG_STACK_CHECK_NORM is not set +# CONFIG_STACK_CHECK_STRONG is not set +# CONFIG_STACK_CHECK_ALL is not set +# CONFIG_WARN_WRITE_STRINGS is not set +# CONFIG_ESP32_APPTRACE_DEST_TRAX is not set +CONFIG_ESP32_APPTRACE_DEST_NONE=y +CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y +# CONFIG_BLUEDROID_ENABLED is not set +CONFIG_NIMBLE_ENABLED=y +CONFIG_NIMBLE_MEM_ALLOC_MODE_INTERNAL=y +# CONFIG_NIMBLE_MEM_ALLOC_MODE_DEFAULT is not set +CONFIG_NIMBLE_MAX_CONNECTIONS=3 +CONFIG_NIMBLE_MAX_BONDS=3 +CONFIG_NIMBLE_MAX_CCCDS=8 +CONFIG_NIMBLE_L2CAP_COC_MAX_NUM=0 +CONFIG_NIMBLE_PINNED_TO_CORE_0=y +# CONFIG_NIMBLE_PINNED_TO_CORE_1 is not set +CONFIG_NIMBLE_PINNED_TO_CORE=0 +CONFIG_NIMBLE_TASK_STACK_SIZE=4096 +CONFIG_BT_NIMBLE_TASK_STACK_SIZE=4096 +CONFIG_NIMBLE_ROLE_CENTRAL=y +CONFIG_NIMBLE_ROLE_PERIPHERAL=y +CONFIG_NIMBLE_ROLE_BROADCASTER=y +CONFIG_NIMBLE_ROLE_OBSERVER=y +# CONFIG_NIMBLE_NVS_PERSIST is not set +CONFIG_NIMBLE_SM_LEGACY=y +CONFIG_NIMBLE_SM_SC=y +# CONFIG_NIMBLE_SM_SC_DEBUG_KEYS is not set +# CONFIG_NIMBLE_DEBUG is not set +CONFIG_NIMBLE_SVC_GAP_DEVICE_NAME="nimble" +CONFIG_NIMBLE_GAP_DEVICE_NAME_MAX_LEN=31 +CONFIG_NIMBLE_ATT_PREFERRED_MTU=256 +CONFIG_NIMBLE_SVC_GAP_APPEARANCE=0 +CONFIG_BT_NIMBLE_MSYS1_BLOCK_COUNT=12 +CONFIG_BT_NIMBLE_ACL_BUF_COUNT=24 +CONFIG_BT_NIMBLE_ACL_BUF_SIZE=255 +CONFIG_BT_NIMBLE_HCI_EVT_BUF_SIZE=70 +CONFIG_BT_NIMBLE_HCI_EVT_HI_BUF_COUNT=30 +CONFIG_BT_NIMBLE_HCI_EVT_LO_BUF_COUNT=8 +CONFIG_NIMBLE_HS_FLOW_CTRL=y +CONFIG_NIMBLE_HS_FLOW_CTRL_ITVL=1000 +CONFIG_NIMBLE_HS_FLOW_CTRL_THRESH=2 +CONFIG_NIMBLE_HS_FLOW_CTRL_TX_ON_DISCONNECT=y +CONFIG_NIMBLE_RPA_TIMEOUT=900 +# CONFIG_NIMBLE_MESH is not set +CONFIG_NIMBLE_CRYPTO_STACK_MBEDTLS=y +CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y +# CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY is not set +# CONFIG_BTDM_CONTROLLER_MODE_BTDM is not set +CONFIG_BTDM_CONTROLLER_BLE_MAX_CONN=3 +CONFIG_BTDM_CONTROLLER_BLE_MAX_CONN_EFF=3 +CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN_EFF=0 +CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN_EFF=0 +CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE=0 +CONFIG_BTDM_CONTROLLER_HCI_MODE_VHCI=y +# CONFIG_BTDM_CONTROLLER_HCI_MODE_UART_H4 is not set +CONFIG_BTDM_CONTROLLER_MODEM_SLEEP=y +CONFIG_BLE_SCAN_DUPLICATE=y +CONFIG_SCAN_DUPLICATE_BY_DEVICE_ADDR=y +# CONFIG_SCAN_DUPLICATE_BY_ADV_DATA is not set +# CONFIG_SCAN_DUPLICATE_BY_ADV_DATA_AND_DEVICE_ADDR is not set +CONFIG_SCAN_DUPLICATE_TYPE=0 +CONFIG_DUPLICATE_SCAN_CACHE_SIZE=100 +# CONFIG_BLE_MESH_SCAN_DUPLICATE_EN is not set +CONFIG_BTDM_CONTROLLER_FULL_SCAN_SUPPORTED=y +CONFIG_BLE_ADV_REPORT_FLOW_CONTROL_SUPPORTED=y +CONFIG_BLE_ADV_REPORT_FLOW_CONTROL_NUM=100 +CONFIG_BLE_ADV_REPORT_DISCARD_THRSHOLD=20 +CONFIG_ADC2_DISABLE_DAC=y +# CONFIG_MCPWM_ISR_IN_IRAM is not set +CONFIG_SW_COEXIST_ENABLE=y +CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE=y +CONFIG_ESP_WIFI_SW_COEXIST_ENABLE=y +# CONFIG_EVENT_LOOP_PROFILING is not set +CONFIG_POST_EVENTS_FROM_ISR=y +CONFIG_POST_EVENTS_FROM_IRAM_ISR=y +# CONFIG_OTA_ALLOW_HTTP is not set +# CONFIG_TWO_UNIVERSAL_MAC_ADDRESS is not set +CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS=y +CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS=4 +# CONFIG_ESP_SYSTEM_PD_FLASH is not set +CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY=2000 +CONFIG_ESP32_RTC_CLK_SRC_INT_RC=y +CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC=y +# CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS is not set +# CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL is not set +# CONFIG_ESP32_RTC_CLK_SRC_EXT_OSC is not set +# CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_OSC is not set +# CONFIG_ESP32_RTC_CLK_SRC_INT_8MD256 is not set +# CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_8MD256 is not set +CONFIG_ESP32_RTC_CLK_CAL_CYCLES=1024 +# CONFIG_ESP32_XTAL_FREQ_26 is not set +CONFIG_ESP32_XTAL_FREQ_40=y +# CONFIG_ESP32_XTAL_FREQ_AUTO is not set +CONFIG_ESP32_XTAL_FREQ=40 +CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y +# CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set +CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20 +CONFIG_ESP32_PHY_MAX_TX_POWER=20 +# CONFIG_REDUCE_PHY_TX_POWER is not set +# CONFIG_ESP32_REDUCE_PHY_TX_POWER is not set +# CONFIG_SPIRAM_SUPPORT is not set +# CONFIG_ESP32_SPIRAM_SUPPORT is not set +# CONFIG_ESP32_DEFAULT_CPU_FREQ_80 is not set +CONFIG_ESP32_DEFAULT_CPU_FREQ_160=y +# CONFIG_ESP32_DEFAULT_CPU_FREQ_240 is not set +CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=160 +CONFIG_TRACEMEM_RESERVE_DRAM=0x0 +# CONFIG_ESP32_PANIC_PRINT_HALT is not set +CONFIG_ESP32_PANIC_PRINT_REBOOT=y +# CONFIG_ESP32_PANIC_SILENT_REBOOT is not set +# CONFIG_ESP32_PANIC_GDBSTUB is not set +CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 +CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304 +CONFIG_MAIN_TASK_STACK_SIZE=3584 +CONFIG_CONSOLE_UART_DEFAULT=y +# CONFIG_CONSOLE_UART_CUSTOM is not set +# CONFIG_CONSOLE_UART_NONE is not set +# CONFIG_ESP_CONSOLE_UART_NONE is not set +CONFIG_CONSOLE_UART=y +CONFIG_CONSOLE_UART_NUM=0 +CONFIG_CONSOLE_UART_BAUDRATE=115200 +CONFIG_INT_WDT=y +CONFIG_INT_WDT_TIMEOUT_MS=300 +CONFIG_INT_WDT_CHECK_CPU1=y +CONFIG_TASK_WDT=y +CONFIG_ESP_TASK_WDT=y +# CONFIG_TASK_WDT_PANIC is not set +CONFIG_TASK_WDT_TIMEOUT_S=5 +CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=y +CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1=y +# CONFIG_ESP32_DEBUG_STUBS_ENABLE is not set +CONFIG_ESP32_DEBUG_OCDAWARE=y +CONFIG_BROWNOUT_DET=y +CONFIG_ESP32_BROWNOUT_DET=y +CONFIG_BROWNOUT_DET_LVL_SEL_0=y +CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_0=y +# CONFIG_BROWNOUT_DET_LVL_SEL_1 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_1 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_2 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_2 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_7 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_7 is not set +CONFIG_BROWNOUT_DET_LVL=0 +CONFIG_ESP32_BROWNOUT_DET_LVL=0 +# CONFIG_DISABLE_BASIC_ROM_CONSOLE is not set +CONFIG_IPC_TASK_STACK_SIZE=1024 +CONFIG_TIMER_TASK_STACK_SIZE=3584 +CONFIG_ESP32_WIFI_ENABLED=y +CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=10 +CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=32 +# CONFIG_ESP32_WIFI_STATIC_TX_BUFFER is not set +CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER=y +CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=1 +CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=32 +# CONFIG_ESP32_WIFI_CSI_ENABLED is not set +CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y +CONFIG_ESP32_WIFI_TX_BA_WIN=6 +CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y +CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y +CONFIG_ESP32_WIFI_RX_BA_WIN=6 +CONFIG_ESP32_WIFI_RX_BA_WIN=6 +CONFIG_ESP32_WIFI_NVS_ENABLED=y +CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y +# CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1 is not set +CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN=752 +CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32 +CONFIG_ESP32_WIFI_IRAM_OPT=y +CONFIG_ESP32_WIFI_RX_IRAM_OPT=y +CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y +CONFIG_ESP32_WIFI_ENABLE_WPA3_OWE_STA=y +CONFIG_WPA_MBEDTLS_CRYPTO=y +CONFIG_WPA_MBEDTLS_TLS_CLIENT=y +# CONFIG_WPA_WAPI_PSK is not set +# CONFIG_WPA_11KV_SUPPORT is not set +# CONFIG_WPA_MBO_SUPPORT is not set +# CONFIG_WPA_DPP_SUPPORT is not set +# CONFIG_WPA_11R_SUPPORT is not set +# CONFIG_WPA_WPS_SOFTAP_REGISTRAR is not set +# CONFIG_WPA_WPS_STRICT is not set +# CONFIG_WPA_DEBUG_PRINT is not set +# CONFIG_WPA_TESTING_OPTIONS is not set +# CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set +# CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set +CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y +CONFIG_TIMER_TASK_PRIORITY=1 +CONFIG_TIMER_TASK_STACK_DEPTH=2048 +CONFIG_TIMER_QUEUE_LENGTH=10 +# CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set +# CONFIG_HAL_ASSERTION_SILIENT is not set +# CONFIG_L2_TO_L3_COPY is not set +CONFIG_ESP_GRATUITOUS_ARP=y +CONFIG_GARP_TMR_INTERVAL=60 +CONFIG_TCPIP_RECVMBOX_SIZE=32 +CONFIG_TCP_MAXRTX=12 +CONFIG_TCP_SYNMAXRTX=12 +CONFIG_TCP_MSS=1440 +CONFIG_TCP_MSL=60000 +CONFIG_TCP_SND_BUF_DEFAULT=5744 +CONFIG_TCP_WND_DEFAULT=5744 +CONFIG_TCP_RECVMBOX_SIZE=6 +CONFIG_TCP_QUEUE_OOSEQ=y +CONFIG_TCP_OVERSIZE_MSS=y +# CONFIG_TCP_OVERSIZE_QUARTER_MSS is not set +# CONFIG_TCP_OVERSIZE_DISABLE is not set +CONFIG_UDP_RECVMBOX_SIZE=6 +CONFIG_TCPIP_TASK_STACK_SIZE=3072 +CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY=y +# CONFIG_TCPIP_TASK_AFFINITY_CPU0 is not set +# CONFIG_TCPIP_TASK_AFFINITY_CPU1 is not set +CONFIG_TCPIP_TASK_AFFINITY=0x7FFFFFFF +# CONFIG_PPP_SUPPORT is not set +CONFIG_ESP32_TIME_SYSCALL_USE_RTC_HRT=y +CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1=y +# CONFIG_ESP32_TIME_SYSCALL_USE_RTC is not set +# CONFIG_ESP32_TIME_SYSCALL_USE_HRT is not set +# CONFIG_ESP32_TIME_SYSCALL_USE_FRC1 is not set +# CONFIG_ESP32_TIME_SYSCALL_USE_NONE is not set +CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5 +CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 +CONFIG_ESP32_PTHREAD_STACK_MIN=768 +CONFIG_ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY=y +# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_0 is not set +# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_1 is not set +CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT=-1 +CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread" +CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y +# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set +# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set +# CONFIG_ESP32_ULP_COPROC_ENABLED is not set +CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y +CONFIG_SUPPORT_TERMIOS=y +CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1 +# End of deprecated options diff --git a/sdkconfig.defaults b/sdkconfig.defaults new file mode 100644 index 0000000..b01f745 --- /dev/null +++ b/sdkconfig.defaults @@ -0,0 +1,3 @@ +CONFIG_BT_ENABLED=y +CONFIG_BT_NIMBLE_ENABLED=y +CONFIG_BT_CONTROLLER_ENABLED=y diff --git a/simulator/CMakeLists.txt b/simulator/CMakeLists.txt new file mode 100644 index 0000000..30528bf --- /dev/null +++ b/simulator/CMakeLists.txt @@ -0,0 +1,33 @@ +cmake_minimum_required(VERSION 3.16) + +project(simulator C) + +# Needed to find GLib +find_package(PkgConfig REQUIRED) +pkg_check_modules(GLIB2 REQUIRED glib-2.0 gio-2.0) + +include_directories(${GLIB2_INCLUDE_DIRS}) +link_directories(${GLIB2_LIBRARY_DIRS}) +add_definitions(${GLIB2_CFLAGS_OTHER}) + +include(FetchContent) + +FetchContent_Declare( + bluez_inc + GIT_REPOSITORY https://github.com/weliem/bluez_inc.git + GIT_TAG main +) + +FetchContent_MakeAvailable(bluez_inc) + +add_executable(simulator main.c) + +target_link_libraries(simulator PRIVATE Binc ${GLIB2_LIBRARIES}) + +# Integration test binary — forks the simulator binary, needs only pthreads +add_executable(test_ble test_ble.c) +target_link_libraries(test_ble PRIVATE pthread) +add_dependencies(test_ble simulator) +target_compile_definitions(test_ble PRIVATE + SIM_BIN="$" +) diff --git a/simulator/main.c b/simulator/main.c new file mode 100644 index 0000000..193af98 --- /dev/null +++ b/simulator/main.c @@ -0,0 +1,283 @@ +#include +#include +#include +#include +#include +#include +#include +#include "adapter.h" +#include "advertisement.h" +#include "device.h" +#include "logger.h" + +#define TAG "commeownder-sim" + +#define MANUFACTURER_ID 0xFFFF +#define MAGIC_0 0xC0 +#define MAGIC_1 0xDE +#define PLAYER_NAME_LEN 8 +#define MAX_OPPONENTS 4 + +#pragma pack(push, 1) +typedef struct { + uint8_t magic[2]; + uint8_t game_id[2]; + char name[PLAYER_NAME_LEN]; + int16_t life; + uint8_t poison; + uint8_t eliminated; + uint8_t player_id; + uint8_t reset_cmd; + uint8_t cmdr_dmg[MAX_OPPONENTS]; +} ble_payload_t; +#pragma pack(pop) + +static GMainLoop *loop = NULL; +static Adapter *default_adapter = NULL; +static Advertisement *adv = NULL; + +static char g_name[PLAYER_NAME_LEN + 1] = {0}; +static int16_t g_life = 40; +static int16_t g_start_life = 40; +static uint8_t g_poison = 0; +static uint8_t g_game_id[2] = {0x42, 0x42}; +static uint8_t g_eliminated = 0; +static uint8_t g_player_id = 0; +static uint8_t g_reset_cmd = 0; +static uint8_t g_cmdr_dmg[MAX_OPPONENTS] = {0}; + +// Monotonic time of last processed reset (microseconds); 0 = never +static gint64 g_last_reset_us = 0; +#define RESET_COOLDOWN_US (10LL * 1000000LL) // 10 seconds + +static void start_advertising(void) { + ble_payload_t payload; + memset(&payload, 0, sizeof(payload)); + payload.magic[0] = MAGIC_0; + payload.magic[1] = MAGIC_1; + payload.game_id[0] = g_game_id[0]; + payload.game_id[1] = g_game_id[1]; + strncpy(payload.name, g_name, PLAYER_NAME_LEN); + payload.life = g_life; + payload.poison = g_poison; + payload.eliminated = g_eliminated; + payload.player_id = g_player_id; + payload.reset_cmd = g_reset_cmd; + memcpy(payload.cmdr_dmg, g_cmdr_dmg, MAX_OPPONENTS); + + GByteArray *data = g_byte_array_new(); + g_byte_array_append(data, (const guint8 *)&payload, sizeof(payload)); + + adv = binc_advertisement_create(); + binc_advertisement_set_manufacturer_data(adv, MANUFACTURER_ID, data); + binc_advertisement_set_interval(adv, 500, 500); + binc_advertisement_set_general_discoverable(adv, FALSE); + g_byte_array_free(data, TRUE); + + binc_adapter_start_advertising(default_adapter, adv); + fprintf(stderr, "advertising: name='%s' life=%d poison=%u game_id=%02X%02X pid=%u reset=%u cmdr=[%u,%u,%u,%u]\n", + g_name, (int)g_life, (unsigned)g_poison, + g_game_id[0], g_game_id[1], (unsigned)g_player_id, (unsigned)g_reset_cmd, + g_cmdr_dmg[0], g_cmdr_dmg[1], g_cmdr_dmg[2], g_cmdr_dmg[3]); +} + +static void restart_advertising(void) { + if (adv) { + binc_adapter_stop_advertising(default_adapter, adv); + binc_advertisement_free(adv); + adv = NULL; + } + start_advertising(); +} + +static void on_scan_result(Adapter *adapter, Device *device) { + (void)adapter; + GHashTable *mfr_data = binc_device_get_manufacturer_data(device); + if (!mfr_data) return; + + int key = MANUFACTURER_ID; + GByteArray *data = g_hash_table_lookup(mfr_data, &key); + if (!data || data->len < (guint)sizeof(ble_payload_t)) return; + + const ble_payload_t *p = (const ble_payload_t *)data->data; + if (p->magic[0] != MAGIC_0 || p->magic[1] != MAGIC_1) return; + if (p->game_id[0] != g_game_id[0] || p->game_id[1] != g_game_id[1]) return; + + char name[PLAYER_NAME_LEN + 1]; + memcpy(name, p->name, PLAYER_NAME_LEN); + name[PLAYER_NAME_LEN] = '\0'; + + printf("PEER addr=%s name=%-8s life=%-5d poison=%u pid=%u cmdr=[%u,%u,%u,%u]%s%s\n", + binc_device_get_address(device), name, + (int)p->life, (unsigned)p->poison, (unsigned)p->player_id, + (unsigned)p->cmdr_dmg[0], (unsigned)p->cmdr_dmg[1], + (unsigned)p->cmdr_dmg[2], (unsigned)p->cmdr_dmg[3], + p->eliminated ? " ELIMINATED" : "", + p->reset_cmd ? " RESET_CMD" : ""); + fflush(stdout); + + // Handle reset_cmd with cooldown to avoid acting on repeated broadcasts + if (p->reset_cmd) { + gint64 now = g_get_monotonic_time(); + if (now - g_last_reset_us >= RESET_COOLDOWN_US) { + g_last_reset_us = now; + g_life = g_start_life; + g_poison = 0; + g_eliminated = 0; + printf("RESET_ALL life=%d\n", (int)g_life); + fflush(stdout); + restart_advertising(); + } + } +} + +static void on_powered_state_changed(Adapter *adapter, gboolean state) { + if (!state) return; + start_advertising(); + binc_adapter_set_discovery_filter(adapter, -100, NULL, NULL); + binc_adapter_set_discovery_cb(adapter, on_scan_result); + binc_adapter_start_discovery(adapter); + fprintf(stderr, "scanning for peers...\n"); +} + +static void cleanup(void) { + if (adv) { + binc_adapter_stop_advertising(default_adapter, adv); + binc_advertisement_free(adv); + adv = NULL; + } + if (default_adapter) { + binc_adapter_stop_discovery(default_adapter); + binc_adapter_free(default_adapter); + default_adapter = NULL; + } + if (loop) g_main_loop_quit(loop); +} + +static gboolean cleanup_handler(gpointer user_data) { + (void)user_data; + cleanup(); + return G_SOURCE_REMOVE; +} + +static void print_usage(const char *prog) { + fprintf(stderr, + "Usage: %s --name [--life ] [--poison ] [--game-id ] [--player-id ] [--eliminated] [--reset-cmd] [--cmdr-dmg :]...\n" + " --name Player name (max 8 chars, required)\n" + " --life Life total (default: 40)\n" + " --poison Poison counters 0-9 (default: 0)\n" + " --game-id 4-hex-digit game ID (default: 4242)\n" + " --player-id Player slot 0-4 (default: 0)\n" + " --eliminated Mark player as eliminated\n" + " --reset-cmd Advertise reset_cmd=1 (tells peers to reset counters)\n" + " --cmdr-dmg Commander damage from opponent slot idx (0-3), e.g. --cmdr-dmg 0:7 (repeatable)\n", + prog); +} + +int main(int argc, char *argv[]) { + log_set_level(LOG_WARN); + + static const struct option long_opts[] = { + {"name", required_argument, NULL, 'n'}, + {"life", required_argument, NULL, 'l'}, + {"poison", required_argument, NULL, 'p'}, + {"game-id", required_argument, NULL, 'g'}, + {"player-id", required_argument, NULL, 'i'}, + {"eliminated", no_argument, NULL, 'e'}, + {"reset-cmd", no_argument, NULL, 'r'}, + {"cmdr-dmg", required_argument, NULL, 'd'}, + {NULL, 0, NULL, 0} + }; + + int name_set = 0; + int opt; + while ((opt = getopt_long(argc, argv, "", long_opts, NULL)) != -1) { + switch (opt) { + case 'n': + strncpy(g_name, optarg, PLAYER_NAME_LEN); + g_name[PLAYER_NAME_LEN] = '\0'; + name_set = 1; + break; + case 'l': + g_life = (int16_t)atoi(optarg); + break; + case 'p': + g_poison = (uint8_t)atoi(optarg); + break; + case 'g': { + unsigned int id; + if (sscanf(optarg, "%x", &id) != 1) { + fprintf(stderr, "invalid game-id '%s' (expected 4 hex digits)\n", optarg); + return 1; + } + g_game_id[0] = (uint8_t)((id >> 8) & 0xFF); + g_game_id[1] = (uint8_t)(id & 0xFF); + break; + } + case 'i': + g_player_id = (uint8_t)atoi(optarg); + break; + case 'e': + g_eliminated = 1; + break; + case 'r': + g_reset_cmd = 1; + break; + case 'd': { + int idx, val; + if (sscanf(optarg, "%d:%d", &idx, &val) != 2 || idx < 0 || idx >= MAX_OPPONENTS || val < 0 || val > 255) { + fprintf(stderr, "invalid cmdr-dmg '%s' (expected :, idx 0-%d, val 0-255)\n", optarg, MAX_OPPONENTS - 1); + return 1; + } + g_cmdr_dmg[idx] = (uint8_t)val; + break; + } + default: + print_usage(argv[0]); + return 1; + } + } + + if (!name_set) { + print_usage(argv[0]); + return 1; + } + + g_start_life = g_life; + + g_unix_signal_add(SIGINT, cleanup_handler, NULL); + g_unix_signal_add(SIGTERM, cleanup_handler, NULL); + + GDBusConnection *dbusConnection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL); + if (!dbusConnection) { + fprintf(stderr, "failed to connect to D-Bus\n"); + return 1; + } + + loop = g_main_loop_new(NULL, FALSE); + + default_adapter = binc_adapter_get_default(dbusConnection); + if (!default_adapter) { + fprintf(stderr, "no Bluetooth adapter found\n"); + return 1; + } + + fprintf(stderr, "adapter: %s (%s)\n", + binc_adapter_get_name(default_adapter), + binc_adapter_get_address(default_adapter)); + + binc_adapter_set_powered_state_cb(default_adapter, on_powered_state_changed); + + if (binc_adapter_get_powered_state(default_adapter)) { + on_powered_state_changed(default_adapter, TRUE); + } else { + binc_adapter_power_on(default_adapter); + } + + g_main_loop_run(loop); + + g_dbus_connection_close_sync(dbusConnection, NULL, NULL); + g_object_unref(dbusConnection); + g_main_loop_unref(loop); + return 0; +} diff --git a/simulator/test_ble.c b/simulator/test_ble.c new file mode 100644 index 0000000..c7840ea --- /dev/null +++ b/simulator/test_ble.c @@ -0,0 +1,1015 @@ +/* simulator/test_ble.c + * + * BLE integration tests for commeownder firmware. + * + * Spawns the simulator binary as fake BLE peers, reads the ESP32 serial port + * for "DBG ..." lines, and verifies correct BLE behaviour. + * + * Firmware must be compiled with -DDEBUG. + * Usage: ./test_ble [--port /dev/ttyUSB0] [--sim ./simulator] + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* ── Compile-time defaults ────────────────────────────────────────────────── */ +#ifndef SIM_BIN +# define SIM_BIN "./simulator" +#endif + +static const char *g_port = "/dev/ttyUSB0"; +static const char *g_sim_bin = SIM_BIN; + +/* ── Firmware constants (must mirror main.c) ─────────────────────────────── */ +#define DEFAULT_GAME_ID "4242" +#define WRONG_GAME_ID "BEEF" +#define BLE_TIMEOUT_S 30 +#define SCAN_CYCLE_S 21 +#define PEER_DETECT_S (SCAN_CYCLE_S + 12) +#define MAX_BLE_PEERS 4 + +/* ── Serial line queue ───────────────────────────────────────────────────── */ +#define LBUF 512 +#define QSIZE 256 + +typedef struct { + char data[QSIZE][LBUF]; + int head, tail, count; + pthread_mutex_t mtx; + pthread_cond_t cond; +} lq_t; + +static lq_t g_q; +static int g_serial_fd = -1; +static pthread_t g_serial_thr; +static volatile int g_serial_stop = 0; + +static void lq_init(lq_t *q) +{ + memset(q, 0, sizeof *q); + pthread_mutex_init(&q->mtx, NULL); + /* use CLOCK_MONOTONIC for timedwait so wall-clock adjustments don't bite */ + pthread_condattr_t attr; + pthread_condattr_init(&attr); + pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); + pthread_cond_init(&q->cond, &attr); + pthread_condattr_destroy(&attr); +} + +static void lq_push(lq_t *q, const char *line) +{ + pthread_mutex_lock(&q->mtx); + if (q->count < QSIZE) { + strncpy(q->data[q->tail], line, LBUF - 1); + q->data[q->tail][LBUF - 1] = '\0'; + q->tail = (q->tail + 1) % QSIZE; + q->count++; + pthread_cond_signal(&q->cond); + } + pthread_mutex_unlock(&q->mtx); +} + +static void lq_drain(lq_t *q) +{ + pthread_mutex_lock(&q->mtx); + q->head = q->tail = q->count = 0; + pthread_mutex_unlock(&q->mtx); +} + +/* + * Block until a queued line contains ALL strings in the NULL-terminated + * `pats` array, or `secs` seconds elapse. Returns 1 on match, 0 on timeout. + * Non-matching lines are consumed and discarded. + * If `out` != NULL, the matching line is copied there. + */ +static int lq_wait(lq_t *q, const char **pats, int secs, char *out) +{ + struct timespec dl; + clock_gettime(CLOCK_MONOTONIC, &dl); + dl.tv_sec += secs; + + pthread_mutex_lock(&q->mtx); + for (;;) { + while (q->count > 0) { + char *line = q->data[q->head]; + q->head = (q->head + 1) % QSIZE; + q->count--; + int ok = 1; + for (int i = 0; pats[i]; i++) + if (!strstr(line, pats[i])) { ok = 0; break; } + if (ok) { + if (out) strncpy(out, line, LBUF - 1); + pthread_mutex_unlock(&q->mtx); + return 1; + } + } + if (pthread_cond_timedwait(&q->cond, &q->mtx, &dl) == ETIMEDOUT) { + pthread_mutex_unlock(&q->mtx); + return 0; + } + } +} + +/* Convenience: wait for one pattern */ +static int wait1(const char *p, int secs, char *out) +{ + const char *pats[] = {p, NULL}; + return lq_wait(&g_q, pats, secs, out); +} + +/* Convenience: wait for two patterns in the same line */ +static int wait2(const char *p1, const char *p2, int secs, char *out) +{ + const char *pats[] = {p1, p2, NULL}; + return lq_wait(&g_q, pats, secs, out); +} + +/* ── Serial reader thread ─────────────────────────────────────────────────── */ +static void *serial_reader(void *arg) +{ + (void)arg; + char line[LBUF]; + int pos = 0; + + while (!g_serial_stop) { + char c; + ssize_t n = read(g_serial_fd, &c, 1); + if (n == 0) continue; /* VTIME timeout — no data yet */ + if (n < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { usleep(1000); continue; } + break; + } + if (c == '\n' || c == '\r') { + if (pos > 0) { + line[pos] = '\0'; + if (strncmp(line, "DBG ", 4) == 0) + lq_push(&g_q, line); + pos = 0; + } + } else if (pos < LBUF - 1) { + line[pos++] = c; + } + } + return NULL; +} + +static int open_serial(const char *port) +{ + int fd = open(port, O_RDWR | O_NOCTTY); + if (fd < 0) { perror("open"); return -1; } + + struct termios tty; + memset(&tty, 0, sizeof tty); + tty.c_cflag = CS8 | CREAD | CLOCAL; + cfsetispeed(&tty, B115200); + cfsetospeed(&tty, B115200); + tty.c_oflag = 0; + tty.c_lflag = 0; + tty.c_cc[VMIN] = 0; + tty.c_cc[VTIME] = 1; /* 0.1 s read timeout */ + if (tcsetattr(fd, TCSANOW, &tty) < 0) { perror("tcsetattr"); close(fd); return -1; } + return fd; +} + +static void serial_send(const char *cmd) +{ + size_t len = strlen(cmd); + if (write(g_serial_fd, cmd, len) < 0) perror("serial_send"); +} + +/* ── Child process tracking ──────────────────────────────────────────────── */ +#define MAX_CHILDREN 32 +static pid_t g_children[MAX_CHILDREN]; +static int g_nchildren = 0; + +static void register_child(pid_t pid) +{ + if (g_nchildren < MAX_CHILDREN) + g_children[g_nchildren++] = pid; +} + +static void kill_all_children(void) +{ + for (int i = 0; i < g_nchildren; i++) { + if (g_children[i] > 0) { + kill(g_children[i], SIGTERM); + waitpid(g_children[i], NULL, WNOHANG); + g_children[i] = 0; + } + } + g_nchildren = 0; +} + +static void sig_cleanup(int sig) +{ + (void)sig; + kill_all_children(); + _exit(1); +} + +/* ── Simulator subprocess helpers ─────────────────────────────────────────── */ +static pid_t sim_start_ex(const char *name, int life, int poison, + const char *game_id, int eliminated, + int player_id, int reset_cmd) +{ + pid_t pid = fork(); + if (pid < 0) { perror("fork"); return -1; } + if (pid == 0) { + close(g_serial_fd); + char lbuf[16], pbuf[16], idbuf[16], n8[9]; + snprintf(lbuf, sizeof lbuf, "%d", life); + snprintf(pbuf, sizeof pbuf, "%d", poison); + snprintf(idbuf, sizeof idbuf, "%d", player_id); + strncpy(n8, name, 8); n8[8] = '\0'; + const char *args[20]; + int ai = 0; + args[ai++] = g_sim_bin; + args[ai++] = "--name"; args[ai++] = n8; + args[ai++] = "--life"; args[ai++] = lbuf; + args[ai++] = "--poison"; args[ai++] = pbuf; + args[ai++] = "--game-id"; args[ai++] = game_id; + args[ai++] = "--player-id"; args[ai++] = idbuf; + if (eliminated) args[ai++] = "--eliminated"; + if (reset_cmd) args[ai++] = "--reset-cmd"; + args[ai] = NULL; + execv(g_sim_bin, (char *const *)args); + _exit(1); + } + register_child(pid); + return pid; +} + +static pid_t sim_start(const char *name, int life, int poison, + const char *game_id, int eliminated) +{ + return sim_start_ex(name, life, poison, game_id, eliminated, 0, 0); +} + +static void sim_stop(pid_t pid) +{ + if (pid <= 0) return; + kill(pid, SIGTERM); + waitpid(pid, NULL, 0); + for (int i = 0; i < g_nchildren; i++) + if (g_children[i] == pid) { g_children[i] = 0; break; } +} + +/* ── Tracked simulator: captures sim stdout into g_sim_q ─────────────────── */ +static lq_t g_sim_q; +static int g_sim_pipe_fd = -1; +static pthread_t g_sim_thr; + +static void *sim_pipe_reader(void *arg) +{ + (void)arg; + char line[LBUF]; + int pos = 0; + char c; + while (read(g_sim_pipe_fd, &c, 1) > 0) { + if (c == '\n' || c == '\r') { + if (pos > 0) { + line[pos] = '\0'; + lq_push(&g_sim_q, line); + pos = 0; + } + } else if (pos < LBUF - 1) { + line[pos++] = c; + } + } + return NULL; +} + +static pid_t sim_start_tracked(const char *name, int life, int poison, + const char *game_id, int player_id) +{ + int pipefd[2]; + if (pipe(pipefd) < 0) { perror("pipe"); return -1; } + g_sim_pipe_fd = pipefd[0]; + + pid_t pid = fork(); + if (pid < 0) { perror("fork"); close(pipefd[0]); close(pipefd[1]); return -1; } + if (pid == 0) { + close(g_serial_fd); + close(pipefd[0]); + dup2(pipefd[1], STDOUT_FILENO); + close(pipefd[1]); + char lbuf[16], pbuf[16], idbuf[16], n8[9]; + snprintf(lbuf, sizeof lbuf, "%d", life); + snprintf(pbuf, sizeof pbuf, "%d", poison); + snprintf(idbuf, sizeof idbuf, "%d", player_id); + strncpy(n8, name, 8); n8[8] = '\0'; + const char *args[] = { + g_sim_bin, + "--name", n8, + "--life", lbuf, + "--poison", pbuf, + "--game-id", game_id, + "--player-id", idbuf, + NULL + }; + execv(g_sim_bin, (char *const *)args); + _exit(1); + } + close(pipefd[1]); + register_child(pid); + lq_drain(&g_sim_q); + pthread_create(&g_sim_thr, NULL, sim_pipe_reader, NULL); + return pid; +} + +static void sim_stop_tracked(pid_t pid) +{ + sim_stop(pid); + pthread_join(g_sim_thr, NULL); + close(g_sim_pipe_fd); + g_sim_pipe_fd = -1; +} + +static int sim_wait1(const char *p, int secs) +{ + const char *pats[] = {p, NULL}; + return lq_wait(&g_sim_q, pats, secs, NULL); +} + +static int sim_wait2(const char *p1, const char *p2, int secs) +{ + const char *pats[] = {p1, p2, NULL}; + return lq_wait(&g_sim_q, pats, secs, NULL); +} + +/* Variant of sim_start_ex with one cmdr-dmg entry, no pipe capture. */ +static pid_t sim_start_ex_cmdr(const char *name, int life, + const char *game_id, int cmdr_idx, int cmdr_val) +{ + pid_t pid = fork(); + if (pid < 0) { perror("fork"); return -1; } + if (pid == 0) { + close(g_serial_fd); + char lbuf[16], cdmg[16], n8[9]; + snprintf(lbuf, sizeof lbuf, "%d", life); + snprintf(cdmg, sizeof cdmg, "%d:%d", cmdr_idx, cmdr_val); + strncpy(n8, name, 8); n8[8] = '\0'; + const char *args[] = { + g_sim_bin, + "--name", n8, + "--life", lbuf, + "--poison", "0", + "--game-id", game_id, + "--player-id", "0", + "--cmdr-dmg", cdmg, + NULL + }; + execv(g_sim_bin, (char *const *)args); + _exit(1); + } + register_child(pid); + return pid; +} + +/* ── Key-value parsing ───────────────────────────────────────────────────── */ +static int kv_int(const char *line, const char *key, int *out) +{ + char s[64]; + snprintf(s, sizeof s, "%s=", key); + const char *p = strstr(line, s); + if (!p) return 0; + *out = atoi(p + strlen(s)); + return 1; +} + +static int kv_str(const char *line, const char *key, char *out, int n) +{ + char s[64]; + snprintf(s, sizeof s, "%s=", key); + const char *p = strstr(line, s); + if (!p) return 0; + p += strlen(s); + int i = 0; + while (*p && *p != ' ' && i < n - 1) out[i++] = *p++; + out[i] = '\0'; + return 1; +} + +/* Parse "[a,b,c]" bracket-list value for key= into out[0..n-1]. */ +static int kv_intlist(const char *line, const char *key, int *out, int n) +{ + char s[64]; + snprintf(s, sizeof s, "%s=[", key); + const char *p = strstr(line, s); + if (!p) return 0; + p += strlen(s); + for (int i = 0; i < n; i++) { + out[i] = atoi(p); + while (*p && *p != ',' && *p != ']') p++; + if (*p == ',') p++; + } + return 1; +} + +/* ── Test framework ──────────────────────────────────────────────────────── */ +static int g_pass = 0, g_fail = 0; + +#define FAIL_MSG(fmt, ...) \ + fprintf(stderr, "\n FAIL: " fmt "\n", ##__VA_ARGS__) + +#define CHECK(cond) \ + do { if (!(cond)) { FAIL_MSG("CHECK(%s)", #cond); return 1; } } while (0) + +#define CHECK_EQ(a, b) \ + do { \ + int _a = (a), _b = (b); \ + if (_a != _b) { FAIL_MSG("%s = %d, want %d", #a, _a, _b); return 1; } \ + } while (0) + +#define CHECK_STR_EQ(a, b) \ + do { \ + if (strcmp((a), (b))) { FAIL_MSG("%s = '%s', want '%s'", #a, (a), (b)); return 1; } \ + } while (0) + +#define CHECK_SEEN(pat, secs, linebuf) \ + do { \ + if (!wait1((pat), (secs), (linebuf))) { \ + FAIL_MSG("timeout waiting for: %s", (pat)); return 1; \ + } \ + } while (0) + +#define CHECK_SEEN2(p1, p2, secs, linebuf) \ + do { \ + if (!wait2((p1), (p2), (secs), (linebuf))) { \ + FAIL_MSG("timeout waiting for: %s + %s", (p1), (p2)); return 1; \ + } \ + } while (0) + +#define CHECK_NOT_SEEN(pat, secs) \ + do { \ + if (wait1((pat), (secs), NULL)) { \ + FAIL_MSG("unexpected line: %s", (pat)); return 1; \ + } \ + } while (0) + +#define CHECK_NOT_SEEN2(p1, p2, secs) \ + do { \ + if (wait2((p1), (p2), (secs), NULL)) { \ + FAIL_MSG("unexpected line: %s + %s", (p1), (p2)); return 1; \ + } \ + } while (0) + +#define RUN(fn) \ + do { \ + kill_all_children(); \ + fprintf(stderr, " %-55s", #fn); \ + lq_drain(&g_q); \ + int _r = fn(); \ + if (_r == 0) { g_pass++; fputs(" PASS\n", stderr); } \ + else { g_fail++; fputs(" FAIL\n", stderr); } \ + } while (0) + +/* ── Tests ───────────────────────────────────────────────────────────────── */ + +/* Device must emit DBG STATE at boot with clean starting values. */ +static int t_startup_state(void) +{ + char line[LBUF]; + int life, poison, eliminated, cmdr[4], counters[3]; + + serial_send("STATE\n"); + CHECK_SEEN("DBG STATE", 15, line); + CHECK(kv_int(line, "life", &life)); + CHECK(kv_int(line, "poison", &poison)); + CHECK(kv_int(line, "eliminated", &eliminated)); + CHECK(life == 20 || life == 30 || life == 40); + CHECK_EQ(poison, 0); + CHECK_EQ(eliminated, 0); + if (kv_intlist(line, "cmdr", cmdr, 4)) { + CHECK_EQ(cmdr[0], 0); CHECK_EQ(cmdr[1], 0); + CHECK_EQ(cmdr[2], 0); CHECK_EQ(cmdr[3], 0); + } + if (kv_intlist(line, "counters", counters, 3)) { + CHECK_EQ(counters[0], 0); CHECK_EQ(counters[1], 0); CHECK_EQ(counters[2], 0); + } + return 0; +} + +/* Device must emit ADV_TX with all required fields present and sane. */ +static int t_adv_tx_fields(void) +{ + char line[LBUF], gid[16]; + int life, poison, eliminated; + + CHECK_SEEN("DBG ADV_TX", 25, line); + CHECK(kv_int(line, "life", &life)); + CHECK(kv_int(line, "poison", &poison)); + CHECK(kv_int(line, "eliminated", &eliminated)); + CHECK(kv_str(line, "game_id", gid, sizeof gid)); + CHECK(life > 0); + CHECK_EQ(poison, 0); + CHECK_EQ(eliminated, 0); + CHECK_STR_EQ(gid, DEFAULT_GAME_ID); + return 0; +} + +/* ADV_TX must reflect the same life/poison/eliminated as DBG STATE. */ +static int t_state_adv_consistent(void) +{ + char sl[LBUF], al[LBUF]; + int sl_life, al_life, sl_poi, al_poi, sl_elim, al_elim; + + serial_send("STATE\n"); + CHECK_SEEN("DBG STATE", 15, sl); + CHECK_SEEN("DBG ADV_TX", 25, al); + CHECK(kv_int(sl, "life", &sl_life)); + CHECK(kv_int(al, "life", &al_life)); + CHECK(kv_int(sl, "poison", &sl_poi)); + CHECK(kv_int(al, "poison", &al_poi)); + CHECK(kv_int(sl, "eliminated", &sl_elim)); + CHECK(kv_int(al, "eliminated", &al_elim)); + CHECK_EQ(al_life, sl_life); + CHECK_EQ(al_poi, sl_poi); + CHECK_EQ(al_elim, sl_elim); + return 0; +} + +/* Device must log PEER_RX when a peer with the correct game_id advertises. */ +static int t_peer_rx_detected(void) +{ + char line[LBUF]; + int slot; + pid_t sim = sim_start("PEER1", 35, 0, DEFAULT_GAME_ID, 0); + int found = wait2("DBG PEER_RX", "PEER1", PEER_DETECT_S, line); + sim_stop(sim); + CHECK(found); + CHECK(kv_int(line, "slot", &slot)); + CHECK(slot >= 0 && slot < MAX_BLE_PEERS); + return 0; +} + +/* PEER_RX life value must exactly match the simulator's advertised life. */ +static int t_peer_rx_life_matches(void) +{ + char line[LBUF]; + int life; + pid_t sim = sim_start("LIFECHK1", 27, 0, DEFAULT_GAME_ID, 0); + int found = wait2("DBG PEER_RX", "LIFECHK1", PEER_DETECT_S, line); + sim_stop(sim); + CHECK(found); + CHECK(kv_int(line, "life", &life)); + CHECK_EQ(life, 27); + return 0; +} + +/* PEER_RX poison value must exactly match the simulator's advertised poison. */ +static int t_peer_rx_poison_matches(void) +{ + char line[LBUF]; + int poison; + pid_t sim = sim_start("POSNCHK1", 40, 5, DEFAULT_GAME_ID, 0); + int found = wait2("DBG PEER_RX", "POSNCHK1", PEER_DETECT_S, line); + sim_stop(sim); + CHECK(found); + CHECK(kv_int(line, "poison", &poison)); + CHECK_EQ(poison, 5); + return 0; +} + +/* PEER_RX eliminated=1 when simulator advertises as eliminated. */ +static int t_peer_rx_eliminated_set(void) +{ + char line[LBUF]; + int elim; + pid_t sim = sim_start("ELIMCHK1", 0, 0, DEFAULT_GAME_ID, 1); + int found = wait2("DBG PEER_RX", "ELIMCHK1", PEER_DETECT_S, line); + sim_stop(sim); + CHECK(found); + CHECK(kv_int(line, "eliminated", &elim)); + CHECK_EQ(elim, 1); + return 0; +} + +/* PEER_RX eliminated=0 when simulator advertises a live player. */ +static int t_peer_rx_eliminated_clear(void) +{ + char line[LBUF]; + int elim; + pid_t sim = sim_start("ALIVCHK1", 40, 0, DEFAULT_GAME_ID, 0); + int found = wait2("DBG PEER_RX", "ALIVCHK1", PEER_DETECT_S, line); + sim_stop(sim); + CHECK(found); + CHECK(kv_int(line, "eliminated", &elim)); + CHECK_EQ(elim, 0); + return 0; +} + +/* PEER_RX must NOT appear for a peer advertising a different game_id. */ +static int t_game_id_filter_wrong_rejected(void) +{ + pid_t sim = sim_start("WRONGID1", 40, 0, WRONG_GAME_ID, 0); + int found = wait2("DBG PEER_RX", "WRONGID1", PEER_DETECT_S, NULL); + sim_stop(sim); + if (found) { FAIL_MSG("wrong game_id peer was logged as PEER_RX"); return 1; } + return 0; +} + +/* A valid peer is still discovered alongside an invalid one. */ +static int t_game_id_filter_correct_accepted(void) +{ + pid_t bad = sim_start("WRONGID2", 40, 0, WRONG_GAME_ID, 0); + pid_t good = sim_start("RIGHTID1", 40, 0, DEFAULT_GAME_ID, 0); + int found = wait2("DBG PEER_RX", "RIGHTID1", PEER_DETECT_S, NULL); + sim_stop(good); + sim_stop(bad); + CHECK(found); + return 0; +} + + +/* + * After the simulator stops, device must emit PEER_EXPIRE within + * BLE_PEER_TIMEOUT ticks (30 s) plus the 1 s expiry-check granularity. + */ +static int t_peer_timeout_expires(void) +{ + char line[LBUF]; + int slot; + pid_t sim = sim_start("TIMEOUT1", 40, 0, DEFAULT_GAME_ID, 0); + + /* wait until device first sees the peer */ + CHECK(wait2("DBG PEER_RX", "TIMEOUT1", PEER_DETECT_S, NULL)); + sim_stop(sim); + + /* wait for expiry: 30 s timeout + 1 s check granularity + 3 s slack */ + CHECK_SEEN2("DBG PEER_EXPIRE", "TIMEOUT1", BLE_TIMEOUT_S + 4, line); + CHECK(kv_int(line, "slot", &slot)); + CHECK(slot >= 0 && slot < MAX_BLE_PEERS); + return 0; +} + +/* + * A continuously advertising peer must NOT be expired within the timeout + * window (checked over BLE_TIMEOUT_S - 5 s to give clear headroom). + */ +static int t_active_peer_not_expired(void) +{ + pid_t sim = sim_start("NOEXP1", 40, 0, DEFAULT_GAME_ID, 0); + + /* wait until device sees the peer at least once */ + CHECK(wait2("DBG PEER_RX", "NOEXP1", PEER_DETECT_S, NULL)); + + /* must not expire in the window */ + int expired = wait2("DBG PEER_EXPIRE", "NOEXP1", BLE_TIMEOUT_S - 5, NULL); + sim_stop(sim); + if (expired) { FAIL_MSG("active peer expired prematurely"); return 1; } + return 0; +} + +/* PEER_RX player_id must match the simulator's --player-id argument. */ +static int t_peer_rx_player_id_matches(void) +{ + char line[LBUF]; + int pid_val; + pid_t sim = sim_start_ex("PIDCHK1", 40, 0, DEFAULT_GAME_ID, 0, 3, 0); + int found = wait2("DBG PEER_RX", "PIDCHK1", PEER_DETECT_S, line); + sim_stop(sim); + CHECK(found); + CHECK(kv_int(line, "pid", &pid_val)); + CHECK_EQ(pid_val, 3); + return 0; +} + +/* + * When a peer advertises reset_cmd=1, the firmware must reset its counters + * (poison=0, eliminated=0, cmdr all 0) and emit a DBG STATE reflecting that. + */ +static int t_reset_cmd_resets_firmware(void) +{ + char line[LBUF]; + int cmdr[4], poison, elim; + + pid_t sim = sim_start_ex("RSTALL1", 40, 0, DEFAULT_GAME_ID, 0, 0, 1); + + /* Wait until firmware logs PEER_RX carrying reset=1 */ + int found = wait2("DBG PEER_RX", "reset=1", PEER_DETECT_S, NULL); + sim_stop(sim); + CHECK(found); + + /* The very next DBG STATE must reflect the reset */ + CHECK_SEEN("DBG STATE", 5, line); + CHECK(kv_int(line, "poison", &poison)); + CHECK(kv_int(line, "eliminated", &elim)); + CHECK_EQ(poison, 0); + CHECK_EQ(elim, 0); + if (kv_intlist(line, "cmdr", cmdr, 4)) { + CHECK_EQ(cmdr[0], 0); CHECK_EQ(cmdr[1], 0); + CHECK_EQ(cmdr[2], 0); CHECK_EQ(cmdr[3], 0); + } + return 0; +} + +/* Serial SET life updates g_life and is reflected in DBG STATE. */ +static int t_serial_set_life(void) +{ + char line[LBUF]; int life; + serial_send("SET life=33\n"); + CHECK_SEEN2("DBG STATE", "life=33", 5, line); + CHECK(kv_int(line, "life", &life)); + CHECK_EQ(life, 33); + serial_send("RESET\n"); + wait1("DBG STATE", 5, NULL); + return 0; +} + +/* Serial SET cmdr0 updates commander damage and is reflected in DBG STATE. */ +static int t_serial_set_cmdr(void) +{ + char line[LBUF]; int cmdr[4]; + serial_send("SET cmdr0=7\n"); + CHECK_SEEN2("DBG STATE", "cmdr=[7,", 5, line); + CHECK(kv_intlist(line, "cmdr", cmdr, 4)); + CHECK_EQ(cmdr[0], 7); + serial_send("RESET\n"); + wait1("DBG STATE", 5, NULL); + return 0; +} + +/* After SET life via serial, simulator sees updated life in firmware PEER adv. */ +static int t_fw_life_syncs_to_sim(void) +{ + serial_send("SET ble=1\n"); + wait1("DBG STATE", 5, NULL); + serial_send("SET life=19\n"); + wait1("DBG STATE", 5, NULL); + + pid_t sim = sim_start_tracked("SYNCL1", 40, 0, DEFAULT_GAME_ID, 1); + int found = sim_wait2("PEER", "life=19", PEER_DETECT_S); + sim_stop_tracked(sim); + serial_send("RESET\n"); + wait1("DBG STATE", 5, NULL); + CHECK(found); + return 0; +} + +/* After SET counter0 (poison) via serial, simulator sees it in firmware adv. */ +static int t_fw_poison_syncs_to_sim(void) +{ + serial_send("SET ble=1\n"); + wait1("DBG STATE", 5, NULL); + serial_send("SET counter0=3\n"); + wait1("DBG STATE", 5, NULL); + + pid_t sim = sim_start_tracked("SYNCP1", 40, 0, DEFAULT_GAME_ID, 1); + int found = sim_wait2("PEER", "poison=3", PEER_DETECT_S); + sim_stop_tracked(sim); + serial_send("RESET\n"); + wait1("DBG STATE", 5, NULL); + CHECK(found); + return 0; +} + +/* Firmware logs correct life from simulator PEER_RX. */ +static int t_sim_life_syncs_to_fw(void) +{ + char line[LBUF]; int life; + pid_t sim = sim_start("SLIFE1", 28, 0, DEFAULT_GAME_ID, 0); + int found = wait2("DBG PEER_RX", "SLIFE1", PEER_DETECT_S, line); + sim_stop(sim); + CHECK(found); + CHECK(kv_int(line, "life", &life)); + CHECK_EQ(life, 28); + return 0; +} + +/* Firmware logs correct cmdr_dmg from simulator PEER_RX. */ +static int t_sim_cmdr_syncs_to_fw(void) +{ + char line[LBUF]; int cmdr[4]; + pid_t sim = sim_start_ex_cmdr("SCMDR1", 40, DEFAULT_GAME_ID, 0, 9); + int found = wait2("DBG PEER_RX", "SCMDR1", PEER_DETECT_S, line); + sim_stop(sim); + CHECK(found); + CHECK(kv_intlist(line, "cmdr", cmdr, 4)); + CHECK_EQ(cmdr[0], 9); + return 0; +} + +/* After SET cmdr0 via serial, simulator sees updated cmdr in firmware adv. */ +static int t_fw_cmdr_syncs_to_sim(void) +{ + serial_send("SET ble=1\n"); + wait1("DBG STATE", 5, NULL); + serial_send("SET cmdr0=11\n"); + wait1("DBG STATE", 5, NULL); + + pid_t sim = sim_start_tracked("CMDR4", 40, 0, DEFAULT_GAME_ID, 1); + int found = sim_wait2("PEER", "cmdr=[11,", PEER_DETECT_S); + sim_stop_tracked(sim); + serial_send("RESET\n"); + wait1("DBG STATE", 5, NULL); + CHECK(found); + return 0; +} + +/* After SET life=0 triggers elimination, simulator sees ELIMINATED in firmware adv. */ +static int t_eliminated_syncs_to_adv(void) +{ + serial_send("SET ble=1\n"); + wait1("DBG STATE", 5, NULL); + serial_send("SET life=0\n"); + wait1("DBG STATE", 5, NULL); + + pid_t sim = sim_start_tracked("ELIMSYN1", 40, 0, DEFAULT_GAME_ID, 1); + int found = sim_wait2("PEER", "ELIMINATED", PEER_DETECT_S); + sim_stop_tracked(sim); + serial_send("RESET\n"); + wait1("DBG STATE", 5, NULL); + CHECK(found); + return 0; +} + +/* + * Slowly steps life through every value 0→80→0, verifying serial state at + * each step. Intended for operator visual confirmation: watch OLED and LED + * sweep continuously through the full gradient. + * + * 0→40: red→green gradient + * 40→80: green→blue gradient + * <10: breathing pulse (speed increases toward 0) + * 0: eliminated (red pulse, BLE ELIMINATED flag) + */ +static int t_life_cycle_visual(void) +{ + char line[LBUF]; + int elim; + + serial_send("SET ble=1\n"); + if (!wait1("DBG STATE", 5, NULL)) { FAIL_MSG("device not responding"); return 1; } + lq_drain(&g_q); + + pid_t sim = sim_start_tracked("VISLIFE1", 40, 0, DEFAULT_GAME_ID, 1); + + /* Ramp 0→80 then 80→0, one step at a time. */ + static const struct { int from; int to; const char *label; } ramps[] = { + { 0, 80, "[visual] life 0→80 (red→green→blue)" }, + { 79, 0, "[visual] life 80→0 (blue→green→red, breathe at <10)" }, + }; + for (int r = 0; r < 2; r++) { + fprintf(stderr, "\n %s\n", ramps[r].label); + int step = ramps[r].from <= ramps[r].to ? 1 : -1; + for (int v = ramps[r].from; v != ramps[r].to + step; v += step) { + char cmd[32], pat[32]; + snprintf(cmd, sizeof cmd, "SET life=%d\n", v); + snprintf(pat, sizeof pat, "life=%d ", v); + lq_drain(&g_q); + serial_send(cmd); + if (!wait2("DBG STATE", pat, 2, line)) { + sim_stop_tracked(sim); + FAIL_MSG("no DBG STATE for life=%d", v); + return 1; + } + usleep(50000); + } + } + + /* life=0 must have set eliminated */ + CHECK(kv_int(line, "eliminated", &elim)); + CHECK_EQ(elim, 1); + + /* BLE: sim must see ELIMINATED within one scan cycle */ + if (!sim_wait2("PEER", "ELIMINATED", PEER_DETECT_S)) { + sim_stop_tracked(sim); + FAIL_MSG("sim did not see ELIMINATED over BLE"); + return 1; + } + + sim_stop_tracked(sim); + serial_send("RESET\n"); + wait1("DBG STATE", 5, NULL); + return 0; +} + +/* ── Entry point ─────────────────────────────────────────────────────────── */ +int main(int argc, char *argv[]) +{ + for (int i = 1; i < argc; i++) { + if (!strcmp(argv[i], "--port") && i + 1 < argc) + g_port = argv[++i]; + else if (!strcmp(argv[i], "--sim") && i + 1 < argc) + g_sim_bin = argv[++i]; + else { + fprintf(stderr, "usage: %s [--port DEV] [--sim PATH]\n", argv[0]); + return 1; + } + } + + signal(SIGINT, sig_cleanup); + signal(SIGTERM, sig_cleanup); + + /* Kill any orphaned simulator processes left by a previous test run. */ + { + const char *bn = strrchr(g_sim_bin, '/'); + bn = bn ? bn + 1 : g_sim_bin; + char cmd[256]; + snprintf(cmd, sizeof cmd, "pkill -x '%s' 2>/dev/null", bn); + system(cmd); + usleep(500000); + } + + g_serial_fd = open_serial(g_port); + if (g_serial_fd < 0) { + fprintf(stderr, "cannot open serial port: %s\n", g_port); + return 1; + } + + lq_init(&g_q); + lq_init(&g_sim_q); + pthread_create(&g_serial_thr, NULL, serial_reader, NULL); + + fprintf(stderr, "\ncommeownder BLE integration tests\n"); + fprintf(stderr, "port: %s sim: %s\n\n", g_port, g_sim_bin); + + /* ── Device setup: wipe NVS, confirm clean state, enable BLE ────────── */ + fprintf(stderr, " setup: CLEARNVS + SET ble=1 ..."); + /* Opening the port can reset the ESP32 (DTR pulse through auto-reset + * circuit). Poll with STATE until the device responds, then send + * CLEARNVS so we don't lose the command while it's still booting. */ + { + int ready = 0; + for (int i = 0; i < 10 && !ready; i++) { + serial_send("STATE\n"); + if (wait1("DBG STATE", 3, NULL)) ready = 1; + } + if (!ready) { + fprintf(stderr, " FAIL (device not responding)\n"); + return 1; + } + lq_drain(&g_q); + } + serial_send("CLEARNVS\n"); + if (!wait1("DBG STATE", 10, NULL)) { + fprintf(stderr, " FAIL (no response to CLEARNVS)\n"); + return 1; + } + serial_send("SET ble=1\n"); + if (!wait1("DBG STATE", 5, NULL)) { + fprintf(stderr, " FAIL (no response to SET ble=1)\n"); + return 1; + } + lq_drain(&g_q); + fprintf(stderr, " OK\n\n"); + + /* ── Advertising & state ────────────────────────────────────────────── */ + RUN(t_startup_state); + RUN(t_adv_tx_fields); + RUN(t_state_adv_consistent); + + /* ── Peer discovery & field accuracy ────────────────────────────────── */ + RUN(t_peer_rx_detected); + RUN(t_peer_rx_life_matches); + RUN(t_peer_rx_poison_matches); + RUN(t_peer_rx_eliminated_set); + RUN(t_peer_rx_eliminated_clear); + + /* ── Game-ID filtering ──────────────────────────────────────────────── */ + RUN(t_game_id_filter_wrong_rejected); + RUN(t_game_id_filter_correct_accepted); + + /* ── Player ID ──────────────────────────────────────────────────────── */ + RUN(t_peer_rx_player_id_matches); + + /* ── Reset all ──────────────────────────────────────────────────────── */ + RUN(t_reset_cmd_resets_firmware); + + /* ── Peer timeout ───────────────────────────────────────────────────── */ + RUN(t_peer_timeout_expires); + RUN(t_active_peer_not_expired); + + /* ── Serial control ─────────────────────────────────────────────────── */ + RUN(t_serial_set_life); + RUN(t_serial_set_cmdr); + + /* ── Bidirectional sync ─────────────────────────────────────────────── */ + RUN(t_fw_life_syncs_to_sim); + RUN(t_fw_poison_syncs_to_sim); + RUN(t_fw_cmdr_syncs_to_sim); + RUN(t_sim_life_syncs_to_fw); + RUN(t_sim_cmdr_syncs_to_fw); + RUN(t_eliminated_syncs_to_adv); + + /* ── Visual life-cycle (operator can watch OLED + LED) ─────────────────── */ + RUN(t_life_cycle_visual); + + fprintf(stderr, "\n%d passed, %d failed\n", g_pass, g_fail); + + g_serial_stop = 1; + pthread_join(g_serial_thr, NULL); + close(g_serial_fd); + return g_fail > 0 ? 1 : 0; +}