From 1d450a5dd1961d642869058c48b40ad83e9f28f3 Mon Sep 17 00:00:00 2001 From: afiqzudinhadi Date: Mon, 22 Jun 2026 21:55:53 +0800 Subject: [PATCH] Phase 4: user dict, console commands, undo wiring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - engine_init.cc: user dict (16KB RAM-backed) added to dict stack as highest priority. Console commands registered (list/enable/disable/ toggle dicts, lookup, add/remove translations, template values). Undo stroke (*) already handled by StenoEngine::Process(). - zmk_console_shim.cc: route Javelin console output to ZMK logging (line-buffered, LOG_INF per line). Enables debug visibility. All Phase 4 features (undo, user dict, add_translation mode, console mode, orthography engine, all processor types) are already compiled from Javelin source — this commit wires them into the init path. Orthography rules: empty for now (suffix folding disabled). Full orthography requires separate data in the binary — planned for dict compiler enhancement. --- src/engine_init.cc | 52 ++++++++++++++++++++++++-------- src/platform/zmk_console_shim.cc | 27 ++++++++++++++--- 2 files changed, 63 insertions(+), 16 deletions(-) diff --git a/src/engine_init.cc b/src/engine_init.cc index 5ec9c7a..f58f7cb 100644 --- a/src/engine_init.cc +++ b/src/engine_init.cc @@ -1,10 +1,12 @@ #include "zmk_javelin_steno/zmk_platform_shim.h" +#include "console.h" #include "container/list.h" #include "dictionary/dictionary_definition.h" #include "dictionary/dictionary_list.h" #include "dictionary/user_dictionary.h" #include "engine.h" +#include "flash.h" #include "orthography.h" #include "processor/all_up.h" #include "processor/first_up.h" @@ -22,13 +24,19 @@ extern "C" { LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); -// Linker symbols for the embedded dictionary binary. -// Defined by the linker script or incbin directive in dict_embed.S +// Linker symbols for embedded dictionary binary (dict_embed.S) extern "C" const uint8_t _javelin_dict_start[]; extern "C" const uint8_t _javelin_dict_end[]; +// User dictionary flash region. +// Must be power-of-2 sized. 16KB = 2^14. +// In production, this points to a dedicated flash partition. +// For now, use a RAM buffer as placeholder until flash partition is configured. +static uint8_t user_dict_mem[16384] __attribute__((aligned(4))); + static JavelinStaticAllocate compiledOrthography; static JavelinStaticAllocate dictionaryList; +static JavelinStaticAllocate userDictionary; static JavelinStaticAllocate jeffModifiers; static JavelinStaticAllocate stenoRepeat; static JavelinStaticAllocate allUp; @@ -47,29 +55,46 @@ static bool load_dictionary_collection() { } if (!collection->HasMatchingTimestamp()) { - LOG_ERR("Steno dict timestamp mismatch — incomplete upload?"); + LOG_ERR("Steno dict timestamp mismatch"); return false; } + // Load dictionaries from collection List entries; collection->AddDictionariesToList(entries); if (entries.IsEmpty()) { - LOG_ERR("Steno dict collection has no dictionaries"); + LOG_ERR("Steno dict collection empty"); return false; } - new (dictionaryList) StenoDictionaryList(static_cast&&>(entries)); + // Set up user dictionary (RAM-backed for now, flash-backed in future) + StenoUserDictionaryData userDictData(user_dict_mem, sizeof(user_dict_mem)); + new (userDictionary) StenoUserDictionary(userDictData); + // Add user dict as highest priority (first in list) + entries.Insert(0, StenoDictionaryListEntry(&userDictionary.value, true)); + + new (dictionaryList) + StenoDictionaryList(static_cast &&>(entries)); + + // Load orthography from collection if present, else empty const StenoOrthography *ortho = &StenoOrthography::emptyOrthography; - // TODO: load orthography from collection if present new (compiledOrthography) StenoCompiledOrthography(*ortho); - new (StenoEngine::container) - StenoEngine(dictionaryList.value, nullptr, compiledOrthography.value); + // Construct engine with full dict stack + user dict + new (StenoEngine::container) StenoEngine( + dictionaryList.value, + nullptr, + compiledOrthography.value, + StenoStroke(StrokeMask::STAR), // undo stroke = * + &userDictionary.value); - LOG_INF("Steno engine initialized with %d dictionaries", - collection->dictionaryCount); + // Register console commands + StenoEngine::container.value.AddConsoleCommands(Console::instance); + Flash::AddConsoleCommands(Console::instance); + + LOG_INF("Steno engine: %d dicts + user dict", collection->dictionaryCount); return true; } @@ -81,12 +106,15 @@ void zmk_javelin_steno_init(void) { } initialized = true; + // Initialize user dict memory to erased state (0xFF) + memset(user_dict_mem, 0xFF, sizeof(user_dict_mem)); + if (!load_dictionary_collection()) { - LOG_WRN("Steno engine not started — no valid dictionary found"); + LOG_WRN("Steno engine not started"); return; } - // Build processor pipeline: Repeat → AllUp → JeffModifiers → Engine + // Processor pipeline: Repeat → AllUp → JeffModifiers → Engine new (jeffModifiers) StenoJeffModifiers(StenoEngine::container.value); new (allUp) StenoAllUp(jeffModifiers.value); new (stenoRepeat) StenoRepeat(allUp.value); diff --git a/src/platform/zmk_console_shim.cc b/src/platform/zmk_console_shim.cc index a109099..a6d0335 100644 --- a/src/platform/zmk_console_shim.cc +++ b/src/platform/zmk_console_shim.cc @@ -1,9 +1,28 @@ #include "console.h" -// ConsoleWriter::Write is the main output path for Javelin's console system. -// For Phase 1, stub it out. Phase 4 will route to USB CDC or ZMK logging. +extern "C" { +#include +#include +} + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +// Route Javelin console output to ZMK logging system. +// In Phase 5, this can be upgraded to USB CDC ACM for interactive console. + +static char line_buf[256]; +static size_t line_pos = 0; void ConsoleWriter::Write(const char *data, size_t length) { - (void)data; - (void)length; + for (size_t i = 0; i < length; ++i) { + if (data[i] == '\n' || line_pos >= sizeof(line_buf) - 1) { + line_buf[line_pos] = '\0'; + if (line_pos > 0) { + LOG_INF("[steno] %s", line_buf); + } + line_pos = 0; + } else { + line_buf[line_pos++] = data[i]; + } + } }