主题对象提供统一的注册接口,以及注册函数 。由观察者本身实例化observer_intf 接口,然后使用注册函数,添加到对应的主题列表中,主题状态发生改变,依次通知列表中的所有对象。
struct observer_ops
{
void*(handle)(uint8_t evt);
};
struct observer_intf
{
struct observer_intf* next;
const char* name;
void* condition;
const struct observer_ops *ops;
}
int observer_register(struct topical* top , struct observer_intf* observer);
当主题状态发生改变,将通知到所有观察者,观察者本身也可以设置条件,是否选择接收通知。
struct observer_intf observer_list;
void XXXX_topical_evt(uint8_t evt)
{
struct observer_intf* cur_observer = observer_list.next;
uint8_t* condition = NULL;
while(cur_observer != NULL)
{
condition = (uint8_t*)cur_observer->condition;
if(NULL == condition || (condition && *condition))
{
if(cur_observer->ops->handle){
cur_observer->ops->handle(evt);
}
}
cur_observer = cur_observer->next;
}
}
实例:嵌入式裸机低功耗框架
PM组件提供的接口:
struct pm
{
struct pm* next;
const char* name;
void(*init)(void);
void(*deinit(void);
void* condition;
};
static struct pm pm_list;
static uint8_t pm_num;
static uint8_t pm_status;
int pm_register(const struct pm* pm , const char* name)
{
struct pm* cur_pm = &pm_list;
while(cur_pm->next)
{
cur_pm = cur_pm->next;
}
cur_pm->next = pm;
pm->next = NULL;
pm->name = name;
pm_num++;
}
void pm_loop(void)
{
uint32_t pm_condition = 0;
struct pm* cur_pm = pm_list.next;
static uint8_t cnt;
/*check all condition*/
while(cur_pm)
{
if(cur_pm->condition){
pm_condition |= *((uint32_t*)(cur_pm->condition));
}
cur_pm = cur_pm->next;
}
if(pm_condition == 0)
{
cnt++;
if(cnt>=5)
{
pm_status = READY_SLEEP;
}
}
else
{
cnt = 0;
}
if( pm_status == READY_SLEEP)
{
cur_pm = pm_list.next;
while(cur_pm)
{
if(cur_pm->deinit){
cur_pm->deinit();
}
cur_pm = cur_pm->next;
}
pm_status = SLEEP;
ENTER_SLEEP_MODE();
}
/*sleep--->wakeup*/
if(pm_status == SLEEP)
{
pm_status = NORMAL;
cur_pm = pm_list.next;
while(cur_pm)
{
if(cur_pm->init){
cur_pm->init();
}
cur_pm = cur_pm->next;
}
}
}
外设使用PM接口:
struct uart_dev
{
...
struct pm pm;
uint32_t pm_condition;
};
struct uart_dev uart1;
void hal_uart1_init(void);
void hal_uart1_deinit(void);
void uart_init(void)
{
uart1.pm.init = hal_uart1_init;
uart1.pm.deinit = hal_uart1_deinit;
uart1.pm.condition = &uart1.pm_condition;
pm_register(&uart1.pm , "uart1");
}
/*接下来串口驱动检查缓存 , 发送 , 接收是否空闲或者忙碌 , 给uart1.pm_condition赋值*/
结论
在存在系统的情况下,此类逻辑可以很容易的用阻塞延时来实现,实现如下:
void process_task(void)
{
task1_process();
msleep(1000);
task2_process();
mq_recv(¶m , 1000);
task3_process();
while(mq_recv(¶m , 1000) != OK)
{
if(retry)
{
task3_process();
--try;
}
}
}
在裸机的情况下,为了保证系统的实时性,无法使用阻塞延时,一般使用定时事件配合状态机来实现:
void process_task(void)
{
switch(task_state)
{
case task1:
task1_process();
set_timeout(1000);break;
case task2:
task1_process();
set_timeout(1000);break;
case task3:
task1_process();
set_timeout(1000)break;
default:break;
}
}
/*定时器超时回调*/
void timeout_cb(void)
{
if(task_state == task1)
{
task_state = task2;
process_task();
}
else //task2 and task3
{
if(retry)
{
retry--;
process_task();
}
}
}
/*任务的应答回调*/
void task_ans_cb(void* param)
{
if(task==task2)
{
task_state = task3;
process_task();
}
}
和系统实现相比,裸机的实现更加复杂,为了避免阻塞,只能通过状态和定时器来实现顺序延时的逻辑,可以看到,实现过程相当分散,对于单个任务的处理分散到了3个函数中处理,这样导致的后果是:修改,移植的不便。而实际的应用中,类似的逻辑相当多,如果按照上面的方法去实现,将会导致应用程序的强耦合。实现 可以发现,上面的情景有以下特点:
node数据结构定义:
/*shadow node api type for req_chain src*/
typedef struct shadow_resp_chain_node
{
uint16_t timeout;
uint16_t duration;
uint8_t init_retry;
uint8_t param_type;
uint16_t retry;
/*used in mpool*/
struct shadow_resp_chain_node* mp_prev;
struct shadow_resp_chain_node* mp_next;
/*used resp_chain*/
struct shadow_resp_chain_node* next;
node_resp_handle_fp handle;
void* param;
}shadow_resp_chain_node_t;
node内存池: 使用内存池的必要性:实际情况下,同一时间,责任链的条数,以及单条链的节点数比较有限,但种类是相当多的。比如一个支持AT指令的模块,可能支持几十条AT指令,但执行一个配置操作,可能就只会使用3-5条指令,若全部静态定义节点,将会消耗大量内存资源。因此动态分配是必要的。 初始化node内存池,内存池内所有节点都将添加到free_list。当申请节点时,会取出第一个空闲节点,加入到used_list , 并且接入到责任链。当责任链某一个节点执行完,将会被自动回收(从责任链中删除,并从used_list中删除,然后添加到free_list)职责链数据结构定义:
typedef struct resp_chain
{
bool enable; //enble == true 责任链启动
bool is_ans; //收到应答,与void* param 共同组成应答信号
uint8_t state;
const char* name;
void* param;
TimerEvent_t timer;
bool timer_is_running;
shadow_resp_chain_node_t node; //节点链
void(*resp_done)(void* result); //执行结果回调
}resp_chain_t;
职责链初始化:
void resp_chain_init(resp_chain_t* chain , const char* name ,
void(*callback)(void* result))
{
RESP_ASSERT(chain);
/*only init one time*/
resp_chain_mpool_init();
chain->enable = false;
chain->is_ans = false;
chain->resp_done = callback;
chain->name = name;
chain->state = RESP_STATUS_IDLE;
chain->node.next = NULL;
chain->param = NULL;
TimerInit(&chain->timer,NULL);
}
职责链添加节点:
int resp_chain_node_add(resp_chain_t* chain ,
node_resp_handle_fp handle , void* param)
{
RESP_ASSERT(chain);
BoardDisableIrq();
shadow_resp_chain_node_t* node = chain_node_malloc();
if(node == NULL)
{
BoardEnableIrq();
RESP_LOG("node malloc error ,no free node");
return -2;
}
/*初始化节点,并加入责任链*/
shadow_resp_chain_node_t* l = &chain->node;
while(l->next != NULL)
{
l = l->next;
}
l->next = node;
node->next = NULL;
node->handle = handle;
node->param = param;
node->timeout = RESP_CHIAN_NODE_DEFAULT_TIMEOUT;
node->duration = RESP_CHIAN_NODE_DEFAULT_DURATION;
node->init_retry = RESP_CHIAN_NODE_DEFAULT_RETRY;
node->retry = (node->init_retry == 0)? 0 :(node->init_retry-1);
BoardEnableIrq();
return 0;
}
职责链的启动:
void resp_chain_start(resp_chain_t* chain)
{
RESP_ASSERT(chain);
chain->enable = true;
}
职责链的应答:
void resp_chain_set_ans(resp_chain_t* chain , void* param)
{
RESP_ASSERT(chain);
if(chain->enable)
{
chain->is_ans = true;
if(param != NULL)
chain->param = param;
else
{
chain->param = "NO PARAM";
}
}
}
职责链的运行:
int resp_chain_run(resp_chain_t* chain)
{
RESP_ASSERT(chain);
if(chain->enable)
{
shadow_resp_chain_node_t* cur_node = chain->node.next;
/*maybe ans occur in handle,so cannot change state direct when ans comming*/
if(chain->is_ans)
{
chain->is_ans = false;
chain->state = RESP_STATUS_ANS;
}
switch(chain->state)
{
case RESP_STATUS_IDLE:
{
if(cur_node)
{
uint16_t retry = cur_node->init_retry;
if(cur_node->handle)
{
cur_node->param_type = RESP_PARAM_INPUT;
chain->state = cur_node->handle((resp_chain_node_t*)cur_node ,cur_node->param);
}
else
{
RESP_LOG("node handle is null ,goto next node");
chain->state = RESP_STATUS_OK;
}
if(retry != cur_node->init_retry)
{
cur_node->retry = cur_node->init_retry>0?(cur_node- >init_retry-1):0;
}
}
else
{
if(chain->resp_done)
{
chain->resp_done((void*)RESP_RESULT_OK);
}
chain->enable = 0;
chain->state = RESP_STATUS_IDLE;
TimerStop(&chain->timer);
chain->timer_is_running = false;
}
break;
}
case RESP_STATUS_DELAY:
{
if(chain->timer_is_running == false)
{
chain->timer_is_running = true;
TimerSetValueStart(&chain->timer , cur_node->duration);
}
if(TimerGetFlag(&chain->timer) == true)
{
chain->state = RESP_STATUS_OK;
chain->timer_is_running = false;
}
break;
}
case RESP_STATUS_BUSY:
{
/*waiting for ans or timeout*/
if(chain->timer_is_running == false)
{
chain->timer_is_running = true;
TimerSetValueStart(&chain->timer , cur_node->timeout);
}
if(TimerGetFlag(&chain->timer) == true)
{
chain->state = RESP_STATUS_TIMEOUT;
chain->timer_is_running = false;
}
break;
}
case RESP_STATUS_ANS:
{
/*already got the ans,put the param back to the request handle*/
TimerStop(&chain->timer);
chain->timer_is_running = false;
if(cur_node->handle)
{
cur_node->param_type = RESP_PARAM_ANS;
chain->state = cur_node->handle((resp_chain_node_t*)cur_node , chain->param);
}
else
{
RESP_LOG("node handle is null ,goto next node");
chain->state = RESP_STATUS_OK;
}
break;
}
case RESP_STATUS_TIMEOUT:
{
if(cur_node->retry)
{
cur_node->retry--;
/*retry to request until cnt is 0*/
chain->state = RESP_STATUS_IDLE;
}
else
{
chain->state = RESP_STATUS_ERROR;
}
break;
}
case RESP_STATUS_ERROR:
{
if(chain->resp_done)
{
chain->resp_done((void*)RESP_RESULT_ERROR);
}
chain->enable = 0;
chain->state = RESP_STATUS_IDLE;
TimerStop(&chain->timer);
chain->timer_is_running = false;
cur_node->retry = cur_node->init_retry>0?(cur_node->init_retry-1):0;
chain_node_free_all(chain);
break;
}
case RESP_STATUS_OK:
{
/*get the next node*/
cur_node->retry = cur_node->init_retry>0?(cur_node->init_retry-1):0;
chain_node_free(cur_node);
chain->node.next = chain->node.next->next;
chain->state = RESP_STATUS_IDLE;
break;
}
default:
break;
}
}
return chain->enable;
}
测试用例:
void chain_test_init(void)
{
resp_chain_init(&test_req_chain , "test request" , test_req_callback);
}
void chain_test_run(void)
{
resp_chain_run(&test_req_chain);
}
void chain_test_tigger(void)
{
resp_chain_node_add(&test_req_chain , node1_req ,NULL);
resp_chain_node_add(&test_req_chain , node2_req,NULL);
resp_chain_node_add(&test_req_chain , node3_req,NULL);
resp_chain_start(&test_req_chain);
}
/*延时1s 后执行下一个节点*/
int node1_req(resp_chain_node_t* cfg, void* param)
{
cfg->duration = 1000;
RESP_LOG("node1 send direct request: delay :%d ms" , cfg->duration);
return RESP_STATUS_DELAY;
}
/*超时时间1S , 重传次数5次*/
int node2_req(resp_chain_node_t* cfg , void* param)
{
static uint8_t cnt;
if(param == NULL)
{
cfg->init_retry = 5;
cfg->timeout = 1000;
RESP_LOG("node2 send request max retry:%d , waiting for ans...");
return RESP_STATUS_BUSY;
}
RESP_LOG("node2 get ans: %d",(int)param);
return RESP_STATUS_OK;
}
/*非异步请求*/
int node3_req(resp_chain_node_t* cfg , void* param)
{
RESP_LOG("node4 send direct request");
return RESP_STATUS_OK;
}
void ans_callback(void* param)
{
resp_chain_set_ans(&test_req_chain , param);
}
结论
全部0条评论
快来发表一下你的评论吧 !