Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@softhack007
Copy link
Collaborator

@softhack007 softhack007 commented Nov 19, 2025

Leverage on what we have already:

  • enable all bitmap glyphs in the existing font files (increases firmware by ~7KB)
  • add translation from unicode codepoints --> codepage437 (as used by font files)
  • segment names are already in UTF-8 "unicode" format, so we only need to modify the scrolling text effect (sic!)

Additionally:

  • Translation from UTF-8 (segment names) -> wchar16_t (basically UTF-16 without extended codes)
  • add a new method Segment::drawText(const char*, size_t maxLen, ...) that wraps drawCharacter() and takes care of unicode translation
  • Use the translated codes as font glyph indices in scrolling text effect -> Segment::drawCharacter() update

this is a simple proof-of-concept (POC) based ideas from

Summary by CodeRabbit

  • New Features

    • Optional "full fonts" mode with expanded glyph coverage, Unicode decoding and conversion, and a Unicode-aware text drawing API (secondary color + optional shadow).
  • Other

    • 2D scrolling text gains Soft and Gradient overlays.
    • Segment-name handling expanded: larger UI maxlength, UTF‑8-safe truncation and preserved characters.
  • Chores

    • Safer buffer handling and larger name buffers; centralized font info and a build flag to enable full-font support.

✏️ Tip: You can customize this high-level summary in your review settings.

part1:

* enable all bitmaps already defined in the font files (increases firmware by ~7KB)
* add traslation for unicode -> codepage437 (as used by font files)
@coderabbitai
Copy link

coderabbitai bot commented Nov 19, 2025

Walkthrough

Adds optional full-font Unicode support: UTF‑8→UTF‑16 decoding, UTF‑16→CP437 mapping, conditional full CP437 font tables and glyph ranges, unicode-aware Segment::drawText/drawCharacter rendering guarded by WLED_ENABLE_FULL_FONTS, widened segment-name buffers, and safer string handling across UI, file, and ledmap code paths.

Changes

Cohort / File(s) Summary
Codepage & Unicode helpers
wled00/src/font/codepages.h, wled00/src/font/unicodetool.cpp, wled00/src/font/codepage437.cpp
New header and guarded implementations: UTF‑8→UTF‑16 decoding (unicodeToWchar16), next‑sequence helper (nextUnicode), strlenUC, cutUnicodeAt, killUnicode, and a large UTF‑16→CP437 mapping (wchar16ToCodepage437) with fallbacks and UNKNOWN/BAD/EXT codes.
Centralized font metadata
wled00/wled_fonts.hpp
New FontInfo_t and getFontInfo(width,height) returning font ranges, data pointers and progmem flags for supported font sizes.
Font data conditionals
wled00/src/font/console_font_4x6.h
console_font_4x6_first/last and glyph array conditionalized on WLED_ENABLE_FULL_FONTS; compact ASCII subset when disabled, full CP437-like glyphs when enabled.
Rendering API declaration
wled00/FX.h
Adds unicode-aware Segment::drawText(...) declaration (wrapper for unicode-aware character rendering).
Rendering implementation & integration
wled00/FX.cpp, wled00/FX_2Dfcn.cpp
Conditional includes of codepages.h; FX.cpp uses strlenUC when FULL_FONTS enabled; FX_2Dfcn.cpp implements Segment::drawText decoding UTF‑8→UTF‑16→CP437, enforces limits, and delegates per-character rendering; drawCharacter logic adjusted to use FontInfo_t and support multiple font sizes.
Segment name handling / UI
wled00/json.cpp, wled00/data/index.js
Segment names truncated to WLED_MAX_SEGNAME_LEN, preserve UTF‑8 boundaries via cutUnicodeAt when FULL_FONTS enabled; JS input maxlength increased (32→64).
Build configuration
platformio.ini
Adds WLED_ENABLE_FULL_FONTS build flag to several ESP32 environments (some active, some commented examples).
Buffer size & safety adjustments
wled00/file.cpp, wled00/presets.cpp, wled00/FX_fcn.cpp
Increased local buffers (JSON keys, quickLoad, filenames, previousSegmentName), replaced manual resets with memset, switched to strlcpy/safer copies, and updated related length checks.
Compile-time flags & constants
wled00/wled.h, wled00/const.h, wled00/image_loader.cpp
Sets ARDUINOJSON_DECODE_UNICODE=1, introduces centralized WLED_MAX_SEGNAME_LEN with platform defaults and minimum enforcement, and removes a local fallback in image_loader.cpp.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Caller as Segment::drawText
    participant UTF8 as UTF-8 buffer
    participant NEXT as nextUnicode()
    participant DEC as unicodeToWchar16()
    participant MAP as wchar16ToCodepage437()
    participant FONT as FontInfo / glyph data
    Note over Caller,FONT: Active when WLED_ENABLE_FULL_FONTS is defined
    Caller->>UTF8: iterate bytes (ptr, maxLen)
    UTF8->>NEXT: get next sequence pointer
    NEXT-->>Caller: next ptr / null
    Caller->>DEC: decode sequence -> UTF-16
    DEC-->>Caller: UTF-16 codepoint (or BAD/UNKNOWN)
    Caller->>MAP: map UTF-16 -> CP437 byte (or UNKNOWN)
    MAP-->>Caller: CP437 index
    Caller->>FONT: lookup glyph bitmap via FontInfo
    FONT-->>Caller: glyph bitmap
    Caller->>Caller: call drawCharacter -> render pixels (clip/shadow)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Inspect large mapping switch in codepage437.cpp for correctness, completeness and duplicates.
  • Validate UTF‑8 decoding edge cases (overlong sequences, surrogates, 4‑byte handling) in unicodetool.cpp.
  • Verify font indexing, first/last offsets and glyph alignment in wled_fonts.hpp and font headers.
  • Check truncation (cutUnicodeAt) and logging in json.cpp for UTF‑8 integrity and off‑by‑one issues.
  • Review resized buffers and strlcpy/memset usage across file.cpp, FX_fcn.cpp, presets.cpp for potential truncation or boundary mistakes.

Possibly related issues

Poem

🐰 I hop through bytes and map each tiny rune,
From UTF‑8 to CP437 beneath a silver moon.
I stretch the names and guard each buffer tight,
I nibble bugs and stitch the glyphs just right.
Your text will glow — I thump with joy tonight.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 64.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main objective: adding Unicode/high ASCII support for scrolling text with CP437 codepage translation, though marked as WIP/POC status.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch high_ascii

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e667637 and e38c2b3.

