Files
AutoFilm-ESP32/main/main.c
gronod 32af44a702
ci / test (pull_request) Successful in 1m22s
ci / firmware (wroom, sdkconfig.wroom, esp32) (pull_request) Failing after 33s
ci / firmware (jc4827w543, sdkconfig.s3, esp32s3) (pull_request) Failing after 37s
ci / test (push) Successful in 1m19s
ci / firmware (wroom, sdkconfig.wroom, esp32) (push) Failing after 30s
ci / firmware (jc4827w543, sdkconfig.s3, esp32s3) (push) Failing after 32s
Drop espressif/arduino-esp32 from IDF firmware
2026-09-16 14:34:25 +00:00

220 lines
5.5 KiB
C

#include "board.h"
#include "app_process.h"
#include "app_machine.h"
#include "app_ui.h"
#include "hal_motor.h"
#include "hal_temp.h"
#include "hal_audio.h"
#include "hal_display.h"
#include "hal_input.h"
#include "ui_cmd.h"
#include <string.h>
#include <stdbool.h>
#include "esp_log.h"
#include "esp_timer.h"
#include "esp_task_wdt.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#ifndef AUTOFILM_GIT_DESC
#define AUTOFILM_GIT_DESC "dev"
#endif
static const char *TAG = "app";
#if defined(AUTOFILM_BOARD_WROOM) || defined(AUTOFILM_BOARD_S3)
static QueueHandle_t s_cmdq;
extern void autofilm_temp_tick(void);
static void map_and_post_key(char key)
{
ui_cmd_t cmd;
memset(&cmd, 0, sizeof(cmd));
machine_state_t st = app_machine_state();
if (key >= '1' && key <= '6') {
cmd.id = CMD_SELECT_PROCESS;
cmd.process_id = (uint8_t)(key - '1');
xQueueSend(s_cmdq, &cmd, 0);
return;
}
switch (key) {
case 'U':
cmd.id = CMD_BROWSE_STEP;
cmd.step_delta = -1;
break;
case 'D':
cmd.id = CMD_BROWSE_STEP;
cmd.step_delta = 1;
break;
case 'L':
cmd.id = CMD_ADJUST_STEP_TIME;
cmd.time_delta_s = -5;
break;
case 'R':
cmd.id = CMD_ADJUST_STEP_TIME;
cmd.time_delta_s = 5;
break;
case 'E':
if (st == ST_STEP_SELECT) {
cmd.id = CMD_ARM_STEP;
cmd.step_index = app_machine_step_index();
} else if (st == ST_ARMED) {
cmd.id = CMD_START_STEP;
} else if (st == ST_STOPPED) {
cmd.id = CMD_RESUME;
} else if (st == ST_COMPLETE) {
cmd.id = CMD_ARM_STEP;
cmd.step_index = app_machine_step_index();
} else {
return;
}
break;
case 'X':
if (st == ST_ARMED) {
cmd.id = CMD_CANCEL_ARMED;
} else if (st == ST_RUNNING) {
/* Dual-path stop: EN-off in this task, then CMD_STOP. */
hal_motor_request_stop();
cmd.id = CMD_STOP;
} else if (st == ST_COMPLETE) {
cmd.id = CMD_STOP;
} else if (st == ST_STOPPED) {
cmd.id = CMD_RETURN_TO_STEP_SELECT;
} else {
return; /* ignore IDLE */
}
break;
default:
return;
}
xQueueSend(s_cmdq, &cmd, 0);
}
static void input_task(void *arg)
{
(void)arg;
esp_task_wdt_add(NULL);
const TickType_t period = pdMS_TO_TICKS(40); /* 25 Hz */
for (;;) {
ui_raw_key_t raw;
while (hal_input_pop_key(&raw)) {
map_and_post_key(raw.key);
}
ui_raw_touch_t touch;
while (hal_input_pop_touch(&touch)) {
char key;
if (app_ui_touch_to_key(touch.x, touch.y, &key)) {
map_and_post_key(key);
}
}
esp_task_wdt_reset();
vTaskDelay(period);
}
}
static void machine_task(void *arg)
{
(void)arg;
esp_task_wdt_add(NULL);
const TickType_t period = pdMS_TO_TICKS(20); /* 50 Hz */
for (;;) {
ui_cmd_t cmd;
while (xQueueReceive(s_cmdq, &cmd, 0) == pdTRUE) {
app_machine_handle_cmd(&cmd);
}
uint32_t now_ms = (uint32_t)(esp_timer_get_time() / 1000ULL);
app_machine_tick(now_ms);
esp_task_wdt_reset();
vTaskDelay(period);
}
}
static void ui_task(void *arg)
{
(void)arg;
esp_task_wdt_add(NULL);
hal_display_clear();
hal_display_text(0, 0, "AUTOFILM");
hal_display_text(0, 1, AUTOFILM_GIT_DESC);
vTaskDelay(pdMS_TO_TICKS(1000));
app_ui_init();
app_ui_draw();
const TickType_t period = pdMS_TO_TICKS(25);
for (;;) {
ui_evt_t ev;
while (app_machine_last_event(&ev) == 1) {
app_ui_on_event(&ev);
}
/* Running remaining is read from the machine on each draw (>=4 Hz). */
if (app_ui_is_dirty() || app_machine_state() == ST_RUNNING) {
app_ui_draw();
}
esp_task_wdt_reset();
vTaskDelay(period);
}
}
static void temp_task(void *arg)
{
(void)arg;
esp_task_wdt_add(NULL);
for (;;) {
#ifdef AUTOFILM_BOARD_WROOM
autofilm_temp_tick();
#endif
float c = 0.0f;
bool ok = (hal_temp_read_c(&c) == ESP_OK);
app_machine_on_temp(ok ? c : 0.0f, ok);
esp_task_wdt_reset();
}
}
#endif
void app_main(void)
{
ESP_LOGI(TAG, "board=%s desc=%s", board_name(), AUTOFILM_GIT_DESC);
gpio_num_t en_pin = board_pin_motor_en();
if (en_pin != GPIO_NUM_NC) {
gpio_config_t io = {
.pin_bit_mask = 1ULL << en_pin,
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
};
gpio_config(&io);
gpio_set_level(en_pin, board_motor_en_disable_level());
}
app_process_init();
hal_motor_init();
hal_temp_init();
hal_audio_init();
app_machine_init();
#if defined(AUTOFILM_BOARD_WROOM) || defined(AUTOFILM_BOARD_S3)
hal_display_init();
hal_input_init();
app_ui_init();
s_cmdq = xQueueCreate(UI_CMD_QUEUE_LEN, sizeof(ui_cmd_t));
xTaskCreate(temp_task, "temp", 4096, NULL, 2, NULL);
xTaskCreate(input_task, "input", 3072, NULL, 8, NULL);
xTaskCreate(machine_task, "machine", 4096, NULL, 6, NULL);
xTaskCreate(ui_task, "ui", 4096, NULL, 4, NULL);
#endif
/* app_main returns; scheduler keeps product tasks. No legacy startingMenu. */
}