Repository navigation
KryonOS v3.0.0 - Major Update: T-Deck Plus Support, Bluetooth, GPS, Local AI & More #22
Haris16-code
announced in
Announcements
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Release Highlights
This major update introduces comprehensive LilyGO T-Deck Plus support, a new on-device AI image generation engine, complete Bluetooth and GPS subsystems, expanded JavaScript APIs, native audio playback, enhanced image rendering, secure MicroSD backup and disaster recovery, improved hardware integration, performance optimizations, and numerous bug fixes.
Added
lilygo-t-deck):src/Hal/Boards/t_deck/(BoardConfig.h,BoardConfig.cpp) and modular PlatformIO environment configurationsrc/Hal/Boards/board_configs/t_deck.ini.rotation 1) matching the device form factor.0x5D/0x14, INT GPIO 16) with direct coordinate mapping, 4-corner touch calibration, and LittleFS calibration persistence.0x55) with interrupt monitoring on GPIO 46, backlight control, and character/modifier decoding.BOARD_KEY_UP,BOARD_KEY_DOWN,BOARD_KEY_LEFT,BOARD_KEY_RIGHT, andBOARD_KEY_ENTER.BOARD_POWERON(GPIO 10) high on hardware init."lilygo-t-deck"target added to release and OTA update workflows (.github/workflows/release.yml,.github/workflows/push-update.yml,updates/esp32/v2/update.json).ImageRunner,AIEngine,LocalAI):src/LocalAI/Runners/ImageRunner.cppexecuting all 4,003,683 INT8 parameters ofkryonimage_3m_96_800.krai(DCGAN-96).init_projLinear(128, 18432) + Folded BatchNorm1d + ReLU -> 4 stages of fused 2x nearest-neighbor upsampling + Conv2d + Folded BatchNorm2d + ReLU -> Conv2d Head + Tanh -> direct RGB565 SPI DMA display blit.m_actBuf0= 1.18 MB,m_actBuf1= 589 KB) and 2D upsampling cache plane (m_upPlane= 36.8 KB).vTaskDelay(1)) preventing Task Watchdog timeouts while keeping the UI and Duktape runtime at 60 FPS on Core 0.GPSEngine,GPSGlobal Object):BOARD_POWERON).38400(u-blox MIA-M10Q default),9600(Quectel L76K / AT6558R default), and115200baud with LittleFS baud persistence (/local/system/gps_settings.json).TinyGPSPluswith a direct checksum-verified multi-constellation NMEA parser supporting all talker prefixes (GP,GN,BD,GB,GL,GA,QZ) and sentence types (RMC,GGA,GNS,GLL,GSA,GSV,VTG)."location"permission) backed by/local/system/app_permissions.jsonwith a 3-choice modal dialog ("Allow Once", "Always Allow", "Deny").GPS.getTime()andGPS.syncSystemTime()calibrating the ESP32 system clock and PCF8563 RTC.GPS.distanceBetween(Haversine),GPS.courseTo(bearing), andGPS.isInsideCircle(geofence radial boundary).GPSobject:isAvailable(),isEnabled(),start(),stop(),enable(),disable(),hasFix(),getStatus(),getLocation(),getLastKnownLocation(),getTime(),syncSystemTime(),watchPosition(),clearWatch(),distanceBetween(),courseTo(),isInsideCircle(),setRate(),getBaud(), andrequestPermission().STATE_SETTINGS_GPS = 24) inside the Connections menu.BluetoothEngine,Bluetooth):src/Hal/Bluetooth/BluetoothEngine.cppexposing globalBluetoothobject in Duktape JavaScript engine (src/Runtime/JSBindings_Bluetooth.cpp).Bluetooth.BLE.Scanner,Bluetooth.Utils.parseBeacon).Bluetooth.BLE.connect) supporting service/characteristic discovery, MTU negotiation (up to 512 bytes), characteristic read/write, descriptor access, and live notification subscriptions (GattCharacteristic.startNotifications).Bluetooth.BLE.Server.createService) and broadcast standard or extended advertising payloads up to 251 bytes (Bluetooth.BLE.Advertiser).Bluetooth.BLE.Keyboard).STATE_SETTINGS_BLUETOOTH 22): Non-destructive runtime power toggle, local GAP name, MAC address, and silicon architecture badges.AudioEngine,minimp3):minimp3fixed-point decoder directly into the OS audio subsystem (src/Hal/Audio/minimp3.h), delivering hardware-accelerated MP3 decoding on ESP32-S3 Core 0./local) and MicroSD Card (/sd), plus in-memory raw buffer decoding (playMp3Memory).Audio.play/Speaker.play) with intelligent magic byte header inspection (RIFFvsID3/sync word0xFFE0) for seamless format auto-detection.Speaker,Audio, andSystem.speaker:playMp3(path),play(path), andseek(positionMs).ImageRenderer,TJpg_Decoder,PNGdec):/local) and MicroSD (/sd).blendRGB565) and 1-bit palette transparency masking on ESP32-S3 SIMD instructions.getImageInfo): queries dimensions, color depth, format, and alpha transparency without decompressing full image payloads into RAM.JSBindings::getActiveSprite()) or directly to the TFT glass.Display.drawImage(path, x, y, [options]),Display.drawPNG(),Display.drawJPG(),Display.drawBMP(), andDisplay.getImageInfo().FS.readChunk,FS.readBinary,FS.writeBinary,FS.copyFile,FS.stat,FS.isSDMounted,FS.rmdir):FS.readChunk(path, offset, length, [asBinary])): Streams arbitrary byte ranges without loading the whole file into RAM, with 16 KB allocation ceiling and seek validation.FS.readBinary(path),FS.writeBinary(path, buf)): Direct TypedArray asset loading intoUint8Arrayfor sprites, audio samples, and fonts.FS.copyFile(src, dst)): High-speed 4 KB heap-buffered stream copy between Internal Flash (/local) and MicroSD (/sd) with anti-self-copy protection and ENOSPC rollback.FS.stat(path)): Returns{ size, isDirectory, isFile, exists, mtime, drive }in a single native call.FS.isSDMounted()check and FreeRTOS recursive mutex (FileSystem::lock(),FSLockGuard) isolating Core 0 audio/BLE tasks from Core 1 file I/O.BackupManager,SettingsUI):/local) to external MicroSD (/sd/backups/kryon_backup_<date>.kbf)./system/configuration files (WiFi credentials, display/keyboard settings, time configurations, touch calibrations, permissions) using unique per-file random 16-byte IVs from silicon TRNG.[ LATEST ]badge,</>carousel selector, interactive deletion confirmation, and on-screen keyboard passphrase prompts.SettingsUI,SponsorAssets.h):PROGMEMlogo alongside a "Want to support?" community banner (https://kryonos.harislab.tech/sponsor).SPONSOR_LIST[]registry (SponsorEntrystruct insrc/Settings/SponsorAssets.h) with automatic</>pagination controls and(1/N)header badge when multiple sponsors are registered.MiniQRnamespace, Versions 1–5, ECC Level L) that dynamically encodes any sponsor or support URL into a scannable QR code modal (< Back+ Sponsor title + QR matrix + URL +[ Scan with phone camera ]) with zero heap allocations.tools/logo_to_rgb565.pyCLI utility to convert transparent PNG sponsor logos into anti-aliased RGB565PROGMEMarrays blended against the KryonOS card surface (0x10A2).Trackball,Keyboard,Speaker,Device):Trackball/System.trackball:getState(),getDelta(),isClicked(),isPressed(),getRawCounts(), andreset().Keyboard/System.keyboard:getKey(),isPressed(),getModifiers(),setBacklightLevel(),getBacklightLevel(), andclear().Speaker/Audio/System.speaker: Asynchronous WAV streaming on Core 0 (playWav,playWavMemory), procedural tone synthesis (playTone), melody engine (playMelody), and built-in preset beeps (playBeep).Device/System.device: Hardware discovery flags (hasTrackball,hasKeyboard,hasSpeaker,hasTouch,hasBattery), battery SoC telemetry (getBatteryPercent,getBatteryVoltage,isCharging,getChargeTimeRemaining,getDischargeTimeRemaining), and display backlight control (setBrightness,getBrightness).LauncherUI,SettingsUI,AppStoreUI,InstallerUI,HelpCenterUI,WebServerAppUI,KryonCloudUI,MyKeyboard).tft.width(),tft.height()) supporting both wide landscape displays (drawSystemTopBar) with dynamic title clipping, live 4-bar WiFi RSSI signal strength monitoring, and precision battery gauge with charging bolt."Connections"hub (STATE_SETTINGS_CONNECTIONS 21) routing to WiFi Options, Bluetooth Options, and GPS Settings.STATE_SETTINGS_DISPLAY 18): Backlight brightness levels and sleep timeout presets.STATE_SETTINGS_KEYBOARD 19): Backlight intensity presets and physical typing preview.STATE_SETTINGS_BATTERY 20): Live SoC gauge, 16-sample oversampled voltage curve, and charge/discharge runtime estimates.JavaScript Apps & Examples
test/com.kryonos.apitest):/local/api_test_report.txtand/sd/api_test_report.txt.test/com.kryonos.imagegen):Normal,Fire,Water,Grass,Electric, etc.), guidance scale & variance sliders,System.ai.blitFrame(), and hardware trackball/keyboard controls.test/com.kryonos.piano):test/com.kryonos.blekeyboard):test/com.kryonos.musicplayer):.mp3,.wav) for Internal Flash and MicroSD, real-time codec badges ([MP3]vs[WAV]), dynamic bitrate duration estimation, asynchronous Core 0 streaming, animated 12-band audio spectrum visualizer, and trackball playlist navigation.test/com.kryonos.imageviewer):/localand/sd.test/com.kryonos.bttest):180A), Tab 4 NUS Terminal (Nordic UART Service console), and Tab 5 Radio Telemetry (power toggle and MAC info).test/com.kryonos.gpstest):test/com.kryonos.fstest):FS.readChunk,FS.readBinary,FS.writeBinary,FS.copyFile,FS.stat,FS.rmdir) with PASS/FAIL badges, live 64-byte block chunk inspector, and storage space visualizers.test/com.kryonos.tdecktest):Changed
lilygo-t-deckacross build, release, and OTA pipelines, settingdefault_envs = lilygo-t-deckinplatformio.ini.src/WebManager/WebManager.cpp) and the Web Server app status view (src/WebServerApp/WebServerAppUI.cpp) to reflect the updated settings path: Settings -> Connections -> WiFi Options -> Web Server."WiFi Options"button with a unified"Connections"hub.3.0.0(-D KRYONOS_VERSION="3.0.0"inplatformio.ini).3(-D KRYONOS_API_LEVEL=3inplatformio.ini).Removed
esp32-cyd-28,esp32doit-devkit-v1):esp32-cyd-28) and generic breadboard WROOM (esp32doit-devkit-v1) targets fromplatformio.ini, GitHub Release matrix (.github/workflows/release.yml), and OTA update manifests (.github/workflows/push-update.yml,updates/esp32/v2/update.json) to standardize active development on ESP32-S3 handheld and dev targets.Fixed
ImageRunner,AIEngine,AIBindings,com.kryonos.imagegen):test/com.kryonos.imagegenfrom synthesizing images despite successfully mountingkryonimage_3m_96_800.krai:ImageRunner::parseTensors()applied a duplicate offset (m_weights + m_header.weights_offset). BecauseAIEngine::loadModel()already loads the weights payload fromweights_offsetintom_modelBuffer, addingweights_offseta second time jumped 240 bytes into the raw weights data, causing tensor name length validation (nlen > 31) to fail and yielding 0 parsed tensors, which causedgenerate()to abort with"required DCGAN tensors missing from .krai model".const uint8_t* ptr = m_weights;andconst uint8_t* end = ptr + m_header.weights_size;, restoring immediate parsing of all 28 INT8 neural tensors (class_embed,init_proj,up1throughup4, andout_conv).AIEnginetoImageRunner::init(m_header, m_modelBuffer, m_vocabBuffer): parses all 18 elemental classes (Normal,Fire,Water,Grass,Electric, etc.) directly from the embedded.kraistring table with safe string length checks and clean fallbacks.taskYIELD()(which only yields to tasks of equal or higher priorityvTaskDelay(pdMS_TO_TICKS(1))every 16 channels inrun_up_block(), every 2048 iterations ininit_proj, after each up-sampling stage, and between output channels inout_conv.if (var < 0.0f) var = 0.0f;) inprecomputeBatchNorm()to preventNaNfloat corruption during BatchNorm parameter folding.((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3)matchingtft.pushImageexpectations on T-Deck ST7789 display controllers.System.ai.blitFrame(x, y)API: exposedAIEngine::blitLastFrame(x, y)to Duktape JavaScript runtime, enablingcom.kryonos.imagegento instantly restore and re-blit synthesized sprites when switching tabs or refreshing status cards without re-running synthesis.AI_EVENT_ERRORinAIEngine::runWorkerwhen image generation cannot proceed, ensuring JavaScriptonErrorcallbacks receive diagnostic error messages.GPSEngine,BoardConfig,com.kryonos.gpstest):test/com.kryonos.gpsteststuck on"Awaiting Fix"with 0 bytes processed under open sky:initHardware()executed a 5 msINPUT_PULLDOWNcheck onBOARD_GPS_RX_PIN(GPIO 44) right at boot before the GNSS module stabilized its internal MCU, falsely settings_isTDeckPlus = falseand disabling GPS availability (hasGPS() = false,isAvailable() = false).INPUT_PULLUPon RX 44,OUTPUT HIGHon TX 43) and keeping GPS available on the T-Deck platform.GPSEngine::gpsTaskWorker: 1200 ms was chopping 1 Hz (1000 ms) NMEA bursts mid-sentence, preventing valid checksum verifications./local/system/gps_settings.json): once locked (38400 for MIA-M10Q, 9600 for L76K), the baud rate is remembered across reboots for instant, zero-delay initialization.status == 'A'), GGA (status == 'A')./local/system/gps_last_loc.jsonevery 30 seconds.test/com.kryonos.gpstestto provide real-time sky search telemetry (visible satellites, carrier signals, ephemeris download timer) while acquiring fix.AppStoreUI):checkUpdates()previously polled remoteapp.jsonwhich does not store package SHA-256 hashes, leavingmetaSha256andappSha256empty and causingperformInstall()to reject updates.deriveCategoryIndexUrl()): dynamically slices{category-name}from anymetaUrlpath (e.g.categories/{category-name}/...->categories/{category-name}/index.json), supporting all categories (Games,Utilities,Multimedia,Demos,System,Tools, etc.) with universal 2-level parent directory traversal.categories/{category-name}/index.jsonbypackageName, querying and populatingmeta_sha256andapp_sha256for seamless SHA-256 integrity verification inCryptoEngine.api <= KRYONOS_API_LEVEL): if an app or update specifies anapilevel higher than the installed system inindex.jsonorapp.json, it is completely hidden from both the App Store category browser and the updates list.AppStoreUI::drawDialog(): explicitly setTC_DATUM(Top-Center) andMC_DATUMondrawString(), eliminating horizontal text clipping and adding a centered modal dialog box with OK button matching the touch hit target.MC_DATUM(Middle-Center) with a clean two-line layout:"No New Updates Available"and"All Apps Are Up To Date"in accent green.com.kryonos.localai,AIEngine):.binmodels (e.g.kryonai_3m.bin): legacy 24-byte header.binfiles lacked an embedded vocabulary table, and attempting to parse companion 255 KBkryon_tokenizer.jsonfiles on ESP32 exhausted Internal SRAM (malloc()failure in ArduinoJsondeserializeJson), leavingm_vocabBuffernull and forcing an ASCII fallback where all tokensSpiRamJsonAllocatorinsrc/LocalAI/AIEngine.cppto stream JSON tokenizer deserialization directly into Octal PSRAM..kraivocabulary extraction: when loadingkryonai_3m.bin,AIEngineautomatically checks for and extracts pre-baked vocabularies from sibling.kraicontainers.kryonai_3m.krai(3.25 MB) with universal 64-byteModelHeader, 4,096 embedded BPE tokens, and 16-byte SIMD-aligned INT8 weights for instantaneous 1 ms loading with zero JSON overhead.AIEngine::runWorkerto ensure prompts match the model's trained dialogue format (<|system|>You are KryonAI, the local assistant for KryonOS.<|user|>{prompt}<|assistant|>).test/com.kryonos.localai/main.js: replaced destructiveappendTokenunderscore strip with clean BPE subword and whitespace reconstruction; made UI fully responsive fors_lastDisconnectMs) insrc/Hal/Boards/t_deck/BoardConfig.cpp.UTC+5 PKTUTC-5) failed to persist across reboots or WiFi connections.src/Kernel/TimeManager.cpp, added.trim()sanitization during preference loading and immediately re-asserted POSIXsetenv("TZ", currentTimezone.c_str(), 1)andtzset()right after Arduino-ESP32'sconfigTime(0, 0, ...)(which internally wipedTZback toUTC0)."ESP32-S3"fallback in device identification strings.BOARD_GPS_RX_PIN(GPIO 44) to distinguish base"T-Deck"from GPS-equipped"T-Deck Plus".GPSEnginecallingsetGpsHardwareConfirmed(true)to lock"T-Deck Plus"once satellite telemetry streams.System.getInfo().deviceName,System.getInfo().boardModel,Device.getName(), and the Settings "About Device" UI.src/Kernel/Services/KryonCloud/KryonCloudUI.cppto dynamically adapt to 320x240 landscape displays.BACKUP_ERR_SECURITY_VIOLATION):Error Code: 10(BACKUP_ERR_SECURITY_VIOLATION).BackupManager::isSafePath: the security validator previously rejected any path starting with/or\\(if (path.startsWith("/") || path.startsWith("\\")) return false;). Because LittleFS directory iteration returns canonical absolute paths (file.path()returning"/system/settings.json","/apps/..."), legitimate archive entries were falsely flagged as malicious path traversals.BackupManager::isSafePathandrestoreBackupto safely normalize absolute paths by stripping leading slashes and relative dot prefixes (./,.\\) while strictly enforcing genuine directory traversal checks (..path segments,/../,\\..\\), null-byte injection prevention (\0), and drive prefix guards (:).SettingsUIerror dialogs to display explicit, user-friendly messages for all failure conditions (Security Error,Storage Error,Key Error,Integrity Error,Format Error) rather than ambiguous numeric codes.Manifest HMAC corrupt! Tampered File.):esptool.py erase_flash) failed to restore withManifest HMAC corrupt! Tampered File.on the same physical board.CryptoEngine::getDeviceKey: the device encryption key was previously generated from volatile random bytes (esp_fill_random) and stored in flash NVS (Preferencesnamespacekryon_sec), which is wiped during a full flash format. On subsequent boot, a new random key was generated, altering the derived master key and causing the backup's HMAC authentication tag to fail validation.CryptoEngine::getDeviceKeyto derive a permanent 256-bit cryptographic Hardware Root Key (esp_efuse_mac_get_default), WiFi STA MAC (esp_read_mac), Bluetooth MAC, 64-bit eFuse MAC (ESP.getEfuseMac()), Chip Model, Chip Revision, and CPU Core count.KRYON_OS_DISASTER_RECOVERY_ROOT_SALT_V1.CryptoEngine::getLegacyNVSKey):BackupManager::restoreBackupautomatically verifies backups with the permanent hardware silicon key first, and if unverified, falls back to legacy NVS keys for archives created on non-erased devices prior to this fix.KryonAudioTask):Guru Meditation Error: Core 0 panic'ed (Unhandled debug exception). Debug exception reason: Stack canary watchpoint triggered (KryonAudioTask)atmp3d_synth_granule/mp3dec_decode_framewhen attempting to play MP3 audio in the music player.mp3dec_scratch_t scratch(16,160 bytes containing MDCT synthesis and polyphase filterbank buffers) insidesrc/Hal/Audio/minimp3.hfrom a local stack variable into the static BSS segment.pcmFrame[MINIMP3_MAX_SAMPLES_PER_FRAME](4,608 bytes) insideAudioEngine::audioTaskinto static BSS (s_pcm_frame).KryonAudioTaskFreeRTOS task stack size from 8,192 bytes (8 KB) to 16,384 bytes (16 KB), providing vast headroom for file I/O, ID3 tag parsing, and I2S DMA streaming without risk of stack canary triggers.WebManager) was unreachable from external devices (browsers on PC/phone) and network applications (App Store, Help Center, OTA Updater) failed withError HTTP -1despite WiFi showing connected.MALLOC_CAP_INTERNAL) required bymbedtls(WiFiClientSecure) andAsyncTCP/lwIP:s_png(PNGdecdecoder context, 45,604 bytes) andlineBuffer(960 bytes) insrc/Hal/Graphics/ImageRenderer.cppout of static.dram0.bssinto on-demand PSRAM/heap allocation duringdrawPNG().mp3dec_scratch_t(16,236 bytes) insrc/Hal/Audio/minimp3.hands_mp3dec(6,668 bytes) /s_pcm_frame(4,608 bytes) insrc/Hal/Audio/AudioEngine.cppout of static.dram0.bssinto on-demand PSRAM/heap allocation during MP3 playback.KryonAudioTaskstack from 16 KB to 6 KB andARDUINO_LOOP_STACK_SIZEfrom 32 KB to 16 KB, dropping total static internal RAM utilization from 58.7% (192,260 bytes) down to 36.1% (118,196 bytes). This guaranteesmbedtls_ssl_setup()always has ample contiguous internal DRAM for its 32 KB+ TLS input/output record buffers.WebManagerout-of-memory connection stall on HTTP root requests:filemanager_html(89 KB) andlogin_html(15 KB) were previously passed asconst char*tobeginResponse(), forcing ESPAsyncWebServer to allocate massive contiguous heapStringbuffers that failed on ESP32 RAM. Refactored to stream directly from flash memory chunks ((const uint8_t*)content, len) with zero heap overhead, preventing browserERR_EMPTY_RESPONSEand connection resets.WiFiClientSecuresocket and connect timeout misconfiguration:client.setTimeout(15000)incorrectly interpreted its argument in seconds rather than milliseconds (setting a 4.16-hour socket timeout), whileHTTPClientdefaulted to a restrictive 5-second_connectTimeout(HTTPCLIENT_DEFAULT_TCP_TIMEOUT). Implemented unifiedTLSHelper::configureHTTP(http, 30000)setting 30-second connection and socket timeouts acrossAppStoreUI,OTAManager,HelpCenterUI, andNetworkClient.WiFiManager::connectTo: resolved out-of-bounds array write fromdns_setserver(2, &dns2)on ESP-IDF whereDNS_MAX_SERVERSis 2 (valid indices: 0 and 1). Secondary fallback DNS (8.8.8.8) is now safely registered at index 1 without corrupting lwIP heap structures.esp_wifi_set_ps(WIFI_PS_NONE)) inWiFiManager,WebManager::startServer(), andTLSHelper::configureTLS(). This bypasses Arduino's internal_sleepEnabledstate cache and guarantees the 2.4 GHz radio never sleeps, eliminating dropped TCP SYN packets on port 80 and multi-packet TLS certificate exchanges.client.lastError(tlsErrBuf)) inAppStoreUI,OTAManager, andHelpCenterUIto output exact mbedtls diagnostic codes instead of generic-1.WiFiClientSecure(mbedtls): whenBluetoothEngineauto-enabled on boot, Bluedroid consumed ~65 KB of internal DRAM (MALLOC_CAP_INTERNAL), starvingmbedtlsof the ~40 KB contiguous internal RAM needed for HTTPS handshakes (Error HTTP -1).BluetoothEngine::init()now stays in standby on boot when WiFi is active, andTLSHelper::configureTLS()/WebManager::startServer()automatically suspend active BLE before allocating TLS buffers or starting the HTTP server.abort()crash incoex_core_enable(esp_bt_controller_enable): ESP-IDF's single-antenna software coexistence requiresWIFI_PS_MIN_MODEM(WiFi.setSleep(true)) whenever both WiFi and Bluetooth are active simultaneously.BluetoothEngine::enable()now enforcesesp_wifi_set_ps(WIFI_PS_MIN_MODEM)prior toBLEDevice::init(), andBluetoothEngine::disable()restoresWIFI_PS_NONE(WiFi.setSleep(false)) when BLE turns off.JSBindings::cleanup()when exiting JavaScript apps so background BLE services (blekeyboard,bttest) immediately return internal SRAM and full 2.4 GHz radio bandwidth to the OS.WiFiManager::connectTo: previously the connection loop exited immediately upon 802.11 link association (WL_CONNECTED), before DHCP IP lease assignment was complete. Connection loop now waits until bothWiFi.status() == WL_CONNECTEDandWiFi.localIP() != 0.0.0.0.WiFiManager::isConnected()to strictly check(WiFi.status() == WL_CONNECTED && WiFi.localIP() != IPAddress(0, 0, 0, 0)), preventing apps from making HTTP requests or binding the Web Server to0.0.0.0.WiFi.hostByName) with exponential retry inAppStoreUI,HelpCenterUI, andOTAManager, providing clear diagnostic messages ("DNS Lookup Failed!") instead of obscure-1connection errors.WiFiManager::smartAutoConnect(): WAN captive portal test failure no longer disconnects an active network unless another matching candidate AP is actually discovered in range.WiFiClientSecure+TLSHelper::configureTLS) inHelpCenterUI::downloadFile, which previously called rawhttp.begin(url)on HTTPS URLs without TLS configuration.WiFiManager::backgroundLoop(): cleanly stops the web server on WiFi link or IP lease loss so that it properly re-binds to the new IPv4 address upon reconnection.OPTIONShandler and/index.htmlalias route inWebManagerto prevent browser connection stalls.getEstimatedOCV()that removed loop resistance compensation when terminal voltage reachedRTC_DATA_ATTR s_rtc_last_soc), ensuring warm reboots and sleep wakeups resume seamlessly from the last recorded battery state.HWCDC::isPlugged()dependency: on battery power with no USB cable connected, the floating D+/D- pins on ESP32-S3 picked up ambient electrostatic noise, causingHWCDC::isPlugged()to flap between true and false every second.Guru Meditation Error: Core 1 panic'ed (LoadProhibited)duringBluetoothEngine::startKeyboard()caused byBLEHIDDevice::manufacturer(std::string)dereferencing an uninitializedm_manufacturerCharacteristicpointer inESP32 BLE Arduino @ 2.0.0. Now calls 0-args_pHidDev->manufacturer()first to allocate the0x2A29characteristic on the Device Info service before invokingsetValue("KryonOS").s_pHidDev->outputReport(1)) to the USB HID report map and explicitly enabledBLE2902CCCD notifications ons_pHidInputReportands_pHidMediaReportso bonded smartphones (iOS/Android) receive key notifications across reconnections.bt_reset_server_state()when toggling radio power and preserved active GATT services acrossstopKeyboard()calls to prevent stalegatts_ifhandle panics.TypeError: undefined not callable (property 'width' of [object Object])when apps invokedSystem.width()orSystem.height().System.width(alias ofSystem.screenWidth) andSystem.height(alias ofSystem.screenHeight) insrc/Runtime/JSBindings.cpp.test/com.kryonos.blekeyboard/main.jswith defensive property resolution(typeof System.screenWidth === "function") ? System.screenWidth() : ....playTrackthat blocked auto-repetition and track advance whenisPlayingwas still set.Speaker.getDuration()andSpeaker.getPosition().elapsedSecstops exactly at total duration upon track completion across all repeat modes (ALL,ONE,OFF).TypeError: undefined not callable (property 'then' of [object Object])in Bluetooth JavaScript APIs.typeof Promise === 'undefined'to evaluate tofalse, leavingPromise.prototype.thenundefined on new Promise instances.globalThisreferences with universal cross-environment global resolution (Function('return this')()).duk_peval_string) injs_init_bluetoothlogging any bootstrap errors to the hardware serial console.BluetoothEngine::poll()was not called during JavaScript application execution, causing incoming BLE advertisement packets and GATT notifications to remain queued in C++ ring buffers without triggering theBluetooth.BLE.Scanner.on('discover')or characteristicon('valueChange')callbacks.BluetoothEngine::poll()directly intoJSBindings::js_delay(ctx)so that all events are dequeued and dispatched on everySystem.delay(ms)frame tick.Bluetooth.poll()in the global JavaScript namespace for explicit manual queue polling.timeout: 0) and near 100% duty cycle (interval: 100ms,window: 99ms), ensuring brief advertising bursts from smartphones and beacons are captured reliably.BluetoothEngine([BLE Scan] Starting scan,[BLE Scan] Discovered: <name> (<mac>) RSSI: <rssi> dBm,[BLE Scan] Hardware scan cycle completed) for physical hardware verification over USB Serial.test/com.kryonos.bttest/main.jswith batch screen refreshes (scanDirty = true) and fallback labeling (e.g.BLE (AB:CD)) for devices broadcasting without GAP name strings.assert failed: xQueueGenericSend queue.c:832 (pxQueue->u.xSemaphore.xMutexHolder == xTaskGetCurrentTaskHandle())occurring when WebManager handled incoming HTTP requests for SD card storage.tft.dmaWait()andtft.endWrite()invocations fromprepareSDSPI()insideWebManager.cpp. Backgroundasync_tcpworker tasks now isolate the shared SPI bus solely via GPIO chip-select lines (TFT_CS,RADIO_CS_PIN) without illegally releasing the main thread's FreeRTOS SPI transaction mutex.CORRUPT HEAP: Bad head(multi_heap_poisoning.c:259) when selecting and playing WAV music tracks.AudioEngine::stop()with Core 0audioTask:stop()now signalss_stop_requestedand waits foraudioTaskto acknowledge and exit its playback loop before freeing PSRAM memory unders_audio_mutex.s_psram_file_bufferownership exclusively to the main thread unders_audio_mutex, eliminating re-entrant/concurrent heap deallocations from the audio worker task.s_dma_chunkallocation toDMA_CHUNK_SAMPLES(4096 samples / 8192 bytes) with strict array bounds checks, preventing 8-bit mono downmix sample expansion from overflowing into adjacent PSRAM heap canaries.lastTouchPressed) and continuous vs. tap touch event partitioning in Wave Player (test/com.kryonos.musicplayer), preventing rapid multi-invocation ofSpeaker.playWavacross consecutive display frames during a single touch tap.WiFi.scanNetworks(false, false)) inWiFiManager::backgroundLoop()when disconnected from Wi-Fi.parseWavStream) that navigatesfmtanddatasubchunks and gracefully skips extended format blocks (cbSize), padding chunks (JUNK), and broadcast headers (bext).datachunk finishes, preventing trailingLIST,INFO, andID3tags from being sent to the MAX98357A I2S DAC as harsh digital noise.s_psram_file_buffer) for MicroSD WAV playback (up to 6 MB), completely isolating playback from the shared SPI bus during audio streaming and preventing hardware SPI collisions with concurrent ST7789 display refresh frames.i2s_zero_dma_bufferand zero-crossing de-click ramp down on playback stop to eliminate lingering pops or hums.AudioEngine::playToneandAudioEngine::playBeepwere directly overwriting master volume (s_volume). Replaced with a separate relatives_tone_volumeso user master volume is never altered by tone/beep playback..mck_io_num = I2S_PIN_NO_CHANGE.This discussion was created from the release KryonOS v3.0.0 - Major Update: T-Deck Plus Support, Bluetooth, GPS, Local AI & More.
All reactions