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
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,17 @@ This project did not use formal release tags through most of its history, so thi

### Changed

- **The status LED shows amber on a firmware hold** (gen2). While a
command-watchdog trip or a latched heater fault holds the heaters off, the
LED is amber (red 50, green 16) instead of green; red still wins while the
e-stop is held, and the LED returns to green once the trip and faults are
cleared. It takes the colour from `bsc::StatusLed::stateFor()`. Requires
bread-slice-core `^0.2.0` (`firmware/platformio.ini` and `slice.yaml`).
The e-stop input keeps the internal pull-up.
Host-tested only: the amber value is worked from the WS2812B datasheet and
has not been seen on a board. Gen2 flash grows by 40 B and RAM by 1 B;
gen1, which has no LED, by 2 B of flash and 1 B of RAM from the core's
e-stop input.
- **The firmware README says which env fits a board** (#32). It links
the generation-to-env map in `docs/hardware-revisions.md` and says to
name the env when flashing, since a bare `pio run` builds `gen2_nano`.
Expand Down
2 changes: 1 addition & 1 deletion firmware/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ lib_deps =
cameronbrooks11/bread-crumbs-contracts @ ^0.11.1
br3ttb/PID @ ^1.2.1
https://github.com/adafruit/MAX6675-library.git
cameronbrooks11/bread-slice-core @ ^0.1.0
cameronbrooks11/bread-slice-core @ ^0.2.0
build_flags =
-DCRUMBS_MAX_HANDLERS=12
; override for flashed board address:
Expand Down
12 changes: 7 additions & 5 deletions firmware/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -471,14 +471,16 @@ void setupRLHT()
timing.relay2Start = millis();
}

// Red while the e-stop is held, green otherwise; StatusLed writes only on a
// change. Called from loop() only. The boot wait in setup() polls the e-stop
// too, and when that wrote the LED, its first pass replaced the boot blue
// within microseconds.
// Red while the e-stop is held, amber while a command-watchdog trip or a
// latched heater fault holds the heaters off (the hold relayControlLogic and
// checkHeaterFaults apply), green otherwise; red wins over amber. StatusLed
// writes only on a change. Called from loop() only. The boot wait in setup()
// polls the e-stop too, and when that wrote the LED, its first pass replaced
// the boot blue within microseconds.
void updateStatusLed()
{
#if RLHT_HAS_STATUS_LED
statusLed.set(estopInput.asserted() ? bsc::StatusLed::EStop : bsc::StatusLed::Running);
statusLed.set(bsc::StatusLed::stateFor(estopInput.asserted(), commandWatchdog.tripped() || heaterFaults != 0));
#endif
}

