开启辅助访问 切换到窄版

打印 上一主题 下一主题

好吧!再包一层,讲讲思想

[复制链接]
楼主
跳转到指定楼层
| 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    写C的很奇怪,感觉有点歧视哪些用java、Python等高级语言的,但是却在用这C不停的一层一层的包,就是想让代码更加像更高级语言。特别是写嵌入式的,跑裸机就是一个while(1)干所有的事情,高级一点用用状态机,但还是逃离不了这个死循环,再高级一点的就是玩玩只有内核的RTOS,例如UCOS和FreeRTOS,目前呢还有aliOS、华为的liteos以及得到linux真传的Zephyr更是火的一塌糊涂。我呢,使用过UCOS、FreeRTOS、编译过liteOS以及使用过Zephyr,其实都大同小异,其实对Zephyr还是非常的想研究的,但是不知咋的,就跟熊大的RT-Thread给干起来了,你说不好玩吧!但是它有finsh,你说它很吊吧!那我肯定得说很吊,因为我写不出啊!这里啰嗦这么多呢!就是想写写我们简单嵌入式,或者设穿戴设备、IOT设备可能使用得到的一种带定时功能的事件推送。好吧!进入正题,看如何进行包的吧!本篇正题是”高级事件推送”。
   RT-Thread的 finsh在调试方面是比较友好的功能的,可以随便调用那个注册过了的函数,但是这个需要控制台进行控制,如果有这样一个接口也同样是调用函数指针运行函数,并且可以指定时间的去执行某个函数,那么这样的接口几乎是无所不能了。上章节中在包定时器时可以体会到一个定时器如果设置为单次执行,那么可以做到指定时间去执行不同的回调函数,貌似这就是我们需要的功能,但是这有一个缺点就是每次定时器只有执行完上一次的回调函数后才能再次被设置新的回调事件,否则就会被冲掉,那么如果有一张表,将回调函数指针放到这个表中,然后每个回调函数的定时时间都挂在这个定时器上面,那么这样就可以实现不被冲掉,而且每个定时器回调都能按时间顺序执行,只是需要维护这张表以及设置这个定时器的延时时间。对于这个功能,我叫做高级event推送。

1.基本思路和流程图

1.1基本思路

先来想想完成这个功能的基本方法和思路,借着图1-1进行分析。


图1-1事件推送示意图

  有一个基础定时器工作于一次性定时模式,这里分4种情况对于事件的推送和取消进行分析。

  • 情形1:事件1第一个推送事件
事件1在时间点A进行推送,希望在B点进行执行,当A点进行推入时,将定时器关闭,同时遍历事件维护数组,找到离当前系统tick时间差最小的事件,并设置到定时器中,这里就是设置事件1的定时时间即B点的系统tick到定时器中,然后启动定时器,如果一切顺利,中途没有异常,那么这个定时器会在B点调用回调函数,在回调函数中又必须再次遍历事件数组进行维护,一方面找到定时时间已经小于或等于0的事件去执行,另一方找到下一个定时事件。

  • 情形2:事件1还没有超时事件2就进行了推送
事件2在B点之前的C点进行推送,并遍历数组,找到一个空位,将刚刚推进来的相关函数指针以及延时函数等放到数组中,继而停止定时器,再次遍历数组,将所有事件的延时函数都减去(C-A)这个失去的时间,当然刚刚推进来的不用减,在这个减的过程中如果有某个事件的延时已经小于等于0,那么立刻进行执行,接着找到下一个延时最小的事件,设置定时器并启动定时器,等待下一次超时或者事件的推送和取消。

  • 情形3:对某个还未被执行的事件进行取消
在D点前的E点将事件1取消,那么就的将事件1和事件2的延时时间都减去(E-C)这个失去的时间,同时维护事件数组,将事件2再次设置到定期中。

  • 情形4:对某个还未被执行的事件进行取消
在事件1即将执行B点前的F点将事件1进行取消,在F点遍历事件数组,将事件1从数组中移除,同时关闭定时器再次对事件数组的延时进行维护,这个时候已经找不到需要执行的事件了,所以定时器也不再开启。
1.2流程图

上面基本上把流程简单过了一遍,那么为了软件更有指定性的编写,设计有如图1-2所示的流程图。


图2-2事件推送流程图

根据流程图,为完成这项任务,需要哪些资源呢?

  • 一个软定时器,用于维护事件数组。
  • 一个事件线程,用于执行事件回调函数。
  • 一个消息队列,用于定时器找到需要执行的事件后传给事件线程去执行。
  • 一个互斥量,因为push事件和remove事件都需要维护事件数组。
由于RT-Thread的定时器回调函数中使用互斥量存在一定的问题,当然在这样类似于中断的地方使用互斥量本身就是有问题的。所以为了解决这个问题,还需额外的一些资源:

  • 一个定时器回调函数执行线程,在这个线程里面就可以使用互斥量了。
  • 一个信号量,用于定时器回调函数通知定时器回调线程执行真正的回调任务。
  好了,写完了,代码就不贴了,整个ZJ-SDK将会在11月底上传github的,这其实是在对我自己说,读者,别心里嘀咕什么啊。好吧!还是贴一个初始化函数占篇幅吧!
typedef void (*event_func_t)( void *arg );
typedef struct
{
void *pargs;
uint32_t debug;
event_func_t pfunc;
} event_data_handle_t;

#define MAX_DELAY_EVENT 64
typedef struct
{
uint32_t event[MAX_DELAY_EVENT];
uint32_t args[MAX_DELAY_EVENT];
uint32_t delay[MAX_DELAY_EVENT];
uint32_t debug[MAX_DELAY_EVENT];
} event_delay_treat_t;

#define APP_EVENT_MESQ_NUM 12
static struct rt_messagequeue app_event_mesq;
static uint8_t event_mq_buffer[APP_EVENT_MESQ_NUM*sizeof(event_data_handle_t)];

static struct rt_mutex app_event_mutex;
static struct rt_timer app_event_timer;
static struct rt_semaphore timeout_event_sem;

#define EVENT_TASK_SIZE 1024
#define EVENT_THREAD_PRIORITY 3
static void app_event_process_thread(void *args);
static struct rt_thread app_event_thread;
static uint8_t event_task_stack_buffer[EVENT_TASK_SIZE];

#define TIMEOUT_TASK_SIZE 1024
#define TIMEOUT_THREAD_PRIORITY 4
static void event_delay_timeout_handler(void *parameter);
static void app_timeout_process_thread(void *args);
static struct rt_thread app_timeout_thread;
static uint8_t timer_task_stack_buffer[TIMEOUT_TASK_SIZE];

static volatile uint32_t s_event_start_ticks = 0;
static volatile event_delay_treat_t event_delay_treat;
static volatile uint32_t event_current_debug;
static volatile uint32_t event_current_event;
初始化代码如下:
void app_event_init(void *args)
{
rt_err_t ret;
event_printf("app_event_mesq..\r\n");
ret = rt_mq_init(&app_event_mesq,
"evtmqt",
&event_mq_buffer[0],
sizeof(event_data_handle_t),
sizeof(event_mq_buffer),
RT_IPC_FLAG_FIFO);
APP_ERROR_CHECK(ret);

if (ret)
{
event_printf("app_event_mesq create failure\n");
}

rt_timer_init(&app_event_timer,
"evttimer",
event_delay_timeout_handler,
NULL,
RT_WAITING_FOREVER,
RT_TIMER_FLAG_ONE_SHOT);

if(rt_thread_find("evttask"))
{
rt_thread_detach(&app_event_thread);
}

if(rt_thread_find("evttask") == NULL)
{
ret = rt_thread_init(&app_event_thread,
"evttask",
app_event_process_thread,
RT_NULL,
&event_task_stack_buffer[0],
EVENT_TASK_SIZE,
EVENT_THREAD_PRIORITY,
20);
APP_ERROR_CHECK(ret);

if (ret == RT_EOK)
{
rt_thread_startup(&app_event_thread);
}
}
event_printf("app_event_thread creat ok!!\r\n");
if(rt_thread_find("evttimer"))
{
rt_thread_detach(&app_event_thread);
}
if(rt_thread_find("evttimer") == NULL)
{
ret = rt_thread_init(&app_timeout_thread,
"evttimer",
app_timeout_process_thread,
RT_NULL,
&timer_task_stack_buffer[0],
TIMEOUT_TASK_SIZE,
TIMEOUT_THREAD_PRIORITY,
20);
APP_ERROR_CHECK(ret);
if (ret == RT_EOK)
{
rt_thread_startup(&app_timeout_thread);
}
}
event_printf("app_timeout_thread creat ok!!\r\n");
ret = rt_sem_init(&timeout_event_sem,"evtsem", 0, RT_IPC_FLAG_FIFO);
APP_ERROR_CHECK(ret);
if (ret)
{
event_printf("timeout_event_sem create failure = %d\n",ret);
}

event_printf("app_event_mutex.owner = %x\r\n",app_event_mutex.owner);
if(app_event_mutex.owner == NULL)
{
event_printf("wait app event init\r\n");
while(1)
{
if(&app_event_timer)
{
break;
}
}
ret = rt_mutex_init(&app_event_mutex,"mutex", RT_IPC_FLAG_FIFO);
APP_ERROR_CHECK(ret);
}
event_printf("app event init complite\r\n");
}






公众号


论坛


QQ群

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表