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
300 lines
9.0 KiB
C
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;
|
|
}
|