Skip to content

feat(v16): add voltage and current for battery, modules and charging HUD - #7496

Merged
pfeerick merged 13 commits into
EdgeTX:mainfrom
helloradiosky:hrs-v16-current_sensor
Oct 25, 2026
Merged

pfeerick merged 13 commits into
EdgeTX:mainfrom
helloradiosky:hrs-v16-current_sensor

Conversation

@helloradiosky

@helloradiosky helloradiosky commented Jun 24, 2026 •

Copy link
Copy Markdown
Contributor

Summary of changes

Target: HelloRadio V16 (Horus / V16_CHARGE_UI + CSD203_SENSOR)

  • Implemented CSD203 voltage and current sensor function module
  • Add CSD203 EMA-filtered getters for battery/module voltage and current
  • Add V16 charge dashboard UI with 2S SOC estimation and debounced USB charger detection
  • Show module sensor readings on the internal/external RF setup page
  • Keep shutdown path visible while charging

Note

New charge UI is triggered in two different manners:

  1. shortly after connecting power to the dedicated USB charge port while the radio is powered up, can be dismissed by pressing RTN
  2. when powering down the radio with power connected, where pressing RTN allows the radio to continue shutting down
image image image

Summary by CodeRabbit

  • New Features
    • Added a charging dashboard on supported hardware, including live SOC/charge indicators and a shutdown-safe “wait while charging” behavior.
    • Added module setup screen sensor lines for module voltage/current (when available).
    • Added new module sensor label translations (voltage/current) across multiple languages.
  • Bug Fixes
    • Improved CSD203 module sensor readings with smoothing/filtering and clamping for more stable voltage/current values overall.

@coderabbitai

coderabbitai Bot commented Jun 24, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds filtered CSD203 measurements and module sensor labels, then wires a Horus V16 charge dashboard into the main loop and shutdown path with a V16-specific build flag.

Changes

CSD203 Sensor Pipeline and Module Setup UI

Layer / File(s) Summary
CSD203 API and i18n strings
radio/src/targets/common/arm/stm32/csd203_sensor.h, radio/src/translations/string_list.h, radio/src/translations/sim_string_list.h, radio/src/translations/i18n/*.h
Declares CSD203 voltage and current getters and adds module sensor string keys plus per-language labels for voltage and current.
CSD203 filtering and getters
radio/src/targets/common/arm/stm32/csd203_sensor.cpp
Adds filtered measurement storage, EMA state and reset logic, raw conversion helpers, and updated read/getter paths.
Module sensor display
radio/src/gui/colorlcd/module/module_setup.cpp
Adds guarded CSD203 include, module sensor lines, and visibility updates when the module type changes.

V16 Charge UI Feature

Layer / File(s) Summary
Build flags and header
radio/src/targets/horus/CMakeLists.txt, radio/src/targets/horus/charge_ui.h
Enables the V16 charge UI build flag and declares the charge UI task and shutdown wait entry points.
Charge UI implementation
radio/src/targets/horus/charge_ui.cpp
Adds charger state helpers, dialog construction, refresh rendering, lifecycle handling, singleton task logic, and shutdown-wait flow.
Main loop and shutdown wiring
radio/src/main.cpp, radio/src/tasks.cpp
Includes the charge UI header in the main loop and calls the task and shutdown wait hooks from the GUI and shutdown paths.

Sequence Diagram(s)

sequenceDiagram
  participant perMain
  participant chargeUiTask
  participant shutdownWaitIfCharging
  participant ChargeDashboardDialog
  participant CSD203
  participant LVGL

  perMain->>chargeUiTask: chargeUiTask()
  chargeUiTask->>CSD203: readCSD203()
  chargeUiTask->>ChargeDashboardDialog: create/update dialog
  ChargeDashboardDialog->>CSD203: getBatteryVoltage(), getSystemCurrent()
  ChargeDashboardDialog->>LVGL: refresh widgets

  shutdownWaitIfCharging->>CSD203: readCSD203()
  shutdownWaitIfCharging->>LVGL: pump MainWindow
  shutdownWaitIfCharging->>ChargeDashboardDialog: open shutdown dialog
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested labels

enhancement ✨, hardware support

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 24.49% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies the V16 voltage/current sensor additions and charging HUD, which are the main changes in the pull request.
Description check ✅ Passed The description provides a detailed summary of the CSD203 sensor, charging HUD, module readings, and shutdown behavior. It is mostly complete despite omitting the template's Fixes # entry.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 11

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@radio/src/targets/common/arm/stm32/csd203_sensor.cpp`:
- Around line 537-562: Keep each CSD203 sensor’s current and VBUS voltage paired
to the same rail in the sensor update path. In the GetSenSorStep 1 and
GetSenSorStep 2 branches of csd203_sensor.cpp, update the assignments so
CSD203_InSensorCFG feeds both csd203IntModuleCurrent and the matching voltage
variable, and CSD203_ExtSensorCFG feeds both csd203ExtModuleCurrent and the
matching battery/module voltage variable. Make the mapping consistent inside the
csd203EmaI32/csd203Clamp* calls so the UI and charge logic read aligned
current/voltage values from the same sensor.

In `@radio/src/targets/horus/charge_ui.cpp`:
- Line 689: The shutdown hold in charge_ui.cpp is using
chargeChargerLedDebounced() as the blocking condition, which can stop waiting
before the USB cable is actually removed. Update the wait loop in the shutdown
flow to use chargeCableConnected() instead, and keep the
s_shutdownChargeForceQuit escape behavior intact so the UI only proceeds once
the cable is unplugged.
- Around line 493-500: Keep SOC smoothing in fixed-point precision instead of
truncating to whole percent in charge_ui.cpp. The current socDisplay_ update
inside the estimateSoc2s()/socFilterInit_ path drops fractional progress each
refresh, so preserve a scaled accumulator (for example, fixed-point state
alongside socDisplay_) and only convert to display units when needed. Update the
smoothing logic in the SOC filter block so small rawSoc changes still accumulate
smoothly rather than stalling until a larger jump occurs.

In `@radio/src/translations/i18n/cz.h`:
- Around line 718-719: The new sensor label constants in cz.h are still using
English literals, so update the TR_MODULE_SENSOR_VOLTAGE and
TR_MODULE_SENSOR_CURRENT definitions to proper Czech translations. Keep the
change localized in the Czech translation header and preserve the existing macro
names so the module setup UI uses translated labels consistently.

In `@radio/src/translations/i18n/da.h`:
- Around line 724-725: The new sensor labels in the Danish translation file are
still using English text, so update the TR_MODULE_SENSOR_VOLTAGE and
TR_MODULE_SENSOR_CURRENT entries in da.h to Danish terms consistent with the
rest of the locale. Use the existing translation pattern in this file to choose
the correct Danish equivalents for these sensor labels and keep the naming
aligned with the module sensor strings.

In `@radio/src/translations/i18n/he.h`:
- Around line 722-723: The new module sensor labels in he.h are still hardcoded
in English, causing mixed-language UI in the Hebrew locale. Update the
TR_MODULE_SENSOR_VOLTAGE and TR_MODULE_SENSOR_CURRENT definitions in the Hebrew
translation header to proper Hebrew text, matching the existing translation
style used by the other TR_MODULE_SENSOR_* entries.

In `@radio/src/translations/i18n/it.h`:
- Around line 719-720: The new sensor label strings in the Italian translation
header are still in English, so update the TR_MODULE_SENSOR_VOLTAGE and
TR_MODULE_SENSOR_CURRENT entries in the i18n locale definitions to proper
Italian user-facing text. Keep the existing symbol names unchanged and only
replace the string literals in the translation table so the module uses
localized labels consistently.

In `@radio/src/translations/i18n/nl.h`:
- Around line 716-717: The new sensor label definitions in the Dutch translation
header are still using English text, causing mixed-language UI in the nl locale.
Update the TR_MODULE_SENSOR_VOLTAGE and TR_MODULE_SENSOR_CURRENT string values
in the nl.h translation set to proper Dutch equivalents, matching the existing
localization style used by nearby sensor/module labels.

In `@radio/src/translations/i18n/pt.h`:
- Around line 719-720: The new sensor label strings in the Portuguese
translation header are still hardcoded in English, so update the
TR_MODULE_SENSOR_VOLTAGE and TR_MODULE_SENSOR_CURRENT entries in pt.h to proper
Portuguese equivalents to keep the UI localized and consistent with the other
TR_MODULE_SENSOR_* translations.

In `@radio/src/translations/i18n/ru.h`:
- Around line 721-722: The new sensor label entries in the Russian translation
header are still in English, so update the TR_MODULE_SENSOR_VOLTAGE and
TR_MODULE_SENSOR_CURRENT definitions in the ru.h translation set to proper
Russian text. Keep the change localized to the existing translation macros so
the Russian UI stays consistent with the rest of the locale strings.

In `@radio/src/translations/i18n/se.h`:
- Around line 719-720: The Swedish translation catalog still contains English
literals for the new module sensor labels, so update the
TR_MODULE_SENSOR_VOLTAGE and TR_MODULE_SENSOR_CURRENT entries in the se.h locale
file to proper Swedish text. Use the existing translation style in this header
and keep the new strings consistent with the other TR_MODULE_SENSOR_*
definitions so Swedish builds do not show mixed-language UI.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e5e6679e-b9ba-4432-901f-198d69646172

📥 Commits

Reviewing files that changed from the base of the PR and between 66463ec and d8ea4db.

📒 Files selected for processing (29)
  • radio/src/gui/colorlcd/module/module_setup.cpp
  • radio/src/main.cpp
  • radio/src/targets/common/arm/stm32/csd203_sensor.cpp
  • radio/src/targets/common/arm/stm32/csd203_sensor.h
  • radio/src/targets/horus/CMakeLists.txt
  • radio/src/targets/horus/charge_ui.cpp
  • radio/src/targets/horus/charge_ui.h
  • radio/src/tasks.cpp
  • radio/src/translations/i18n/cn.h
  • radio/src/translations/i18n/cz.h
  • radio/src/translations/i18n/da.h
  • radio/src/translations/i18n/de.h
  • radio/src/translations/i18n/en.h
  • radio/src/translations/i18n/es.h
  • radio/src/translations/i18n/fi.h
  • radio/src/translations/i18n/fr.h
  • radio/src/translations/i18n/he.h
  • radio/src/translations/i18n/it.h
  • radio/src/translations/i18n/jp.h
  • radio/src/translations/i18n/ko.h
  • radio/src/translations/i18n/nl.h
  • radio/src/translations/i18n/pl.h
  • radio/src/translations/i18n/pt.h
  • radio/src/translations/i18n/ru.h
  • radio/src/translations/i18n/se.h
  • radio/src/translations/i18n/tw.h
  • radio/src/translations/i18n/ua.h
  • radio/src/translations/sim_string_list.h
  • radio/src/translations/string_list.h

Comment thread radio/src/targets/common/arm/stm32/csd203_sensor.cpp Outdated
Comment thread radio/src/targets/horus/charge_ui.cpp Outdated
Comment thread radio/src/targets/horus/charge_ui.cpp Outdated
Comment thread radio/src/translations/i18n/cz.h Outdated
Comment thread radio/src/translations/i18n/da.h Outdated
Comment thread radio/src/translations/i18n/it.h Outdated
Comment thread radio/src/translations/i18n/nl.h Outdated
Comment thread radio/src/translations/i18n/pt.h Outdated
Comment thread radio/src/translations/i18n/ru.h Outdated
Comment thread radio/src/translations/i18n/se.h Outdated
@pfeerick pfeerick added hardware support enhancement ✨ New feature or request labels Aug 25, 2026
@pfeerick
pfeerick force-pushed the hrs-v16-current_sensor branch from d575cee to e0e870d Compare August 25, 2026 08:23
@pfeerick pfeerick changed the title hrs v16 added voltage and current sensor module feat(v16): add voltage and current for battery, modules and charging HUD Aug 25, 2026
@pfeerick pfeerick added this to the 3.0 milestone Oct 8, 2026
helloradiosky and others added 6 commits October 22, 2026 04:36
Collapse the six copy-pasted EMA filter-state variable pairs in
csd203_sensor.cpp into two small per-channel arrays, and move the
commented-out TRACE calls behind a new opt-in DEBUG_CSD203 guard
(matching the existing DEBUG_LATENCY pattern in heartbeat_driver.cpp)
instead of leaving them dead. Also drop the unused colText() helper
in charge_ui.cpp. No behavior change to sensor readings or the UI.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Use the existing weak per-radio hooks instead of V16_CHARGE_UI ifdefs in
main.cpp and tasks.cpp, matching how the HRS V15 target wires its charge UI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@pfeerick
pfeerick force-pushed the hrs-v16-current_sensor branch from e0e870d to 6aac430 Compare October 22, 2026 04:46
pfeerick and others added 7 commits October 22, 2026 09:47
Move cancelShutdownAnimation() from menusTask() into the V16 charge UI
shutdown wait, so other color radios' shutdown path is unchanged and the
sleep bitmap is cleared before the charge screen is shown.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
edgeTxClose() already removes the sleep bitmap and all windows via
MainWindow::shutdown(), so pumping LVGL before creating the shutdown
charge dialog (and after closing it) rendered the bare MainWindow
background for ~100-150ms.

Create the dialog before any LVGL refresh, after a short CSD203 poll to
replace readings left stale while I2C tasks were suspended. On exit,
draw the sleep bitmap over the dialog instead of exposing the empty
MainWindow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replace the ad hoc charger LED debounce, stable-on and off-tick logic
with a ChargeMonitor that tracks Idle, Detecting, Charging, Topping,
Full and NoCharge phases from VBUS, the charger STAT pin and battery
current. It owns the filtered readings and SOC smoothing, outlives the
dialog, and is ticked from customUIActions() and the shutdown loop, so
the runtime and shutdown HUDs share one state.

The runtime HUD now opens on plug-in showing "Detecting..." (current
bar neutral while the charger ramps up), shows once per plug-in, and
closes on unplug or shortly after Full/NoCharge.

Move the HUD text to translated strings (reusing BATTERYCHARGING and
BATTERYFULL), guarded by V16_CHARGE_UI, and give the RTN hint its own
line below the current strip. Regenerate LVGL fonts for the new glyphs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Top-right icon button on both charge HUDs, doing the same as RTN: close
on the runtime HUD, power off on the shutdown HUD (charging continues).
Uses LV_SYMBOL_CLOSE / LV_SYMBOL_POWER, so no new strings. Touch only;
removed from the key group so RTN remains the sole key action.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The charger STAT pin does not pulse during CV on V16, so Topping never
showed. Enter Topping when, for 2s, the pack reads >= 8.30V (also covers
a near-full pack starting straight in CV), or >= 8.25V with current
below 70% of the charge's peak (higher currents with more IR drop).

Voltage-based SOC reads ~99% well before termination and sags once the
radio runs from the pack again, so cap it at 99% while charging and
hold 100% when Full while the pack stays above 8.0V.

Lower the near-full threshold to 8.1V: a full pack under radio load
reads ~8.2V, which could show "Not charging" instead of "Battery full".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@pfeerick
pfeerick merged commit f84644b into EdgeTX:main Oct 25, 2026
47 checks passed
pfeerick added a commit that referenced this pull request Oct 25, 2026
#7496 added CSD203 module/system current and voltage readouts to the
module setup page and charge UI, but the getters only exist in the STM32
csd203_sensor driver, so the v16 WASM simulator failed to link.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants