以按键事件为例阐述消息传递机制
来源:互联网 发布:可以听pdf的软件 编辑:程序博客网 时间:2024/05/20 09:24
以按键事件为例阐述消息传递机制
这里主要想说的是按键事件发生后,app层是怎么收到消息的一些想法。
main.c: 执行InitBoard( OB_COLD ) // OB_COLD宏定义为0 { if ( level == OB_COLD ) { *(uint8 *)0x0 = 0; osal_int_disable( INTS_ALL ) } }
这个函数执行完毕系统关禁止中断
然后执行HalDriverInit (void) //头文件有#define HAL_KEY TRUE { ...... #if (defined HAL_KEY) && (HAL_KEY == TRUE) HalKeyInit(); #endif ..... }
———————————————————————————————————————
hal_key.c:
执行HalKeyInit( void ) //这是关于按键初始化的配置,比如回调函数,按键储存变量 { halKeySavedKeys = 0; ....... pHalKeyProcessFunction = NULL;//回调函数为空 HalKeyConfigured = FALSE; //按键还没有配置 }
执行完返回main.c
———————————————————————————————————————
顺着main函数的函数体往下执行,再次遇到
InitBoard( OB_READY ); // #define OB_READY 2 { ...... else { HalKeyConfig(HAL_KEY_INTERRUPT_DISABLE, OnBoard_KeyCallback); } }
hal_key.c:
// #define HAL_KEY_INTERRUPT_DISABLE 0x00
执行 HalKeyConfig ( bool interruptEnable , halKeyCBack_t cback ) { Hal_KeyIntEnable = interruptEnable; //将0x00赋值给Hal_KeyIntEnable pHalKeyProcessFunction = cback; /*回调函数赋值给 pHalKeyProcessFunction,往上查定义得到 static halKeyCBack_t pHalKeyProcessFunction,再往上查得到 typedef void (*halKeyCBack_t) (uint8 keys, uint8 state); 说白了pHalKeyProcessFunction就是个函数指针*/ ...... else { HAL_KEY_SW_6_ICTL &= ~(HAL_KEY_SW_6_ICTLBIT); /* don't generate interrupt */ HAL_KEY_SW_6_IEN &= ~(HAL_KEY_SW_6_IENBIT); /* Clear interrupt enable bit */ osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_POLLING_VALUE); // #define HAL_KEY_EVENT 0x0001 HAL_KEY_POLLING_VALUE定义为500ms,开始计时任务,每100ms触发一次。意思就是HAL_KEY_EVENT这个事件100ms发生一次 } HalKeyConfigured = TRUE;}
——————————————————————————————————————
到此为止,按键相关的初始化都搞完了。接下来就是等第一个100ms
现在第一个100ms来了。
main.c: osal_start_system() for(;;) { osal_run_system();}
________________________________________________________________________________________________
执行 osal_run_system(); { osalTimeUpdate(); Hal_ProcessPoll(); //上面两个函数实现了计时和事件置位 ...... events = tasksEvents[idx]; tasksEvents[idx] = 0; events = (tasksArr[idx])( idx, events ); }
主循环里面检测到Hal_TaskID这个任务被置位(至于osal_start_timerEx是怎么让任务置位这个问题我还没弄懂,暂且当做已知…),保存在event,然后把任务清0。进入事件处理函数(这里为什么叫事件处理函数而不是叫任务处理函数呢?我想是因为一个任务可以接受处理很多个事件,这个函数只是个入口,函数体里面是会具体区分什么事件的)。
———————————————————————————————————————
hal_drivers.c Hal_ProcessEvent( uint8 task_id, uint16 events ) { if (events & HAL_KEY_EVENT) { #if (defined HAL_KEY) && (HAL_KEY == TRUE) HalKeyPoll(); if (!Hal_KeyIntEnable) { osal_start_timerEx( Hal_TaskID, HAL_KEY_EVENT, 100); } #endif // HAL_KEY return events ^ HAL_KEY_EVENT; } }
这里想说,osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_POLLING_VALUE)传递给Hal_TaskID这个任务的事件是HAL_KEY_EVENT。(events & HAL_KEY_EVENT)的结果就是1,进入if判断,HalKeyPoll()获得是哪个按键按下了。然后继续osal_start_timerEx( Hal_TaskID, HAL_KEY_EVENT, 100),为什么要这样做呢?因为在osal_run_system()里面有tasksEvents[idx] = 0 意味着这个事件被处理过了,但是谁知道什么时候有人要按键呢,所以只能不停的查询。
——————————————————————————————————————————
看到这里,好像还是没说怎么通知app层啊?仔细找找,原来在HalKeyPoll();里hal_key.c:
HalKeyPoll(){if (!Hal_KeyIntEnable) { if (keys == halKeySavedKeys) { return; } halKeySavedKeys = keys; } else {/* Key interrupt handled here */ } if (keys && (pHalKeyProcessFunction)) { (pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL); }
创建halKeySavedKeys变量是为了下一次触发事件的时候和keys进行比较,如果相同则说明
这一次轮询没有按键,就return回去(橙色代码)。如果keys有值并且回调函数已经定义了的话就调用回调函数。
#define HAL_KEY_STATE_NORMAL 0x00
———————————————————————————————————————
Onboard.c:
回调函数前面说了是个函数指针,实际上调用:
OnBoard_KeyCallback ( uint8 keys, uint8 state ){ ...... if ( OnBoard_SendKeys( keys, shift ) != ZSuccess ) .......}OnBoard_SendKeys( uint8 keys, uint8 state ){ //在这里正式填充消息结构体(不是那种无线消息),而是“keyChange_t”,我觉得是这个层次向app层发消息的特定的结构体,是不是别的层向app层发送的话有别的结构体样式? if ( registeredKeysTaskID != NO_TASK_ID ) { msgPtr = (keyChange_t *)osal_msg_allocate( sizeof(keyChange_t) ); if ( msgPtr ) { msgPtr->hdr.event = KEY_CHANGE; msgPtr->state = state; msgPtr->keys = keys; osal_msg_send( registeredKeysTaskID, (uint8 *)msgPtr ); } return ( ZSuccess ); }
在文件开头有static uint8 registeredKeysTaskID = NO_TASK_ID;
在这个文件里有函数RegisterForKeys( uint8 task_id ) 。函数实现了registeredKeysTaskID = task_id。 那么到底谁调用了这个函数呢?全局查找之后发现在sampleapp.c里面调用了它,这里就明白了很多教程说使用按键就一定要先调用按键注册函数,因为如果不这样做的话if循环根本进不去….
define KEY_CHANGE 0xC0 这是一个事件的编号,猜想应该还有很多事件的宏定义散落在不同的文件里,但是好像记得说过事件是独热码编码的,那怎么会有0xc0这种东西,暂时保留疑问….
———————————————————————————————————————————
OSAL.c: osal_msg_send(destination_task, (uint8 *)msgPtr ) { ...... osal_msg_enqueue( &osal_qHead, msg_ptr ); osal_set_event( destination_task, SYS_EVENT_MSG ); ...... }
// destination_task就是app层的id
//这里就正式将消息传给destination_task,也就是SampleApp_TaskID。其实我们口中说的将消息传给谁,程序中的实现是这样的:将这个消息加入消息队列(所有任务都能访问的一个队列),然后那个消息传给了哪个任务,就将那个任务事件标志位置1(main循环就能轮询到),那个任务对应的事件处理函数里面就会去取属于自己的消息(函数是不知道属于自己的消息放在哪里的,所以它一定要将整个消息队列遍历一次,这个说法在osal_msg_receive( SampleApp_TaskID )的函数体中可以证实)
————————————————————————————————————————————
OSAL.c:osal_set_event( uint8 task_id, uint16 event_flag ){.......tasksEvents[task_id] |= event_flag;......}
这句话牛逼啦,event_flag就是传递的参数SYS_EVENT_MSG,也就是0x8000.
task¬_id下标对应的tasksevents就变成了0x8000。为什么要这样?理由 1.统一规定一个强制的参数作为事件发生的标志,清晰明了 2.后面的事件处理函数好判断
_ ____________________________________________________________________
sampleapp.c:
现在任务已经被置位,并进入了事件处理函数
SampleApp_ProcessEvent( uint8 task_id, uint16 events ){ ...... if ( events & SYS_EVENT_MSG ) //没有上面的event_flag,这个if是进不去的。 { ........ while ( MSGpkt ) { switch ( MSGpkt->hdr.event ) { ...... case KEY_CHANGE: SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys ); break; } ...... }}
SYS_EVENT_MSG告诉你有事件发生了,发生的事什么事件通过(MSGpkt->hdr.event)来判断,通过switch语句跳转到不同的处理函数上。
———————————————————————————————————————
关于消息从产生到传递到处理暂时只能理解这个份上了….
- 以按键事件为例阐述消息传递机制
- Android按键事件传递机制
- Android事件传递机制【按键事件】
- Android事件传递机制【按键事件】
- Android事件传递机制【按键事件】
- Android事件传递机制【按键事件】
- 以android状态栏虚拟按键消息为例学习在input系统插入按键消息的处理
- 事件处理方式 && 消息传递机制
- 以自定义圆形进度条为例阐述自定义view步骤
- 以ontouch为例说明android事件发送机制
- Java回调机制(以Android事件监听器为例)
- nginx中的事件响应机制(以epoll为例)
- Android按键拦截处理最佳实践范例(以Back事件为例)
- 以消息为基础,以事件驱动之
- 事件处理机制之Handler消息传递机制浅析
- BSP编程模型(以NMF为例,试验基于消息传递的模型BSP过程)
- BSP编程模型(以NMF为例,试验基于消息传递的模型BSP过程)
- BSP编程模型(以NMF为例,试验基于消息传递的模型BSP过程)
- C/C++的四大内存分区
- 数据结构之贪心算法(背包问题的思考)-(十)
- 从 Yii 1.1升级到 Yii2
- android常见的事件
- Bitwise AND of Numbers Range
- 以按键事件为例阐述消息传递机制
- hdu4407 Sum(容斥原理)
- 解题报告 之 SOJ2714 Mountains(II)
- 死锁
- C# + Xamarin 开发应用-- Call API时遇到错误: Error: NameResolutionFailure
- java 死锁及避免死锁
- Android实现自定义AlertDialog的自下向上的动画效果(并消除dialog边框)
- Test
- 自制操作系统-最简单的系统hello World