Expand Down
2 changes: 1 addition & 1 deletion firmware/test/host/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ FW_SRC := $(wildcard $(FW)/src/*.cpp) $(PIDLIB)/PID_v1.cpp $(wildcard $(CORE)/
CRUMBS_OBJ := $(OUT)/crumbs_core.o $(OUT)/crumbs_crc.o $(OUT)/crc8_nibble.o
# test_status_led runs once per e-stop case (the test target); the others
# run once.
SINGLE := test_dispatch test_estop_hold test_watchdog_trip test_serial_burst test_serial_numbers test_set_pid_length test_setpoint_limits test_heater_faults test_watchdog_lease test_pid_sample test_tc_select
SINGLE := test_dispatch test_estop_hold test_watchdog_trip test_serial_burst test_serial_numbers test_set_pid_length test_setpoint_limits test_heater_faults test_watchdog_lease test_pid_sample test_tc_select test_status_led_hold
TESTS := $(SINGLE) test_status_led

.PHONY: all test clean check-libdeps FORCE
Expand Down
1 change: 1 addition & 0 deletions firmware/test/host/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ the board. `make` exits non-zero if any check fails.
| `test_tc_select.cpp` | A heater's thermocouple select can't change while it heats in closed loop: SET_TC_SELECT is refused `WRONG_MODE` for that channel and applies the other, resending the select in force is applied, serial `R1TC=` is ignored; with the setpoint at 0 it changes, and the heater restarts on the new sensor with no derivative kick and no P term carried over (#54). The serial status line shows the selected reading in open loop (#28) |
| `test_set_pid_length.cpp` | SET_PID takes 6 bytes (u8 x10) and 12 bytes (u16 x1000, up to 65.535, `RLHT_CAP_PID_X1000`); 5, 7, 11 and 13 bytes are refused `MALFORMED` and change no gain (#50, bread-crumbs-contracts#64) |
| `test_status_led.cpp` | Blue through the boot wait, then green or red on the first `loop()` pass, with the e-stop released or held from power-up; no LED driven on gen1 (#46) |
| `test_status_led_hold.cpp` | Amber while a command-watchdog trip or a latched heater fault holds the heaters off, red over amber while the e-stop is held, amber again on the release while the hold stays latched, and green once it is cleared; no LED driven on gen1 |

## Writing a test

Expand Down
108 changes: 108 additions & 0 deletions firmware/test/host/test_status_led_hold.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// The status LED through a firmware hold: amber while a command-watchdog trip
// or a latched heater fault holds the heaters off, red over amber while the
// e-stop is held, amber again on the release while the hold stays latched,
// and green once it is cleared. Gen1 boards have no LED, and their firmware
// must never drive one.
#include "host.h"
#include "globals.h"
#include <bread/rlht_ops.h>
#include <bsc_status_led.h>

void setup();
void loop();

// The last frame the core's StatusLed sent, in GRB order (BSC_HOST_TEST
// records it instead of sending it).
static bool shown(uint8_t g, uint8_t r, uint8_t b)
{
return bsc_host_led_writes > 0 && bsc_host_led_frame[0] == g && bsc_host_led_frame[1] == r &&
bsc_host_led_frame[2] == b;
}

static bool green() { return shown(25, 0, 0); }
static bool red() { return shown(0, 50, 0); }
static bool amber() { return shown(16, 50, 0); }

static void arm(uint16_t ms)
{
const uint8_t d[2] = {(uint8_t)(ms & 0xFF), (uint8_t)(ms >> 8)};
host_send(RLHT_TYPE_ID, BREAD_OP_SET_WATCHDOG, d, 2);
(void)host_read_ack();
}

static void press()
{
host_estop_level = LOW;
loop();
}

// Past the core's 25 ms release debounce.
static void release()
{
host_estop_level = HIGH;
loop();
host_now += 30;
loop();
loop();
}

static void check(const char *what, bool led_ok)
{
#if RLHT_HAS_STATUS_LED
host_check(what, led_ok);
#else
(void)what;
(void)led_ok;
#endif
}

int main()
{
host_estop_level = HIGH;
host_tc1_celsius = 25.0f;
host_tc2_celsius = 25.0f;
setup();
loop();
check("running shows green", green());

// ---- A command-watchdog trip.
arm(100);
host_now += 100;
loop(); // trips
loop(); // shows it
check("a watchdog trip shows amber", commandWatchdog.tripped() && amber());
press();
check("an e-stop over a watchdog trip shows red", red());
release();
check("the release with the trip latched shows amber", commandWatchdog.tripped() && amber());
arm(0);
host_send(RLHT_TYPE_ID, BREAD_OP_CLEAR_WATCHDOG_TRIP, nullptr, 0);
(void)host_read_ack();
loop();
check("clearing the trip shows green", !commandWatchdog.tripped() && green());

// ---- A latched heater fault (an over-temperature, which latches in
// either mode).
host_tc1_celsius = RLHT_OVERTEMP_C + 5.0f;
for (int i = 0; i < RLHT_OVERTEMP_READS; i++)
{
host_now += THERMO_UPDATE_TIME_MS;
loop();
}
loop();
check("a latched heater fault shows amber", heaterFaults != 0 && amber());
press();
check("an e-stop over a latched fault shows red", red());
release();
check("the release with the fault latched shows amber", heaterFaults != 0 && amber());
host_tc1_celsius = 25.0f;
host_send(RLHT_TYPE_ID, BREAD_OP_CLEAR_FAULTS, nullptr, 0);
(void)host_read_ack();
loop();
check("clearing the fault shows green", heaterFaults == 0 && green());

#if !RLHT_HAS_STATUS_LED
host_check("no LED is driven on a board without one", bsc_host_led_writes == 0);
#endif
return host_finish();
}
2 changes: 1 addition & 1 deletion slice.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ firmware:
- "gen1_nanoevery"
- "gen2_nanoevery"
lib_deps:
- "cameronbrooks11/bread-slice-core @ ^0.1.0"
- "cameronbrooks11/bread-slice-core @ ^0.2.0"
- "cameronbrooks11/CRUMBS @ ^0.17.0"
- "cameronbrooks11/bread-crumbs-contracts @ ^0.11.1"
- "br3ttb/PID @ ^1.2.1"
Expand Down
Loading