4 Commits
Author SHA1 Message Date
gronod adff1d963b Mark A01 status DONE
ci / test (push) Successful in 1m7s
ci / firmware (wroom, sdkconfig.wroom, esp32) (push) Successful in 4m0s
ci / firmware (jc4827w543, sdkconfig.s3, esp32s3) (push) Successful in 4m8s
2026-09-17 07:24:09 +01:00
gronod d84116c45b Replace machine event ring with FreeRTOS queue 2026-09-17 07:23:23 +01:00
gronod 1ade64b2b2 Fix step deadline to derive from real uptime 2026-09-17 07:22:57 +01:00
gronod 20535ceb14 Add FreeRTOS queue shim for host tests 2026-09-17 07:22:17 +01:00
8 changed files with 129 additions and 31 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
idf_component_register(SRCS "app_machine.c"
INCLUDE_DIRS "include"
REQUIRES ui_cmd app_process
PRIV_REQUIRES hal_motor hal_temp hal_audio)
PRIV_REQUIRES hal_motor hal_temp hal_audio freertos)
+23 -23
View File
@@ -1,3 +1,6 @@
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "app_machine.h"
#include "app_process.h"
#include "hal_motor.h"
@@ -5,6 +8,7 @@
#include "hal_audio.h"
#include <string.h>
#include <stddef.h>
#define AGITATE_RPM 60u
@@ -16,20 +20,13 @@ static uint32_t s_deadline_ms;
static bool s_have_deadline;
static bool s_resume_pending;
static bool s_auto_advance;
static ui_evt_t s_q[UI_EVT_QUEUE_LEN];
static uint8_t s_q_head;
static uint8_t s_q_tail;
static uint8_t s_q_count;
static QueueHandle_t s_evtq;
static void emit(ui_evt_t ev)
{
if (s_q_count == UI_EVT_QUEUE_LEN) {
s_q_head = (uint8_t)((s_q_head + 1u) % UI_EVT_QUEUE_LEN);
s_q_count--;
if (s_evtq != NULL) {
xQueueSend(s_evtq, &ev, 0);
}
s_q[s_q_tail] = ev;
s_q_tail = (uint8_t)((s_q_tail + 1u) % UI_EVT_QUEUE_LEN);
s_q_count++;
}
static void fill_common(ui_evt_t *ev)
@@ -122,14 +119,13 @@ static void enter_armed(void)
emit_id(EVT_STEP_ARMED);
}
static void start_running(uint32_t now_ms)
static void start_running(void)
{
const process_def_t *p = app_process_get(s_proc);
uint16_t t_s = app_process_time_s(s_proc, s_step);
s_remaining_ms = (uint32_t)t_s * 1000u;
s_deadline_ms = now_ms + s_remaining_ms;
s_have_deadline = true;
s_resume_pending = false;
s_have_deadline = false;
s_resume_pending = true;
if (t_s == 0 || p == NULL) {
hal_motor_enable(false);
@@ -199,9 +195,13 @@ void app_machine_init(void)
s_have_deadline = false;
s_resume_pending = false;
s_auto_advance = false;
s_q_head = 0;
s_q_tail = 0;
s_q_count = 0;
if (s_evtq == NULL) {
s_evtq = xQueueCreate(UI_EVT_QUEUE_LEN, sizeof(ui_evt_t));
} else {
xQueueReset(s_evtq);
}
app_process_init();
hal_motor_init();
hal_temp_init();
@@ -230,13 +230,13 @@ uint32_t app_machine_remaining_ms(void)
int app_machine_last_event(ui_evt_t *out)
{
if (s_q_count == 0 || out == NULL) {
if (s_evtq == NULL || out == NULL) {
return 0;
}
*out = s_q[s_q_head];
s_q_head = (uint8_t)((s_q_head + 1u) % UI_EVT_QUEUE_LEN);
s_q_count--;
return 1;
if (xQueueReceive(s_evtq, out, 0) == pdTRUE) {
return 1;
}
return 0;
}
void app_machine_on_temp(float c, bool ok)
@@ -336,7 +336,7 @@ void app_machine_handle_cmd(const ui_cmd_t *cmd)
enter_armed();
} else if (s_state == ST_ARMED) {
apply_step_index(cmd->step_index);
start_running(0);
start_running();
} else if (s_state == ST_COMPLETE) {
arm_or_next_from_complete();
}
+1 -1
View File
@@ -42,7 +42,7 @@ The branch was cut with uncommitted `components/app_machine/app_machine.c` chang
| ID | File | Session goal | STATUS |
| --- | --- | --- | --- |
| A00 | `audit/A00-docs.md` | Land audit doc + megaplan + phase files | DONE |
| A01 | `audit/A01-machine-timing-queue.md` | Deadline fix + FreeRTOS event queue + host queue shim | TODO |
| A01 | `audit/A01-machine-timing-queue.md` | Deadline fix + FreeRTOS event queue + host queue shim | DONE |
| A02 | `audit/A02-auto-advance.md` | Restore auto-arm after step complete + test rework | TODO |
| A03 | `audit/A03-task-wdt.md` | Explicit TWDT init/reconfigure + `add()` failure logging | TODO |
| A04 | `audit/A04-temp-nonblocking.md` | OPTIONAL: non-blocking DS18B20 conversion | TODO |
@@ -1,6 +1,6 @@
# A01 — app_machine deadline fix + FreeRTOS event queue + host queue shim
STATUS: TODO
STATUS: DONE
DEPENDS: A00
**READ:** this file, `docs/megaplans/AUDIT-MEGAPLAN.md`, `docs/audit_remediation_plan.md` items 1–2, `components/app_machine/app_machine.c`, `tests/host/CMakeLists.txt`
@@ -37,8 +37,8 @@ All green. Firmware builds run in CI on push.
Stage hunks per concern (`git add -p` or re-apply in order) — the dirty file combines all three changes plus the A02 flag.
**DoD checkboxes:**
- [ ] `start_running` takes no `now_ms`; deadline set on the first `RUNNING` tick.
- [ ] `emit`/`app_machine_last_event` go through `s_evtq`; `app_machine_init` creates or resets the queue.
- [ ] `s_auto_advance` still `false`.
- [ ] Host ctest green with zero test changes.
- [ ] STATUS → DONE here and in the megaplan table.
- [x] `start_running` takes no `now_ms`; deadline set on the first `RUNNING` tick.
- [x] `emit`/`app_machine_last_event` go through `s_evtq`; `app_machine_init` creates or resets the queue.
- [x] `s_auto_advance` still `false`.
- [x] Host ctest green with zero test changes.
- [x] STATUS → DONE here and in the megaplan table.
+1
View File
@@ -37,6 +37,7 @@ add_executable(test_machine
stubs/hal_motor.c
stubs/hal_temp.c
stubs/hal_audio.c
freertos/queue.c
)
target_include_directories(test_machine PRIVATE ${HOST_INCLUDES})
+14
View File
@@ -0,0 +1,14 @@
#pragma once
#include <stdint.h>
typedef long BaseType_t;
typedef unsigned long UBaseType_t;
typedef uint32_t TickType_t;
#define pdFALSE ((BaseType_t)0)
#define pdTRUE ((BaseType_t)1)
#define pdPASS pdTRUE
#define pdFAIL pdFALSE
#define pdMS_TO_TICKS(xTimeInMs) ((TickType_t)(xTimeInMs))
+72
View File
@@ -0,0 +1,72 @@
#include "freertos/queue.h"
#include <stdlib.h>
#include <string.h>
struct QueueDefinition {
UBaseType_t len;
UBaseType_t item_size;
UBaseType_t head;
UBaseType_t tail;
UBaseType_t count;
uint8_t *storage;
};
QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength, UBaseType_t uxItemSize)
{
struct QueueDefinition *q = calloc(1, sizeof(*q));
if (q == NULL) {
return NULL;
}
q->storage = malloc((size_t)uxQueueLength * uxItemSize);
if (q->storage == NULL) {
free(q);
return NULL;
}
q->len = uxQueueLength;
q->item_size = uxItemSize;
return q;
}
BaseType_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait)
{
(void)xTicksToWait;
if (xQueue == NULL || pvItemToQueue == NULL) {
return pdFALSE;
}
if (xQueue->count == xQueue->len) {
return pdFALSE;
}
memcpy(xQueue->storage + (size_t)xQueue->tail * xQueue->item_size,
pvItemToQueue, xQueue->item_size);
xQueue->tail = (xQueue->tail + 1u) % xQueue->len;
xQueue->count++;
return pdTRUE;
}
BaseType_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait)
{
(void)xTicksToWait;
if (xQueue == NULL || pvBuffer == NULL) {
return pdFALSE;
}
if (xQueue->count == 0u) {
return pdFALSE;
}
memcpy(pvBuffer, xQueue->storage + (size_t)xQueue->head * xQueue->item_size,
xQueue->item_size);
xQueue->head = (xQueue->head + 1u) % xQueue->len;
xQueue->count--;
return pdTRUE;
}
BaseType_t xQueueReset(QueueHandle_t xQueue)
{
if (xQueue == NULL) {
return pdFALSE;
}
xQueue->head = 0;
xQueue->tail = 0;
xQueue->count = 0;
return pdTRUE;
}
+11
View File
@@ -0,0 +1,11 @@
#pragma once
#include "freertos/FreeRTOS.h"
struct QueueDefinition;
typedef struct QueueDefinition *QueueHandle_t;
QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength, UBaseType_t uxItemSize);
BaseType_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait);
BaseType_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait);
BaseType_t xQueueReset(QueueHandle_t xQueue);