The Tesla OBC hardware already publishes 9 temperature probes (3
modules × {tmp1, tmp2, tmpin}) on CAN 0x237/0x239/0x23B which the
teslacharger receives as c[123]tmp[12,in]. Until now none of these
were forwarded downstream — the Polarity VCU's STATUS_SCREEN OBC-temp
and DCDC-temp fields rendered 0 °C on OI-OBC cars.
This commit:
- Adds Param::tmpobcmax — derived value computed each Ms100Task tick
as the max across the 9 probes, skipping any that read -40 °C
(sensor absent / module not present).
- Maps it to 0x211 byte 7 (previously reserved, the last unused byte
of the 7-byte frame). Wire encoding uses the Tesla OBC convention
of offset 40 (wire = °C + 40), matching c[123]tmp* upstream so
receivers can decode with the same formula.
- Bumps VERSTR to -S5 so the right firmware is visually confirmable
in the OpenInverter web UI.
The new byte is purely additive — existing 0x211 consumers that read
only bytes 0-6 continue to work unchanged.
The Polarity VCU's 0x211 RX handler grows a corresponding decode +
display path in a paired stm32-hal-vcu commit.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
src/main.cpp:161:16: warning: cannot declare '::main' with a linkage
specification [-Wpedantic]
Long-standing upstream OpenInverter code (predates SKUDAK). C++ forbids
linkage specifications on main; with -pedantic in CPPFLAGS this fires
every build.
Confirmed safe to drop:
- libopencm3 vector.c:35 forward-declares int main(void) with default
linkage and invokes it at boot.
- Linker resolves main by symbol name, not by linkage attribute.
- stm32-sine has the same upstream issue; same fix applies if we ever
push upstream.
Bump VERSTR -S3 -> -S4 so the OI web UI version field shows the new
build. Verified in the built binary as "4=1.20.R-S4".
Build: clean, no compiler warnings (only the long-standing linker RWX
notice remains, unrelated).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pairs with stm32-hal-vcu PR #42. Adds a runtime "vcuchglim" param that
the VCU broadcasts every 200 ms; on receipt, the param's Change()
callback translates 20-100% to the charger's udcspnt (DC voltage
setpoint) using a linear cell-voltage ramp.
Without this, the teslacharger had no path for the user's app-set
charge limit to actually limit charging — udcspnt was effectively
a compile-time setpoint.
What's added
------------
- Param::vcuchglim in include/param_prj.h:
PARAM_ENTRY(CAT_CHARGER, vcuchglim, "%", 20, 100, 80, 23)
- Range 20-100 (matches VCU validation)
- Default 80% if VCU never connects
- ID 23 (next free per the comment, bumped to 24)
- Saveable so a flashed charger paired with a silent VCU still
behaves predictably across reboots
- can->AddRecv(Param::vcuchglim, 0x212, 0, 8, 1) registration in
ChargerCAN::MapMessages() — libopeninv's CanMap dispatches to the
Change() callback on each received frame.
- Param::Change(vcuchglim) handler in src/main.cpp:
cell_target = 3.30 + (4.15 - 3.30) * (pct - 20) / 80
udcspnt = cell_target * 96
Endpoints chosen to be safe across Tesla LDU / VW MEB / Volt2:
20% → 3.30 V/cell × 96 = 316.8 V (deep-cycle storage floor)
80% → 3.94 V/cell × 96 = 378.0 V (recommended daily ceiling)
100% → 4.15 V/cell × 96 = 398.4 V (matches existing udclim default)
Tuneable here as constants if a particular pack needs a tighter range.
- VER bump 1.19.R → 1.20.R. Combined with the pre-existing -S1 suffix
the OI web UI shows "4=1.20.R-S1", visually distinct from upstream
and from the previous Skudak build.
Build
-----
text=25288, links clean. The "RWX LOAD segment" linker warning is
pre-existing on this template, unrelated. No new warnings from this
change.
Version string in the binary verified as "4=1.20.R-S1".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Upstream openinverter bug surfaced after recent SKUDAK PRs.
Symptom (reported by Kyle on the bench): teslacharger detects EVSE,
shows the AC limit, but stays stuck in WaitStart and never proceeds
to Enable / Activate / Run. State machine looks like it's the OFF
state but it's actually one step further on.
Root cause in src/charger.cpp:85-91:
bool CheckDelay()
{
uint32_t now = rtc_get_counter_val();
uint32_t start = Param::GetInt(Param::timedly) * 60;
return start <= 0 || (now - startTime) > start;
}
With timedly = -1 (the param's documented "no delay" sentinel and its
default value), the math is:
Param::GetInt(timedly) -> -1 (signed int)
-1 * 60 -> -60 (signed)
assigned to uint32_t -> 0xFFFFFFC4 (~4.29 billion)
start <= 0 -> false (uint32_t can't be negative)
(now - startTime) > 4294967236 -> false for ~136 years
So CheckDelay() returns false forever; charger wedges in WaitStart.
Why "it was working before": every SKUDAK PR that bumped the param
table (uaux broadcast, expanded 0x210, 0x210->0x211, version suffix)
invalidates the saved-params CRC and resets timedly to its -1 default.
Kyle had a non-default value (probably 0) saved before.
Fix: signed math for the short-circuit so timedly <= 0 still means
"start immediately." Cast to uint32_t only on the right operand, which
is only evaluated when start > 0 — can't reinterpret negative as huge.
The companion CheckTimeout() at line 75 has the same uint32_t pattern
but works "correctly by accident" because timelim = -1 makes timeout
huge and (now - startTime) > timeout is false, which matches the
intended "no timeout" semantics. Leaving that alone — fixing it would
change behaviour, not bugs.
VER suffix bumped -S1 -> -S2 so the OI web UI clearly shows the
deployed firmware (post-fix). Confirmed in built binary as
"4=1.19.R-S2".
Build: text=25192, links clean, pre-existing pedantic warning unchanged.
This bug is also present upstream (johanneshuebner/stm32-charger);
worth a PR upstream once we've confirmed the fix on the bench.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The OpenInverter web UI displays the firmware version from the 'version'
parameter (entry 2001), which expands VERSTR. Out of the box this reads
'4=1.19.R' (upstream version, no Skudak indicator). With this change it
reads '4=1.19.R-S1' so we can visually confirm we're running the Skudak
fork and not stock OpenInverter firmware.
Matches the convention already used in stm32-sine ('-sine-S6' / '-foc-S6')
where the -S<N> suffix bumps on each Skudak-side change.
Verified: 'strings stm32_charger.bin | grep S1' shows '4=1.19.R-S1' in the
built artifact.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>