蓝牙40协议栈按键流程分析.docx
- 文档编号:11466199
- 上传时间:2023-03-01
- 格式:DOCX
- 页数:13
- 大小:19.32KB
蓝牙40协议栈按键流程分析.docx
《蓝牙40协议栈按键流程分析.docx》由会员分享,可在线阅读,更多相关《蓝牙40协议栈按键流程分析.docx(13页珍藏版)》请在冰豆网上搜索。
蓝牙40协议栈按键流程分析
蓝牙4.0协议栈按键流程分析
在介绍蓝牙按键流程分析之前,我们需要了解一个概念,那就是就是OSAL。
什么是OSAL呢?
可能大伙对于OS是比较了解的,学了计算机的搞过OS的也基本接触过,简单来说就是一个操作系统抽象层,可以理解为运行在CC2540上的操作系统,说操作系统还不能算,TI的OSAL只实现了任务切换和消息机制。
并且把协议栈的代码、硬件处理的代码,用户程序的代码等分别放到了OSAL层的不同任务处理函数中去了,各任务函数之间通过消息机制、同一个任务之间通过事件的的方式来通信。
什么是EVENT事件?
OSAL为每个任务函数分配了一个16位的事件变量,每一位代表一个事件,最高位为0x8000
表示为系统事件SYS_EVENT_MSG。
其余的15位留给用户自定义需要的事件。
通常事件由定时
器启动,比如一秒后我要点亮LED2,这就需要发送一个点亮LED2的事件,然后等待定时器1s后溢出,于是启动点亮LED2事件,事件会调用相应的hal层API点亮LED2。
什么是MSG消息
MSG是比EVENT事件更具体并且可以携带数据的一种通信方式,MSG的标记是按数值,而不是按位。
比如0x01和0x02是两个不同的消息,但对于事件0x03则是0x01事件和0x02事件的组合。
MSG收发使用osal_msg_send()和osal_msg_receive();当调用osal_msg_send()发送一个msg的同时会在EVENT列表中触发一个messagereadyevent。
(请注意最后一句话,这句话点出了为什么按键时间的触发为何会导致系统事件也接受到了)
现在以SimpleBLEPeripheral为例说明按键流程
在SimpleBLEPeripheral任务初始化函数中有这样一条代码:
//Registerforallkeyevents-Thisappwillhandleallkeyevents
RegisterForKeys(simpleBLEPeripheral_TaskID);
这个函数来自OnBoard.c源文件中
/*********************************************************************
*KeyboardRegisterfunction
*
*Thekeyboardhandlerissetuptosendallkeyboardchangesto
*onetask(ifataskisregistered).
*
*Ifataskregisters,itwillgetallthekeys.Youcanchangethis
*toregisterforindividualkeys.
*********************************************************************/
uint8RegisterForKeys(uint8task_id)
{
//Allowonlythefirsttask
if(registeredKeysTaskID==NO_TASK_ID)
{
registeredKeysTaskID=task_id;
return(true);
}
else
return(false);
}
向一个全局变量registeredKeysTaskID中赋值自己的任务ID,调用了这个函数就能成功注册按键服务,那这个全局变量在何时使用呢?
分析到这里,感觉有点迷糊了,我们可以从顶到下分析。
任何一个程序都是从main函数开始的,这点我们要坚信。
所以我们首先找到这个main函数
打开SimpleBLEPeripheral_Main.c文件可以看到/**************************************************************************************************
*@fn main
*
*@brief Startofapplication.
*
*@param none
*
*@return none
**************************************************************************************************
*/
intmain(void)
{
/*Initializehardware*/
HAL_BOARD_INIT();
//InitializeboardI/O
InitBoard(OB_COLD);
/*InitialzetheHALdriver*/
HalDriverInit();
/*InitializeNVsystem*/
osal_snv_init();
/*InitializeLL*/
/*Initializetheoperatingsystem*/
osal_init_system();
/*Enableinterrupts*/
HAL_ENABLE_INTERRUPTS();
//Finalboardinitialization
InitBoard(OB_READY);
#ifdefined(POWER_SAVING)
osal_pwrmgr_device(PWRMGR_BATTERY);
#endif
/*StartOSAL*/
osal_start_system();//NoReturnfromhere
return0;
}
我们打开InitBoard(OB_READY);可以看到如下代码
/*********************************************************************
*@fn InitBoard()
*@brief InitializetheCC2540DBBoardPeripherals
*@param level:
COLD,WARM,READY
*@return None
*/
voidInitBoard(uint8level)
{
if(level==OB_COLD)
{
//Interruptsoff
osal_int_disable(INTS_ALL);
//TurnallLEDsoff
HalLedSet(HAL_LED_ALL,HAL_LED_MODE_OFF);
//CheckforBrown-Outreset
// ChkReset();
}
else //!
OB_COLD
{
/*InitializeKeystuff*/
OnboardKeyIntEnable=HAL_KEY_INTERRUPT_ENABLE;
//OnboardKeyIntEnable=HAL_KEY_INTERRUPT_DISABLE;
HalKeyConfig(OnboardKeyIntEnable,OnBoard_KeyCallback);
}
}
看到我上面标注的函数了吧?
那个是一个按键回调服务注册函数,注册了一个OnBoard_KeyCallback函数
HalKeyConfig函数的实现:
将上述的回调函数的地址复制给了函数指针变量。
通过跟踪发现该函数的指针变量在按键的轮询函数中调用了,如下图:
/**************************************************************************************************
*@fn HalKeyPoll
*
*@brief Calledbyhal_drivertopollthekeys
*
*@param None
*
*@return None
**************************************************************************************************/
voidHalKeyPoll(void)
{
uint8keys=0;
uint8notify=0;
#ifdefined(CC2540_MINIDK)
if(!
(HAL_KEY_SW_1_PORT&HAL_KEY_SW_1_BIT)) /*Keyisactivelow*/
{
keys|=HAL_KEY_SW_1;
}
if(!
(HAL_KEY_SW_2_PORT&HAL_KEY_SW_2_BIT)) /*Keyisactivelow*/
{
keys|=HAL_KEY_SW_2;
}
#else
if(!
(HAL_KEY_SW_6_PORT&HAL_KEY_SW_6_BIT)) /*Keyisactivelow*/
{
keys|=HAL_KEY_SW_6;
}
if((HAL_KEY_JOY_MOVE_PORT&HAL_KEY_JOY_MOVE_BIT)) /*KeyisactiveHIGH*/
{
keys=halGetJoyKeyInput();
}
#endif
/*Ifinterruptsarenotenabled,previouskeystatusandcurrentkeystatus
*arecomparedtofindoutifakeyhaschangedstatus.
*/
if(!
Hal_KeyIntEnable)
{
if(keys==halKeySavedKeys)
{
/*Exit-sincenokeyshavechanged*/
return;
}
else
{
notify=1;
}
}
else
{
/*Keyinterrupthandledhere*/
if(keys)
{
notify=1;
}
}
/*Storethecurrentkeysforcomparationnexttime*/
halKeySavedKeys=keys;
/*InvokeCallbackifnewkeysweredepressed*/
if(notify&&(pHalKeyProcessFunction))
{
(pHalKeyProcessFunction)(keys,HAL_KEY_STATE_NORMAL);
}
}
在这里底层的按键查询函数调用一个函数指针,而非具体的函数,这样就将处理按键的接口留给了上层,上层应用中,叧需解析的函数指针传入的参数1:
keys就知道是哪个按键被按下了。
我们再回到刚才的OnBoard_KeyCallback回调函数处,该回调函数代码如下:
/*********************************************************************
*@fn OnBoard_KeyCallback
*
*@brief Callbackserviceforkeys
*
*@param keys -keysthatwerepressed
* state-shifted
*
*@return void
*********************************************************************/
voidOnBoard_KeyCallback(uint8keys,uint8state)
{
uint8shift;
(void)state;
//shiftkey(S1)isusedtogeneratekeyinterrupt
//applicationsshouldnotuseS1whenkeyinterruptisenabled
shift=(OnboardKeyIntEnable==HAL_KEY_INTERRUPT_ENABLE)?
false:
((keys&HAL_KEY_SW_6)?
true:
false);
if( OnBoard_SendKeys(keys,shift)!
=SUCCESS ) //就是这句话将按键消息上传到应用层去处理的
{
//ProcessSW1here
if(keys&HAL_KEY_SW_1) //Switch1
{
}
//ProcessSW2here
if(keys&HAL_KEY_SW_2) //Switch2
{
}
//ProcessSW3here
if(keys&HAL_KEY_SW_3) //Switch3
{
}
//ProcessSW4here
if(keys&HAL_KEY_SW_4) //Switch4
{
}
//ProcessSW5here
if(keys&HAL_KEY_SW_5) //Switch5
{
}
//ProcessSW6here
if(keys&HAL_KEY_SW_6) //Switch6
{
}
}
/*Ifanykeyiscurrentlypresseddownandinterrupt
isstillenabled,disableinterruptandswitchtopolling*/
if(keys!
=0)
{
if(OnboardKeyIntEnable==HAL_KEY_INTERRUPT_ENABLE)
{
OnboardKeyIntEnable=HAL_KEY_INTERRUPT_DISABLE;
HalKeyConfig(OnboardKeyIntEnable,OnBoard_KeyCallback);
}
}
/*Ifnokeyiscurrentlypresseddownandinterrupt
isdisabled,enableinterruptandturnoffpolling*/
else
{
if(OnboardKeyIntEnable==HAL_KEY_INTERRUPT_DISABLE)
{
OnboardKeyIntEnable=HAL_KEY_INTERRUPT_ENABLE;
HalKeyConfig(OnboardKeyIntEnable,OnBoard_KeyCallback);
}
}
}
进入按键消息发送函数中可以看到
/*********************************************************************
*@fn OnBoard_SendKeys
*
*@brief Send"KeyPressed"messagetoapplication.
*
*@param keys -keysthatwerepressed
* state-shifted
*
*@return status
*********************************************************************/
uint8OnBoard_SendKeys(uint8keys,uint8state)
{
keyChange_t*msgPtr;
if(registeredKeysTaskID!
=NO_TASK_ID)
{
//Sendtheaddresstothetask
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(SUCCESS);
}
else
return(FAILURE);
}
主要是将按键时间,状态和按键值打包到信息中最后通过 osal_msg_send(registeredKeysTaskID,(uint8*)msgPtr);发送到注册了按键服务的应用层去 ,最终用户按了哪个按键,如何响应该按键在系统事件SYS_EVENT_MSG中处理。
疑问又来了,为什么通过osal_msg_send收发的消息会出现在SYS_EVENT_MSG中呢?
这个疑问,就是刚才我说过的osal_msg_send(registeredKeysTaskID,(uint8*)msgPtr)会产生一个 amessage readyeventinthedestinationtaskseventlist.
/*********************************************************************
*@fn osal_msg_send
*
*@brief
*
* Thisfunctioniscalledbyatasktosendacommandmessageto
* anothertaskorprocessingelement. Thesending_taskfieldmust
* refertoavalidtask,sincethetaskIDwillbeused
* fortheresponsemessage. Thisfunctionwillalsosetamessage
* readyeventinthedestinationtaskseventlist.
*
*
*@param uint8destination_task-SendmsgtoTaskID
*@param uint8*msg_ptr-pointertonewmessagebuffer
*
*@return SUCCESS,INVALID_TASK,INVALID_MSG_POINTER
*/
uint8osal_msg_send(uint8destination_task,uint8*msg_ptr)
{
return(osal_msg_enqueue_push(destination_task,msg_ptr,FALSE));
}
/*********************************************************************
*@fn simpleBLEPeripheral_ProcessOSALMsg
*
*@brief Processanincomingtaskmessage.
*
*@param pMsg-messagetoprocess
*
*@return none
*/
staticvoidsimpleBLEPeripheral_ProcessOSALMsg(osal_event_hdr_t*pMsg)
{
switch(pMsg->event)
{
#ifdefined(CC2540_MINIDK)
caseKEY_CHANGE:
//按键处理事件,用户产生的按键都是在这里处理
simpleBLEPeripheral_HandleKeys(((keyChange_t*)pMsg)->state,((keyChange_t*)pMsg)->keys);
break;
#endif//#ifdefined(CC2540_MINIDK)
default:
//donothing
break;
}
}
在SimpleBLEPeripheral中,对按键的响应如下:
joystickright(SW2)收发广播的开启和关闭
/*********************************************************************
*@fn simpleBL
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 蓝牙 40 协议 按键 流程 分析
![提示](https://static.bdocx.com/images/bang_tan.gif)