基于函数模板的状态机
模板
模板代码在 BaseFSM.h和BaseFSM.c中
#ifndef _CANFSM_H
#define _CANFSM_H
#include"../../BasicType.h"
#ifdef APP_ACTDISCHARGE_C
#define APP_ACTDISCHARGE_EXTERN
#else
#define APP_ACTDISCHARGE_EXTERN extern
#endif
typedef struct TimerNode{
BOOL Flag;
uint16_t Counter;
uint16_t Threshold;
}TimerNode; //定时节点,定义定时计数阈值和标志
typedef struct
{
TimerNode Task_1ms;
TimerNode Task_10ms;
TimerNode Task_100ms;
TimerNode Task_200ms;
TimerNode Task_500ms;
TimerNode Task_1000ms;
}TASK_FLAG; //定时结构体
typedef struct StateCDT
{
void(*taskExe_handler)(void); //执行函数体,全速执行
void(*timeTick_handler)(TASK_FLAG *); //执行函数,定时执行
void(*enterEventHandler)(const struct StateCDT *); //入口函数,使能时进入状态执行
void(*exitEventHandler)(const struct StateCDT *); //出口函数,使能时跳出状态执行
} StateCDT;
typedef const struct StateCDT *State;
APP_ACTDISCHARGE_EXTERN State CurState; //表示当前状态的变量
void State_TransitionTo(State state, //状态转移函数,参数是转移到的新状态,是否使能入口函数,是否使能出口函数
BOOL desStateEnterEventEnable,
BOOL currentStateExitEventEnable);
#endif
在BaseFSM.c中只需要实现State_TransitionTo函数体
#define APP_ACTDISCHARGE_C
#include "../inc/BaseFSM.h"
void State_TransitionTo(State state,
BOOL desStateEnterEventEnable,
BOOL currentStateExitEventEnable)
{
State temp;
if (CurState == state)
{
return;
}
temp = CurState;
if (currentStateExitEventEnable)
{
(CurState->exitEventHandler)(state);
}
CurState = state;
if (desStateEnterEventEnable)
{
(CurState->enterEventHandler)(temp);
}
}
顶层调度代码
顶层代码提供调用和初始化接口
StateTop.h
#ifndef STATE_TOP_H
#define STATE_TOP_H
#include "BaseFSM.h"
extern const StateCDT State_Top;
void StateInit();
#endif
StateTop.c
#include "../inc/StateTop.h"
#include "../inc/Trace.h" //包含子状态
void StateInit()
{
CurState = &Trace; //定义初始状态
}
static void _taskExe(void)
{
CurState->taskExe_handler(); //执行全速任务
}
static void _timeTick(TASK_FLAG *tm)
{
CurState->timeTick_handler(tm); //执行定时任务
}
static void _enterEventDeal(State lastSta)
{
}
static void _exitEventDeal(State targetSta)
{
}
const struct StateCDT State_Top =
{
_taskExe,
_timeTick,
_enterEventDeal,
_exitEventDeal
};
子状态
子状态是一组独立的.h和.c代码基于函数模板,在其中实现具体的业务代码,举例
子状态Trace
Trace.h
#ifndef __CANTRACE__H
#define __CANTRACE__H
#include "BaseFSM.h"
extern const StateCDT Trace;
#endif
Trace.c
#include "../inc/Trace.h"
#include "../inc/NewState.h"
static uint32_t i = 0;
static void _timeTick(TASK_FLAG *tm)
{
if (tm->Task_10ms.Flag == TRUE)
{
printf("TraceThread:%d\n", i++);
tm->Task_10ms.Flag = FALSE;
}
}
static void _taskExe(void)
{
if (i >= 100)
{
State_TransitionTo(&NewState, FALSE, FALSE); //这里模拟了一个跳转条件,i加到100时跳转到新的子状态NewState
i = 0;
}
}
static void _enterEventDeal(State lastState)
{
}
static void _exitEventDeal(State targetState)
{
}
const struct StateCDT Trace =
{
_taskExe,
_timeTick,
_enterEventDeal,
_exitEventDeal
};
实际调用
在实际调用中需要在定时器中对定时结构体中的计数值累加和赋触发标志,进入主循环前初始化状态机,主循环中运行State_Top.timeTick_handler和State_Top.taskExe_handler句柄函数即可
#include <stdio.h>
#include "../../inc/BaseFSM.h"
#include <Windows.h>
#include <process.h>
#include <string.h>
#include "../../inc/StateTop.h"
/* 线程函数声明 */
void TimerThread(void*);
void Thread2(void*);
/* 线程句柄 */
HANDLE h1;
HANDLE g_Mutex; //互斥锁
/* 线程共享内存 */
volatile TASK_FLAG Flags;
/* 主线程 */
int main()
{
static int i = 0;
/* 初始化定时器结构体*/
memset(&Flags, 0, sizeof(Flags));
Flags.Task_1ms.Threshold = 1;
Flags.Task_10ms.Threshold = 10;
Flags.Task_100ms.Threshold = 100;
Flags.Task_200ms.Threshold = 200;
Flags.Task_500ms.Threshold = 500;
Flags.Task_1000ms.Threshold = 1000;
StateInit(); //初始化状态机
/* 创建线程 */
g_Mutex = CreateMutex(NULL, FALSE, NULL);
h1 = (HANDLE)_beginthread(TimerThread, 0, NULL);//定时线程
while (1)
{
WaitForSingleObject(g_Mutex, INFINITE); //等待互斥量触发
State_Top.timeTick_handler(&Flags);
State_Top.taskExe_handler();
ReleaseMutex(g_Mutex); // 触发互斥量
}
WaitForSingleObject(h1, INFINITE);//等待线程1结束
printf("主线程结束\n");
return 0;
}
/* 定时线程,模拟定时中断 */
void TimerThread(void* arg)
{
static uint64_t i = 0;
while (1)
{
WaitForSingleObject(g_Mutex, INFINITE); //等待互斥量触发
Flags.Task_1ms.Counter++;
Flags.Task_10ms.Counter++;
Flags.Task_100ms.Counter++;
Flags.Task_200ms.Counter++;
Flags.Task_500ms.Counter++;
Flags.Task_1000ms.Counter++;
if (Flags.Task_1ms.Counter >= Flags.Task_1ms.Threshold)
{
Flags.Task_1ms.Counter = 0;
Flags.Task_1ms.Flag = TRUE;
}
if (Flags.Task_10ms.Counter >= Flags.Task_10ms.Threshold)
{
Flags.Task_10ms.Counter = 0;
Flags.Task_10ms.Flag = TRUE;
}
if (Flags.Task_100ms.Counter >= Flags.Task_100ms.Threshold)
{
Flags.Task_100ms.Counter = 0;
Flags.Task_100ms.Flag = TRUE;
}
if (Flags.Task_200ms.Counter >= Flags.Task_200ms.Threshold)
{
Flags.Task_200ms.Counter = 0;
Flags.Task_200ms.Flag = TRUE;
}
if (Flags.Task_500ms.Counter >= Flags.Task_500ms.Threshold)
{
Flags.Task_500ms.Counter = 0;
Flags.Task_500ms.Flag = TRUE;
}
if (Flags.Task_1000ms.Counter >= Flags.Task_1000ms.Threshold)
{
Flags.Task_1000ms.Counter = 0;
Flags.Task_1000ms.Flag = TRUE;
}
printf("Thread1:%d\n",i++);
ReleaseMutex(g_Mutex); // 触发互斥量
Sleep(1);
}
}