Files
gronod 8f5b41ebba
ci / test (pull_request) Failing after 12s
ci / firmware (jc4827w543, sdkconfig.s3, esp32s3) (pull_request) Skipped
ci / firmware (wroom, sdkconfig.wroom, esp32) (pull_request) Skipped
ci / test (push) Failing after 12s
ci / firmware (jc4827w543, sdkconfig.s3, esp32s3) (push) Skipped
ci / firmware (wroom, sdkconfig.wroom, esp32) (push) Skipped
Add host tests for machine stop resume and complete
2026-09-16 11:58:06 +00:00

300 lines
9.0 KiB
C

#include "app_machine.h"
#include "app_process.h"
#include "hal_motor.h"
#include <stdio.h>
#include <string.h>
extern bool stub_motor_enabled;
extern int stub_stop_count;
extern int stub_agitate_start_count;
extern int stub_beep_count;
extern int stub_alarm_count;
extern int stub_alarm_cancel_count;
static int g_failures;
static void fail(const char *msg)
{
fprintf(stderr, "FAIL: %s\n", msg);
g_failures++;
}
static void expect_int(int got, int want, const char *msg)
{
if (got != want) {
fprintf(stderr, "FAIL: %s got=%d want=%d\n", msg, got, want);
g_failures++;
}
}
static void expect_u32(uint32_t got, uint32_t want, const char *msg)
{
if (got != want) {
fprintf(stderr, "FAIL: %s got=%u want=%u\n", msg, got, want);
g_failures++;
}
}
static void drain_events(void)
{
ui_evt_t ev;
while (app_machine_last_event(&ev) == 1) {
}
}
static int pop_ids(ui_evt_id_t *ids, int max)
{
int n = 0;
ui_evt_t ev;
while (n < max && app_machine_last_event(&ev) == 1) {
ids[n++] = ev.id;
}
return n;
}
static bool has_id(const ui_evt_id_t *ids, int n, ui_evt_id_t id)
{
for (int i = 0; i < n; i++) {
if (ids[i] == id) {
return true;
}
}
return false;
}
static ui_cmd_t cmd_select(uint8_t proc)
{
ui_cmd_t c;
memset(&c, 0, sizeof(c));
c.id = CMD_SELECT_PROCESS;
c.process_id = proc;
return c;
}
static ui_cmd_t cmd_arm(uint8_t step)
{
ui_cmd_t c;
memset(&c, 0, sizeof(c));
c.id = CMD_ARM_STEP;
c.step_index = step;
return c;
}
static ui_cmd_t cmd_start(uint8_t step)
{
ui_cmd_t c;
memset(&c, 0, sizeof(c));
c.id = CMD_START_STEP;
c.step_index = step;
return c;
}
static ui_cmd_t cmd_id(ui_cmd_id_t id)
{
ui_cmd_t c;
memset(&c, 0, sizeof(c));
c.id = id;
return c;
}
static void select_c41_step_view(void)
{
app_machine_init();
ui_cmd_t c = cmd_select(PROC_C41);
app_machine_handle_cmd(&c);
expect_int((int)app_machine_state(), ST_STEP_SELECT, "select_c41_step_view state");
expect_int((int)app_machine_process_id(), PROC_C41, "select_c41_step_view proc");
expect_int((int)app_machine_step_index(), 0, "select_c41_step_view step");
ui_evt_id_t ids[8];
int n = pop_ids(ids, 8);
if (!has_id(ids, n, EVT_PROCESS_SELECTED) || !has_id(ids, n, EVT_STEP_VIEW)) {
fail("select_c41_step_view events");
}
}
static void adjust_does_not_mutate_const(void)
{
app_machine_init();
ui_cmd_t c = cmd_select(PROC_C41);
app_machine_handle_cmd(&c);
ui_cmd_t adj;
memset(&adj, 0, sizeof(adj));
adj.id = CMD_ADJUST_STEP_TIME;
adj.time_delta_s = 5;
app_machine_handle_cmd(&adj);
const process_def_t *p = app_process_get(PROC_C41);
expect_int((int)p->steps[0].time_s, 180, "adjust_does_not_mutate_const const time");
expect_int((int)app_process_time_s(PROC_C41, 0), 185, "adjust_does_not_mutate_const overlay");
}
static void arm_start_complete_custom_10s(void)
{
app_machine_init();
ui_cmd_t c = cmd_select(PROC_CUSTOM);
app_machine_handle_cmd(&c);
ui_cmd_t arm = cmd_arm(0);
app_machine_handle_cmd(&arm);
expect_int((int)app_machine_state(), ST_ARMED, "custom arm state");
ui_cmd_t start = cmd_start(0);
app_machine_handle_cmd(&start);
expect_int((int)app_machine_state(), ST_RUNNING, "custom start state");
expect_int(stub_motor_enabled ? 1 : 0, 1, "custom motor on");
app_machine_tick(0);
expect_int((int)app_machine_state(), ST_RUNNING, "custom tick0");
app_machine_tick(9999);
expect_int((int)app_machine_state(), ST_RUNNING, "custom tick9999");
app_machine_tick(10000);
expect_int((int)app_machine_state(), ST_COMPLETE, "custom complete");
expect_int(stub_motor_enabled ? 1 : 0, 0, "custom motor off complete");
expect_int(stub_alarm_count >= 1 ? 1 : 0, 1, "custom alarm");
/* default auto_advance false */
app_machine_tick(10001);
expect_int((int)app_machine_state(), ST_COMPLETE, "auto_advance stays complete");
}
static void stop_disables_motor_and_resume(void)
{
app_machine_init();
ui_cmd_t c = cmd_select(PROC_CUSTOM);
app_machine_handle_cmd(&c);
ui_cmd_t arm = cmd_arm(0);
app_machine_handle_cmd(&arm);
ui_cmd_t start = cmd_start(0);
app_machine_handle_cmd(&start);
app_machine_tick(0);
app_machine_tick(1000);
int stops_before = stub_stop_count;
ui_cmd_t stop = cmd_id(CMD_STOP);
app_machine_handle_cmd(&stop);
expect_int((int)app_machine_state(), ST_STOPPED, "stop state");
expect_int(stub_motor_enabled ? 1 : 0, 0, "stop motor disabled");
expect_int(stub_stop_count >= stops_before + 1 ? 1 : 0, 1, "stop_count");
uint32_t rem = app_machine_remaining_ms();
if (rem < 8000 || rem > 10000) {
fprintf(stderr, "FAIL: remaining after stop got=%u\n", rem);
g_failures++;
}
int beeps = stub_beep_count;
ui_cmd_t resume = cmd_id(CMD_RESUME);
app_machine_handle_cmd(&resume);
expect_int((int)app_machine_state(), ST_RUNNING, "resume state");
expect_int(stub_beep_count >= beeps + 1 ? 1 : 0, 1, "resume beep");
app_machine_tick(1000);
app_machine_tick(1000 + rem);
expect_int((int)app_machine_state(), ST_COMPLETE, "resume then complete");
}
static void return_from_stopped(void)
{
app_machine_init();
ui_cmd_t c = cmd_select(PROC_CUSTOM);
app_machine_handle_cmd(&c);
ui_cmd_t arm = cmd_arm(0);
app_machine_handle_cmd(&arm);
ui_cmd_t start = cmd_start(0);
app_machine_handle_cmd(&start);
app_machine_tick(0);
app_machine_tick(1000);
ui_cmd_t stop = cmd_id(CMD_STOP);
app_machine_handle_cmd(&stop);
uint32_t rem = app_machine_remaining_ms();
ui_cmd_t ret = cmd_id(CMD_RETURN_TO_STEP_SELECT);
app_machine_handle_cmd(&ret);
expect_int((int)app_machine_state(), ST_STEP_SELECT, "return_from_stopped state");
uint16_t overlay = app_process_time_s(PROC_CUSTOM, 0);
uint16_t expect_s = (uint16_t)((rem + 999u) / 1000u);
expect_int((int)overlay, (int)expect_s, "return_from_stopped overlay");
expect_int((int)app_process_get(PROC_CUSTOM)->steps[0].time_s, 10, "const still 10");
}
static void stop_during_complete_cancels_alarm(void)
{
app_machine_init();
ui_cmd_t c = cmd_select(PROC_CUSTOM);
app_machine_handle_cmd(&c);
ui_cmd_t arm = cmd_arm(0);
app_machine_handle_cmd(&arm);
ui_cmd_t start = cmd_start(0);
app_machine_handle_cmd(&start);
app_machine_tick(0);
app_machine_tick(10000);
expect_int((int)app_machine_state(), ST_COMPLETE, "complete before stop");
int cancels = stub_alarm_cancel_count;
ui_cmd_t stop = cmd_id(CMD_STOP);
app_machine_handle_cmd(&stop);
expect_int((int)app_machine_state(), ST_STEP_SELECT, "stop from complete");
expect_int(stub_alarm_cancel_count >= cancels + 1 ? 1 : 0, 1, "alarm cancel");
}
static void ecn2_remjet_zero_time(void)
{
app_machine_init();
ui_cmd_t c = cmd_select(PROC_ECN2);
app_machine_handle_cmd(&c);
ui_cmd_t browse;
memset(&browse, 0, sizeof(browse));
browse.id = CMD_BROWSE_STEP;
browse.step_delta = 1;
app_machine_handle_cmd(&browse);
expect_int((int)app_machine_step_index(), 1, "remjet index");
ui_cmd_t arm = cmd_arm(1);
app_machine_handle_cmd(&arm);
int starts = stub_agitate_start_count;
ui_cmd_t start = cmd_start(1);
app_machine_handle_cmd(&start);
expect_int(stub_motor_enabled ? 1 : 0, 0, "remjet no enable");
expect_int(stub_agitate_start_count, starts, "remjet no agitate");
app_machine_tick(0);
expect_int((int)app_machine_state(), ST_COMPLETE, "remjet complete next tick");
}
static void stop_ignored_meaningless_in_idle(void)
{
app_machine_init();
int stops = stub_stop_count;
int enables = stub_motor_enabled ? 1 : 0;
ui_cmd_t stop = cmd_id(CMD_STOP);
app_machine_handle_cmd(&stop);
expect_int((int)app_machine_state(), ST_IDLE, "idle stays idle");
expect_int(stub_stop_count, stops, "idle no request_stop required");
(void)enables;
}
static void c41_clock(void)
{
app_machine_init();
ui_cmd_t c = cmd_select(PROC_C41);
app_machine_handle_cmd(&c);
ui_cmd_t arm = cmd_arm(0);
app_machine_handle_cmd(&arm);
ui_cmd_t start = cmd_start(0);
app_machine_handle_cmd(&start);
app_machine_tick(0);
expect_int((int)app_machine_state(), ST_RUNNING, "c41 tick0");
app_machine_tick(179999);
expect_int((int)app_machine_state(), ST_RUNNING, "c41 tick179999");
app_machine_tick(180000);
expect_int((int)app_machine_state(), ST_COMPLETE, "c41 tick180000");
}
int main(void)
{
select_c41_step_view();
adjust_does_not_mutate_const();
arm_start_complete_custom_10s();
stop_disables_motor_and_resume();
return_from_stopped();
stop_during_complete_cancels_alarm();
ecn2_remjet_zero_time();
stop_ignored_meaningless_in_idle();
c41_clock();
if (g_failures == 0) {
printf("test_machine: all assertions passed\n");
return 0;
}
fprintf(stderr, "test_machine: %d failure(s)\n", g_failures);
return 1;
}