表驱法
参考:
D:\skill收集\embedded-project-scaffold\embedded-project-scaffold\SKILL.md
app_event.h
#ifndef APP_EVENT_H
#define APP_EVENT_H
typedef enum {
EVENT_NONE = 0,
EVENT_START,
EVENT_STOP,
EVENT_FAULT,
EVENT_MAX
} AppEvent;
#endifapp_message.h
#ifndef APP_MESSAGE_H
#define APP_MESSAGE_H
#include <stdint.h>
#define APP_MESSAGE_DATA_LEN 64U
typedef enum {
MSG_SRC_UART1 = 0,
MSG_SRC_CAN1_RX,
MSG_SRC_ADC_READY,
MSG_SRC_MAX
} MsgSource_t;
typedef struct {
MsgSource_t source_id;
uint16_t length;
uint8_t data[APP_MESSAGE_DATA_LEN];
} EventMessage_t;
#endifmsg_queue.h
#ifndef MSG_QUEUE_H
#define MSG_QUEUE_H
#include "app_message.h"
#define MSG_QUEUE_SIZE 8U
#define QUEUE_OK 0U
#define QUEUE_EMPTY 1U
#define QUEUE_FULL 2U
typedef struct {
EventMessage_t buffer[MSG_QUEUE_SIZE];
uint8_t head;
uint8_t tail;
uint8_t count;
} MsgQueue_t;
extern MsgQueue_t g_msgQueue;
void Queue_Init(MsgQueue_t *queue);
uint8_t Queue_Push(MsgQueue_t *queue, const EventMessage_t *msg);
uint8_t Queue_Pop(MsgQueue_t *queue, EventMessage_t *msg);
#endifmsg_queue.c
#include "msg_queue.h"
MsgQueue_t g_msgQueue;
void Queue_Init(MsgQueue_t *queue)
{
if (queue == NULL) {
return;
}
queue->head = 0U;
queue->tail = 0U;
queue->count = 0U;
}
uint8_t Queue_Push(MsgQueue_t *queue, const EventMessage_t *msg)
{
if ((queue == NULL) || (msg == NULL)) {
return QUEUE_FULL;
}
if (queue->count >= MSG_QUEUE_SIZE) {
return QUEUE_FULL;
}
queue->buffer[queue->head] = *msg;
queue->head = (uint8_t)((queue->head + 1U) % MSG_QUEUE_SIZE);
queue->count++;
return QUEUE_OK;
}
uint8_t Queue_Pop(MsgQueue_t *queue, EventMessage_t *msg)
{
if ((queue == NULL) || (msg == NULL)) {
return QUEUE_EMPTY;
}
if (queue->count == 0U) {
return QUEUE_EMPTY;
}
*msg = queue->buffer[queue->tail];
queue->tail = (uint8_t)((queue->tail + 1U) % MSG_QUEUE_SIZE);
queue->count--;
return QUEUE_OK;
}app_event_flag.h
#ifndef APP_EVENT_FLAG_H
#define APP_EVENT_FLAG_H
#include <stdint.h>
#define APP_EVENT_MESSAGE_READY 0x01U
void Set_EventFlag(uint32_t flag);
void Clear_EventFlag(uint32_t flag);
uint32_t Get_EventFlag(uint32_t flag);
#endifapp_event_flag.c
#include "app_event_flag.h"
static volatile uint32_t g_appEventFlags = 0U;
void Set_EventFlag(uint32_t flag)
{
g_appEventFlags |= flag;
}
void Clear_EventFlag(uint32_t flag)
{
g_appEventFlags &= ~flag;
}
uint32_t Get_EventFlag(uint32_t flag)
{
return (g_appEventFlags & flag);
}app_state.h
#ifndef APP_STATE_H
#define APP_STATE_H
#include "app_event.h"
#include "app_message.h"
typedef enum {
STATE_IDLE = 0,
STATE_RUNNING,
STATE_ERROR,
STATE_MAX
} AppState;
typedef void (*StateAction)(const EventMessage_t *msg);
typedef struct {
AppState current_state;
AppEvent event;
AppState next_state;
StateAction action;
} Transition;
void app_state_init(void);
void app_state_process_event(AppEvent event, const EventMessage_t *msg);
AppState app_state_get_current(void);
#endifapp_state.c
#include "app_state.h"
static void action_on_start(const EventMessage_t *msg);
static void action_on_stop(const EventMessage_t *msg);
static void action_on_fault(const EventMessage_t *msg);
static AppState g_currentState = STATE_IDLE;
static volatile uint8_t g_lastCommand = 0U;
static volatile MsgSource_t g_lastFaultSource = MSG_SRC_MAX;
static const Transition g_transitionTable[] = {
{ STATE_IDLE, EVENT_START, STATE_RUNNING, action_on_start },
{ STATE_RUNNING, EVENT_STOP, STATE_IDLE, action_on_stop },
{ STATE_RUNNING, EVENT_FAULT, STATE_ERROR, action_on_fault },
{ STATE_ERROR, EVENT_STOP, STATE_IDLE, action_on_stop },
};
void app_state_init(void)
{
g_currentState = STATE_IDLE;
}
void app_state_process_event(AppEvent event, const EventMessage_t *msg)
{
unsigned int i;
unsigned int tableSize = (unsigned int)(sizeof(g_transitionTable) / sizeof(g_transitionTable[0]));
for (i = 0U; i < tableSize; i++) {
if ((g_transitionTable[i].current_state == g_currentState) &&
(g_transitionTable[i].event == event)) {
g_currentState = g_transitionTable[i].next_state;
if (g_transitionTable[i].action != 0) {
g_transitionTable[i].action(msg);
}
return;
}
}
}
AppState app_state_get_current(void)
{
return g_currentState;
}
static void action_on_start(const EventMessage_t *msg)
{
if ((msg != 0) && (msg->length > 0U)) {
g_lastCommand = msg->data[0];
}
}
static void action_on_stop(const EventMessage_t *msg)
{
(void)msg;
g_lastCommand = 0U;
}
static void action_on_fault(const EventMessage_t *msg)
{
if (msg != 0) {
g_lastFaultSource = msg->source_id;
}
}msg_dispatcher.h
#ifndef MSG_DISPATCHER_H
#define MSG_DISPATCHER_H
#include "app_message.h"
typedef void (*MsgHandler_t)(const EventMessage_t *msg);
void msg_dispatcher_dispatch(const EventMessage_t *msg);
void do_read_message(void);
#endifmsg_dispatcher.c
#include "msg_dispatcher.h"
#include "app_state.h"
#include "msg_queue.h"
static void Parse_UART1_Data(const EventMessage_t *msg);
static void Parse_CAN1_Data(const EventMessage_t *msg);
static void Parse_ADC_Data(const EventMessage_t *msg);
static const MsgHandler_t HandlerTable[MSG_SRC_MAX] = {
[MSG_SRC_UART1] = Parse_UART1_Data,
[MSG_SRC_CAN1_RX] = Parse_CAN1_Data,
[MSG_SRC_ADC_READY] = Parse_ADC_Data,
};
void msg_dispatcher_dispatch(const EventMessage_t *msg)
{
if (msg == 0) {
return;
}
if ((msg->source_id < MSG_SRC_MAX) &&
(HandlerTable[msg->source_id] != 0)) {
HandlerTable[msg->source_id](msg);
}
}
void do_read_message(void)
{
EventMessage_t msg;
while (Queue_Pop(&g_msgQueue, &msg) == QUEUE_OK) {
msg_dispatcher_dispatch(&msg);
}
}
static void Parse_UART1_Data(const EventMessage_t *msg)
{
if ((msg == 0) || (msg->length == 0U)) {
return;
}
switch (msg->data[0]) {
case 0xA1U:
app_state_process_event(EVENT_START, msg);
break;
case 0xA2U:
app_state_process_event(EVENT_STOP, msg);
break;
default:
app_state_process_event(EVENT_FAULT, msg);
break;
}
}
static void Parse_CAN1_Data(const EventMessage_t *msg)
{
if ((msg == 0) || (msg->length == 0U)) {
return;
}
if (msg->data[0] == 0xE0U) {
app_state_process_event(EVENT_FAULT, msg);
}
}
static void Parse_ADC_Data(const EventMessage_t *msg)
{
uint16_t adcValue;
if ((msg == 0) || (msg->length < 2U)) {
return;
}
adcValue = (uint16_t)(((uint16_t)msg->data[0] << 8) | msg->data[1]);
if (adcValue > 3000U) {
app_state_process_event(EVENT_FAULT, msg);
}
}hal_uart.c
#include "app_event_flag.h"
#include "app_message.h"
#include "msg_queue.h"
uint16_t HAL_UART_Read(uint8_t *buffer, uint16_t maxLen);
void UART1_IRQHandler(void)
{
EventMessage_t msg;
msg.source_id = MSG_SRC_UART1;
msg.length = HAL_UART_Read(msg.data, APP_MESSAGE_DATA_LEN);
if (msg.length > 0U) {
if (Queue_Push(&g_msgQueue, &msg) == QUEUE_OK) {
Set_EventFlag(APP_EVENT_MESSAGE_READY);
}
}
}main.c
#include "app_event_flag.h"
#include "app_state.h"
#include "msg_dispatcher.h"
#include "msg_queue.h"
int main(void)
{
Queue_Init(&g_msgQueue);
app_state_init();
while (1) {
if (Get_EventFlag(APP_EVENT_MESSAGE_READY) != 0U) {
Clear_EventFlag(APP_EVENT_MESSAGE_READY);
do_read_message();
}
}
return 0;
}复制顺序
app_event.happ_message.hmsg_queue.hmsg_queue.capp_event_flag.happ_event_flag.capp_state.happ_state.cmsg_dispatcher.hmsg_dispatcher.chal_uart.cmain.c
这套模板怎么走
- 中断把原始数据读出来,封装成
EventMessage_t - 中断把消息压进
g_msgQueue - 中断置位
APP_EVENT_MESSAGE_READY - 主循环检测标志后调用
do_read_message() do_read_message()从队列取消息msg_dispatcher_dispatch()按source_id查HandlerTable- 对应的
Parse_XXX_Data()把原始数据翻译成EVENT_START / EVENT_STOP / EVENT_FAULT app_state_process_event()查g_transitionTable- 命中后执行带
msg参数的回调函数
关键点
- 信息处理能力来自这里:
typedef void (*StateAction)(const EventMessage_t *msg);不是 void (*action)(void)。
- 消息分发表在这里:
static const MsgHandler_t HandlerTable[MSG_SRC_MAX]- 状态转移表在这里:
static const Transition g_transitionTable[]新增一路外设时,只改这 4 处
app_message.h里给MsgSource_t加枚举项msg_dispatcher.c里新增一个Parse_XXX_Data()msg_dispatcher.c里给HandlerTable加一项- 对应外设 ISR 里按同样方式封装
EventMessage_t入队
新增一个状态事件时,只改这 3 处
app_event.h里加事件枚举app_state.c里新增动作函数app_state.c里给g_transitionTable加一行
一句话
表驱法要能处理信息,最关键的不是只有状态表,而是要把“消息结构体、消息队列、消息分发表、带消息参数的状态回调、中断入队、主循环出队”整套链路一起写完整。