📒 Files selected for processing (2)
  • wled00/FX_2Dfcn.cpp (2 hunks)
  • wled00/wled_fonts.hpp (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
wled00/**/*.{cpp,h}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use spaces (2 per level) for C++ firmware source and headers in wled00

Files:

  • wled00/FX_2Dfcn.cpp
🧠 Learnings (11)
📓 Common learnings
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR #270, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue #272; do not address it within PR #270.
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-14T13:55:44.442Z
Learning: In MoonModules/WLED-MM, always flag Variable Length Arrays (VLA) during code reviews, especially when they could overflow available stack space (typically 2K-4K on ESP32/ESP8266). VLAs based on dynamic parameters like segment dimensions, particle counts, or pixel buffers should be highlighted and require justification from the author. Prefer fixed-size arrays, heap allocation, or bounded VLAs with explicit maximum size constraints.
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.
📚 Learning: 2025-11-02T22:17:26.380Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-02T22:17:26.380Z
Learning: In wled00/FX.cpp, the `#ifndef WLED_DISABLE_2D` guard around the Akemi 2D fallback in the `mode_oops()` function (lines 142-146) is intentionally kept. This guard is necessary because when users build with `-D WLED_DISABLE_2D` to remove all 2D effects from the build, the Akemi effect is also not compiled, so the guard prevents calling a non-existent function.

Applied to files:

  • wled00/FX_2Dfcn.cpp
  • wled00/wled_fonts.hpp
📚 Learning: 2025-10-22T21:59:24.331Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR #270, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue #272; do not address it within PR #270.

Applied to files:

  • wled00/FX_2Dfcn.cpp
  • wled00/wled_fonts.hpp
📚 Learning: 2025-11-14T13:55:44.442Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-14T13:55:44.442Z
Learning: In MoonModules/WLED-MM, always flag Variable Length Arrays (VLA) during code reviews, especially when they could overflow available stack space (typically 2K-4K on ESP32/ESP8266). VLAs based on dynamic parameters like segment dimensions, particle counts, or pixel buffers should be highlighted and require justification from the author. Prefer fixed-size arrays, heap allocation, or bounded VLAs with explicit maximum size constraints.

Applied to files:

  • wled00/FX_2Dfcn.cpp
  • wled00/wled_fonts.hpp
📚 Learning: 2025-10-22T21:50:25.839Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.

Applied to files:

  • wled00/FX_2Dfcn.cpp
  • wled00/wled_fonts.hpp
📚 Learning: 2025-10-22T22:24:46.163Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/json.cpp:295-304
Timestamp: 2025-10-22T22:24:46.163Z
Learning: When deriving an upper-bound index from a count in WLED-MM PR #270, use a safe guard: last = count ? count - 1 : 0. Avoid min/max with 0 on unsigned types and never pass (count-1) directly to helpers (e.g., updateVal16, relativeChange, random8) without guarding. Effect IDs are 16-bit; palette IDs remain 8-bit but should use the same guard when count can be 0.

Applied to files:

  • wled00/FX_2Dfcn.cpp
  • wled00/wled_fonts.hpp
📚 Learning: 2025-07-12T04:20:14.546Z
Learnt from: DedeHai
Repo: MoonModules/WLED-MM PR: 253
File: usermods/audioreactive/audio_source.h:1256-1261
Timestamp: 2025-07-12T04:20:14.546Z
Learning: In WLED AudioReactive usermod, DC offset removal optimization in DMAadcSource::getSamples() should be implemented after PR #248 merges, which will change the sample buffer from float to int16. This eliminates the need for temporary integer buffers and allows direct integer arithmetic on the native buffer type for better memory efficiency on resource-constrained MCUs like C3 and S2.

Applied to files:

  • wled00/FX_2Dfcn.cpp
  • wled00/wled_fonts.hpp
📚 Learning: 2025-11-02T22:07:15.689Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-02T22:07:15.689Z
Learning: In MoonModules/WLED-MM, WLEDMM_FASTPATH will become the default code path. Code inside "#ifndef WLEDMM_FASTPATH" blocks represents deprecated paths that are being phased out and should be ignored during reviews.

Applied to files:

  • wled00/FX_2Dfcn.cpp
  • wled00/wled_fonts.hpp
📚 Learning: 2025-11-14T12:42:22.059Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 240
File: wled00/image_loader.cpp:0-0
Timestamp: 2025-11-14T12:42:22.059Z
Learning: In MoonModules/WLED-MM and embedded systems code, the pattern `unsigned timePassed = millis() - last_time;` is rollover-safe and proven to work correctly even when millis() wraps around at ~49.7 days uptime. This works due to modular arithmetic in unsigned integers. The subtraction yields the correct elapsed time regardless of rollover. This pattern should not be flagged as problematic or refactored to use signed arithmetic.

Applied to files:

  • wled00/FX_2Dfcn.cpp
  • wled00/wled_fonts.hpp
📚 Learning: 2025-06-30T17:53:37.232Z
Learnt from: DedeHai
Repo: MoonModules/WLED-MM PR: 248
File: usermods/audioreactive/audio_reactive.h:199-200
Timestamp: 2025-06-30T17:53:37.232Z
Learning: In WLED AudioReactive usermod, when using ArduinoFFT (enabled via UM_AUDIOREACTIVE_USE_ARDUINO_FFT), it's acceptable and necessary to redefine the global sqrt macro to sqrtf within the conditional compilation block for performance optimization. This is a specific requirement for ArduinoFFT optimization that can provide 10-50% performance improvement on ESP32.

Applied to files:

  • wled00/wled_fonts.hpp
📚 Learning: 2025-10-22T21:50:22.379Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/FX.cpp:11799-11813
Timestamp: 2025-10-22T21:50:22.379Z
Learning: In PR #270 (16-bit effect IDs PoC), the current addEffect behavior of appending and ignoring explicit ids >= _mode.size() is intentional for the proof-of-concept; changes to honor explicit ids are deferred to a follow-up.

Applied to files:

  • wled00/wled_fonts.hpp
🧬 Code graph analysis (2)
wled00/FX_2Dfcn.cpp (4)
wled00/FX.h (10)
  • virtualWidth (722-728)
  • virtualHeight (729-735)
  • setPixelColorXY (794-794)
  • setPixelColorXY (796-796)
  • setPixelColorXY (797-797)
  • setPixelColorXY (841-841)
  • setPixelColorXY (842-842)
  • setPixelColorXY (844-844)
  • setPixelColorXY (845-845)
  • setPixelColorXY (1195-1195)
wled00/wled_fonts.hpp (2)
  • getFontInfo (33-85)
  • getFontInfo (33-33)
wled00/src/font/unicodetool.cpp (4)
  • nextUnicode (56-80)
  • nextUnicode (56-56)
  • unicodeToWchar16 (20-52)
  • unicodeToWchar16 (20-20)
wled00/src/font/codepage437.cpp (2)
  • wchar16ToCodepage437 (17-234)
  • wchar16ToCodepage437 (17-17)
wled00/wled_fonts.hpp (1)
wled00/FX.h (2)
  • width (616-616)
  • height (617-617)
🪛 Clang (14.0.6)
wled00/wled_fonts.hpp

[error] 4-4: 'stdlib.h' file not found

(clang-diagnostic-error)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (19)
  • GitHub Check: Builds (esp8266pro_16MB_M)
  • GitHub Check: Builds (esp01_1MB_S)
  • GitHub Check: Builds (esp32S3_16MB_PSRAM_M_HUB75)
  • GitHub Check: Builds (esp32_4MB_V4_S)
  • GitHub Check: Builds (adafruit_matrixportal_esp32s3_tinyUF2)
  • GitHub Check: Builds (esp32S3_8MB_M)
  • GitHub Check: Builds (esp32S3_4MB_PSRAM_M)
  • GitHub Check: Builds (athom_music_esp32_4MB_M)
  • GitHub Check: Builds (esp32S3_WROOM-2_M)
  • GitHub Check: Builds (esp32s2_PSRAM_S)
  • GitHub Check: Builds (esp32c3dev_2MB_M)
  • GitHub Check: Builds (esp32S3_8MB_PSRAM_M)
  • GitHub Check: Builds (esp32s2_PSRAM_M)
  • GitHub Check: Builds (esp32S3_16MB_PSRAM_M_HUB75)
  • GitHub Check: Builds (esp32_4MB_PSRAM_S)
  • GitHub Check: Builds (esp32c3dev_4MB_M)
  • GitHub Check: Builds (esp32_4MB_V4_HUB75_forum)
  • GitHub Check: Builds (esp32_16MB_V4_M)
  • GitHub Check: Builds (esp32S3_4MB_S)
🔇 Additional comments (2)
wled00/wled_fonts.hpp (1)

33-85: LGTM: ODR issue resolved.

The inline getFontInfo function now correctly returns a local FontInfo_t by value (line 34). The previous ODR violation from using static storage in an inline function has been fixed. The font selection logic is sound and all code paths properly initialize and return the font descriptor.

wled00/FX_2Dfcn.cpp (1)

917-964: Unicode-aware character rendering looks solid.

The drawCharacter function correctly uses centralized getFontInfo (line 921), validates character bounds against font limits (line 923), adjusts the character index to be font-relative (line 924), and safely reads from PROGMEM (lines 942-943). The shadow rendering logic is properly restored with (i>0) guards.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
wled00/src/font/codepage437.cpp (1)

12-204: Remove redundant break statements after return.

Each case statement has a break; after a return statement, which is unreachable code. While harmless, removing these improves code clarity.

Example pattern to apply throughout the switch:

-    case 0x263A: return 0x01; break; // ☺︎
+    case 0x263A: return 0x01; // ☺︎
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 219355d and 43ab0dd.

📒 Files selected for processing (3)
  • wled00/src/font/codepage437.cpp (1 hunks)
  • wled00/src/font/codepages.h (1 hunks)
  • wled00/src/font/console_font_4x6.h (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
wled00/**/*.{cpp,h}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use spaces (2 per level) for C++ firmware source and headers in wled00

Files:

  • wled00/src/font/codepages.h
  • wled00/src/font/codepage437.cpp
  • wled00/src/font/console_font_4x6.h
🧠 Learnings (3)
📓 Common learnings
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR #270, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue #272; do not address it within PR #270.
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-02T22:07:15.689Z
Learning: In MoonModules/WLED-MM, WLEDMM_FASTPATH will become the default code path. Code inside "#ifndef WLEDMM_FASTPATH" blocks represents deprecated paths that are being phased out and should be ignored during reviews.
📚 Learning: 2025-10-22T21:50:25.839Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.

Applied to files:

  • wled00/src/font/codepage437.cpp
  • wled00/src/font/console_font_4x6.h
📚 Learning: 2025-10-22T22:24:46.163Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/json.cpp:295-304
Timestamp: 2025-10-22T22:24:46.163Z
Learning: When deriving an upper-bound index from a count in WLED-MM PR #270, use a safe guard: last = count ? count - 1 : 0. Avoid min/max with 0 on unsigned types and never pass (count-1) directly to helpers (e.g., updateVal16, relativeChange, random8) without guarding. Effect IDs are 16-bit; palette IDs remain 8-bit but should use the same guard when count can be 0.

Applied to files:

  • wled00/src/font/console_font_4x6.h
🧬 Code graph analysis (1)
wled00/src/font/codepages.h (1)
wled00/src/font/codepage437.cpp (2)
  • wchar16ToCodepage437 (7-206)
  • wchar16ToCodepage437 (7-7)
🪛 Clang (14.0.6)
wled00/src/font/codepages.h

[error] 1-1: 'string.h' file not found

(clang-diagnostic-error)

wled00/src/font/console_font_4x6.h

[error] 2-2: unknown type name 'constexpr'

(clang-diagnostic-error)


[error] 2-2: expected ';' after top level declarator

(clang-diagnostic-error)


[error] 3-3: unknown type name 'constexpr'

(clang-diagnostic-error)


[error] 3-3: expected ';' after top level declarator

(clang-diagnostic-error)


[error] 10-10: expected ';' after top level declarator

(clang-diagnostic-error)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: Builds (esp8266pro_16MB_M)
  • GitHub Check: Builds (adafruit_matrixportal_esp32s3_tinyUF2)
  • GitHub Check: Builds (esp32s2_PSRAM_M)
  • GitHub Check: Builds (esp8266_4MB_M)
  • GitHub Check: Builds (athom_music_esp32_4MB_M)
  • GitHub Check: Builds (esp32c3dev_2MB_M)
  • GitHub Check: Builds (esp32c3dev_4MB_M)
  • GitHub Check: Builds (esp32S3_WROOM-2_M)
  • GitHub Check: Builds (esp32c3mini_dio_4MB_M)
  • GitHub Check: Builds (esp32_16MB_V4_M)
  • GitHub Check: Builds (esp32S3_8MB_PSRAM_M)
  • GitHub Check: Builds (esp32S3_4MB_PSRAM_S)
  • GitHub Check: Builds (esp32_4MB_PSRAM_S)
  • GitHub Check: Builds (esp32S3_4MB_PSRAM_M)
  • GitHub Check: Builds (esp32S3_16MB_PSRAM_M_HUB75)
  • GitHub Check: Builds (esp32S3_8MB_M)
  • GitHub Check: Builds (esp32_16MB_V4_S)
  • GitHub Check: Builds (esp32S3_4MB_S)
  • GitHub Check: Builds (esp32_4MB_V4_HUB75_forum)
  • GitHub Check: Builds (esp32_4MB_V4_S)
🔇 Additional comments (4)
wled00/src/font/codepage437.cpp (1)

7-206: LGTM! Well-documented character mapping implementation.

The translation table comprehensively maps UTF-16 code points to CP437, with:

  • Direct ASCII passthrough for values < 127
  • Explicit mappings for control characters, box-drawing, Latin-1, Greek letters, and mathematical symbols
  • Special fallback mappings for visually similar characters
  • Reasonable default fallback to middle dot (250) for unmapped characters

The implementation is clear and maintainable.

wled00/src/font/console_font_4x6.h (3)

1-7: LGTM! Conditional font range configuration is correct.

The font range constants properly reflect the two configurations:

  • Without WLED_ENABLE_FULL_FONTS: Standard ASCII range (32-126)
  • With WLED_ENABLE_FULL_FONTS: Extended CP437 range (1-254)

This aligns with the codepage translation feature and allows optional memory savings.


27-337: Extensive font data expansion is properly guarded.

The extended character set (codes 1-31 and 127-254) is correctly conditionalized with WLED_ENABLE_FULL_FONTS, providing:

  • Control characters and symbols (1-31)
  • Box-drawing, blocks, and extended characters (127-254)

This implementation matches the CP437 character set and enables the UTF-16 translation feature. The ~7KB firmware size increase mentioned in the PR description is reasonable for full internationalization support.

Also applies to: 1288-2568


15-25: Code points 0 and 255 exclusion is intentional and well-documented.

The exclusion is consistent across all font files (4x6, 5x8, 6x8, 7x9, 5x12) with explicit documentation: "code points 0-31 and 127-255 are commented out to save memory." When WLED_ENABLE_FULL_FONTS is enabled, the font range is set to 1–254 (not 1–255), confirming that excluding code point 255 is a deliberate design decision, not an oversight. Code point 255 is specifically marked as "skip 255 = NBSP" for memory optimization purposes.

* prototypes for UTF-8 ==> wchar16 conversion
* minor fixes
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
wled00/src/font/codepages.h (1)

1-15: Fix <stdlib.h> to <stdint.h> and <stddef.h> for proper type definitions

The header currently includes <stdlib.h> to get uint16_t, but this is incorrect. The uint16_t type is defined in <stdint.h>, and size_t should come from <stddef.h>. These are the standard C headers for fixed-width integer types and size types respectively.

#ifndef WLED_CODEPAGES_H
#define WLED_CODEPAGES_H
-#include <stdlib.h> // needed to get uint16_t definition
+#include <stdint.h>  // uint16_t
+#include <stddef.h>  // size_t

The optional suggestion to guard the UTF-8 helper declarations with WLED_ENABLE_FULL_FONTS is good defensive programming. Both implementations (unicodetool.cpp and codepage437.cpp) are already guarded by this macro, so adding the guard to the declarations would ensure consistency:

#ifdef WLED_ENABLE_FULL_FONTS
uint16_t unicodeToWchar16(const char* utf8, size_t maxLen);
const char* nextUnicode(const char* utf8, size_t maxLen);
#endif

uint16_t wchar16ToCodepage437(uint16_t wideChar);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 43ab0dd and 55c9741.

📒 Files selected for processing (3)
  • wled00/src/font/codepage437.cpp (1 hunks)
  • wled00/src/font/codepages.h (1 hunks)
  • wled00/src/font/unicodetool.cpp (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
wled00/**/*.{cpp,h}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use spaces (2 per level) for C++ firmware source and headers in wled00

Files:

  • wled00/src/font/codepages.h
  • wled00/src/font/unicodetool.cpp
  • wled00/src/font/codepage437.cpp
🧠 Learnings (6)
📓 Common learnings
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR #270, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue #272; do not address it within PR #270.
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.
📚 Learning: 2025-10-22T22:24:46.163Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/json.cpp:295-304
Timestamp: 2025-10-22T22:24:46.163Z
Learning: When deriving an upper-bound index from a count in WLED-MM PR #270, use a safe guard: last = count ? count - 1 : 0. Avoid min/max with 0 on unsigned types and never pass (count-1) directly to helpers (e.g., updateVal16, relativeChange, random8) without guarding. Effect IDs are 16-bit; palette IDs remain 8-bit but should use the same guard when count can be 0.

Applied to files:

  • wled00/src/font/codepages.h
📚 Learning: 2025-10-22T21:50:25.839Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.

Applied to files:

  • wled00/src/font/codepages.h
  • wled00/src/font/unicodetool.cpp
  • wled00/src/font/codepage437.cpp
📚 Learning: 2025-10-12T21:55:59.766Z
Learnt from: CR
Repo: MoonModules/WLED-MM PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-12T21:55:59.766Z
Learning: Applies to wled00/**/*.{cpp,h} : Use spaces (2 per level) for C++ firmware source and headers in wled00

Applied to files:

  • wled00/src/font/codepages.h
  • wled00/src/font/unicodetool.cpp
📚 Learning: 2025-11-02T22:17:26.380Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-02T22:17:26.380Z
Learning: In wled00/FX.cpp, the `#ifndef WLED_DISABLE_2D` guard around the Akemi 2D fallback in the `mode_oops()` function (lines 142-146) is intentionally kept. This guard is necessary because when users build with `-D WLED_DISABLE_2D` to remove all 2D effects from the build, the Akemi effect is also not compiled, so the guard prevents calling a non-existent function.

Applied to files:

  • wled00/src/font/codepages.h
📚 Learning: 2025-11-02T22:07:15.689Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-02T22:07:15.689Z
Learning: In MoonModules/WLED-MM, WLEDMM_FASTPATH will become the default code path. Code inside "#ifndef WLEDMM_FASTPATH" blocks represents deprecated paths that are being phased out and should be ignored during reviews.

Applied to files:

  • wled00/src/font/unicodetool.cpp
🧬 Code graph analysis (1)
wled00/src/font/codepages.h (2)
wled00/src/font/unicodetool.cpp (4)
  • unicodeToWchar16 (7-9)
  • unicodeToWchar16 (7-7)
  • nextUnicode (13-15)
  • nextUnicode (13-13)
wled00/src/font/codepage437.cpp (2)
  • wchar16ToCodepage437 (8-207)
  • wchar16ToCodepage437 (8-8)
🪛 Clang (14.0.6)
wled00/src/font/codepages.h

[error] 3-3: 'stdlib.h' file not found

(clang-diagnostic-error)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (19)
  • GitHub Check: Builds (esp32S3_4MB_PSRAM_S)
  • GitHub Check: Builds (esp32_16MB_V4_M)
  • GitHub Check: Builds (adafruit_matrixportal_esp32s3_tinyUF2)
  • GitHub Check: Builds (athom_music_esp32_4MB_M)
  • GitHub Check: Builds (esp32c3dev_4MB_M)
  • GitHub Check: Builds (seeed_esp32c3_4MB_S)
  • GitHub Check: Builds (esp32s2_PSRAM_S)
  • GitHub Check: Builds (esp32s2_PSRAM_M)
  • GitHub Check: Builds (esp32S3_8MB_PSRAM_M)
  • GitHub Check: Builds (esp32_16MB_V4_M)
  • GitHub Check: Builds (esp32S3_8MB_M)
  • GitHub Check: Builds (esp32S3_4MB_PSRAM_M)
  • GitHub Check: Builds (esp32S3_WROOM-2_M)
  • GitHub Check: Builds (esp32_16MB_V4_S)
  • GitHub Check: Builds (esp32S3_4MB_PSRAM_S)
  • GitHub Check: Builds (esp32_4MB_PSRAM_S)
  • GitHub Check: Builds (esp32S3_8MB_S)
  • GitHub Check: Builds (esp32_4MB_V4_HUB75_forum)
  • GitHub Check: Builds (esp32S3_4MB_S)
🔇 Additional comments (1)
wled00/src/font/codepage437.cpp (1)

6-205: CP437 mapping and fallback behavior look consistent

The ASCII fast‑path, explicit CP437 mappings, and “nearby” fallbacks all look coherent, and the default 250 glyph is a reasonable unknown‑character marker for this font set. No functional issues spotted here.

just to sketch out the final implementation
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
wled00/src/font/unicodetool.cpp (1)

6-12: Consider a more distinctive sentinel value.

The current stub returns 0, which could be confused with a valid NULL character (U+0000). For a "no character" sentinel, consider using the Unicode replacement character 0xFFFD or checking maxLen == 0 explicitly before returning a sentinel.

For example:

 uint16_t unicodeToWchar16(const char* utf8, size_t maxLen) {
-  // TODO: implement proper UTF‑8 → reduced UTF‑16 decoding
-  (void)utf8;
-  (void)maxLen;
-  return 0;  // sentinel: "no character"
+  // TODO: implement proper UTF‑8 → reduced UTF‑16 decoding
+  if (!utf8 || maxLen == 0) return 0xFFFD;  // Unicode replacement character
+  // Stub: treat first byte as-is (ASCII only)
+  return (uint16_t)(uint8_t)utf8[0];
 }

This provides a slightly safer stub that at least handles ASCII correctly until full UTF-8 decoding is implemented.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 55c9741 and 8219feb.

📒 Files selected for processing (2)
  • wled00/FX.h (1 hunks)
  • wled00/src/font/unicodetool.cpp (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
wled00/**/*.{cpp,h}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use spaces (2 per level) for C++ firmware source and headers in wled00

Files:

  • wled00/FX.h
  • wled00/src/font/unicodetool.cpp
🧠 Learnings (8)
📓 Common learnings
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR #270, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue #272; do not address it within PR #270.
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.
📚 Learning: 2025-11-02T22:17:26.380Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-02T22:17:26.380Z
Learning: In wled00/FX.cpp, the `#ifndef WLED_DISABLE_2D` guard around the Akemi 2D fallback in the `mode_oops()` function (lines 142-146) is intentionally kept. This guard is necessary because when users build with `-D WLED_DISABLE_2D` to remove all 2D effects from the build, the Akemi effect is also not compiled, so the guard prevents calling a non-existent function.

Applied to files:

  • wled00/FX.h
  • wled00/src/font/unicodetool.cpp
📚 Learning: 2025-10-12T21:55:59.766Z
Learnt from: CR
Repo: MoonModules/WLED-MM PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-12T21:55:59.766Z
Learning: Applies to wled00/**/*.{cpp,h} : Use spaces (2 per level) for C++ firmware source and headers in wled00

Applied to files:

  • wled00/src/font/unicodetool.cpp
📚 Learning: 2025-10-22T21:50:25.839Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.

Applied to files:

  • wled00/src/font/unicodetool.cpp
📚 Learning: 2025-10-22T21:59:24.331Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR #270, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue #272; do not address it within PR #270.

Applied to files:

  • wled00/src/font/unicodetool.cpp
📚 Learning: 2025-11-14T13:55:44.372Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-14T13:55:44.372Z
Learning: In MoonModules/WLED-MM, always flag Variable Length Arrays (VLA) during code reviews, especially when they could overflow available stack space (typically 2K-4K on ESP32/ESP8266). VLAs based on dynamic parameters like segment dimensions, particle counts, or pixel buffers should be highlighted and require justification from the author. Prefer fixed-size arrays, heap allocation, or bounded VLAs with explicit maximum size constraints.

Applied to files:

  • wled00/src/font/unicodetool.cpp
📚 Learning: 2025-10-22T22:24:46.163Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/json.cpp:295-304
Timestamp: 2025-10-22T22:24:46.163Z
Learning: When deriving an upper-bound index from a count in WLED-MM PR #270, use a safe guard: last = count ? count - 1 : 0. Avoid min/max with 0 on unsigned types and never pass (count-1) directly to helpers (e.g., updateVal16, relativeChange, random8) without guarding. Effect IDs are 16-bit; palette IDs remain 8-bit but should use the same guard when count can be 0.

Applied to files:

  • wled00/src/font/unicodetool.cpp
📚 Learning: 2025-11-02T22:07:15.689Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-02T22:07:15.689Z
Learning: In MoonModules/WLED-MM, WLEDMM_FASTPATH will become the default code path. Code inside "#ifndef WLEDMM_FASTPATH" blocks represents deprecated paths that are being phased out and should be ignored during reviews.

Applied to files:

  • wled00/src/font/unicodetool.cpp
🧬 Code graph analysis (1)
wled00/FX.h (1)
wled00/FX_2Dfcn.cpp (1)
  • drawCharacter (888-888)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: Builds (esp32S3_8MB_PSRAM_M)
  • GitHub Check: Builds (athom_music_esp32_4MB_M)
  • GitHub Check: Builds (esp32c3dev_4MB_M)
  • GitHub Check: Builds (esp8266pro_16MB_M)
  • GitHub Check: Builds (adafruit_matrixportal_esp32s3_tinyUF2)
  • GitHub Check: Builds (esp01_1MB_S)
  • GitHub Check: Builds (esp32_4MB_V4_S)
  • GitHub Check: Builds (esp32c3mini_dio_4MB_M)
  • GitHub Check: Builds (esp32s2_PSRAM_S)
  • GitHub Check: Builds (esp32_4MB_PSRAM_S)
  • GitHub Check: Builds (seeed_esp32c3_4MB_S)
  • GitHub Check: Builds (esp32S3_4MB_S)
  • GitHub Check: Builds (esp32c3dev_2MB_M)
  • GitHub Check: Builds (esp32S3_4MB_PSRAM_S)
  • GitHub Check: Builds (esp32S3_16MB_PSRAM_M_HUB75)
  • GitHub Check: Builds (esp32S3_WROOM-2_M)
  • GitHub Check: Builds (esp32_16MB_V4_M)
  • GitHub Check: Builds (esp32_4MB_V4_HUB75_forum)
  • GitHub Check: Builds (esp32_16MB_V4_S)
  • GitHub Check: Builds (esp32S3_8MB_M)

@softhack007 softhack007 marked this pull request as draft November 19, 2025 17:15
* should properly decode all unicodes that fit into 2bytes UTF-16
* with error handling for well-known "malformed UTF-8" expoits
* puh, this stuff looks simple but the details are CRAZY 😝
@softhack007
Copy link
Collaborator Author

@coderabbitai review

In addition to your usual code analysis, pleae verify if the two functions in unicodetools.cpp will properly handle UTF-8 codepoint extraction for any encoded character where the codepoint fits into 2-byte UTF-16. Assume that the input utf8 is always NUL terminated.

@coderabbitai
Copy link

coderabbitai bot commented Nov 19, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Read the unicodetool.cpp file to analyze the UTF-8 decoding implementation
cat wled00/src/font/unicodetool.cpp

Length of output: 3518


🏁 Script executed:

#!/bin/bash
# Read the codepages.h header to check function signatures
cat wled00/src/font/codepages.h

Length of output: 845


🏁 Script executed:

#!/bin/bash
# Check how drawText uses the unicode functions
rg -n -C5 "unicodeToWchar16|nextUnicode" --type=cpp --type=h -g '!**/font/**'

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for drawText implementation
rg -n -A20 "void Segment::drawText" wled00/

# Also check for any includes of codepages.h
rg -n "codepages.h" wled00/

Length of output: 113


🏁 Script executed:

#!/bin/bash
# Search for drawText more broadly
rg -n "drawText" wled00/ -A10

# Also check if there's an FX.cpp or FX_fcn.cpp file
fd -e cpp FX wled00/

Length of output: 973


🏁 Script executed:

#!/bin/bash
# Search for drawText implementation in FX cpp files
rg -n "drawText" wled00/FX*.cpp -B2 -A30

# Also look for any TODO or WIP comments in the font directory
rg -n "TODO|FIXME|WIP" wled00/src/font/

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for where these functions might be called or any tests
rg -n "WLED_ENABLE_FULL_FONTS" wled00/ -B2 -A2

# Check console_font_5x8.h for similar pattern
head -50 wled00/src/font/console_font_5x8.h

Length of output: 6088


@softhack007, I've completed a thorough analysis of the UTF-8 decoding functions in unicodetool.cpp. Here's my detailed review:

unicodeToWchar16() - CORRECT Implementation

The function properly handles UTF-8 codepoint extraction for all characters that fit into 2-byte UTF-16 (the Basic Multilingual Plane, U+0000 to U+FFFF). Here's what it does correctly:

Proper Handling:

  • 1-byte sequences (U+0000–U+007F): Direct ASCII passthrough ✓
  • 2-byte sequences (U+0080–U+07FF): Correct bit manipulation and decoding ✓
  • 3-byte sequences (U+0800–U+FFFF): Correct bit manipulation and decoding ✓
  • 4-byte sequences (U+10000+): Properly rejected with error marker ✓

Validation Features:

  • ✅ Continuation byte validation via isValidContinuation()
  • ✅ Overlong encoding rejection (e.g., 0xC0 0x80 for null byte)
  • ✅ UTF-16 surrogate pair rejection (U+D800–U+DFFF range)
  • ✅ Buffer boundary checks
  • ✅ Proper error handling with 0x2022 (•) as fallback

Minor Note:

Line 37: The check if (codepoint >= 0x010000) is redundant since a 3-byte UTF-8 sequence can only encode up to U+FFFF, but it's harmless and adds defensive programming.


⚠️ nextUnicode() - Issues Found

This function mostly works but has a critical flaw:

The Problem:

Lines 54-61: The function calculates the UTF-8 sequence length from the lead byte but does not validate continuation bytes before advancing. This means:

// Current implementation blindly advances:
if      ((ch0 & 0b11100000) == 0b11000000) codeLength = 2;
else if ((ch0 & 0b11110000) == 0b11100000) codeLength = 3;
// ...
return utf8 + codeLength; // Advances without checking continuation bytes!

Impact:

If the UTF-8 stream contains a valid lead byte (e.g., 0xE0 for 3-byte sequence) followed by invalid continuation bytes, nextUnicode() will still advance by 3 bytes, potentially:

  • Skipping over valid ASCII characters
  • Getting out of sync with actual character boundaries
  • Causing unicodeToWchar16() on subsequent calls to read garbage

Recommended Fix:

const unsigned char* nextUnicode(const unsigned char* utf8, size_t maxLen) {
  if ((!utf8) || (maxLen < 1) || (*utf8 == 0)) return nullptr;
  
  size_t length = strlen((const char*) utf8);
  length = min(length, maxLen);
  if (length < 1) return nullptr;

  unsigned char ch0 = *utf8;
  size_t codeLength = 1;
  
  if (ch0 >= 0x80) {
    if ((ch0 & 0b11100000) == 0b11000000) {
      // 2-byte sequence: validate continuation byte
      if (length >= 2 && isValidContinuation(utf8[1])) {
        codeLength = 2;
      }
      // else: treat as 1-byte error and resync
    } else if ((ch0 & 0b11110000) == 0b11100000) {
      // 3-byte sequence: validate continuation bytes
      if (length >= 3 && isValidContinuation(utf8[1]) && isValidContinuation(utf8[2])) {
        codeLength = 3;
      }
      // else: treat as 1-byte error and resync
    } else if ((ch0 & 0b11111000) == 0b11110000) {
      // 4-byte sequence: validate continuation bytes
      if (length >= 4 && isValidContinuation(utf8[1]) && 
          isValidContinuation(utf8[2]) && isValidContinuation(utf8[3])) {
        codeLength = 4;
      }
      // else: treat as 1-byte error and resync
    }
    // else: invalid lead byte, advance 1 byte to resync (current behavior)
  }

  if (length < codeLength) return nullptr;
  return utf8 + codeLength;
}

Additional Observations:

  1. Type signatures: Both header and implementation correctly use const unsigned char* (the AI summary incorrectly stated const char*)

  2. strlen cast (Line 45): The cast from unsigned char* to char* is safe since the input is NUL-terminated, but you could use strnlen() to avoid the cast

  3. Missing implementation: The drawText() function is declared in FX.h but its implementation wasn't found in the codebase. This is expected for a WIP/POC PR.


Summary:

  • unicodeToWchar16(): Fully correct for all BMP codepoints
  • ⚠️ nextUnicode(): Functionally correct for valid UTF-8 but vulnerable to malformed sequences. Adding continuation byte validation would make it robust.

The current implementation will work fine if the input UTF-8 is well-formed (which it typically should be from segment names), but adding the validation would make it production-ready and prevent potential issues with corrupted data.

[review]


🧠 Learnings used
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR #270, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue #272; do not address it within PR #270.

Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.

@softhack007 softhack007 marked this pull request as ready for review November 19, 2025 23:04
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
wled00/src/font/codepages.h (1)

3-3: Critical: Wrong header for uint16_t definition.

stdlib.h does not define uint16_t. The correct header is <stdint.h>.

Apply this diff:

-#include <stdlib.h> // needed to get uint16_t definition
+#include <stdint.h> // needed to get uint16_t definition
🧹 Nitpick comments (1)
wled00/src/font/unicodetool.cpp (1)

15-45: LGTM: UTF-8 decoding logic is correct.

The function properly validates UTF-8 sequences, rejects overlong encodings, surrogate pairs, and 4-byte sequences. The implementation correctly handles the Basic Multilingual Plane (U+0000–U+FFFF).

Minor note: Line 39's check codepoint >= 0x010000 is mathematically unreachable since a 3-byte UTF-8 sequence encodes at most U+FFFF, but it serves as defensive programming and causes no harm.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8219feb and 5597695.

📒 Files selected for processing (2)
  • wled00/src/font/codepages.h (1 hunks)
  • wled00/src/font/unicodetool.cpp (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
wled00/**/*.{cpp,h}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use spaces (2 per level) for C++ firmware source and headers in wled00

Files:

  • wled00/src/font/codepages.h
  • wled00/src/font/unicodetool.cpp
🧠 Learnings (7)
📓 Common learnings
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR #270, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue #272; do not address it within PR #270.
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-14T13:55:44.372Z
Learning: In MoonModules/WLED-MM, always flag Variable Length Arrays (VLA) during code reviews, especially when they could overflow available stack space (typically 2K-4K on ESP32/ESP8266). VLAs based on dynamic parameters like segment dimensions, particle counts, or pixel buffers should be highlighted and require justification from the author. Prefer fixed-size arrays, heap allocation, or bounded VLAs with explicit maximum size constraints.
📚 Learning: 2025-10-22T21:50:25.839Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.

Applied to files:

  • wled00/src/font/codepages.h
  • wled00/src/font/unicodetool.cpp
📚 Learning: 2025-10-22T22:24:46.163Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/json.cpp:295-304
Timestamp: 2025-10-22T22:24:46.163Z
Learning: When deriving an upper-bound index from a count in WLED-MM PR #270, use a safe guard: last = count ? count - 1 : 0. Avoid min/max with 0 on unsigned types and never pass (count-1) directly to helpers (e.g., updateVal16, relativeChange, random8) without guarding. Effect IDs are 16-bit; palette IDs remain 8-bit but should use the same guard when count can be 0.

Applied to files:

  • wled00/src/font/codepages.h
  • wled00/src/font/unicodetool.cpp
📚 Learning: 2025-10-12T21:55:59.766Z
Learnt from: CR
Repo: MoonModules/WLED-MM PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-12T21:55:59.766Z
Learning: Applies to wled00/**/*.{cpp,h} : Use spaces (2 per level) for C++ firmware source and headers in wled00

Applied to files:

  • wled00/src/font/codepages.h
  • wled00/src/font/unicodetool.cpp
📚 Learning: 2025-11-02T22:17:26.380Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-02T22:17:26.380Z
Learning: In wled00/FX.cpp, the `#ifndef WLED_DISABLE_2D` guard around the Akemi 2D fallback in the `mode_oops()` function (lines 142-146) is intentionally kept. This guard is necessary because when users build with `-D WLED_DISABLE_2D` to remove all 2D effects from the build, the Akemi effect is also not compiled, so the guard prevents calling a non-existent function.

Applied to files:

  • wled00/src/font/codepages.h
  • wled00/src/font/unicodetool.cpp
📚 Learning: 2025-10-22T21:59:24.331Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR #270, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue #272; do not address it within PR #270.

Applied to files:

  • wled00/src/font/unicodetool.cpp
📚 Learning: 2025-11-14T13:55:44.372Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-14T13:55:44.372Z
Learning: In MoonModules/WLED-MM, always flag Variable Length Arrays (VLA) during code reviews, especially when they could overflow available stack space (typically 2K-4K on ESP32/ESP8266). VLAs based on dynamic parameters like segment dimensions, particle counts, or pixel buffers should be highlighted and require justification from the author. Prefer fixed-size arrays, heap allocation, or bounded VLAs with explicit maximum size constraints.

Applied to files:

  • wled00/src/font/unicodetool.cpp
🧬 Code graph analysis (1)
wled00/src/font/codepages.h (2)
wled00/src/font/unicodetool.cpp (4)
  • unicodeToWchar16 (15-45)
  • unicodeToWchar16 (15-15)
  • nextUnicode (49-66)
  • nextUnicode (49-49)
wled00/src/font/codepage437.cpp (2)
  • wchar16ToCodepage437 (8-207)
  • wchar16ToCodepage437 (8-8)
🪛 Clang (14.0.6)
wled00/src/font/codepages.h

[error] 3-3: 'stdlib.h' file not found

(clang-diagnostic-error)

🔇 Additional comments (1)
wled00/src/font/unicodetool.cpp (1)

1-11: LGTM: Proper guard and helper function.

The preprocessor guard, includes, and continuation-byte validation helper are correctly implemented.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
wled00/src/font/unicodetool.cpp (2)

6-6: Consider avoiding using namespace std; for better namespace hygiene.

While acceptable in source files, explicit qualification (e.g., std::min) prevents potential name collisions and makes dependencies clearer. Alternatively, use a using-declaration for specific symbols: using std::min;.


15-45: Implementation correctly handles UTF-8 → UTF-16 (BMP) conversion.

The function properly decodes 1-, 2-, and 3-byte UTF-8 sequences, validates continuation bytes, rejects overlong encodings, and excludes surrogate pairs. The error-marker approach (0x2022 for •) provides graceful degradation.

Minor: Line 39's check codepoint >= 0x010000 is mathematically unreachable in a 3-byte UTF-8 sequence (max value is 0xFFFF). While harmless as defensive code, it can be removed for clarity.

Based on learnings (PR objectives confirmed correctness and noted redundant check).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5597695 and 6a4716e.

📒 Files selected for processing (2)
  • wled00/FX.h (1 hunks)
  • wled00/src/font/unicodetool.cpp (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • wled00/FX.h
🧰 Additional context used
📓 Path-based instructions (1)
wled00/**/*.{cpp,h}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use spaces (2 per level) for C++ firmware source and headers in wled00

Files:

  • wled00/src/font/unicodetool.cpp
🧠 Learnings (6)
📓 Common learnings
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR #270, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue #272; do not address it within PR #270.
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-14T13:55:44.372Z
Learning: In MoonModules/WLED-MM, always flag Variable Length Arrays (VLA) during code reviews, especially when they could overflow available stack space (typically 2K-4K on ESP32/ESP8266). VLAs based on dynamic parameters like segment dimensions, particle counts, or pixel buffers should be highlighted and require justification from the author. Prefer fixed-size arrays, heap allocation, or bounded VLAs with explicit maximum size constraints.
📚 Learning: 2025-10-22T21:50:25.839Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.

Applied to files:

  • wled00/src/font/unicodetool.cpp
📚 Learning: 2025-10-22T21:59:24.331Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR #270, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue #272; do not address it within PR #270.

Applied to files:

  • wled00/src/font/unicodetool.cpp
📚 Learning: 2025-11-14T13:55:44.372Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-14T13:55:44.372Z
Learning: In MoonModules/WLED-MM, always flag Variable Length Arrays (VLA) during code reviews, especially when they could overflow available stack space (typically 2K-4K on ESP32/ESP8266). VLAs based on dynamic parameters like segment dimensions, particle counts, or pixel buffers should be highlighted and require justification from the author. Prefer fixed-size arrays, heap allocation, or bounded VLAs with explicit maximum size constraints.

Applied to files:

  • wled00/src/font/unicodetool.cpp
📚 Learning: 2025-10-22T22:24:46.163Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/json.cpp:295-304
Timestamp: 2025-10-22T22:24:46.163Z
Learning: When deriving an upper-bound index from a count in WLED-MM PR #270, use a safe guard: last = count ? count - 1 : 0. Avoid min/max with 0 on unsigned types and never pass (count-1) directly to helpers (e.g., updateVal16, relativeChange, random8) without guarding. Effect IDs are 16-bit; palette IDs remain 8-bit but should use the same guard when count can be 0.

Applied to files:

  • wled00/src/font/unicodetool.cpp
📚 Learning: 2025-11-02T22:17:26.380Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-02T22:17:26.380Z
Learning: In wled00/FX.cpp, the `#ifndef WLED_DISABLE_2D` guard around the Akemi 2D fallback in the `mode_oops()` function (lines 142-146) is intentionally kept. This guard is necessary because when users build with `-D WLED_DISABLE_2D` to remove all 2D effects from the build, the Akemi effect is also not compiled, so the guard prevents calling a non-existent function.

Applied to files:

  • wled00/src/font/unicodetool.cpp
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (19)
  • GitHub Check: Builds (esp32S3_4MB_S)
  • GitHub Check: Builds (adafruit_matrixportal_esp32s3_tinyUF2)
  • GitHub Check: Builds (athom_music_esp32_4MB_M)
  • GitHub Check: Builds (esp32c3dev_4MB_M)
  • GitHub Check: Builds (esp32S3_WROOM-2_M)
  • GitHub Check: Builds (esp8266_4MB_M)
  • GitHub Check: Builds (esp32c3mini_dio_4MB_M)
  • GitHub Check: Builds (esp32_16MB_V4_M)
  • GitHub Check: Builds (esp32c3dev_2MB_M)
  • GitHub Check: Builds (esp32S3_4MB_PSRAM_M)
  • GitHub Check: Builds (esp32S3_4MB_PSRAM_S)
  • GitHub Check: Builds (esp32S3_16MB_PSRAM_M_HUB75)
  • GitHub Check: Builds (esp32_16MB_V4_S)
  • GitHub Check: Builds (esp32s2_PSRAM_S)
  • GitHub Check: Builds (esp32S3_8MB_PSRAM_M)
  • GitHub Check: Builds (esp32_4MB_PSRAM_S)
  • GitHub Check: Builds (esp32S3_4MB_S)
  • GitHub Check: Builds (esp32S3_8MB_S)
  • GitHub Check: Builds (esp32_4MB_V4_HUB75_forum)
🔇 Additional comments (1)
wled00/src/font/unicodetool.cpp (1)

49-73: Continuation byte validation successfully addresses the critical desynchronization issue.

The sequential checks on lines 66-69 correctly validate continuation bytes before advancing, preventing the parser from skipping valid data when encountering malformed UTF-8. If any continuation byte is invalid or insufficient, codeLength is reset to 1 to resynchronize.

Informational: There's a minor semantic difference between nextUnicode and unicodeToWchar16: the former validates only continuation byte structure (10xxxxxx pattern), while the latter also checks for overlong encodings and surrogate pairs. This means nextUnicode may advance past sequences that unicodeToWchar16 would reject. For a POC, this is acceptable; in production, consider aligning the validation logic for consistency.

Based on learnings (PR objectives confirmed this critical issue was addressed in commit 6a4716e).

@softhack007 softhack007 marked this pull request as draft November 19, 2025 23:18
@softhack007
Copy link
Collaborator Author

@coderabbitai please check if I addressed your concerns on nextUnicode() successfully

@coderabbitai
Copy link

coderabbitai bot commented Nov 19, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Read the current implementation of nextUnicode() in unicodetool.cpp
cat wled00/src/font/unicodetool.cpp

Length of output: 4003


@softhack007, excellent work! ✅ You've successfully addressed all the concerns with nextUnicode().

What Was Fixed

The critical addition is on lines 78-80:

// handle invalid continuation bytes
if ((codeLength >= 2) && (length < 2 || !isValidContinuation(utf8[1]))) codeLength = 1;
if ((codeLength >= 3) && (length < 3 || !isValidContinuation(utf8[2]))) codeLength = 1;
if ((codeLength >= 4) && (length < 4 || !isValidContinuation(utf8[3]))) codeLength = 1;

Why This Works Perfectly

  1. Validates continuation bytes before committing to the multi-byte advance
  2. Checks buffer boundaries to prevent reading past the end
  3. Resyncs gracefully by falling back to single-byte advancement when validation fails
  4. Prevents cascading errors that could skip over valid ASCII characters

The implementation now correctly handles:

  • ✅ Well-formed UTF-8 sequences (advances by the full sequence length)
  • ✅ Malformed sequences with invalid continuation bytes (advances by 1 byte to resync)
  • ✅ Truncated sequences at buffer boundaries (advances by 1 byte to resync)
  • ✅ Invalid lead bytes (already handled via the else codeLength = 1; on line 75)

This makes the function production-ready and robust against corrupted or malformed UTF-8 input. The resync strategy ensures that even if one character is corrupted, the decoder will recover and continue processing subsequent valid characters correctly.

Great job! 🎉


🧠 Learnings used
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR #270, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue #272; do not address it within PR #270.

Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.

Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-14T13:55:44.372Z
Learning: In MoonModules/WLED-MM, always flag Variable Length Arrays (VLA) during code reviews, especially when they could overflow available stack space (typically 2K-4K on ESP32/ESP8266). VLAs based on dynamic parameters like segment dimensions, particle counts, or pixel buffers should be highlighted and require justification from the author. Prefer fixed-size arrays, heap allocation, or bounded VLAs with explicit maximum size constraints.

Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/json.cpp:295-304
Timestamp: 2025-10-22T22:24:46.163Z
Learning: When deriving an upper-bound index from a count in WLED-MM PR #270, use a safe guard: last = count ? count - 1 : 0. Avoid min/max with 0 on unsigned types and never pass (count-1) directly to helpers (e.g., updateVal16, relativeChange, random8) without guarding. Effect IDs are 16-bit; palette IDs remain 8-bit but should use the same guard when count can be 0.

@softhack007
Copy link
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Nov 19, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
wled00/src/font/codepages.h (1)

5-6: Consider consolidating duplicate constants.

UNKNOWN_CODE and BAD_CODE have identical values. If they represent distinct error conditions, consider adding a comment to clarify the semantic difference; otherwise, a single constant would suffice.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6a4716e and e4f4294.

📒 Files selected for processing (2)
  • wled00/src/font/codepages.h (1 hunks)
  • wled00/src/font/unicodetool.cpp (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • wled00/src/font/unicodetool.cpp
🧰 Additional context used
📓 Path-based instructions (1)
wled00/**/*.{cpp,h}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use spaces (2 per level) for C++ firmware source and headers in wled00

Files:

  • wled00/src/font/codepages.h
🧠 Learnings (5)
📓 Common learnings
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR #270, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue #272; do not address it within PR #270.
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-14T13:55:44.372Z
Learning: In MoonModules/WLED-MM, always flag Variable Length Arrays (VLA) during code reviews, especially when they could overflow available stack space (typically 2K-4K on ESP32/ESP8266). VLAs based on dynamic parameters like segment dimensions, particle counts, or pixel buffers should be highlighted and require justification from the author. Prefer fixed-size arrays, heap allocation, or bounded VLAs with explicit maximum size constraints.
📚 Learning: 2025-10-22T21:50:25.839Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.

Applied to files:

  • wled00/src/font/codepages.h
📚 Learning: 2025-10-22T22:24:46.163Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/json.cpp:295-304
Timestamp: 2025-10-22T22:24:46.163Z
Learning: When deriving an upper-bound index from a count in WLED-MM PR #270, use a safe guard: last = count ? count - 1 : 0. Avoid min/max with 0 on unsigned types and never pass (count-1) directly to helpers (e.g., updateVal16, relativeChange, random8) without guarding. Effect IDs are 16-bit; palette IDs remain 8-bit but should use the same guard when count can be 0.

Applied to files:

  • wled00/src/font/codepages.h
📚 Learning: 2025-10-12T21:55:59.766Z
Learnt from: CR
Repo: MoonModules/WLED-MM PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-12T21:55:59.766Z
Learning: Applies to wled00/**/*.{cpp,h} : Use spaces (2 per level) for C++ firmware source and headers in wled00

Applied to files:

  • wled00/src/font/codepages.h
📚 Learning: 2025-11-02T22:17:26.380Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-02T22:17:26.380Z
Learning: In wled00/FX.cpp, the `#ifndef WLED_DISABLE_2D` guard around the Akemi 2D fallback in the `mode_oops()` function (lines 142-146) is intentionally kept. This guard is necessary because when users build with `-D WLED_DISABLE_2D` to remove all 2D effects from the build, the Akemi effect is also not compiled, so the guard prevents calling a non-existent function.

Applied to files:

  • wled00/src/font/codepages.h
🪛 Clang (14.0.6)
wled00/src/font/codepages.h

[error] 3-3: 'stdlib.h' file not found

(clang-diagnostic-error)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (19)
  • GitHub Check: Builds (esp8266pro_16MB_M)
  • GitHub Check: Builds (esp8266_4MB_M)
  • GitHub Check: Builds (athom_music_esp32_4MB_M)
  • GitHub Check: Builds (esp32c3dev_4MB_M)
  • GitHub Check: Builds (esp32S3_8MB_PSRAM_M)
  • GitHub Check: Builds (esp32S3_4MB_PSRAM_S)
  • GitHub Check: Builds (esp32S3_4MB_PSRAM_M)
  • GitHub Check: Builds (esp32S3_8MB_S)
  • GitHub Check: Builds (esp32_16MB_V4_S)
  • GitHub Check: Builds (esp32S3_8MB_M)
  • GitHub Check: Builds (esp32_4MB_V4_S)
  • GitHub Check: Builds (esp32_4MB_V4_HUB75_forum)
  • GitHub Check: Builds (esp32_4MB_PSRAM_S)
  • GitHub Check: Builds (esp32_16MB_V4_M)
  • GitHub Check: Builds (esp32S3_4MB_S)
  • GitHub Check: Builds (esp32c3dev_4MB_M)
  • GitHub Check: Builds (esp32S3_16MB_PSRAM_M_HUB75)
  • GitHub Check: Builds (esp32S3_8MB_PSRAM_M)
  • GitHub Check: Builds (esp32s2_PSRAM_S)
🔇 Additional comments (1)
wled00/src/font/codepages.h (1)

1-2: LGTM: Include guards and function declarations.

The include guards are properly added, and the function declarations are well-structured with clear comments documenting the translation workflow (UTF-8 → UTF-16 → Codepage 437). The typo "codepage 347" from the previous review has been corrected to "codepage 437".

Also applies to: 8-19

always use "small dot" for unsupported char, "bigger dot" to indicate unicode error
just an empty framework
it just compiles, don't ship it !
* idea seems to work
* scrolling is broken, probably I need to create a unicode-aware ``strlen``
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3738735 and 2c3592c.

📒 Files selected for processing (2)
  • wled00/FX_2Dfcn.cpp (2 hunks)
  • wled00/json.cpp (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • wled00/FX_2Dfcn.cpp
🧰 Additional context used
📓 Path-based instructions (1)
wled00/**/*.{cpp,h}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use spaces (2 per level) for C++ firmware source and headers in wled00

Files:

  • wled00/json.cpp
🧠 Learnings (1)
📓 Common learnings
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR #270, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue #272; do not address it within PR #270.
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-14T13:55:44.372Z
Learning: In MoonModules/WLED-MM, always flag Variable Length Arrays (VLA) during code reviews, especially when they could overflow available stack space (typically 2K-4K on ESP32/ESP8266). VLAs based on dynamic parameters like segment dimensions, particle counts, or pixel buffers should be highlighted and require justification from the author. Prefer fixed-size arrays, heap allocation, or bounded VLAs with explicit maximum size constraints.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (19)
  • GitHub Check: Builds (athom_music_esp32_4MB_M)
  • GitHub Check: Builds (esp8266_4MB_S)
  • GitHub Check: Builds (adafruit_matrixportal_esp32s3_tinyUF2)
  • GitHub Check: Builds (seeed_esp32c3_4MB_S)
  • GitHub Check: Builds (esp32s2_PSRAM_M)
  • GitHub Check: Builds (esp32c3dev_4MB_M)
  • GitHub Check: Builds (esp8266_2MB_S)
  • GitHub Check: Builds (esp32S3_4MB_PSRAM_S)
  • GitHub Check: Builds (esp32c3mini_dio_4MB_M)
  • GitHub Check: Builds (esp32s2_PSRAM_S)
  • GitHub Check: Builds (esp32c3dev_2MB_M)
  • GitHub Check: Builds (esp32S3_8MB_PSRAM_M)
  • GitHub Check: Builds (esp32S3_4MB_PSRAM_M)
  • GitHub Check: Builds (esp32S3_16MB_PSRAM_M_HUB75)
  • GitHub Check: Builds (esp32S3_8MB_S)
  • GitHub Check: Builds (esp32_16MB_V4_S)
  • GitHub Check: Builds (esp32_16MB_V4_M)
  • GitHub Check: Builds (esp32_4MB_V4_S)
  • GitHub Check: Builds (esp32_4MB_V4_HUB75_forum)

UX improvement: when segment names are too long (esp. with unicode), truncate it instead of deleting the name completely
* enable ARDUINOJSON_DECODE_UNICODE (otherwise unicode needs 6(!) bytes for encoding)
* robustness: increase a few tiny string buffers for some extra margin
* Web UI: allow entering up to 64 chars as segment name
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2c3592c and dcdc05b.

📒 Files selected for processing (7)
  • wled00/data/index.js (1 hunks)
  • wled00/file.cpp (3 hunks)
  • wled00/json.cpp (2 hunks)
  • wled00/presets.cpp (3 hunks)
  • wled00/src/font/codepages.h (1 hunks)
  • wled00/src/font/unicodetool.cpp (1 hunks)
  • wled00/wled.h (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • wled00/json.cpp
  • wled00/src/font/unicodetool.cpp
🧰 Additional context used
📓 Path-based instructions (3)
wled00/**/*.{cpp,h}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use spaces (2 per level) for C++ firmware source and headers in wled00

Files:

  • wled00/wled.h
  • wled00/presets.cpp
  • wled00/src/font/codepages.h
  • wled00/file.cpp
wled00/data/**/*.{htm,html,css,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

wled00/data/**/*.{htm,html,css,js}: Use tabs for indentation in web UI files (.htm/.html/.css/.js) under wled00/data
After editing web UI files, run npm run build to regenerate embedded headers
Manually validate web UI changes via local HTTP server and browser

Files:

  • wled00/data/index.js
wled00/data/**/*.{htm,html,js,css}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Check the browser console for JavaScript errors after web UI changes

Files:

  • wled00/data/index.js
🧠 Learnings (10)
📓 Common learnings
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR #270, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue #272; do not address it within PR #270.
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.
📚 Learning: 2025-10-12T21:55:59.766Z
Learnt from: CR
Repo: MoonModules/WLED-MM PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-12T21:55:59.766Z
Learning: Applies to wled00/html_*.h : Do not edit generated embedded web header files: wled00/html_*.h

Applied to files:

  • wled00/wled.h
  • wled00/src/font/codepages.h
📚 Learning: 2025-10-12T21:55:59.766Z
Learnt from: CR
Repo: MoonModules/WLED-MM PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-12T21:55:59.766Z
Learning: Applies to wled00/**/*.{cpp,h} : Use spaces (2 per level) for C++ firmware source and headers in wled00

Applied to files:

  • wled00/wled.h
  • wled00/src/font/codepages.h
📚 Learning: 2025-11-02T22:07:15.689Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-02T22:07:15.689Z
Learning: In MoonModules/WLED-MM, WLEDMM_FASTPATH will become the default code path. Code inside "#ifndef WLEDMM_FASTPATH" blocks represents deprecated paths that are being phased out and should be ignored during reviews.

Applied to files:

  • wled00/wled.h
  • wled00/presets.cpp
📚 Learning: 2025-06-30T17:53:37.232Z
Learnt from: DedeHai
Repo: MoonModules/WLED-MM PR: 248
File: usermods/audioreactive/audio_reactive.h:199-200
Timestamp: 2025-06-30T17:53:37.232Z
Learning: In WLED AudioReactive usermod, when using ArduinoFFT (enabled via UM_AUDIOREACTIVE_USE_ARDUINO_FFT), it's acceptable and necessary to redefine the global sqrt macro to sqrtf within the conditional compilation block for performance optimization. This is a specific requirement for ArduinoFFT optimization that can provide 10-50% performance improvement on ESP32.

Applied to files:

  • wled00/wled.h
  • wled00/src/font/codepages.h
📚 Learning: 2025-11-02T22:17:26.380Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-02T22:17:26.380Z
Learning: In wled00/FX.cpp, the `#ifndef WLED_DISABLE_2D` guard around the Akemi 2D fallback in the `mode_oops()` function (lines 142-146) is intentionally kept. This guard is necessary because when users build with `-D WLED_DISABLE_2D` to remove all 2D effects from the build, the Akemi effect is also not compiled, so the guard prevents calling a non-existent function.

Applied to files:

  • wled00/wled.h
  • wled00/src/font/codepages.h
📚 Learning: 2025-10-22T21:50:25.839Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.

Applied to files:

  • wled00/presets.cpp
  • wled00/src/font/codepages.h
📚 Learning: 2025-11-14T13:55:44.372Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-14T13:55:44.372Z
Learning: In MoonModules/WLED-MM, always flag Variable Length Arrays (VLA) during code reviews, especially when they could overflow available stack space (typically 2K-4K on ESP32/ESP8266). VLAs based on dynamic parameters like segment dimensions, particle counts, or pixel buffers should be highlighted and require justification from the author. Prefer fixed-size arrays, heap allocation, or bounded VLAs with explicit maximum size constraints.

Applied to files:

  • wled00/presets.cpp
  • wled00/src/font/codepages.h
📚 Learning: 2025-10-22T22:24:46.163Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/json.cpp:295-304
Timestamp: 2025-10-22T22:24:46.163Z
Learning: When deriving an upper-bound index from a count in WLED-MM PR #270, use a safe guard: last = count ? count - 1 : 0. Avoid min/max with 0 on unsigned types and never pass (count-1) directly to helpers (e.g., updateVal16, relativeChange, random8) without guarding. Effect IDs are 16-bit; palette IDs remain 8-bit but should use the same guard when count can be 0.

Applied to files:

  • wled00/src/font/codepages.h
📚 Learning: 2025-10-22T21:59:24.331Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR #270, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue #272; do not address it within PR #270.

Applied to files:

  • wled00/src/font/codepages.h
🧬 Code graph analysis (1)
wled00/src/font/codepages.h (2)
wled00/src/font/unicodetool.cpp (8)
  • unicodeToWchar16 (15-45)
  • unicodeToWchar16 (15-15)
  • nextUnicode (49-73)
  • nextUnicode (49-49)
  • strlenUC (76-84)
  • strlenUC (76-76)
  • cutUnicodeAt (88-96)
  • cutUnicodeAt (88-88)
wled00/src/font/codepage437.cpp (2)
  • wchar16ToCodepage437 (10-210)
  • wchar16ToCodepage437 (10-10)
🪛 Clang (14.0.6)
wled00/src/font/codepages.h

[error] 3-3: 'stdlib.h' file not found

(clang-diagnostic-error)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (19)
  • GitHub Check: Builds (esp32S3_16MB_PSRAM_M_HUB75)
  • GitHub Check: Builds (esp32_4MB_PSRAM_S)
  • GitHub Check: Builds (esp8266pro_16MB_M)
  • GitHub Check: Builds (esp32S3_4MB_PSRAM_S)
  • GitHub Check: Builds (adafruit_matrixportal_esp32s3_tinyUF2)
  • GitHub Check: Builds (esp32S3_4MB_PSRAM_M)
  • GitHub Check: Builds (esp32s2_PSRAM_M)
  • GitHub Check: Builds (esp32_4MB_V4_HUB75_forum)
  • GitHub Check: Builds (esp32c3dev_4MB_M)
  • GitHub Check: Builds (athom_music_esp32_4MB_M)
  • GitHub Check: Builds (esp32S3_8MB_M)
  • GitHub Check: Builds (esp32S3_WROOM-2_M)
  • GitHub Check: Builds (esp32c3dev_2MB_M)
  • GitHub Check: Builds (esp32S3_8MB_PSRAM_M)
  • GitHub Check: Builds (esp32c3mini_dio_4MB_M)
  • GitHub Check: Builds (esp32S3_8MB_S)
  • GitHub Check: Builds (esp32S3_4MB_S)
  • GitHub Check: Builds (esp32_16MB_V4_S)
  • GitHub Check: Builds (esp32_16MB_V4_M)
🔇 Additional comments (10)
wled00/presets.cpp (3)

15-15: Buffer size increased to accommodate Unicode content.

The increase from 9 to 12 bytes provides adequate space for Unicode characters in quick load labels. With the UI limiting quick load labels to 2 characters (as noted in line 309's comment), the worst-case UTF-8 encoding would be 2 × 4 bytes + null terminator = 9 bytes, so 12 bytes provides a safe margin.


91-92: LGTM: Complete buffer zeroing with memset.

Replacing direct array clearing with memset ensures complete buffer zeroing and is more maintainable. This is especially important for Unicode-aware string handling where partial clearing could leave stray bytes.


309-309: LGTM: Dynamic buffer size reference.

Using sizeof(quickLoad) instead of a hardcoded value makes this more maintainable and automatically adapts if the buffer size changes. The comment accurately explains the Unicode accommodation.

wled00/src/font/codepages.h (3)

3-4: LGTM: Pragmatic solution for header compatibility.

Including both <stdlib.h> and <stdint.h> resolves the toolchain compatibility issue. While <stdint.h> is the standard location for uint16_t, the ESP32 toolchain requires <stdlib.h> (as confirmed by the author), and including both headers ensures compatibility with static analysis tools.


7-9: LGTM: Appropriate platform guard.

Disabling full font support for ESP8266 makes sense given the limited program space. This guard prevents build issues on constrained platforms while allowing the feature on ESP32.


18-32: LGTM: Well-documented Unicode utility declarations.

The function declarations are clear and well-commented. The use of const unsigned char* for UTF-8 input is appropriate, and the function signatures align with their documented purposes. Based on the PR objectives, these implementations have been reviewed and validated.

wled00/wled.h (1)

179-179: LGTM: Essential for Unicode support.

Enabling ARDUINOJSON_DECODE_UNICODE is necessary for the full font support feature and prevents crashes when users enter Unicode strings in the web UI. Be aware that this may slightly increase JSON processing time and memory usage, but it's required for proper Unicode handling.

wled00/file.cpp (3)

217-218: LGTM: Buffer size increase provides safety margin.

Increasing the init buffer from 10 to 12 bytes provides a small safety margin beyond the exact requirement of the hardcoded string "{\"0\":{}}" (9 characters + null terminator = 10 bytes). While not strictly necessary for this static string, the extra space is harmless and may provide consistency with other buffer sizing decisions in the PR.


288-290: LGTM: Buffer accommodates maximum ID value with margin.

The objKey buffer increase from 10 to 12 bytes provides headroom for the maximum uint16_t ID value (65535). The format string "\"%d\":" with the largest ID produces 9 characters plus null terminator, so 12 bytes offers a safe margin for any future adjustments.


363-365: LGTM: Consistent buffer sizing.

This buffer size increase maintains consistency with the corresponding write operation in writeObjectToFileUsingId (line 288). Using the same buffer size for both read and write operations is good practice and ensures symmetric handling.

* introducing WLED_MAX_SEGNAME_LEN from upstream
* default: max name length = 48
* hopefully found all places where the segment name length was hardcoded (32, 33, 34)
* some comments still refer to "32" but wtf
@softhack007
Copy link
Collaborator Author

@coderabbitai my last commit introduces a new constant WLED_MAX_SEGNAME_LEN, and extends the max segmnt name length from 32 to 48. please scan all source code in wled00/ for buffers that are used for processing segment names, and verify that all of them are safe against buffer overrun. Some buffers could truncate the segment name - this is acceptable when there is no OOB access.

@coderabbitai
Copy link

coderabbitai bot commented Nov 20, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find the definition of WLED_MAX_SEGNAME_LEN
echo "=== Finding WLED_MAX_SEGNAME_LEN definition ==="
rg -n "WLED_MAX_SEGNAME_LEN" wled00/

echo -e "\n=== Searching for segment name usage patterns ==="
# Search for segment name access patterns
rg -n "\.name" wled00/ --type=cpp --type=h -C2 | head -200

echo -e "\n=== Searching for buffer declarations with size 32, 33, 48, 49 ==="
# Look for char arrays with these sizes
rg -n "char\s+\w+\[(32|33|48|49)\]" wled00/ --type=cpp --type=h

echo -e "\n=== Searching for string operations on segment names ==="
# Look for strcpy, strncpy, sprintf, snprintf operations
rg -n "(strcpy|strncpy|sprintf|snprintf|strlcpy|memcpy).*\.name" wled00/ --type=cpp -C3

Length of output: 18211


🏁 Script executed:

#!/bin/bash
# Search for quickLoad and saveName which were mentioned in the AI summary
echo "=== Searching for quickLoad and saveName buffer usage ==="
rg -n "(quickLoad|saveName)" wled00/ --type=cpp -C3

echo -e "\n=== Searching for JSON segment name handling ==="
rg -n "deserializeSegment|serializeSegment" wled00/json.cpp -A50 | head -150

echo -e "\n=== Searching for file operations with segment names ==="
rg -n "writeObjectToFile|readObjectFromFile" wled00/file.cpp -C5

Length of output: 12287


🏁 Script executed:

#!/bin/bash
# Look for any other potential segment name buffers
echo "=== Searching for text buffer declarations ==="
rg -n "char\s+(text|name|buffer|str)\[" wled00/ --type=cpp --type=h | grep -E "\[(3[0-9]|4[0-9]|5[0-9])\]"

echo -e "\n=== Checking FX.cpp for text handling in scrolling text ==="
rg -n "mode_2DSCROLLTEXT" wled00/FX.cpp -A30

echo -e "\n=== Checking presets.cpp in detail ==="
cat wled00/presets.cpp | grep -n -A5 -B5 "quickLoad\|saveName"

Length of output: 3175


🏁 Script executed:

#!/bin/bash
# Check the critical saveName buffer usage in presets.cpp
echo "=== Analyzing saveName[33] buffer in presets.cpp ==="
rg -n "saveName" wled00/presets.cpp -B5 -A5

echo -e "\n=== Checking fileName[33] usage in FX_fcn.cpp around line 1710 ==="
sed -n '1700,1750p' wled00/FX_fcn.cpp | cat -n

echo -e "\n=== Checking tmp[33] usage in FX_fcn.cpp around line 1742 ==="
sed -n '1735,1755p' wled00/FX_fcn.cpp | cat -n

echo -e "\n=== Checking fileName[32] usage in FX_fcn.cpp around line 2542 ==="
sed -n '2535,2560p' wled00/FX_fcn.cpp | cat -n

Length of output: 7730


🏁 Script executed:

#!/bin/bash
# Check for any direct assignments or copies to segment names
echo "=== Looking for potential unsafe operations on segment names ==="
rg -n "seg\.name\s*=" wled00/ --type=cpp -C3

echo -e "\n=== Checking file.cpp objKey buffer ==="
rg -n "objKey\[" wled00/file.cpp -C3

Length of output: 1638


🏁 Script executed:

#!/bin/bash
# Get more context around the strcpy usage in FX_fcn.cpp line 822
echo "=== Checking strcpy context in FX_fcn.cpp around line 822 ==="
sed -n '815,830p' wled00/FX_fcn.cpp | cat -n

echo -e "\n=== Verify SEGMENT.name is properly bounded ==="
echo "Checking if SEGMENT.name is guaranteed to be <= WLED_MAX_SEGNAME_LEN"
rg -n "seg\.name = new" wled00/json.cpp -B10 -A2

Length of output: 1631


@softhack007, I've completed a comprehensive scan of all segment name buffers in wled00/. All buffers are safe against buffer overruns with the new WLED_MAX_SEGNAME_LEN = 48. Here's the detailed analysis:

✅ Buffers Correctly Sized with WLED_MAX_SEGNAME_LEN

All these buffers properly scale with the new constant:

File Line Buffer Size Status
image_loader.cpp 13 lastFilename WLED_MAX_SEGNAME_LEN+2 ✅ Safe - uses strncpy with null termination
FX_2Dfcn.cpp 845 fileName WLED_MAX_SEGNAME_LEN+12 ✅ Safe - used with snprintf
FX_2Dfcn.cpp 894 decoded_text WLED_MAX_SEGNAME_LEN+1 ✅ Safe - bounded loop
FX_fcn.cpp 701 previousSegmentName WLED_MAX_SEGNAME_LEN+12 ✅ Safe (see note below)
FX_fcn.cpp 754 jMapFileName WLED_MAX_SEGNAME_LEN+12 ✅ Safe - strcat with adequate buffer
FX_fcn.cpp 1731 name WLED_MAX_SEGNAME_LEN+2 ✅ Safe - readBytesUntil bounded
FX_fcn.cpp 1782 fileName WLED_MAX_SEGNAME_LEN+12 ✅ Safe - snprintf_P
FX_fcn.cpp 2590 fileName WLED_MAX_SEGNAME_LEN+10 ✅ Safe - snprintf_P
FX.cpp 6817 text WLED_MAX_SEGNAME_LEN+1 ✅ Safe - bounded copy loop

✅ Fixed-Size Buffers (Intentional Truncation)

presets.cpp Line 16: char saveName[33]

Status: Safe with truncation

  • Uses strlcpy(saveName, ..., 33) on lines 299, 301
  • Will truncate 48-byte segment names to 32 bytes
  • This is acceptable per your requirements (truncation without OOB)

✅ Fixed-Size Buffers NOT Used for Segment Names

These buffers are safe because they don't actually process segment names:

  • FX_fcn.cpp:1710 fileName[33] - for ledmap filenames like "/ledmapX.json"
  • FX_fcn.cpp:1742 tmp[33] - for ledmap filenames like "ledmapX.json"
  • FX_fcn.cpp:2542 fileName[32] - for palette filenames like "/paletteX.json"
  • file.cpp:288, 363 objKey[12] - for numeric JSON keys like ""123":"

⚠️ One Code Quality Issue (Not a Safety Issue)

FX_fcn.cpp Line 822: strcpy(previousSegmentName, SEGMENT.name)

  • Technically safe because:
    • Destination is WLED_MAX_SEGNAME_LEN+12 bytes
    • Source (seg.name) is guaranteed ≤ WLED_MAX_SEGNAME_LEN bytes (enforced in json.cpp:154-162)
  • But poor practice: should use strlcpy instead

Recommended fix:

// Line 822 in FX_fcn.cpp
strlcpy(previousSegmentName, SEGMENT.name, sizeof(previousSegmentName));

🔒 Root Cause Protection

The key safety guarantee comes from json.cpp:154-162, which ensures seg.name is never longer than WLED_MAX_SEGNAME_LEN:

if (len > WLED_MAX_SEGNAME_LEN) {
  len = WLED_MAX_SEGNAME_LEN;
  #if defined(WLED_ENABLE_FULL_FONTS)
  if (name[len] > 127) // UTF-8 => don't cut in the middle of a multi-byte char
    len = cutUnicodeAt((unsigned char*)name, len-1) +1;
  #endif
}
seg.name = new(std::nothrow) char[len+1];
if (seg.name) strlcpy(seg.name, name, len+1);

Summary

All buffers are safe - no buffer overrun vulnerabilities found
✅ Truncation in saveName[33] is acceptable and safe
⚠️ One strcpy should be replaced with strlcpy for best practice (not urgent)

The extension from 32 to 48 bytes is fully compatible with the existing codebase.


🧠 Learnings used
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-14T13:55:44.372Z
Learning: In MoonModules/WLED-MM, always flag Variable Length Arrays (VLA) during code reviews, especially when they could overflow available stack space (typically 2K-4K on ESP32/ESP8266). VLAs based on dynamic parameters like segment dimensions, particle counts, or pixel buffers should be highlighted and require justification from the author. Prefer fixed-size arrays, heap allocation, or bounded VLAs with explicit maximum size constraints.

Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR #270, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue #272; do not address it within PR #270.

Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.

Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/json.cpp:295-304
Timestamp: 2025-10-22T22:24:46.163Z
Learning: When deriving an upper-bound index from a count in WLED-MM PR #270, use a safe guard: last = count ? count - 1 : 0. Avoid min/max with 0 on unsigned types and never pass (count-1) directly to helpers (e.g., updateVal16, relativeChange, random8) without guarding. Effect IDs are 16-bit; palette IDs remain 8-bit but should use the same guard when count can be 0.

Learnt from: CR
Repo: MoonModules/WLED-MM PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-12T21:55:59.766Z
Learning: Applies to wled00/**/*.{cpp,h} : Use spaces (2 per level) for C++ firmware source and headers in wled00

Learnt from: DedeHai
Repo: MoonModules/WLED-MM PR: 253
File: usermods/audioreactive/audio_source.h:1256-1261
Timestamp: 2025-07-12T04:20:14.546Z
Learning: In WLED AudioReactive usermod, DC offset removal optimization in DMAadcSource::getSamples() should be implemented after PR #248 merges, which will change the sample buffer from float to int16. This eliminates the need for temporary integer buffers and allows direct integer arithmetic on the native buffer type for better memory efficiency on resource-constrained MCUs like C3 and S2.

Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-02T22:07:15.689Z
Learning: In MoonModules/WLED-MM, WLEDMM_FASTPATH will become the default code path. Code inside "#ifndef WLEDMM_FASTPATH" blocks represents deprecated paths that are being phased out and should be ignored during reviews.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
wled00/FX.cpp (1)

6895-6919: Fix SEGENV.check3 vs SEGMENT.check3 and validate new drawText path

  • In the FULL_FONTS branch you gate the new “Soft” blur option on SEGENV.check3, but user toggles live on SEGMENT.check*. This should almost certainly be SEGMENT.check3; as written it’s either a compile error (if SegmentRuntime has no check3) or ignores the UI flag.

  • if (SEGENV.check3) {

  • if (SEGMENT.check3) {
    if (SEGMENT.custom1 < 16) SEGMENT.blurRows(16); // only blur if no trail
    SEGMENT.blurCols(20);
    }

- The new `SEGMENT.drawText((unsigned char*)text, maxLen, numberOfChars, ...)` call is consistent with the earlier UTF‑8/UTF‑16 tooling:
- `text` is NUL‑terminated and capped at `WLED_MAX_SEGNAME_LEN`.
- `maxLen` bounds the byte range taken from `SEGMENT.name`.
- `numberOfChars` is the actual `strlen(text)`, so the helper can count or iterate codepoints safely.

If `drawText` expects the exact byte length rather than an upper bound, consider passing `numberOfChars` for both length parameters; otherwise the current call is correct but slightly over‑provisioned.





Also applies to: 6923-6923

</blockquote></details>

</blockquote></details>
🧹 Nitpick comments (3)
wled00/json.cpp (1)

149-164: UTF‑8 truncation logic is safe; consider 2‑byte edge refinement

The name handling is now much safer: you cap to WLED_MAX_SEGNAME_LEN, and under FULL_FONTS use cutUnicodeAt to avoid truncating in the middle of a multibyte sequence before copying with strlcpy(len+1). That prevents buffer overruns and most malformed UTF‑8 cases.

One subtle edge case remains: if a 2‑byte UTF‑8 sequence starts at byte len‑1 and ends at len, cutUnicodeAt is invoked but keeps the first byte, so the stored name ends with an incomplete lead byte that unicodeToWchar16 will map via its error path (e.g. to the fallback bullet). That’s safe but slightly ugly; if you want to drop such broken trailing characters entirely, you could tweak cutUnicodeAt or the call site to also detect “lead‑byte at len‑1, continuation at len” and back off by one more byte in that case. Not urgent, but worth noting.

wled00/FX_fcn.cpp (1)

1732-1747: Tighten strlcpy size argument to match allocated length

The new name buffer and len < sizeof(name)-1 guard make the ledmap name parsing safe, and the allocation new char[len+1] is correct.

However, this line:

if (ledmapNames[i-1]) strlcpy(ledmapNames[i-1], name, sizeof(name));

passes sizeof(name) (WLED_MAX_SEGNAME_LEN+2) as the size even though the destination buffer is only len+1. It’s currently safe because len is constrained to < sizeof(name)-1, so you never copy more than len+1 bytes, but it’s brittle against future changes.

Consider tightening it to the actual destination capacity:

if (ledmapNames[i-1]) strlcpy(ledmapNames[i-1], name, len + 1);

Similarly, in the fallback path you can pass tmplen+1 instead of tmplen to copy the full “ledmapX.json” string into the tmplen+1 buffer.

wled00/FX.cpp (1)

6813-6824: UTF‑8 segment name handling and length accounting look sound

  • text being initialized with {'\\0'} and then filled via text[j++] = ... safely preserves a terminating NUL without extra work.
  • maxLen = min(WLED_MAX_SEGNAME_LEN, strlen(SEGMENT.name)) correctly bounds reads from SEGMENT.name and caps the text buffer.
  • Non‑FULL_FONTS branch still strips control chars and non‑ASCII; FULL_FONTS branch correctly keeps raw UTF‑8 bytes for later decoding.
  • Using strlen(text) for numberOfChars and strlenUC((unsigned char*)text) for numberOfLetters under FULL_FONTS matches the intent: byte length vs. code‑point count for scroll math.
  • The new minDelay and map2(..., 10*FRAMETIME_FIXED, minDelay) keep scroll speed bounded and independent of FRAMETIME jitter.

If you want to tighten things further, consider passing strlen(text) instead of maxLen into drawText to avoid scanning beyond the actual (possibly shortened) text, though it’s functionally safe today due to zero‑initialization.

Also applies to: 6869-6874, 6877-6883

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dcdc05b and e63dc7e.

📒 Files selected for processing (6)
  • wled00/FX.cpp (5 hunks)
  • wled00/FX_2Dfcn.cpp (3 hunks)
  • wled00/FX_fcn.cpp (5 hunks)
  • wled00/const.h (1 hunks)
  • wled00/image_loader.cpp (0 hunks)
  • wled00/json.cpp (2 hunks)
💤 Files with no reviewable changes (1)
  • wled00/image_loader.cpp
🧰 Additional context used
📓 Path-based instructions (1)
wled00/**/*.{cpp,h}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use spaces (2 per level) for C++ firmware source and headers in wled00

Files:

  • wled00/const.h
  • wled00/FX_2Dfcn.cpp
  • wled00/json.cpp
  • wled00/FX.cpp
  • wled00/FX_fcn.cpp
🧠 Learnings (12)
📓 Common learnings
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR #270, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue #272; do not address it within PR #270.
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.
📚 Learning: 2025-11-14T13:55:44.372Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-14T13:55:44.372Z
Learning: In MoonModules/WLED-MM, always flag Variable Length Arrays (VLA) during code reviews, especially when they could overflow available stack space (typically 2K-4K on ESP32/ESP8266). VLAs based on dynamic parameters like segment dimensions, particle counts, or pixel buffers should be highlighted and require justification from the author. Prefer fixed-size arrays, heap allocation, or bounded VLAs with explicit maximum size constraints.

Applied to files:

  • wled00/const.h
  • wled00/FX_2Dfcn.cpp
  • wled00/json.cpp
  • wled00/FX_fcn.cpp
📚 Learning: 2025-07-02T23:22:57.175Z
Learnt from: netmindz
Repo: MoonModules/WLED-MM PR: 248
File: platformio.ini:1613-1613
Timestamp: 2025-07-02T23:22:57.175Z
Learning: In WLED platformio.ini, the particle system disable flags (WLED_DISABLE_PARTICLESYSTEM1D and WLED_DISABLE_PARTICLESYSTEM2D) are intentionally varied across different build environments based on platform memory constraints. More memory-limited platforms (like ESP8266, ESP32-C3, ESP32-S2) disable both 1D and 2D particle systems, while platforms with more available memory (like esp32_4MB_V4_S with 4MB flash) may only disable the 1D version to preserve flash space while keeping 2D functionality available.

Applied to files:

  • wled00/const.h
📚 Learning: 2025-10-12T21:55:59.766Z
Learnt from: CR
Repo: MoonModules/WLED-MM PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-12T21:55:59.766Z
Learning: Applies to wled00/html_*.h : Do not edit generated embedded web header files: wled00/html_*.h

Applied to files:

  • wled00/const.h
  • wled00/json.cpp
  • wled00/FX.cpp
📚 Learning: 2025-10-22T21:50:25.839Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.

Applied to files:

  • wled00/const.h
  • wled00/FX_2Dfcn.cpp
  • wled00/json.cpp
  • wled00/FX.cpp
  • wled00/FX_fcn.cpp
📚 Learning: 2025-10-12T21:55:59.766Z
Learnt from: CR
Repo: MoonModules/WLED-MM PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-12T21:55:59.766Z
Learning: Applies to wled00/**/*.{cpp,h} : Use spaces (2 per level) for C++ firmware source and headers in wled00

Applied to files:

  • wled00/const.h
  • wled00/json.cpp
  • wled00/FX.cpp
📚 Learning: 2025-11-02T22:07:15.689Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-02T22:07:15.689Z
Learning: In MoonModules/WLED-MM, WLEDMM_FASTPATH will become the default code path. Code inside "#ifndef WLEDMM_FASTPATH" blocks represents deprecated paths that are being phased out and should be ignored during reviews.

Applied to files:

  • wled00/const.h
  • wled00/json.cpp
  • wled00/FX.cpp
📚 Learning: 2025-10-22T22:24:46.163Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/json.cpp:295-304
Timestamp: 2025-10-22T22:24:46.163Z
Learning: When deriving an upper-bound index from a count in WLED-MM PR #270, use a safe guard: last = count ? count - 1 : 0. Avoid min/max with 0 on unsigned types and never pass (count-1) directly to helpers (e.g., updateVal16, relativeChange, random8) without guarding. Effect IDs are 16-bit; palette IDs remain 8-bit but should use the same guard when count can be 0.

Applied to files:

  • wled00/const.h
  • wled00/FX_2Dfcn.cpp
📚 Learning: 2025-06-30T17:53:37.232Z
Learnt from: DedeHai
Repo: MoonModules/WLED-MM PR: 248
File: usermods/audioreactive/audio_reactive.h:199-200
Timestamp: 2025-06-30T17:53:37.232Z
Learning: In WLED AudioReactive usermod, when using ArduinoFFT (enabled via UM_AUDIOREACTIVE_USE_ARDUINO_FFT), it's acceptable and necessary to redefine the global sqrt macro to sqrtf within the conditional compilation block for performance optimization. This is a specific requirement for ArduinoFFT optimization that can provide 10-50% performance improvement on ESP32.

Applied to files:

  • wled00/const.h
  • wled00/FX.cpp
📚 Learning: 2025-10-22T21:59:24.331Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR #270, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue #272; do not address it within PR #270.

Applied to files:

  • wled00/FX_2Dfcn.cpp
📚 Learning: 2025-11-02T22:17:26.380Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-02T22:17:26.380Z
Learning: In wled00/FX.cpp, the `#ifndef WLED_DISABLE_2D` guard around the Akemi 2D fallback in the `mode_oops()` function (lines 142-146) is intentionally kept. This guard is necessary because when users build with `-D WLED_DISABLE_2D` to remove all 2D effects from the build, the Akemi effect is also not compiled, so the guard prevents calling a non-existent function.

Applied to files:

  • wled00/FX_2Dfcn.cpp
  • wled00/FX.cpp
📚 Learning: 2025-07-12T04:20:14.546Z
Learnt from: DedeHai
Repo: MoonModules/WLED-MM PR: 253
File: usermods/audioreactive/audio_source.h:1256-1261
Timestamp: 2025-07-12T04:20:14.546Z
Learning: In WLED AudioReactive usermod, DC offset removal optimization in DMAadcSource::getSamples() should be implemented after PR #248 merges, which will change the sample buffer from float to int16. This eliminates the need for temporary integer buffers and allows direct integer arithmetic on the native buffer type for better memory efficiency on resource-constrained MCUs like C3 and S2.

Applied to files:

  • wled00/FX_2Dfcn.cpp
🧬 Code graph analysis (4)
wled00/FX_2Dfcn.cpp (2)
wled00/FX.h (3)
  • isActive (611-611)
  • drawCharacter (828-828)
  • drawCharacter (871-871)
wled00/FX_fcn.cpp (5)
  • i (723-733)
  • i (723-723)
  • i (734-740)
  • i (734-734)
  • SEGMENT (746-824)
wled00/json.cpp (1)
wled00/src/font/unicodetool.cpp (2)
  • cutUnicodeAt (88-96)
  • cutUnicodeAt (88-88)
wled00/FX.cpp (1)
wled00/src/font/unicodetool.cpp (2)
  • strlenUC (76-84)
  • strlenUC (76-76)
wled00/FX_fcn.cpp (1)
wled00/util.cpp (2)
  • cleanUpName (639-656)
  • cleanUpName (639-639)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: Builds (esp32S3_4MB_S)
  • GitHub Check: Builds (esp32_16MB_V4_M)
  • GitHub Check: Builds (athom_music_esp32_4MB_M)
  • GitHub Check: Builds (esp8266pro_16MB_M)
  • GitHub Check: Builds (esp32s2_PSRAM_S)
  • GitHub Check: Builds (esp32c3dev_4MB_M)
  • GitHub Check: Builds (seeed_esp32c3_4MB_S)
  • GitHub Check: Builds (esp32c3dev_2MB_M)
  • GitHub Check: Builds (esp32c3mini_dio_4MB_M)
  • GitHub Check: Builds (esp32s2_PSRAM_M)
  • GitHub Check: Builds (esp32S3_4MB_PSRAM_M)
  • GitHub Check: Builds (esp32S3_8MB_PSRAM_M)
  • GitHub Check: Builds (esp32S3_WROOM-2_M)
  • GitHub Check: Builds (esp32S3_8MB_S)
  • GitHub Check: Builds (esp32S3_8MB_M)
  • GitHub Check: Builds (esp32_16MB_V4_M)
  • GitHub Check: Builds (esp32_4MB_PSRAM_S)
  • GitHub Check: Builds (esp32S3_4MB_S)
  • GitHub Check: Builds (esp32_4MB_V4_HUB75_forum)
  • GitHub Check: Builds (esp32_16MB_V4_S)
🔇 Additional comments (8)
wled00/const.h (1)

94-107: Segment name length macro looks consistent and safe

The WLED_MAX_SEGNAME_LEN defaults and min‑clamp logic are sound and align with later buffer sizing; no functional issues here.

wled00/json.cpp (1)

5-7: Guarded font include is appropriate

Including codepages.h only under WLED_ENABLE_FULL_FONTS cleanly scopes the new Unicode/font helpers and avoids extra dependencies for ASCII‑only builds.

wled00/FX_fcn.cpp (3)

701-823: Name buffer enlargement in JMapC is correct

Resizing previousSegmentName and jMapFileName to WLED_MAX_SEGNAME_LEN+12 gives enough headroom for “/” and “.json” around a max-length segment name, and all uses (strlcpy + strcat) stay within bounds given segment names are pre‑truncated to WLED_MAX_SEGNAME_LEN.


1782-1787: Segment-name ledmap filenames sized safely

Using char fileName[WLED_MAX_SEGNAME_LEN+12] for /lm<segname>.json and snprintf with sizeof(fileName)-1 ensures the generated filenames remain within bounds even for max-length segment names.


2590-2690: deserializeMap filename and mapping-table growth look safe

Bumping the fileName buffer to WLED_MAX_SEGNAME_LEN+10 and consistently using it for both numeric and segment-name ledmaps avoids earlier hard-coded limits. The customMappingTable resize via reallocf/calloc is guarded by a computed size and only executed when size>0, so you won’t overflow that buffer when reading the "map" entries. ErrorFlag paths and early returns on allocation failure also look reasonable for this code path.

wled00/FX_2Dfcn.cpp (2)

843-852: jsonToPixels filename buffer correctly scaled

Using char fileName[WLED_MAX_SEGNAME_LEN+12] and snprintf(fileName, sizeof(fileName)-1, "/%s%d.json", name, fileNr) gives ample room for the prefix/suffix around any valid name and avoids the previous hard-coded 40-byte limit.


885-917: drawText decoding pipeline is bounded and consistent

The new Segment::drawText correctly:

  • Limits the decoded UTF‑16 buffer to WLED_MAX_SEGNAME_LEN entries and NUL-terminates it.
  • Uses unicodeToWchar16 + wchar16ToCodepage437 to map UTF‑8 text into CP437 glyph indices under FULL_FONTS.
  • Caps the rendered length by maxLetters and the decoded length before calling drawCharacter.

Given the existing validation in unicodeToWchar16/nextUnicode, this keeps decoding robust while honoring the configured name length limit.

wled00/FX.cpp (1)

13-15: FULL_FONTS include guard is correct and localized

Including src/font/codepages.h only under WLED_ENABLE_FULL_FONTS cleanly scopes the new font machinery without impacting default builds.

stupid mistake ... it must still be "i>0" because its about the scanline, not the character code
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
wled00/FX_2Dfcn.cpp (1)

928-932: TODO comments remain unaddressed (tracked from previous review).

The hardcoded bounds check chr < 1 || chr > 254 and generic chr = chr - 1 adjustment should ideally use per-font limits (e.g., console_font_YxZ_first and console_font_YxZ_last). This was already flagged in the previous review and remains open.

Since this is a POC and the previous review comment is still tracking this issue, ensure it's addressed before final release.

🧹 Nitpick comments (1)
wled00/FX_2Dfcn.cpp (1)

845-845: Update comment to match actual buffer size.

The comment states "we need up to 40 bytes" but the buffer is sized at WLED_MAX_SEGNAME_LEN+12 = 44 bytes. Update the comment to reflect the correct size or explain the calculation.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e63dc7e and c3dce13.

📒 Files selected for processing (1)
  • wled00/FX_2Dfcn.cpp (4 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
wled00/**/*.{cpp,h}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use spaces (2 per level) for C++ firmware source and headers in wled00

Files:

  • wled00/FX_2Dfcn.cpp
🧠 Learnings (7)
📓 Common learnings
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR #270, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue #272; do not address it within PR #270.
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.
📚 Learning: 2025-11-02T22:17:26.380Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-02T22:17:26.380Z
Learning: In wled00/FX.cpp, the `#ifndef WLED_DISABLE_2D` guard around the Akemi 2D fallback in the `mode_oops()` function (lines 142-146) is intentionally kept. This guard is necessary because when users build with `-D WLED_DISABLE_2D` to remove all 2D effects from the build, the Akemi effect is also not compiled, so the guard prevents calling a non-existent function.

Applied to files:

  • wled00/FX_2Dfcn.cpp
📚 Learning: 2025-10-22T21:59:24.331Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR #270, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue #272; do not address it within PR #270.

Applied to files:

  • wled00/FX_2Dfcn.cpp
📚 Learning: 2025-11-14T13:55:44.372Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-14T13:55:44.372Z
Learning: In MoonModules/WLED-MM, always flag Variable Length Arrays (VLA) during code reviews, especially when they could overflow available stack space (typically 2K-4K on ESP32/ESP8266). VLAs based on dynamic parameters like segment dimensions, particle counts, or pixel buffers should be highlighted and require justification from the author. Prefer fixed-size arrays, heap allocation, or bounded VLAs with explicit maximum size constraints.

Applied to files:

  • wled00/FX_2Dfcn.cpp
📚 Learning: 2025-10-22T21:50:25.839Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.

Applied to files:

  • wled00/FX_2Dfcn.cpp
📚 Learning: 2025-10-22T22:24:46.163Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/json.cpp:295-304
Timestamp: 2025-10-22T22:24:46.163Z
Learning: When deriving an upper-bound index from a count in WLED-MM PR #270, use a safe guard: last = count ? count - 1 : 0. Avoid min/max with 0 on unsigned types and never pass (count-1) directly to helpers (e.g., updateVal16, relativeChange, random8) without guarding. Effect IDs are 16-bit; palette IDs remain 8-bit but should use the same guard when count can be 0.

Applied to files:

  • wled00/FX_2Dfcn.cpp
📚 Learning: 2025-07-12T04:20:14.546Z
Learnt from: DedeHai
Repo: MoonModules/WLED-MM PR: 253
File: usermods/audioreactive/audio_source.h:1256-1261
Timestamp: 2025-07-12T04:20:14.546Z
Learning: In WLED AudioReactive usermod, DC offset removal optimization in DMAadcSource::getSamples() should be implemented after PR #248 merges, which will change the sample buffer from float to int16. This eliminates the need for temporary integer buffers and allows direct integer arithmetic on the native buffer type for better memory efficiency on resource-constrained MCUs like C3 and S2.

Applied to files:

  • wled00/FX_2Dfcn.cpp
🧬 Code graph analysis (1)
wled00/FX_2Dfcn.cpp (2)
wled00/FX.h (3)
  • isActive (611-611)
  • drawCharacter (828-828)
  • drawCharacter (871-871)
wled00/FX_fcn.cpp (5)
  • i (723-733)
  • i (723-723)
  • i (734-740)
  • i (734-734)
  • SEGMENT (746-824)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (18)
  • GitHub Check: Builds (esp32_16MB_V4_M)
  • GitHub Check: Builds (esp32_16MB_V4_S)
  • GitHub Check: Builds (esp32_4MB_PSRAM_S)
  • GitHub Check: Builds (adafruit_matrixportal_esp32s3_tinyUF2)
  • GitHub Check: Builds (esp32c3mini_dio_4MB_M)
  • GitHub Check: Builds (esp32S3_WROOM-2_M)
  • GitHub Check: Builds (esp32s2_PSRAM_M)
  • GitHub Check: Builds (esp32S3_8MB_PSRAM_M)
  • GitHub Check: Builds (esp32S3_16MB_PSRAM_M_HUB75)
  • GitHub Check: Builds (esp32s2_PSRAM_S)
  • GitHub Check: Builds (esp32c3dev_2MB_M)
  • GitHub Check: Builds (esp32S3_4MB_PSRAM_S)
  • GitHub Check: Builds (esp32S3_4MB_PSRAM_M)
  • GitHub Check: Builds (esp32_4MB_PSRAM_S)
  • GitHub Check: Builds (esp32S3_8MB_M)
  • GitHub Check: Builds (esp32_4MB_V4_HUB75_forum)
  • GitHub Check: Builds (esp32_16MB_V4_M)
  • GitHub Check: Builds (esp32_16MB_V4_S)
🔇 Additional comments (3)
wled00/FX_2Dfcn.cpp (3)

885-887: LGTM!

The conditional include for codepages.h is correctly guarded by WLED_ENABLE_FULL_FONTS and aligns with the Unicode translation features added in this PR.


889-917: LGTM! Bounds checking is correct.

The buffer bounds checking has been properly fixed from the previous review. The array decoded_text[WLED_MAX_SEGNAME_LEN+1] has 33 elements, and the loop correctly limits utf16_index < WLED_MAX_SEGNAME_LEN (< 32), ensuring the NUL terminator at line 906 is written within bounds at index 32.

The TODO comments at lines 892 and 900-902 about font limits validation should be addressed in a follow-up, but don't block this POC.


954-968: Now let me check the actual end of a font array to confirm it includes 254 characters:

Now let me verify the actual line of code to ensure chr bounds checking is indeed in place:Based on my verification of the code and font array implementation:

  1. Bounds checking exists: Line 930 has if (chr < 1 || chr > 254) return; when WLED_ENABLE_FULL_FONTS is enabled
  2. Character index conversion: Line 931 converts chr from [1,254] to [0,253] with chr -= 1
  3. Index calculation: The max array index is (253 * 12) + 11 = 3047 for the 5x12 font
  4. Font arrays: Defined without explicit size, implicitly sized by initializers. When WLED_ENABLE_FULL_FONTS is enabled, they include data for all 254 characters

The original review comment raises a valid concern but the code has already implemented proper bounds checking that prevents out-of-bounds access when FULL_FONTS is enabled.

Font array sizes support the full character set indexing (254 characters) when WLED_ENABLE_FULL_FONTS is enabled. The code properly validates chr in the range [1, 254] at line 930 before conversion to array indices [0, 253], preventing out-of-bounds access.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c3dce13 and 7ef94bc.

📒 Files selected for processing (1)
  • wled00/FX_fcn.cpp (6 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
wled00/**/*.{cpp,h}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use spaces (2 per level) for C++ firmware source and headers in wled00

Files:

  • wled00/FX_fcn.cpp
🧠 Learnings (6)
📓 Common learnings
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR #270, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue #272; do not address it within PR #270.
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-14T13:55:44.372Z
Learning: In MoonModules/WLED-MM, always flag Variable Length Arrays (VLA) during code reviews, especially when they could overflow available stack space (typically 2K-4K on ESP32/ESP8266). VLAs based on dynamic parameters like segment dimensions, particle counts, or pixel buffers should be highlighted and require justification from the author. Prefer fixed-size arrays, heap allocation, or bounded VLAs with explicit maximum size constraints.
📚 Learning: 2025-11-14T13:55:44.372Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-14T13:55:44.372Z
Learning: In MoonModules/WLED-MM, always flag Variable Length Arrays (VLA) during code reviews, especially when they could overflow available stack space (typically 2K-4K on ESP32/ESP8266). VLAs based on dynamic parameters like segment dimensions, particle counts, or pixel buffers should be highlighted and require justification from the author. Prefer fixed-size arrays, heap allocation, or bounded VLAs with explicit maximum size constraints.

Applied to files:

  • wled00/FX_fcn.cpp
📚 Learning: 2025-10-22T21:50:25.839Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.

Applied to files:

  • wled00/FX_fcn.cpp
📚 Learning: 2025-11-02T22:07:15.689Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-02T22:07:15.689Z
Learning: In MoonModules/WLED-MM, WLEDMM_FASTPATH will become the default code path. Code inside "#ifndef WLEDMM_FASTPATH" blocks represents deprecated paths that are being phased out and should be ignored during reviews.

Applied to files:

  • wled00/FX_fcn.cpp
📚 Learning: 2025-10-12T21:55:59.766Z
Learnt from: CR
Repo: MoonModules/WLED-MM PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-12T21:55:59.766Z
Learning: Applies to wled00/**/*.{cpp,h} : Use spaces (2 per level) for C++ firmware source and headers in wled00

Applied to files:

  • wled00/FX_fcn.cpp
📚 Learning: 2025-10-22T22:24:46.163Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/json.cpp:295-304
Timestamp: 2025-10-22T22:24:46.163Z
Learning: When deriving an upper-bound index from a count in WLED-MM PR #270, use a safe guard: last = count ? count - 1 : 0. Avoid min/max with 0 on unsigned types and never pass (count-1) directly to helpers (e.g., updateVal16, relativeChange, random8) without guarding. Effect IDs are 16-bit; palette IDs remain 8-bit but should use the same guard when count can be 0.

Applied to files:

  • wled00/FX_fcn.cpp
🧬 Code graph analysis (1)
wled00/FX_fcn.cpp (1)
wled00/util.cpp (2)
  • cleanUpName (639-656)
  • cleanUpName (639-639)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (18)
  • GitHub Check: Builds (adafruit_matrixportal_esp32s3_tinyUF2)
  • GitHub Check: Builds (esp01_1MB_S)
  • GitHub Check: Builds (esp32c3dev_4MB_M)
  • GitHub Check: Builds (athom_music_esp32_4MB_M)
  • GitHub Check: Builds (esp8266_4MB_M)
  • GitHub Check: Builds (esp32c3dev_2MB_M)
  • GitHub Check: Builds (esp32c3mini_dio_4MB_M)
  • GitHub Check: Builds (seeed_esp32c3_4MB_S)
  • GitHub Check: Builds (esp32s2_PSRAM_M)
  • GitHub Check: Builds (esp32S3_8MB_S)
  • GitHub Check: Builds (esp32S3_8MB_PSRAM_M)
  • GitHub Check: Builds (esp32s2_PSRAM_S)
  • GitHub Check: Builds (esp32_16MB_V4_S)
  • GitHub Check: Builds (esp32S3_4MB_PSRAM_M)
  • GitHub Check: Builds (esp32S3_8MB_M)
  • GitHub Check: Builds (esp32_4MB_V4_HUB75_forum)
  • GitHub Check: Builds (esp32S3_4MB_S)
  • GitHub Check: Builds (esp32_4MB_V4_S)
🔇 Additional comments (5)
wled00/FX_fcn.cpp (5)

701-701: LGTM: Buffer size increased to support longer segment names.

The expansion from char[50] to char[WLED_MAX_SEGNAME_LEN+12] correctly accommodates the new maximum segment name length with sufficient space for path construction.


754-754: Buffer sizing is conservative and safe.

The comment states "we need at most 32 + 7 bytes" but allocates WLED_MAX_SEGNAME_LEN+12. For path "/.json", the actual requirement is name_length + 7 bytes. The +12 provides a safety margin, which is acceptable.


822-822: LGTM: Correct strlcpy usage.

Using sizeof(previousSegmentName) correctly provides the destination buffer size for safe string copying.


1782-1782: LGTM: Buffer size is sufficient for path construction.

For path "/lm.json", the worst case is 3 + 32 + 5 + 1 = 41 bytes. The allocated size of WLED_MAX_SEGNAME_LEN+12 (44 bytes) provides adequate space.


2590-2590: LGTM: Buffer size calculation is correct.

The comment "we need at least 32 + 7 bytes" (39 bytes total) correctly accounts for the path "/<segment_name>.json". The allocated size of WLED_MAX_SEGNAME_LEN+10 (42 bytes) provides adequate space with a small safety margin.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
wled00/FX.cpp (1)

6817-6925: Fix maxLen passed to drawText() after macro expansion

The UTF‑8 path in mode_2Dscrollingtext() looks generally solid (bounded buffer, Unicode counting via strlenUC, and resynchronizing iteration), but there is a subtle correctness issue around maxLen:

  • maxLen is computed once from the original SEGMENT.name:
    unsigned maxLen = (SEGMENT.name) ? min(WLED_MAX_SEGNAME_LEN, (int)strlen(SEGMENT.name)) : 0;
  • Later, text can be completely replaced by various sprintf_P calls (#TIME, #DATE, #ERR, etc.), producing strings that can be longer than the original name (e.g. "#TIME""12:34:56").
  • In the FULL_FONTS branch you then call:
    SEGMENT.drawText((unsigned char*)text, maxLen, numberOfChars,
                     int(cols) - int(SEGENV.aux0), yoffset,
                     letterWidth, letterHeight, col1, col2, drawShadow);
    where numberOfChars = strlen(text).

If text grew after macro replacement, maxLen is now too small, so drawText() may see only a truncated slice of the buffer or stop parsing earlier than numberOfChars suggests. That will manifest as truncated date/time/error strings when FULL_FONTS is enabled.

Minimal fix: recompute maxLen from the final text just before using it for drawText():

-  const int numberOfChars = strlen(text);
+  const int numberOfChars = strlen(text);
@@
-  uint32_t col1 = SEGMENT.color_from_palette(SEGENV.aux1, false, PALETTE_SOLID_WRAP, 0);
+  // Ensure maxLen reflects the actual rendered text, not the original SEGMENT.name
+  maxLen = numberOfChars;
+
+  uint32_t col1 = SEGMENT.color_from_palette(SEGENV.aux1, false, PALETTE_SOLID_WRAP, 0);
   uint32_t col2 = BLACK;
@@
-  SEGMENT.drawText((unsigned char*)text, maxLen, numberOfChars,
+  SEGMENT.drawText((unsigned char*)text, maxLen, numberOfChars,
                    int(cols) - int(SEGENV.aux0), yoffset,
                    letterWidth, letterHeight, col1, col2, drawShadow);

This keeps the existing logic but guarantees maxLen and numberOfChars describe the same buffer contents for both plain names and macro‑generated strings.

🧹 Nitpick comments (2)
wled00/FX_fcn.cpp (1)

2590-2590: Standardize buffer size for consistency.

Line 2590 uses WLED_MAX_SEGNAME_LEN+10 while similar declarations at lines 754 and 1782 use WLED_MAX_SEGNAME_LEN+12. Although +10 is sufficient for the actual usage ("/<name>.json" needs 39 bytes), using +12 consistently across the codebase reduces cognitive load and provides a uniform safety margin.

Apply this diff:

-  char fileName[WLED_MAX_SEGNAME_LEN+10] = {'\0'};
+  char fileName[WLED_MAX_SEGNAME_LEN+12] = {'\0'};
wled00/FX_2Dfcn.cpp (1)

923-930: Track font range validation as follow-up task.

The character validation logic (lines 928-929) uses hardcoded bounds (1–254) and a fixed offset (-1) instead of per-font range constants (e.g., console_font_YxZ_first, console_font_YxZ_last). The inline TODO comments acknowledge this limitation. Since this is a WIP/POC, consider tracking proper per-font bounds validation and index calculation as a follow-up issue.

Would you like me to open a new issue to track implementing proper font range validation for each supported font (4x6, 5x8, 5x12, 6x8, 7x9)?

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7ef94bc and 053551d.

📒 Files selected for processing (3)
  • wled00/FX.cpp (5 hunks)
  • wled00/FX_2Dfcn.cpp (4 hunks)
  • wled00/FX_fcn.cpp (6 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
wled00/**/*.{cpp,h}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use spaces (2 per level) for C++ firmware source and headers in wled00

Files:

  • wled00/FX_fcn.cpp
  • wled00/FX_2Dfcn.cpp
  • wled00/FX.cpp
🧠 Learnings (10)
📓 Common learnings
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR #270, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue #272; do not address it within PR #270.
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-14T13:55:44.372Z
Learning: In MoonModules/WLED-MM, always flag Variable Length Arrays (VLA) during code reviews, especially when they could overflow available stack space (typically 2K-4K on ESP32/ESP8266). VLAs based on dynamic parameters like segment dimensions, particle counts, or pixel buffers should be highlighted and require justification from the author. Prefer fixed-size arrays, heap allocation, or bounded VLAs with explicit maximum size constraints.
📚 Learning: 2025-11-14T13:55:44.372Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-14T13:55:44.372Z
Learning: In MoonModules/WLED-MM, always flag Variable Length Arrays (VLA) during code reviews, especially when they could overflow available stack space (typically 2K-4K on ESP32/ESP8266). VLAs based on dynamic parameters like segment dimensions, particle counts, or pixel buffers should be highlighted and require justification from the author. Prefer fixed-size arrays, heap allocation, or bounded VLAs with explicit maximum size constraints.

Applied to files:

  • wled00/FX_fcn.cpp
  • wled00/FX_2Dfcn.cpp
📚 Learning: 2025-10-22T21:50:25.839Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.

Applied to files:

  • wled00/FX_fcn.cpp
  • wled00/FX_2Dfcn.cpp
  • wled00/FX.cpp
📚 Learning: 2025-10-12T21:55:59.766Z
Learnt from: CR
Repo: MoonModules/WLED-MM PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-12T21:55:59.766Z
Learning: Applies to wled00/**/*.{cpp,h} : Use spaces (2 per level) for C++ firmware source and headers in wled00

Applied to files:

  • wled00/FX_fcn.cpp
📚 Learning: 2025-11-02T22:07:15.689Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-02T22:07:15.689Z
Learning: In MoonModules/WLED-MM, WLEDMM_FASTPATH will become the default code path. Code inside "#ifndef WLEDMM_FASTPATH" blocks represents deprecated paths that are being phased out and should be ignored during reviews.

Applied to files:

  • wled00/FX_fcn.cpp
  • wled00/FX_2Dfcn.cpp
  • wled00/FX.cpp
📚 Learning: 2025-10-22T21:59:24.331Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR #270, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue #272; do not address it within PR #270.

Applied to files:

  • wled00/FX_fcn.cpp
  • wled00/FX_2Dfcn.cpp
📚 Learning: 2025-10-22T22:24:46.163Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/json.cpp:295-304
Timestamp: 2025-10-22T22:24:46.163Z
Learning: When deriving an upper-bound index from a count in WLED-MM PR #270, use a safe guard: last = count ? count - 1 : 0. Avoid min/max with 0 on unsigned types and never pass (count-1) directly to helpers (e.g., updateVal16, relativeChange, random8) without guarding. Effect IDs are 16-bit; palette IDs remain 8-bit but should use the same guard when count can be 0.

Applied to files:

  • wled00/FX_fcn.cpp
  • wled00/FX_2Dfcn.cpp
📚 Learning: 2025-07-12T04:20:14.546Z
Learnt from: DedeHai
Repo: MoonModules/WLED-MM PR: 253
File: usermods/audioreactive/audio_source.h:1256-1261
Timestamp: 2025-07-12T04:20:14.546Z
Learning: In WLED AudioReactive usermod, DC offset removal optimization in DMAadcSource::getSamples() should be implemented after PR #248 merges, which will change the sample buffer from float to int16. This eliminates the need for temporary integer buffers and allows direct integer arithmetic on the native buffer type for better memory efficiency on resource-constrained MCUs like C3 and S2.

Applied to files:

  • wled00/FX_fcn.cpp
  • wled00/FX_2Dfcn.cpp
📚 Learning: 2025-11-02T22:17:26.380Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-02T22:17:26.380Z
Learning: In wled00/FX.cpp, the `#ifndef WLED_DISABLE_2D` guard around the Akemi 2D fallback in the `mode_oops()` function (lines 142-146) is intentionally kept. This guard is necessary because when users build with `-D WLED_DISABLE_2D` to remove all 2D effects from the build, the Akemi effect is also not compiled, so the guard prevents calling a non-existent function.

Applied to files:

  • wled00/FX_2Dfcn.cpp
  • wled00/FX.cpp
📚 Learning: 2025-06-30T17:53:37.232Z
Learnt from: DedeHai
Repo: MoonModules/WLED-MM PR: 248
File: usermods/audioreactive/audio_reactive.h:199-200
Timestamp: 2025-06-30T17:53:37.232Z
Learning: In WLED AudioReactive usermod, when using ArduinoFFT (enabled via UM_AUDIOREACTIVE_USE_ARDUINO_FFT), it's acceptable and necessary to redefine the global sqrt macro to sqrtf within the conditional compilation block for performance optimization. This is a specific requirement for ArduinoFFT optimization that can provide 10-50% performance improvement on ESP32.

Applied to files:

  • wled00/FX.cpp
🧬 Code graph analysis (3)
wled00/FX_fcn.cpp (1)
wled00/util.cpp (2)
  • cleanUpName (639-656)
  • cleanUpName (639-639)
wled00/FX_2Dfcn.cpp (2)
wled00/FX.h (3)
  • isActive (611-611)
  • drawCharacter (828-828)
  • drawCharacter (871-871)
wled00/FX_fcn.cpp (5)
  • i (723-733)
  • i (723-723)
  • i (734-740)
  • i (734-734)
  • SEGMENT (746-824)
wled00/FX.cpp (2)
wled00/FX_fcn.cpp (5)
  • SEGMENT (746-824)
  • i (723-733)
  • i (723-723)
  • i (734-740)
  • i (734-734)
wled00/src/font/unicodetool.cpp (2)
  • strlenUC (76-84)
  • strlenUC (76-76)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: Builds (esp32_16MB_V4_M)
  • GitHub Check: Builds (esp32_4MB_V4_S)
  • GitHub Check: Builds (adafruit_matrixportal_esp32s3_tinyUF2)
  • GitHub Check: Builds (esp8266pro_16MB_M)
  • GitHub Check: Builds (athom_music_esp32_4MB_M)
  • GitHub Check: Builds (esp32S3_4MB_PSRAM_S)
  • GitHub Check: Builds (seeed_esp32c3_4MB_S)
  • GitHub Check: Builds (esp32c3dev_4MB_M)
  • GitHub Check: Builds (esp32S3_8MB_PSRAM_M)
  • GitHub Check: Builds (esp32S3_WROOM-2_M)
  • GitHub Check: Builds (esp32S3_16MB_PSRAM_M_HUB75)
  • GitHub Check: Builds (esp32s2_PSRAM_S)
  • GitHub Check: Builds (esp32S3_8MB_S)
  • GitHub Check: Builds (esp32S3_4MB_S)
  • GitHub Check: Builds (esp32S3_4MB_PSRAM_M)
  • GitHub Check: Builds (esp32_16MB_V4_M)
  • GitHub Check: Builds (esp32S3_8MB_M)
  • GitHub Check: Builds (esp32_4MB_PSRAM_S)
  • GitHub Check: Builds (esp32_4MB_V4_HUB75_forum)
  • GitHub Check: Builds (esp32_16MB_V4_S)
🔇 Additional comments (6)
wled00/FX.cpp (1)

13-16: Conditional include for full-fonts utilities looks correct

The #if defined(WLED_ENABLE_FULL_FONTS) guard around codepages.h matches the conditional use of strlenUC/Unicode helpers later in this file and avoids pulling them in when full fonts are disabled. No issues here.

wled00/FX_fcn.cpp (1)

701-701: LGTM!

Buffer expansion from 50 to WLED_MAX_SEGNAME_LEN+12 correctly accommodates longer segment names introduced by this PR. Usage at line 822 properly passes sizeof(previousSegmentName) to strlcpy.

wled00/FX_2Dfcn.cpp (4)

885-887: LGTM!

Conditional inclusion of codepage support is properly guarded and aligns with the PR's Unicode/CP437 translation features.


889-917: LGTM!

The bounds checking in drawText() is now correct. The condition utf16_index < WLED_MAX_SEGNAME_LEN (line 897) allows indices 0–31, and the NUL terminator is written at index 32, which is valid for the 33-element array. The off-by-one overflow identified in past review comments has been properly fixed.


845-845: LGTM!

Buffer sizing WLED_MAX_SEGNAME_LEN+12 is consistent with similar declarations in wled00/FX_fcn.cpp (lines 754, 1782) and provides adequate space for segment-name-based file paths.


951-968: LGTM!

The shadow logic now correctly uses (i>0) to guard previous-scanline reads (lines 953, 956, 959, 962, 965) instead of the incorrect (i>space) check that previously disabled shadows in FULL_FONTS mode. This fix was properly addressed per past review comments.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
wled00/FX.cpp (1)

6817-6825: Unicode-aware scrolling text path looks good; double‑check drawText length semantics

The refactor around mode_2Dscrollingtext() is generally solid:

  • text is now bounded by WLED_MAX_SEGNAME_LEN+1, zero‑initialized, and maxLen is clamped to min(WLED_MAX_SEGNAME_LEN, strlen(SEGMENT.name)), so the manual copy loops cannot overflow the buffer in either ASCII‑filtered or FULL_FONTS paths.
  • The non‑FULL_FONTS branch preserves legacy behavior by stripping non‑ASCII glyphs; the FULL_FONTS branch correctly preserves raw UTF‑8 bytes instead of "killing" Unicode.
  • Using strlenUC((unsigned char*)text) to derive numberOfLetters for layout and scroll width (i.e., numberOfLetters * letterWidth) matches the UTF‑8/BMP decoding model introduced in unicodetool.cpp.
  • The new scroll timing using minDelay = max(FRAMETIME_FIXED*3/4, int(FRAMETIME)) and map2(SEGMENT.speed, 0, 255, 10*FRAMETIME_FIXED, minDelay) avoids stepping faster than frame time and is consistent with other effects.
  • The new “Soft” option (SEGMENT.check3) that adds blurRows/blurCols is bounded (small fixed blur amounts) and only active when explicitly requested, so it won’t unexpectedly degrade performance.

One area worth clarifying:

  • In the FULL_FONTS path you call:
    maxLen = numberOfChars;
    SEGMENT.drawText((unsigned char*)text, maxLen, numberOfChars,
                     int(cols) - int(SEGENV.aux0), yoffset,
                     letterWidth, letterHeight, col1, col2, drawShadow);
    while numberOfLetters already holds the Unicode letter count. If Segment::drawText interprets its third argument as a codepoint/letter count rather than a byte count, you probably want to pass numberOfLetters there instead of numberOfChars, and treat maxLen purely as a byte bound. If drawText already treats both maxLen and the length parameter as byte counts and derives the letter count internally via its own UTF‑8 walker, then the current call is fine but the API contract should be documented clearly.

Also, if Segment::drawText takes const unsigned char* (or can be changed to), aligning its first parameter type would let you drop the C‑style cast in favor of a natural call.

Overall behavior and safety look good; I’d just confirm the intended drawText parameter semantics and adjust to use numberOfLetters if it’s meant to be codepoint‑based.

Also applies to: 6868-6875, 6881-6882, 6895-6915, 6917-6921, 6925-6925

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 053551d and aea83a3.

📒 Files selected for processing (1)
  • wled00/FX.cpp (5 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
wled00/**/*.{cpp,h}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use spaces (2 per level) for C++ firmware source and headers in wled00

Files:

  • wled00/FX.cpp
🧠 Learnings (5)
📓 Common learnings
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR #270, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue #272; do not address it within PR #270.
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-14T13:55:44.372Z
Learning: In MoonModules/WLED-MM, always flag Variable Length Arrays (VLA) during code reviews, especially when they could overflow available stack space (typically 2K-4K on ESP32/ESP8266). VLAs based on dynamic parameters like segment dimensions, particle counts, or pixel buffers should be highlighted and require justification from the author. Prefer fixed-size arrays, heap allocation, or bounded VLAs with explicit maximum size constraints.
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.
📚 Learning: 2025-11-02T22:17:26.380Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-02T22:17:26.380Z
Learning: In wled00/FX.cpp, the `#ifndef WLED_DISABLE_2D` guard around the Akemi 2D fallback in the `mode_oops()` function (lines 142-146) is intentionally kept. This guard is necessary because when users build with `-D WLED_DISABLE_2D` to remove all 2D effects from the build, the Akemi effect is also not compiled, so the guard prevents calling a non-existent function.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-10-22T21:50:25.839Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-11-02T22:07:15.689Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-02T22:07:15.689Z
Learning: In MoonModules/WLED-MM, WLEDMM_FASTPATH will become the default code path. Code inside "#ifndef WLEDMM_FASTPATH" blocks represents deprecated paths that are being phased out and should be ignored during reviews.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-06-30T17:53:37.232Z
Learnt from: DedeHai
Repo: MoonModules/WLED-MM PR: 248
File: usermods/audioreactive/audio_reactive.h:199-200
Timestamp: 2025-06-30T17:53:37.232Z
Learning: In WLED AudioReactive usermod, when using ArduinoFFT (enabled via UM_AUDIOREACTIVE_USE_ARDUINO_FFT), it's acceptable and necessary to redefine the global sqrt macro to sqrtf within the conditional compilation block for performance optimization. This is a specific requirement for ArduinoFFT optimization that can provide 10-50% performance improvement on ESP32.

Applied to files:

  • wled00/FX.cpp
🧬 Code graph analysis (1)
wled00/FX.cpp (2)
wled00/FX_fcn.cpp (5)
  • SEGMENT (746-824)
  • i (723-733)
  • i (723-723)
  • i (734-740)
  • i (734-734)
wled00/src/font/unicodetool.cpp (2)
  • strlenUC (76-84)
  • strlenUC (76-76)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (19)
  • GitHub Check: Builds (athom_music_esp32_4MB_M)
  • GitHub Check: Builds (adafruit_matrixportal_esp32s3_tinyUF2)
  • GitHub Check: Builds (esp8266_4MB_M)
  • GitHub Check: Builds (esp32c3mini_dio_4MB_M)
  • GitHub Check: Builds (seeed_esp32c3_4MB_S)
  • GitHub Check: Builds (esp32s2_PSRAM_M)
  • GitHub Check: Builds (esp32S3_4MB_PSRAM_S)
  • GitHub Check: Builds (esp32s2_PSRAM_S)
  • GitHub Check: Builds (esp32c3dev_2MB_M)
  • GitHub Check: Builds (esp32S3_8MB_S)
  • GitHub Check: Builds (esp32S3_WROOM-2_M)
  • GitHub Check: Builds (esp32S3_4MB_PSRAM_M)
  • GitHub Check: Builds (esp32S3_16MB_PSRAM_M_HUB75)
  • GitHub Check: Builds (esp32_16MB_V4_S)
  • GitHub Check: Builds (esp32_16MB_V4_M)
  • GitHub Check: Builds (esp32S3_8MB_M)
  • GitHub Check: Builds (esp32_4MB_V4_HUB75_forum)
  • GitHub Check: Builds (esp32S3_4MB_S)
  • GitHub Check: Builds (esp32_4MB_V4_S)
🔇 Additional comments (1)
wled00/FX.cpp (1)

13-15: Guarded FULL_FONTS include is safe and scoped correctly

Wrapping #include "src/font/codepages.h" in #if defined(WLED_ENABLE_FULL_FONTS) keeps the dependency optional and avoids touching non‑FULL_FONTS builds. No functional or safety concerns here.

did I mention already that this is complicated stuff? oh yes, it is.
…ring

* explanation for CP437 glyph groups
* translation for MonnModules symbol
* "smiley" replacement for 4-bytes and overlong unicode codes
* always compile unicodetool.cpp (codepage translation still depends on WLED_ENABLE_UNICODE)
* bugfix: DrawString now skips over glyphs that would be rejected by DrawCharacter
* minor cleanup
* centralize font selection logic into  getFontInfo()
* removed unneeded parameter "numberOfChars" from drawText()
* new file: wled_fonts.hpp to centralize font management logic (inline)
* only compile wchar16ToCodepage437 when WLED_ENABLE_FULL_FONTS
* minor cleanup
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (1)
wled00/FX.h (1)

829-832: LGTM - past concerns addressed.

The drawText declaration has been updated to address previous review concerns:

  • ✓ Parameter renamed from Text to text (lowercase)
  • maxLen parameter added
  • ✓ Declaration doesn't require WLED_ENABLE_FULL_FONTS guard (implementation provides fallback path at lines 905-908 of FX_2Dfcn.cpp)

The signature is now consistent with the implementation.

🧹 Nitpick comments (7)
wled00/src/font/codepage437.cpp (3)

11-11: Remove unused include.

The string.h include appears unused—no string functions are called in this file.

Apply this diff:

 #include "codepages.h"
-#include <string.h>

17-17: Consider narrowing return type to uint8_t.

CP437 is an 8-bit encoding (0–255), so returning uint8_t would more accurately reflect the codepage's domain and avoid unnecessary widening.

Apply this diff:

-uint16_t wchar16ToCodepage437(uint16_t wideChar) {
+uint8_t wchar16ToCodepage437(uint16_t wideChar) {

20-25: Simplify backspace handling.

Lines 20 and 25 redundantly handle 0x0008 (backspace): line 20 excludes it from pass-through, then line 25 explicitly maps it to itself. Since the mapping is identity (0x08 → 0x08), removing the exclusion at line 20 achieves the same result more simply.

Apply this diff:

-  if ((wideChar < 0x7F) && (wideChar != 0x08)) return wideChar; // excludes 127 = DEL and 8 = BS, so we can map them
+  if (wideChar < 0x7F) return wideChar; // excludes 127 = DEL so we can map it

And remove the explicit case:

-    // original IBM PC would interpret codes 0x07, 0x08, 0x0A, and 0x0D as BEL, BS, LF, and CR, respectively. 
-    // we don't implement any special handling at the moment
-    case 0x0008: return 0x08; break; // Backspace: pass through (could be handled differently in future)
-
wled00/wled_fonts.hpp (1)

77-82: Clarify default case for unsupported fonts.

Setting firstChar = lastChar = 1 in the default case creates a single-character range at position 1, which is misleading. Consider using firstChar = lastChar = 0 or firstChar = 1, lastChar = 0 to signal an explicitly empty range, making unsupported fonts easier to detect.

Apply this diff:

     default: // no font
       font.raw        = nullptr;
       font.isProgMem  = false;
-      font.firstChar  = 1;
-      font.lastChar   = 1;
+      font.firstChar  = 0;
+      font.lastChar   = 0;
       font.width_bytes= 1;
wled00/src/font/codepages.h (1)

42-48: Simplify redundant unsigned comparison.

Line 46: The condition (utf8[i] > 0) is redundant because utf8[i] is unsigned char, which is always >= 0. The check utf8[i] < 128 alone is sufficient to exclude both NUL (0) and extended ASCII (128–255).

Apply this diff:

 inline void killUnicode(unsigned char* utf8) {
   if (utf8 == nullptr) return;
   size_t clean_index = 0;
   for (size_t i=0; utf8[i] != '\0'; i++)
-    if ((utf8[i] > 0) && (utf8[i] < 128)) utf8[clean_index++] = utf8[i];
+    if (utf8[i] < 128 && utf8[i] != '\0') utf8[clean_index++] = utf8[i];
   utf8[clean_index] = '\0';
 }

Note: Adding the explicit != '\0' check makes the intent clearer (excluding NUL from output), though the loop already terminates on NUL.

wled00/FX_2Dfcn.cpp (1)

944-964: Remove dead legacy code.

Lines 944–964 contain legacy font-switching code that is no longer executed (guarded by #if 1 ... #else). Since the new centralized font path (lines 939–942) is active and stable, you can delete the #else branch to reduce code clutter.

Apply this diff:

-#if 1
-    // new code - experimental
     bits = pgm_read_byte_near(&font.raw[(chr * h) + i]);
     if ((i>0) && drawShadow) bits_up = pgm_read_byte_near(&font.raw[(chr * h) + i -1]);
-#else
-  // legacy code, will be deleted after some tests
-    int pixels = w*h; 
-    switch (pixels) {
-      case 24: bits = pgm_read_byte_near(&console_font_4x6[(chr * h) + i]);
-        if ((i>0) && drawShadow) bits_up = pgm_read_byte_near(&console_font_4x6[(chr * h) + i -1]);
-        break;
-      ...
-      default: return;
-    }
-#endif
wled00/FX.cpp (1)

6817-6825: String buffer sizing and copy logic are safe; consider UTF‑8‑aware clipping as a refinement

  • text is sized as WLED_MAX_SEGNAME_LEN+1 and initialized to '\0', so both the ASCII-filtering and FULL_FONTS copy paths stay within bounds and end up NUL‑terminated even when truncating.
  • In the ASCII path, j can grow to at most maxLen ≤ WLED_MAX_SEGNAME_LEN, so all writes fit in the buffer.
  • In the FULL_FONTS path, truncation is by raw byte length; this can split a multi‑byte UTF‑8 sequence, which the decoder will treat as an invalid/truncated codepoint and replace with the fallback glyph. If you want to avoid that visual artifact, a later refactor could clip at a codepoint boundary instead (e.g., via a small helper using nextUnicode/unicodeToWchar16).
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 213cd18 and e667637.

📒 Files selected for processing (6)
  • wled00/FX.cpp (5 hunks)
  • wled00/FX.h (1 hunks)
  • wled00/FX_2Dfcn.cpp (3 hunks)
  • wled00/src/font/codepage437.cpp (1 hunks)
  • wled00/src/font/codepages.h (1 hunks)
  • wled00/wled_fonts.hpp (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
wled00/**/*.{cpp,h}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use spaces (2 per level) for C++ firmware source and headers in wled00

Files:

  • wled00/src/font/codepage437.cpp
  • wled00/FX_2Dfcn.cpp
  • wled00/FX.cpp
  • wled00/FX.h
  • wled00/src/font/codepages.h
🧠 Learnings (11)
📓 Common learnings
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR #270, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue #272; do not address it within PR #270.
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-14T13:55:44.442Z
Learning: In MoonModules/WLED-MM, always flag Variable Length Arrays (VLA) during code reviews, especially when they could overflow available stack space (typically 2K-4K on ESP32/ESP8266). VLAs based on dynamic parameters like segment dimensions, particle counts, or pixel buffers should be highlighted and require justification from the author. Prefer fixed-size arrays, heap allocation, or bounded VLAs with explicit maximum size constraints.
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.
📚 Learning: 2025-10-22T21:50:25.839Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.

Applied to files:

  • wled00/src/font/codepage437.cpp
  • wled00/FX_2Dfcn.cpp
  • wled00/FX.cpp
  • wled00/src/font/codepages.h
📚 Learning: 2025-11-02T22:17:26.380Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-02T22:17:26.380Z
Learning: In wled00/FX.cpp, the `#ifndef WLED_DISABLE_2D` guard around the Akemi 2D fallback in the `mode_oops()` function (lines 142-146) is intentionally kept. This guard is necessary because when users build with `-D WLED_DISABLE_2D` to remove all 2D effects from the build, the Akemi effect is also not compiled, so the guard prevents calling a non-existent function.

Applied to files:

  • wled00/FX_2Dfcn.cpp
  • wled00/FX.cpp
  • wled00/FX.h
  • wled00/src/font/codepages.h
📚 Learning: 2025-10-22T21:59:24.331Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR #270, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue #272; do not address it within PR #270.

Applied to files:

  • wled00/FX_2Dfcn.cpp
  • wled00/src/font/codepages.h
📚 Learning: 2025-11-14T13:55:44.442Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-14T13:55:44.442Z
Learning: In MoonModules/WLED-MM, always flag Variable Length Arrays (VLA) during code reviews, especially when they could overflow available stack space (typically 2K-4K on ESP32/ESP8266). VLAs based on dynamic parameters like segment dimensions, particle counts, or pixel buffers should be highlighted and require justification from the author. Prefer fixed-size arrays, heap allocation, or bounded VLAs with explicit maximum size constraints.

Applied to files:

  • wled00/FX_2Dfcn.cpp
  • wled00/FX.h
  • wled00/src/font/codepages.h
📚 Learning: 2025-10-22T22:24:46.163Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/json.cpp:295-304
Timestamp: 2025-10-22T22:24:46.163Z
Learning: When deriving an upper-bound index from a count in WLED-MM PR #270, use a safe guard: last = count ? count - 1 : 0. Avoid min/max with 0 on unsigned types and never pass (count-1) directly to helpers (e.g., updateVal16, relativeChange, random8) without guarding. Effect IDs are 16-bit; palette IDs remain 8-bit but should use the same guard when count can be 0.

Applied to files:

  • wled00/FX_2Dfcn.cpp
  • wled00/src/font/codepages.h
📚 Learning: 2025-07-12T04:20:14.546Z
Learnt from: DedeHai
Repo: MoonModules/WLED-MM PR: 253
File: usermods/audioreactive/audio_source.h:1256-1261
Timestamp: 2025-07-12T04:20:14.546Z
Learning: In WLED AudioReactive usermod, DC offset removal optimization in DMAadcSource::getSamples() should be implemented after PR #248 merges, which will change the sample buffer from float to int16. This eliminates the need for temporary integer buffers and allows direct integer arithmetic on the native buffer type for better memory efficiency on resource-constrained MCUs like C3 and S2.

Applied to files:

  • wled00/FX_2Dfcn.cpp
📚 Learning: 2025-11-02T22:07:15.689Z
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-02T22:07:15.689Z
Learning: In MoonModules/WLED-MM, WLEDMM_FASTPATH will become the default code path. Code inside "#ifndef WLEDMM_FASTPATH" blocks represents deprecated paths that are being phased out and should be ignored during reviews.

Applied to files:

  • wled00/FX_2Dfcn.cpp
  • wled00/FX.cpp
📚 Learning: 2025-06-30T17:53:37.232Z
Learnt from: DedeHai
Repo: MoonModules/WLED-MM PR: 248
File: usermods/audioreactive/audio_reactive.h:199-200
Timestamp: 2025-06-30T17:53:37.232Z
Learning: In WLED AudioReactive usermod, when using ArduinoFFT (enabled via UM_AUDIOREACTIVE_USE_ARDUINO_FFT), it's acceptable and necessary to redefine the global sqrt macro to sqrtf within the conditional compilation block for performance optimization. This is a specific requirement for ArduinoFFT optimization that can provide 10-50% performance improvement on ESP32.

Applied to files:

  • wled00/FX.cpp
  • wled00/wled_fonts.hpp
  • wled00/src/font/codepages.h
📚 Learning: 2025-10-12T21:55:59.766Z
Learnt from: CR
Repo: MoonModules/WLED-MM PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-12T21:55:59.766Z
Learning: Applies to wled00/html_*.h : Do not edit generated embedded web header files: wled00/html_*.h

Applied to files:

  • wled00/wled_fonts.hpp
📚 Learning: 2025-10-12T21:55:59.766Z
Learnt from: CR
Repo: MoonModules/WLED-MM PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-12T21:55:59.766Z
Learning: Applies to wled00/**/*.{cpp,h} : Use spaces (2 per level) for C++ firmware source and headers in wled00

Applied to files:

  • wled00/wled_fonts.hpp
  • wled00/src/font/codepages.h
🧬 Code graph analysis (5)
wled00/FX_2Dfcn.cpp (4)
wled00/FX.h (13)
  • isActive (611-611)
  • drawCharacter (828-828)
  • drawCharacter (871-871)
  • virtualWidth (722-728)
  • virtualHeight (729-735)
  • setPixelColorXY (794-794)
  • setPixelColorXY (796-796)
  • setPixelColorXY (797-797)
  • setPixelColorXY (841-841)
  • setPixelColorXY (842-842)
  • setPixelColorXY (844-844)
  • setPixelColorXY (845-845)
  • setPixelColorXY (1195-1195)
wled00/wled_fonts.hpp (2)
  • getFontInfo (33-85)
  • getFontInfo (33-33)
wled00/src/font/unicodetool.cpp (4)
  • nextUnicode (56-80)
  • nextUnicode (56-56)
  • unicodeToWchar16 (20-52)
  • unicodeToWchar16 (20-20)
wled00/src/font/codepage437.cpp (2)
  • wchar16ToCodepage437 (17-234)
  • wchar16ToCodepage437 (17-17)
wled00/FX.cpp (2)
wled00/FX_fcn.cpp (5)
  • SEGMENT (746-824)
  • i (723-733)
  • i (723-723)
  • i (734-740)
  • i (734-734)
wled00/src/font/unicodetool.cpp (2)
  • strlenUC (83-91)
  • strlenUC (83-83)
wled00/wled_fonts.hpp (1)
wled00/FX.h (2)
  • width (616-616)
  • height (617-617)
wled00/FX.h (1)
wled00/FX_2Dfcn.cpp (3)
  • drawCharacter (917-917)
  • drawText (886-913)
  • drawText (886-886)
wled00/src/font/codepages.h (2)
wled00/src/font/unicodetool.cpp (8)
  • unicodeToWchar16 (20-52)
  • unicodeToWchar16 (20-20)
  • nextUnicode (56-80)
  • nextUnicode (56-56)
  • strlenUC (83-91)
  • strlenUC (83-83)
  • cutUnicodeAt (95-108)
  • cutUnicodeAt (95-95)
wled00/src/font/codepage437.cpp (2)
  • wchar16ToCodepage437 (17-234)
  • wchar16ToCodepage437 (17-17)
🪛 Clang (14.0.6)
wled00/wled_fonts.hpp

[error] 4-4: 'stdlib.h' file not found

(clang-diagnostic-error)

wled00/src/font/codepages.h

[error] 3-3: 'stdlib.h' file not found

(clang-diagnostic-error)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (19)
  • GitHub Check: Builds (esp32S3_4MB_PSRAM_S)
  • GitHub Check: Builds (esp32S3_16MB_PSRAM_M_HUB75)
  • GitHub Check: Builds (athom_music_esp32_4MB_M)
  • GitHub Check: Builds (esp01_1MB_S)
  • GitHub Check: Builds (esp8266_2MB_S)
  • GitHub Check: Builds (esp32c3dev_4MB_M)
  • GitHub Check: Builds (esp32c3dev_2MB_M)
  • GitHub Check: Builds (esp32s2_PSRAM_S)
  • GitHub Check: Builds (esp32_16MB_V4_M)
  • GitHub Check: Builds (seeed_esp32c3_4MB_S)
  • GitHub Check: Builds (esp32S3_8MB_PSRAM_M)
  • GitHub Check: Builds (esp32_4MB_V4_HUB75_forum)
  • GitHub Check: Builds (esp32S3_WROOM-2_M)
  • GitHub Check: Builds (esp32s2_PSRAM_M)
  • GitHub Check: Builds (esp32S3_4MB_PSRAM_M)
  • GitHub Check: Builds (esp32_4MB_PSRAM_S)
  • GitHub Check: Builds (esp32S3_16MB_PSRAM_M_HUB75)
  • GitHub Check: Builds (esp32S3_8MB_M)
  • GitHub Check: Builds (esp32S3_8MB_S)
🔇 Additional comments (7)
wled00/src/font/codepage437.cpp (1)

17-234: LGTM—Comprehensive CP437 mapping.

The function provides extensive Unicode-to-CP437 mappings covering dingbats, international text, box-drawing, Greek letters, and math symbols. The logic correctly handles pass-through for ASCII, validates special cases, and falls back to CP437_UNKNOWN (middle dot) for unmapped characters.

wled00/FX.cpp (6)

13-15: Conditional include for codepage support looks correct

The codepages.h include is properly guarded by WLED_ENABLE_FULL_FONTS, so it won’t impact non‑Unicode or ESP8266 builds and matches the rest of the FULL_FONTS plumbing.


6869-6874: Letter/byte counting is consistent with Unicode and non‑Unicode paths

  • numberOfChars = strlen(text) correctly reflects the post‑macro, possibly truncated UTF‑8 byte length.
  • numberOfLetters is numberOfChars on non‑FULL_FONTS (and ESP8266), and strlenUC(text) otherwise. Given text is limited to WLED_MAX_SEGNAME_LEN+1 and always NUL‑terminated, this stays small and safe.
  • Using numberOfLetters * letterWidth for scroll distance matches the visual width both in the ASCII and BMP‑Unicode cases.

6877-6883: Scroll offset and timing updates preserve behavior while tightening min delay

  • The offset update now uses numberOfLetters * letterWidth, which is correct for both ASCII and Unicode and keeps the modulo range bounded.
  • minDelay computed via max(0.75*FRAMETIME_FIXED, FRAMETIME) and the subsequent map2 keep the scroll step interval positive and in a sensible range; no underflow/overflow concerns with the current FRAMETIME constants.

6896-6915: ASCII vs Unicode drawing paths are wired correctly into drawText

  • The non‑FULL_FONTS path retains the per‑character drawCharacter loop and uses numberOfLetters == strlen(text), so behavior is unchanged for ASCII builds.
  • In the FULL_FONTS path, maxLen is deliberately reset to numberOfChars so Segment::drawText receives the actual UTF‑8 byte length after macro expansion, not the original SEGMENT.name length. That matches the new drawText contract and keeps decoding bounded to the text buffer.
  • Guarding the Unicode path with !defined(WLED_ENABLE_FULL_FONTS) || defined(ESP8266) ensures older/ESP8266 builds do not accidentally invoke the heavy Unicode machinery.

6918-6921: Optional blur for non‑overlay text is reasonable

The conditional blur (check3 && !overlay) is applied after text rendering and only when not in overlay mode, which avoids smearing overlay content while still letting users soften standalone text. No correctness issues here.


6925-6925: Mode metadata string aligns with new controls

The updated _data_FX_MODE_2DSCROLLTEXT descriptor adds the “Soft” flag and keeps parameter ordering consistent with the newly used check/custom fields, so JSON/UI parsing for 2D Scrolling Text should remain coherent.

* replace strlen with strnlen
* avoid static variable in getFontInfo
* remove legacy code in drawCharacter (new code works well)

it works for me, let's ship it ;-)
// special utility function for @troyhacks ;-)
// removes all unicode letter from a C style char[] - conversion is in-place, to avoid heap fragging
// doesn't work on PROGMEM strings, unless you strdup() them into RAM before calling this function
inline void killUnicode(unsigned char* utf8) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@coderabbitai this function is not tested yet, please verify it the logic is sound, assuming that utf8 is well-formed and resides in RAM.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# View the full implementation of killUnicode function in codepages.h
cat wled00/src/font/codepages.h | tail -n 10

Length of output: 453


@softhack007, I've verified the killUnicode() implementation and the logic is sound for its purpose. Here's my analysis:

✅ Correct behaviors:

  1. Null safety: Properly guards against nullptr input
  2. In-place filtering: Uses clean_index for writing and i for reading, safely compacting the string without additional memory allocation
  3. ASCII preservation: Correctly keeps bytes in range [1, 127]
  4. UTF-8 removal: All UTF-8 multi-byte sequences have bytes ≥ 128 (lead bytes 0xC0-0xFD and continuation bytes 0x80-0xBF), so they're correctly filtered out
  5. Null termination: Properly terminates the cleaned string at clean_index
  6. Edge cases: Handles empty strings, pure ASCII, and pure Unicode correctly

📝 Minor observation:

The condition (utf8[i] > 0) is redundant since the loop condition utf8[i] != '\0' already ensures the byte isn't zero. You could simplify to:

if (utf8[i] < 128) utf8[clean_index++] = utf8[i];

However, the redundancy is harmless and arguably makes the intent more explicit (keeping positive ASCII values).

✅ Verdict:

The implementation is correct and will reliably strip all non-ASCII bytes from a well-formed UTF-8 string in RAM, leaving only pure ASCII characters.


🧠 Learnings used
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR #270, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.

Learnt from: CR
Repo: MoonModules/WLED-MM PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-12T21:55:59.766Z
Learning: Applies to wled00/**/*.{cpp,h} : Use spaces (2 per level) for C++ firmware source and headers in wled00

Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR #270, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue #272; do not address it within PR #270.

Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-14T13:55:44.442Z
Learning: In MoonModules/WLED-MM, always flag Variable Length Arrays (VLA) during code reviews, especially when they could overflow available stack space (typically 2K-4K on ESP32/ESP8266). VLAs based on dynamic parameters like segment dimensions, particle counts, or pixel buffers should be highlighted and require justification from the author. Prefer fixed-size arrays, heap allocation, or bounded VLAs with explicit maximum size constraints.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@troyhacks enjoy :-)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

@softhack007 softhack007 merged commit cf99928 into mdev Nov 21, 2025
57 checks passed
@softhack007 softhack007 deleted the high_ascii branch November 21, 2025 16:45
@softhack007 softhack007 changed the title (WIP, POC) Full "high ASCII" support for scrolling text (POC) Full "high ASCII" support for scrolling text Dec 23, 2025
@softhack007 softhack007 added this to the 14.7.1 milestone Dec 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants