tooling: sync bench + debug console to live STM32 protocol
The mppt-testbench Python tooling had drifted from the flashed firmware
(bundled fw e7a23a3 vs live 1b85532) and could no longer communicate:
- stm32_link.py: CRC8 -> CRC-16/CCITT-FALSE; telemetry 68B -> 78B
(btemp, cmp_outer/inner, iout_slow, vfly_ofs_applied); add PTYPE_INT16
and commands 0x12-0x18; replace PARAMS with the current 37-param map
(single dt_normal, no dt brackets; test_corr/phase_ofs, phase PI,
precharge PI, duty dither; vfly_active 0-3).
- tuner.py: retire per-bracket deadtime; sweep the single dt_normal.
- cli.py: update tune-deadtime, help/examples, btemp readout;
default ports COM11 (load) / COM4 (stm32).
- debug console TUI: sync protocol.py/app.py/status_bar/telemetry_panel
from live (new command keys, link RX/TX/loss stats, single dead-time,
new telemetry fields, param-write auto-retry); add duty_fft.py.
- README: rewrite parameter table, deadtime section, ports, keybindings.
Verified: protocol round-trip self-tests + live `bench stm32-read`
reading all 37 params over COM4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -18,9 +18,10 @@ class TelemetryPanel(Static):
|
||||
|
||||
ALPHA = 0.05 # EMA filter coefficient
|
||||
|
||||
DT_BREAKPOINTS = [0, 3000, 5000, 10000, 20000, 30000, 45000]
|
||||
DT_DEFAULTS = [25, 20, 20, 20, 15, 15]
|
||||
DT_PARAM_IDS = [0x60, 0x61, 0x62, 0x63, 0x64, 0x65]
|
||||
MASTER_TICKS_MID = 7158 # s = 2*last_tmp - MASTER_TICKS_MID (edge-separation abscissa)
|
||||
# dead-time is a single static value now (dt_normal, 0x60); track it for display
|
||||
DT_IDS = {0x60}
|
||||
DT_DEFAULTS = {0x60: 20}
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Waiting for telemetry...")
|
||||
@@ -32,7 +33,11 @@ class TelemetryPanel(Static):
|
||||
self._vfly_f: float = 0.0
|
||||
self._seeded: bool = False
|
||||
self.filter_enabled: bool = True
|
||||
self._dt_values: list[int] = list(self.DT_DEFAULTS)
|
||||
self._dt_params: dict[int, float] = dict(self.DT_DEFAULTS)
|
||||
# Link stats, set by the app's 0.5 s status timer
|
||||
self.link_rx: float = 0.0
|
||||
self.link_tx: float | None = None
|
||||
self.link_loss: float = 0.0
|
||||
|
||||
def update_telemetry(self, t: TelemetryData):
|
||||
self._data = t
|
||||
@@ -65,15 +70,25 @@ class TelemetryPanel(Static):
|
||||
else:
|
||||
eta = 0.0
|
||||
|
||||
# Compute active deadtime from iout using same lookup as ISR
|
||||
active_dt = self._dt_values[0]
|
||||
for i in range(len(self.DT_BREAKPOINTS) - 1, -1, -1):
|
||||
if i_out >= self.DT_BREAKPOINTS[i]:
|
||||
active_dt = self._dt_values[min(i, len(self._dt_values) - 1)]
|
||||
break
|
||||
# Dead-time is a single static value (dt_normal), applied to both edges/timers.
|
||||
active_dt = self._dt_params.get(0x60, 20)
|
||||
|
||||
if self.link_tx is not None:
|
||||
if self.link_loss >= 5.0:
|
||||
loss_s = f"[red]{self.link_loss:.0f}%[/red]"
|
||||
else:
|
||||
loss_s = f"{self.link_loss:.0f}%"
|
||||
link_lines = [
|
||||
f" link rx : {self.link_rx:8.1f} Hz",
|
||||
f" link tx : {self.link_tx:8.1f} Hz",
|
||||
f" link loss : {loss_s}",
|
||||
]
|
||||
else:
|
||||
link_lines = [" link : measuring..."]
|
||||
|
||||
lines = [
|
||||
"[bold]MEASUREMENTS[/bold]",
|
||||
*link_lines,
|
||||
"",
|
||||
f" vin : {self._vin_f if self.filter_enabled else t.vin:8.0f} mV",
|
||||
f" vout : {self._vout_f if self.filter_enabled else t.vout:8.0f} mV",
|
||||
@@ -84,23 +99,28 @@ class TelemetryPanel(Static):
|
||||
f" EFF : {eta:8.1f} %" if p_in > 0.1 else " EFF : --- %",
|
||||
f" vfly : {self._vfly_f if self.filter_enabled else t.vfly:8.0f} mV",
|
||||
f" etemp : {t.etemp:8.1f} C",
|
||||
f" deadtime : {active_dt:8d} ticks",
|
||||
f" btemp : {t.btemp:8.1f} C",
|
||||
f" deadtime : {active_dt:8.1f} ticks",
|
||||
f" : {active_dt / 1.36:8.1f} ns",
|
||||
"",
|
||||
f" last_tmp : {t.last_tmp:8d}",
|
||||
f" s : {2 * t.last_tmp - self.MASTER_TICKS_MID:+8d} ({'D>0.5' if 2 * t.last_tmp >= self.MASTER_TICKS_MID else 'D<0.5'})",
|
||||
f" VREF : {t.VREF:8d}",
|
||||
f" vfly_corr : {t.vfly_correction:8d}",
|
||||
f" cmp_outer : {t.cmp_outer:8d} (F: T1/T4)",
|
||||
f" cmp_inner : {t.cmp_inner:8d} (E: T2/T3)",
|
||||
f" cmp_diff : {t.cmp_outer - t.cmp_inner:+8d}",
|
||||
f" phase_ofs : {t.vfly_ofs_applied:+8d} (applied)",
|
||||
"",
|
||||
f" vfly_int : {t.vfly_integral:10.3f}",
|
||||
f" vfly_avg : {t.vfly_avg_debug:10.1f}",
|
||||
f" cc.out_f : {t.cc_output_f:10.1f}",
|
||||
f" mppt.iref : {t.mppt_iref:8.0f} mA",
|
||||
f" mppt.vin : {t.mppt_last_vin:8.0f}",
|
||||
f" mppt.iin : {t.mppt_last_iin:8.0f}",
|
||||
f" mppt.duty : {t.mppt_iref:8.0f}",
|
||||
f" mppt.power: {t.mppt_last_vin:12.0f}",
|
||||
f" mppt.dir : {t.mppt_last_iin:4.0f}",
|
||||
]
|
||||
self.update("\n".join(lines))
|
||||
|
||||
def update_dt_param(self, param_id: int, value: float):
|
||||
if param_id in self.DT_PARAM_IDS:
|
||||
idx = self.DT_PARAM_IDS.index(param_id)
|
||||
self._dt_values[idx] = int(value)
|
||||
if param_id in self.DT_IDS:
|
||||
self._dt_params[param_id] = value
|
||||
|
||||
Reference in New Issue
Block a user