- #include "vsf.h"
- #include "usrapp.h"
- struct usrapp_t usrapp;
- void usrapp_on_timer1S(void *param)
- {
- struct usrapp_t *app = (struct usrapp_t *)param;
- if (app->toggle)
- vsfhal_gpio_set(0, 1 << 1);
- else
- vsfhal_gpio_clear(0, 1 << 1);
- app->toggle = !app->toggle;
- }
- void usrapp_srt_init(struct usrapp_t *app)
- {
- vsfhal_gpio_init(0);
- vsfhal_gpio_config_pin(0, 1, GPIO_OUTPP);
- usrapp_on_timer1S(app);
- vsftimer_create_cb(1000, -1, usrapp_on_timer1S, app);
- }
这里,在软实时初始化代码里,调用vsftimer_create_cb建立一个定时器,每隔1000ms调用一次usrapp_on_timer1S。回调接口的方式,有一点需要处理,就是回调函数的运行时优先级,就是定时器模块的优先级。VSF中,很多模块都用到了回调函数,比如流模块等等。
2. 事件驱动构架:
- #include "vsf.h"
- #include "usrapp.h"
- struct vsfsm_state_t*
- usrapp_led_evt_handler(struct vsfsm_t *sm, vsfsm_evt_t evt);
- struct usrapp_t usrapp =
- {
- .sm.init_state.evt_handler = usrapp_led_evt_handler,
- .sm.user_data = &usrapp,
- };
- #define USRAPP_EVT_ON1S VSFSM_EVT_USER
- struct vsfsm_state_t*
- usrapp_led_evt_handler(struct vsfsm_t *sm, vsfsm_evt_t evt)
- {
- struct usrapp_t *app = (struct usrapp_t *)sm->user_data;
- switch (evt)
- {
- case VSFSM_EVT_INIT:
- vsfhal_gpio_init(0);
- vsfhal_gpio_config_pin(0, 1, GPIO_OUTPP);
- vsftimer_create(sm, 1000, -1, USRAPP_EVT_ON1S);
- // fall through
- case USRAPP_EVT_ON1S:
- if (app->toggle)
- vsfhal_gpio_set(0, 1 << 1);
- else
- vsfhal_gpio_clear(0, 1 << 1);
- app->toggle = !app->toggle;
- break;
- }
- return NULL;
- }
- void usrapp_srt_init(struct usrapp_t *app)
- {
- vsfsm_init(&app->sm);
- }
软实时初始化代码里,启动一个事件处理任务。事件处理任务里,处理初始化事件的时候,建立一个定时器,每隔1000ms发送USRAPP_EVT_ON1S事件给自己。事件驱动的方式,是最普通的VSF多任务实现方式。
3. 原状态机(msm):
- #include "vsf.h"
- #include "usrapp.h"
- enum
- {
- STATE_INIT = 0,
- STATE_ON,
- STATE_OFF,
- };
- #define USRAPP_EVT_ON1S VSFSM_EVT_USER
- int usrapp_do_init(struct vsfsm_msm_t *msm);
- int usrapp_do_on(struct vsfsm_msm_t *msm);
- int usrapp_do_off(struct vsfsm_msm_t *msm);
- struct usrapp_t usrapp =
- {
- .msm.entry_num = dimof(usrapp.trans_tbl),
- .msm.trans_tbl = usrapp.trans_tbl,
- .msm.user_data = &usrapp,
- .msm.state = STATE_INIT,
- .trans_tbl[0] = {STATE_INIT, VSFSM_EVT_INIT, NULL, usrapp_do_init},
- .trans_tbl[1] = {STATE_ON, USRAPP_EVT_ON1S, NULL, usrapp_do_off},
- .trans_tbl[2] = {STATE_OFF, USRAPP_EVT_ON1S, NULL, usrapp_do_on},
- };
- int usrapp_do_on(struct vsfsm_msm_t *msm)
- {
- vsfhal_gpio_set(1, 1 << 1);
- return STATE_ON;
- }
- int usrapp_do_off(struct vsfsm_msm_t *msm)
- {
- vsfhal_gpio_clear(1, 1 << 1);
- return STATE_OFF;
- }
- int usrapp_do_init(struct vsfsm_msm_t *msm)
- {
- vsfhal_gpio_init(1);
- vsfhal_gpio_config_pin(1, 1, GPIO_OUTPP);
- vsftimer_create(msm->sm, 1000, -1, USRAPP_EVT_ON1S);
- return usrapp_do_off(msm);
- }
- void usrapp_srt_init(struct usrapp_t *app)
- {
- vsfsm_msm_init(&app->sm, &app->msm);
- }
元状态机以数据的方式,定义了状态机。这个在VSF的应用中,从来没用到,不过在一些应用中,会使用到元状态机,比如wifi的协议栈。
4. PT协程:
- #include "vsf.h"
- #include "usrapp.h"
- vsf_err_t usrapp_led_thread(struct vsfsm_pt_t *pt, vsfsm_evt_t evt);
- struct usrapp_t usrapp =
- {
- .pt.thread = usrapp_led_thread,
- .pt.user_data = &usrapp,
- };
- #define USRAPP_EVT_ON1S VSFSM_EVT_USER
- vsf_err_t usrapp_led_thread(struct vsfsm_pt_t *pt, vsfsm_evt_t evt)
- {
- struct usrapp_t *app = (struct usrapp_t *)pt->user_data;
- vsfsm_pt_begin(pt);
- vsfhal_gpio_init(0);
- vsfhal_gpio_config_pin(0, 1, GPIO_OUTPP);
- vsftimer_create(pt->sm, 1000, -1, USRAPP_EVT_ON1S);
- while (1)
- {
- if (app->toggle)
- vsfhal_gpio_set(0, 1 << 1);
- else
- vsfhal_gpio_clear(0, 1 << 1);
- app->toggle = !app->toggle;
- vsfsm_pt_wfe(pt, USRAPP_EVT_ON1S);
- }
- vsfsm_pt_end(pt);
- return VSFERR_NONE;
- }
- void usrapp_srt_init(struct usrapp_t *app)
- {
- vsfsm_pt_init(&app->sm, &app->pt);
- }
PT协程就是使用状态机的方式,模拟普通阻塞的代码。在VSF构架中,一般避免使用,因为占用的ram和flash资源,相对其他方式更大。不过,在一些直接把阻塞代码,转换成VSF里可以运行的代码的时候,这个就会非常方便。
5. setjmp方式:
- #include "vsf.h"
- #include "usrapp.h"
- void usrapp_led_thread(struct vsfsm_ljmp_t *ljmp);
- struct usrapp_t usrapp =
- {
- .ljmp.thread = usrapp_led_thread,
- .ljmp.user_data = &usrapp,
- .ljmp.stack = usrapp.stack + sizeof(usrapp.stack),
- };
- #define USRAPP_EVT_ON1S VSFSM_EVT_USER
- void usrapp_led_thread(struct vsfsm_ljmp_t *ljmp)
- {
- struct usrapp_t *app = (struct usrapp_t *)ljmp->user_data;
- vsfhal_gpio_init(0);
- vsfhal_gpio_config_pin(0, 1, GPIO_OUTPP);
- vsftimer_create(ljmp->sm, 1000, -1, USRAPP_EVT_ON1S);
- while (1)
- {
- if (app->toggle)
- vsfhal_gpio_set(0, 1 << 1);
- else
- vsfhal_gpio_clear(0, 1 << 1);
- app->toggle = !app->toggle;
- vsfsm_ljmp_wfe(ljmp, USRAPP_EVT_ON1S);
- }
- }
- void usrapp_srt_init(struct usrapp_t *app)
- {
- vsfsm_ljmp_init(&app->sm, &app->ljmp);
- }
setjmp是标准的C库中的组件,一般用于实现类似try...exception...的功能,也可以用于实现一个独立堆栈的协程(PT协程是共享堆栈)。这个和PT比较的话,需要设置独立的堆栈,但是,没有PT协程重建堆栈的过程,性能会高很多。不过,在实际VSF的应用中,也没用到过这种方式。