层次状态机-HSM应用解析

在上一面文章中分析了HSM的核心代码,本文章主要是对HSM的应用解析,以相机拍照为例子,对状态和事件的调用,实现拍照、查看照片、切换拍照模式、低电量关机等功能。

一、状态和事件

这个例子里面用了四种事件、六个状态,作用文章原文有解释:

a82cb550998c45c492b6fa2ca30ba8fa.png 总结来说也就是举了个相机拍照的例子,相机有三个按键事件,分别为电源按键(PWR)、快门按键(RELEASE)和模式选择按键(MODE),一个被动触发事件,为电池电量低(LOWBATT);

相机有五个状态,分别为相机处于电源打开状态(on)、处于电源关闭状态(off)、处于相机拍照状态(OnShoot)、处于查看照片状态(OnDisplay)、处于查看菜单状态(OnDispMenu),OnDisp应该是OnDisplay和OnDispMenu状态的父状态;

二、代码解析

首先定义了程序中会用到的四种事件和六个状态的句柄,basic最原始的父状态句柄;

#include "hsm.h"
#include <stdio.h>

// Camera HSM Events
#define HSME_PWR        (HSME_START)
#define HSME_RELEASE    (HSME_START + 1)
#define HSME_MODE       (HSME_START + 2)
#define HSME_LOWBATT    (HSME_START + 3)


typedef struct CAMERA_T
{
   /*
    Class that implements the Camera HSM and inherits from the HSM class
    Creating a HSM requires the following steps:
        1) Initialize the base HSM class
        2) Define the HSM states hierarchy
        3) Set the starting state
        4) Define the state handlers
            a) State handler must return "None" if the event IS handled
            b) State handler must return "event" if the event IS NOT handled
            c) State handler may handle the ENTRY event for state setup
            d) State handler may handle the EXIT event for state teardown/cleanup
            e) State handler may handle the INIT for self transition to child state
            f) Self transition to child state MUST NOT be handled by ENTRY or EXIT event
            g) Events ENTRY, EXIT and INIT do no need to return None for brevity
    */
    // Parent
    HSM parent;
    // Child members
    char param1;
    char param2;
} CAMERA;

CAMERA basic;
HSM_STATE CAMERA_StateOff;
HSM_STATE CAMERA_StateOn;
HSM_STATE CAMERA_StateOnShoot;
HSM_STATE CAMERA_StateOnDisp;
HSM_STATE CAMERA_StateOnDispPlay;
HSM_STATE CAMERA_StateOnDispMenu;

 该函数注册了状态对应的回调处理函数,以"on"状态为例,使用HSM_STATE_Create函数对&CAMERA_StateOn句柄添加回调函数CAMERA_StateOnHndlr,只要处于"on"就会一直进入该函数进行事件的处理;在使用HSM_Create父状态,初始状态为&CAMERA_StateOff;

void CAMERA_Init(CAMERA *This, char *name)
{
    // Step 1: Create the HSM States
    HSM_STATE_Create(&CAMERA_StateOff, "Off", CAMERA_StateOffHndlr, NULL); //相机电源off 2
    HSM_STATE_Create(&CAMERA_StateOn, "On", CAMERA_StateOnHndlr, NULL);    //相机电源on 1
    HSM_STATE_Create(&CAMERA_StateOnShoot, "On.Shoot", CAMERA_StateOnShootHndlr, &CAMERA_StateOn);// 相机处于拍照状态 1-1
    HSM_STATE_Create(&CAMERA_StateOnDisp, "On.Disp", CAMERA_StateOnDispHndlr, &CAMERA_StateOn);   // 相机处于照片和菜单显示父状态 1-2 
    HSM_STATE_Create(&CAMERA_StateOnDispPlay, "On.Disp.Play", CAMERA_StateOnDispPlayHndlr, &CAMERA_StateOnDisp); //相机显示照片状态 1-2-1
    HSM_STATE_Create(&CAMERA_StateOnDispMenu, "On.Disp.Menu", CAMERA_StateOnDispMenuHndlr, &CAMERA_StateOnDisp); //相机显示菜单状态 1-2-2
    // Step 2: Initiailize the HSM and starting state
    HSM_Create((HSM *)This, name, &CAMERA_StateOff);
    // Step 3: [Optional] Enable HSM debug
    HSM_SET_PREFIX((HSM *)This, "[DBG] ");
    HSM_SET_DEBUG((HSM *)This, HSM_SHOW_ALL);
    // Step 4: CAMERA member initialization
    This->param1 = 0;
    This->param2 = 1;
}

以上六个状态的回调函数,执行代码如下

HSM_EVENT CAMERA_StateOffHndlr(HSM *This, HSM_EVENT event, void *param)
{
    if (event == HSME_ENTRY)
    {
        printf("\tEnter Low Power Mode\n");
    }
    else if (event == HSME_EXIT)
    {
        printf("\tExit Low Power Mode\n");
    }
    else if (event == HSME_PWR)
    {
        HSM_Tran(This, &CAMERA_StateOn, 0, NULL);
        return 0;
    }
    return event;
}

HSM_EVENT CAMERA_StateOnHndlr(HSM *This, HSM_EVENT event, void *param)
{
    if (event == HSME_ENTRY)
    {
        printf ("\tOpen Lens\n");
    }
    else if (event == HSME_EXIT)
    {
        printf ("\tClose Lens\n");
    }
    else if (event == HSME_INIT)
    {
        HSM_Tran(This, &CAMERA_StateOnShoot, 0, NULL);
    }
    else if (event == HSME_PWR)
    {
        HSM_Tran(This, &CAMERA_StateOff, 0, NULL);
        return 0;
    }
    else if (event == HSME_LOWBATT)
    {
        printf("\tBeep low battery warning\n");
        return 0;
    }
    return event;
}

