Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/lib/table-model.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ describe("buildTable", () => {
expect(placement("pos_error_counts")).toEqual(["Settings", "Safety"]);
expect(placement("sensor_bad_count")).toEqual(["Settings", "Safety"]);
expect(placement("cutoff_cc")).toEqual(["Settings", "Thermal"]);
expect(placement("rtherm_i_min_counts")).toEqual(["Settings", "Thermal"]);
});

test("id and baud are read-only with links; the deadline is editable", () => {
Expand Down Expand Up @@ -147,6 +146,7 @@ describe("buildTable", () => {
expect(placement("shunt_r_mohm")).toEqual(["Board", "Board constants"]);
expect(placement("v_window_min_ticks")).toEqual(["Board", "Board constants"]);
expect(placement("ntc_beta")).toEqual(["Board", "Board constants"]);
expect(placement("th_rise_q016")).toEqual(["Board", "Board constants"]);
expect(placement("vmotor_bias_nom_counts")).toEqual(["Board", "Board constants"]);
expect(rowOf("shunt_r_mohm").editable).toBe(false);
expect(rowOf("vdd_mv").editable).toBe(true);
Expand Down
3 changes: 1 addition & 2 deletions src/lib/table-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ const LOOP_VELOCITY = 0x038;
const LOOP_POSITION = 0x040;
const LIMITS = 0x048;
const THERMAL = 0x060;
const THERMAL_EXT = 0x06a;
const FUSION = 0x06e;
const FAULT_CFG = 0x074;
const MOTOR = 0x080;
Expand Down Expand Up @@ -119,7 +118,7 @@ const TABS: readonly TabSpec[] = [
},
// Fault thresholds are the other half of the stall and trip policy.
{ label: "Safety", help: true, blocks: [LIMITS, FAULT_CFG] },
{ label: "Thermal", help: true, collapsed: true, blocks: [THERMAL, THERMAL_EXT] },
{ label: "Thermal", help: true, collapsed: true, blocks: [THERMAL] },
],
},
{
Expand Down
8 changes: 2 additions & 6 deletions src/lib/thermal.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,12 @@ describe("therm_flags", () => {
[0, []],
[1 << 0, ["off"]],
[1 << 1, []],
[1 << 2, ["check cold R"]],
[1 << 2, []],
[1 << 3, []],
[1 << 4, []],
[1 << 5, []],
[1 << 6, []],
[1 << 7, []],
[(1 << 2) | (1 << 3), ["check cold R"]],
[0xff, ["off"]],
])("flags %i states %j", (flags, words) => {
expect(thermStates({ ...warm, flags }).map((s) => s.word)).toEqual(words);
Expand All @@ -65,10 +64,7 @@ describe("therm_flags", () => {
expect(thermStates({ ...hot, iLimCounts: 280 })).toEqual([]);
expect(thermStates({ ...hot, windingCc: 8000 })).toEqual([]);
expect(thermStates({ ...warm, iLimCounts: 60 })).toEqual([]);
expect(thermStates({ ...hot, flags: 1 << 2 }).map((s) => s.word)).toEqual([
"derating",
"check cold R",
]);
expect(thermStates({ ...hot, flags: 0xfe }).map((s) => s.word)).toEqual(["derating"]);
});
});

Expand Down
15 changes: 5 additions & 10 deletions src/lib/thermal.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
// The winding thermometer's telemetry (firmware core estimator/thermal.rs)
// The winding estimate's telemetry (firmware core estimator/thermal.rs)
// and the CONFIG thresholds the current limit derates against
// (kernel/limits.rs).

import type { ReadRegister } from "./units";

/** `t_winding_cc` while the thermometer is off (thermal.rs `UNSET_CC`). */
/** `t_winding_cc` while the estimate is unset (thermal.rs `UNSET_CC`). */
export const UNSET_CC = -32768;

/**
* `therm_flags` bits (thermal.rs `flag`); bit 1, TRACK (a same-seat reference
* is live), names no state, and bits 3-7 are reserved.
*/
/** `therm_flags` bit 0 (thermal.rs `flag`); bits 1-7 are reserved. */
const UNSET = 1 << 0;
const COLD_RECAL = 1 << 2;

export const THERMAL_REGISTERS: readonly string[] = [
"current_limit_counts",
Expand Down Expand Up @@ -53,7 +49,7 @@ export function celsius(cc: number): number {
return cc / 100;
}

/** The winding in C, NaN while the thermometer reads its sentinel. */
/** The winding in C, NaN while the estimate reads its sentinel. */
export function windingC(cc: number): number {
return cc === UNSET_CC ? NaN : celsius(cc);
}
Expand All @@ -70,7 +66,7 @@ export function thermOff(t: Thermal): boolean {
}

/**
* Off stands alone: an unset thermometer clears every other bit. Derating is
* Off stands alone: an unset estimate clears every other bit. Derating is
* the winding past derate_start with the limit actually folded under the
* configured one, so a stall yield alone never reads as heat.
*/
Expand All @@ -80,6 +76,5 @@ export function thermStates(t: Thermal): ThermState[] {
if (t.windingCc > t.derateStartCc && t.iLimCounts < t.currentLimitCounts) {
out.push({ word: "derating", level: "warn" });
}
if ((t.flags & COLD_RECAL) !== 0) out.push({ word: "check cold R", level: "notice" });
return out;
}
4 changes: 2 additions & 2 deletions src/lib/units.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,8 @@ test("degenerate calibration gives zero scale instead of infinity", () => {
expect(degToCounts(10, flat)).toBe(flat.rawMin);
});

// No firmware math to mirror: t_winding_cc comes from the winding-resistance
// thermometer, not from ntc_raw, so the divider plus beta lives only here.
// No firmware math to mirror: the firmware reads ntc_raw through the
// host-written quadratic in CALIB, so the divider plus beta lives only here.
test("temperatureC reads 25 C when the NTC equals its R25", () => {
expect(temperatureC(ADC_FULL_SCALE / 2, sense)).toBeCloseTo(25, 9);
});
Expand Down
2 changes: 1 addition & 1 deletion src/routes/table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const HELP: ReadonlyMap<string, string> = new Map([
"Gains of the current, velocity and position loops and the observer behind them.",
],
["Safety", "Trip thresholds and what the servo does when one is crossed."],
["Thermal", "The winding temperature model and its cutoff."],
["Thermal", "Derate and cutoff on the winding estimate."],
["Motor model", "Electrical and mechanical constants of the motor the estimators rely on."],
["Profile/capture", "Read profiles and the telemetry burst window."],
]);
Expand Down
4 changes: 2 additions & 2 deletions tests/e2e/winding.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { expect, test, type Page } from "@playwright/test";
import { gotoSim, openTable, tableRow } from "./helpers";

// The fake servo has no kernel: its thermometer registers hold what the
// table boots with, and CONFIG carries the firmware's default thresholds.
// The fake servo publishes the winding estimate as the kernel would, and
// CONFIG carries the firmware's default thresholds.
const THRESHOLDS = "Derate at 80.0 C, cutoff at 100.0 C, recover at 90.0 C";

function winding(page: Page) {
Expand Down
Loading