HSM_EVENT CAMERA_StateOnShootHndlr(HSM *This, HSM_EVENT event, void *param)
{
    if (event == HSME_ENTRY)
    {
        printf("\tEnable Sensor\n");
    }
    else if (event == HSME_EXIT)
    {
        printf("\tDisable Sensor\n");
    }
    else if (event == HSME_RELEASE)
    {
        printf("\tCLICK!, save photo\n");
        return 0;
    }
    else if (event == HSME_MODE)
    {
        HSM_Tran(This, &CAMERA_StateOnDispPlay, 0, NULL);
        return 0;
    }
    return event;
}

HSM_EVENT CAMERA_StateOnDispHndlr(HSM *This, HSM_EVENT event, void *param)
{
    if (event == HSME_ENTRY)
    {
        printf("\tTurn on LCD\n");
    }
    else if (event == HSME_EXIT)
    {
        printf("\tTurn off LCD\n");
    }
    return event;
}

HSM_EVENT CAMERA_StateOnDispPlayHndlr(HSM *This, HSM_EVENT event, void *param)
{
    if (event == HSME_ENTRY)
    {
        printf("\tDisplay Pictures\n");
    }
    else if (event == HSME_MODE)
    {
        HSM_Tran(This, &CAMERA_StateOnDispMenu, 0, NULL);
        return 0;
    }
    return event;
}

HSM_EVENT CAMERA_StateOnDispMenuHndlr(HSM *This, HSM_EVENT event, void *param)
{
    if (event == HSME_ENTRY)
    {
        printf("\tDisplay Menu\n");
    }
    else if (event == HSME_MODE)
    {
        HSM_Tran(This, &CAMERA_StateOnShoot, 0, NULL);
        return 0;
    }
    return event;
}

下面开始介绍程序主函数,执行步骤如注释

void main(void)
{
    // 1-Instantiate Camera
    CAMERA_Init(&basic, "Canon");
    // 2-Turn on the Power
    CAMERA_Run(&basic, HSME_PWR, 0);
    // 3-Take a picture
    CAMERA_Run(&basic, HSME_RELEASE, 0);
    // 4-Take another picture
    CAMERA_Run(&basic, HSME_RELEASE, 0);
    // 5-Playback the photo
    CAMERA_Run(&basic, HSME_MODE, 0);
    // 6-Oops, pushed the release button by accident
    CAMERA_Run(&basic, HSME_RELEASE, 0);
    // 7-Go to menu settings
    CAMERA_Run(&basic, HSME_MODE, 0);
    // 8-Uh oh, low battery
    CAMERA_Run(&basic, HSME_LOWBATT, 0);
    // 9-Time to turn it off
    CAMERA_Run(&basic, HSME_PWR, 0);
}

三、编译运行验证

查看源码文件

5975adf99b3c4f5fbd000355cb661afb.png

编译源码

d4393609770d4d2ea93a177193fe7e66.png

 运行代码

4be2ef52bc3b407194a684edb74caaa0.png

 步骤1:处于低电量关机模式。初始化一个相机HSM实例为Canon,默认进入Canon[off]状态。

 步骤2:等待拍照,打开相机电源开关,打开传感器,。Canon[off](HSME_PWR)事件触发,最终进入Canon[on](INIT)状态,再进入Canon[on.shoot](INIT)状态。

 步骤3:拍照按键触发,拍下一张照片。触发Canon[on.shoot](HSME_RELEASE)事件。

 步骤4:拍照按键触发,拍下另一张照片。触发Canon[on.shoot](HSME_RELEASE)事件。

 步骤5:屏幕查看照片,关闭镜头传感器,打开屏幕LCD,显示图片。Canon[on.shoot](HSME_MODE)事件触发,进入Canon[on.Dis.Play](HSME_MODE)事件。

 步骤6:拍照按键触发,由于处于查看照片模式,不响应拍照事件。Canon[on.Dis.Play](HSME_RELEASE)事件触发,但是遍历Canon[on.shoot]的状态和父状态都找不到该事件,不做处理。

 步骤7:屏幕切换到菜单模式。Canon[on.Dis.Play](HSME_MODE)触发,切换到Canon[on.Disp.Memu](INIT)。

 步骤8:相机电池电量低,蜂鸣器报警。触发HSME_LOWBATT事件,Canon[on.Disp.Memu]没有该事件,遍历其父状态,在Canon[on](HSME_LOWBATT)触发。

 步骤9:相机电源按键触发,屏幕LCD关闭,镜头传感器关闭,切换回关机模式。HSME_PWR事件触发,Canon[on.Disp.Memu]找不到该状态,遍历其父状态在Canon[on](HSME_PWR)触发关机。

四、总结

至此层次状态机-HSM应用解析到此结束,上一篇文章和本文章是紧密结合的,必须看懂前者才能看明白上述的相机工作例子。理解HSM的状态调度机制和事件调度机制非常重要,笔者总结能力有限,可能没办法很清晰的描述出来,但是建议读者使用笔将整个状态和事件关系列举出来,相信会有不一样的收获哦。后续估计会再写一篇关于HSM的文章,不过是在C++中使用HSM,本人觉得HSM更适合结合C++封装继承特性去使用。

 

GitHub源码链接:GitHub - howard-chan/HSM: Hierarchical State Machine

 

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值