csr8670--sink工程的大致工作流程分析(以speaker为例)一
来源:互联网 发布:mysql 5.5.21.tar.gz 编辑:程序博客网 时间:2024/06/03 23:48
今天是14号 15号更新,说明,刚开始看程序有点复杂 没办法,必须看代码
建议首先先把ADK3.5.1中的例程tutorials看完,对学习很有帮助
1.csr中的消息机制
1.1 adk3.5.1中的led的例子
- csr8670中是以消息机制进行任务调度的,根据消息调用相应的回调函数进行处理,如下面这个例子所示:在主函数中,首先设置PIO为输出并且设置为低电平,然后调用了messagesend函数和messageloop函数
- TaskData :这个结构体是最重要的,可以看出定义了一个函数指针,其参数有三个
typedef struct TaskData { void (*handler)(Task, MessageId, Message); } TaskData;
- messagesend:这个函数能够向某个任务发送消息
- messageloop:开始任务调度,不会返回
static void led_controller1( Task t, MessageId id, Message payload ){ PioSet32( LED1, (PioGet32() ^ LED1) ); MessageSendLater( t, 0, 0, DELAY1 );}static void led_controller2( Task t, MessageId id, Message payload ){ PioSet32( LED2, (PioGet32() ^ LED2) ); MessageSendLater( t, 0, 0, DELAY2 );}static TaskData led_controller1_task = { led_controller1 };//实例化了一个任务,并初始化了其参数,即回调函数static TaskData led_controller2_task = { led_controller2 };int main(void){ PioSetDir32(0xFF, 0xFF); /* Set all PIO to be output */ PioSet32(0xFF, 0); /* Set all PIO off (0) */ MessageSend( &led_controller1_task, 0 , 0 );//第一个参数为发送给哪个任务 MessageSend( &led_controller2_task, 0 , 0 ); MessageLoop();//开始任务调度 return 0;}
1.2 hsTaskData结构体
csr中是以消息机制来进行任务的处理的,其中最大的任务为theSink,其结构体如下
/* Sink application data */typedef struct{ /* Main task */ TaskData task;//最重要的任务,指向最高层的回到函数,即main函数里边的app_handler /* Config variables */ ButtonsTaskData *theButtonsTask;//按键的任务,这些是最高层任务之下的任务,之所以定义在最高层里面,应该是想让最高层具有知道所有事件运行情况的能力 LedTaskData *theLEDTask;//led显示的任务,同上 runtime_block1_t *rundata;//运行时的数据,目前还不了解 config_block1_t *conf1;//解下来的7个block以后会分析 config_block2_t *conf2; config_block3_t *conf3; config_block4_t *conf4; config_block5_t *conf5; config_block6_t *conf6; config_block7_t *conf7; ConfigTone_t gConfigTones; volume_levels_t *volume_levels; /* current operating volume levels for a2dp/usb/wired modes */ power_table *user_power_table; /* pointer to user power table if available in ps */ hfp_common_plugin_params_t hfp_plugin_params; HFP_features_type HFP_supp_features; feature_config_type features; bdaddr local_bd_addr; /* Local BD Address of the sink device available in ps */ /* Runtime variables */ /*下面这些运行时的变量都是在动态的生成或者释放的,每一个和button一样都是一个任务*/ Task codec_task ; Sink routed_audio; uint16 NoOfReconnectionAttempts; profile_data_t profile_data[MAX_MULTIPOINT_CONNECTIONS]; a2dp_data *a2dp_link_data;#ifdef ENABLE_AVRCP avrcp_data *avrcp_link_data;#endif tp_bdaddr *confirmation_addr; inquiry_data_t inquiry;#ifdef ENABLE_PBAP pbapc_data_t pbapc_data;#endif#ifdef ENABLE_USB usb_info *usb;#endif#ifdef ENABLE_PEER bdaddr remote_peer_ag_bd_addr;#endif user_eq_bank_t *PEQ; /*! Runtime flags*/ /*word 1*/ unsigned PowerOffIsEnabled:1; /*自行百度结构体的用法,这样写应该是为了节省空间*/ unsigned SinkInitialising:1; unsigned VolumeOrientationIsInverted:1; /*whether or not the vol buttons are inverted*/ unsigned NetworkIsPresent:1; unsigned inquiry_scan_enabled:1; unsigned page_scan_enabled:1 ; unsigned csr_speech_recognition_is_active:1 ; unsigned csr_speech_recognition_tuning_active:1 ; unsigned panic_reconnect:1; unsigned last_outgoing_ag:2 ; /* which AG made the last outgoing call */ unsigned audio_prompts_enabled:1; unsigned confirmation:1; unsigned debug_keys_enabled:1; unsigned RepeatCallerIDFlag:1; unsigned mute_all_outputs:1; /*word 2*/ unsigned audio_prompt_language:4; unsigned num_audio_prompt_languages:4; unsigned MultipointEnable:1; unsigned powerup_no_connection:1; /* bit to indicate device has powered and no connections yet */ unsigned paging_in_progress:1; /* bit to indicate that device is curretly paging whilst in connectable state */ unsigned audioAmpPowerPin:1; /* bit to indicate logic state of audio amplifier power pin */ unsigned battery_state:3; unsigned gVolButtonsInverted:1; /*! whether or not the volume button operation is currently inverted*/ /*word 3*/ unsigned FailAudioNegotiation:1; unsigned RenegotiateSco:1; unsigned lbipmEnable:1; /* enable Low Battery Intelligent Power Management feature */ unsigned buttons_locked:1; /* Flag to indicate if button locking is enabled */ unsigned HeldCallIndex:4; /* which call to route in the case of multiple held calls */ unsigned inquiry_tx:8; /*word 4*/ unsigned MissedCallIndicated:8; unsigned gEventQueuedOnConnection:8 ; /*word 5*/ unsigned mute_states:3; unsigned pbap_access:1; /* Link Policy expedites PBAP access */ unsigned dfu_access:1; /* Link Policy expedites DFU data transfer */ unsigned hfp_profiles:3; unsigned ssr_enabled:1; unsigned VoiceRecognitionIsActive:2; unsigned PartyModeEnabled:1;#ifdef ENABLE_PEER unsigned remote_peer_audio_conn_status:3; /* Flag to indicate which Audio sources are connected to the remote peer */ unsigned tws_qual_enable_peer_open:1; /* Flag to indicate App to trigger opening of Peer media channel */#else unsigned unused4:4;#endif /* word 6 */ unsigned gated_audio:8; /* Bitmask indicating which audio sources are prevented from being routed */ unsigned linkLossReminderTime:8; /* word 7 */ peer_states_t peer;#if defined(ENABLE_PEER) && defined( ENABLE_PEER_BATTERY_LEVEL) uint16 peer_battery_level;#endif} hsTaskData;
2.sink工程的流程分析
2.1 sink的初始化和工具
- 如下图所示,描述了之前提到过的csr的开发流程,即pc工具和开发环境配合使用,所以在程序中需要读取这些配置的参数等数据
2.2 speaker流程分析
- 第一步:init函数,对sink工程进行单步调试发现,工程首先进入的入口函数是init函数,而不是main函数,下面都是大致的分析,对整个流程有个初步的认识即可
/* Time critical initialisation */#ifdef HOSTED_TEST_ENVIRONMENTvoid _sink_init(void)#elsevoid _init(void)#endif{ /* Set the application task */ theSink.task.handler = app_handler; /*这个就是上面提及的最重要的任务的回调函数,如果其他任务想让这个任务的事件触发,则向它发送消息,第一个参数为这个任务的TASK*/ /* set flag to indicate that configuration is being read, use to prevent use of variables prior to completion of initialisation */ theSink.SinkInitialising = TRUE;/*将sink的正在初始化标志置位*/ /* Read in any PIOs required */ configManagerPioMap();/*根据配置文件获取PIO的设置和映射关系*/ /* Time critical USB setup */ usbTimeCriticalInit();/*目前没有用到*/}
- 第二步:mian函数,看函数注释说sink引用程序从这里开始,突然发现上面的init函数前面包含了一个下划线,这个带下划线的函数我们应该是单步不到的,应该是系统自动上电执行的,超出我们单步调试的范围,应该是系统内部的函数,目前不是很了解。
/* The Sink Application starts here...*/#ifdef HOSTED_TEST_ENVIRONMENTint sink_main(void)#elseint main(void)#endif{ DEBUG (("Main [%s]\n",__TIME__)); /* Initialise the Upgrade lib */ sinkUpgradeInit(&theSink.task);/*这个和更新有关,暂不考虑*/ /* check and update as necessary the software version pskey, this is used for ensuring maximum compatibility with the sinkg configuration tool */ configManagerSetVersionNo();/*版本相关*/ /* Initialise memory required early */ configManagerInitMemory();/*这个函数里面开辟了runtime_block1_t 这个结构体,初始化为0*/ /* initialise memory for the led manager */ LedManagerMemoryInit();/*开辟了LedTaskData结构体的空间,初始化为0*/ /* Initialise device state */ AuthResetConfirmationFlags();/*不懂?*/ /*the internal regs must be latched on (smps and LDO)*/ PioSetPowerPin ( TRUE ) ;/*不懂?*/ switch (BootGetMode() )/*配置工具可以设置系统的启动模式*/ {#ifdef CVC_PRODTEST case BOOTMODE_CVC_PRODTEST: /*run the cvc prod test code and dont start the applicaiton */ cvcProductionTestEnter() ; break ;#endif case BOOTMODE_DFU: /*do nothing special for the DFU boot mode, This mode expects to have the appropriate host interfface enabled Don't start the application */ /* Initializing only the system components required for flashing the led pattern in the DFU mode*/ configManagerInit(FALSE); LEDManagerIndicateEvent(EventUsrEnterDFUMode); break ; case BOOTMODE_DEFAULT: case BOOTMODE_CUSTOM: case BOOTMODE_USB_LOW_POWER: case BOOTMODE_ALT_FSTAB: default: { /* Initialise the Connection lib */ sinkConnectionInit();/*初始化连接库,从这里开始,可以把整个连接库从初始化调用到完成分析一下*/ #ifdef TEST_HARNESS test_init(); #endif } break ; } /* Make sure the mute states are correctly set up */ VolumeSetInitialMuteState();/*静音模式初始化*/ /* Start the message scheduler loop */ MessageLoop();/*开始任务调度*/ /* Never get here...*/ return 0;}
- 第三步:连接库的具体初始化过程
- 2.3.1.sinkConnectionInit函数,注意这个函数使用static修饰
static void sinkConnectionInit(void){ /* read the lengths key into a temporary malloc to get pdl length */ /*给pdl分配空间*/ lengths_config_type * lengths_key = PanicUnlessMalloc(sizeof(lengths_config_type)); /* The number of paired devices can be restricted using pskey user 40, a number between 1 and 8 is allowed */ /*读取pdl*/ ConfigRetrieve(CONFIG_LENGTHS, lengths_key , sizeof(lengths_config_type) ); DEBUG (("PDLSize[%d]\n" , lengths_key->pdl_size )); /* Initialise the Connection Library with the options */ /*具体的初始化函数,注意(0001)第一个参数为最上层的任务,第三个参数为pdl的个数*/ ConnectionInitEx2(&theSink.task , NULL, lengths_key->pdl_size ); /* free the malloc'd memory */ free(lengths_key);/*这里需要关注一下,这种malloc,free的模式在工程中很常见,都是先分配空间,使用之后再释放,在哪里看的目的好像是说减少栈内存的使用*/}
- 2.3.2.看源代码可知ConnectionInitEx2–>ConnectionInitEx3,所以接下来是ConnectionInitEx3这个函数,参数前三个对应
void ConnectionInitEx3(Task theAppTask, const msg_filter *msgFilter , uint16 TdlNumberOfDevices , uint16 options){ /*注意这里面又有了一个theCm,自己可以分析一下,怎样和最重要的任务产生关系*/ theCm.msgFilter = (msgFilter == NULL) ? &defaultMsgFilter : msgFilter; /* Initialise the Connection Library Task, all upstream messages sent by Bluestack will be handled by this task */ /*这也是个任务,初始化其回调函数*/ theCm.task.handler = connectionBluestackHandler; /* If a task is already registered to receive BlueStack prims then we panic! */ if (MessageBlueStackTask(connectionGetCmTask())) { CL_DEBUG(("ERROR - task already registered\n")); } /* Init the resource locks */ initLocks(); /* Init the sm_init_msg types.*/ theCm.smState.sm_init_msg = sm_init_set_none; /* Store the application task */ /*在这一步,将最终要的任务,赋值给这个任务的结构体,这样这个任务就可以向最重要任务发消息*/ theCm.theAppTask = theAppTask; /*set the number of devices to the requested value if in the range 1 to 8*/ theCm.smState.TdlNumberOfDevices = DEFAULT_NO_DEVICES_TO_MANAGE ; if ((TdlNumberOfDevices >= MIN_NO_DEVICES_TO_MANAGE) && (TdlNumberOfDevices <= MAX_NO_DEVICES_TO_MANAGE)) { theCm.smState.TdlNumberOfDevices = TdlNumberOfDevices ; } /* Process options */ /* Enable SC */ if (options & CONNLIB_OPTIONS_SC_ENABLE) theCm.flags |= CONNECTION_FLAG_SC_ENABLE; /* Enable SC only mode. It implies SC must be turned on as well */ if (options & CONNLIB_OPTIONS_SCOM_ENABLE) theCm.flags |= (CONNECTION_FLAG_SCOM_ENABLE | CONNECTION_FLAG_SC_ENABLE); /* Start the initialisation process */ MessageSend(connectionGetCmTask(), CL_INTERNAL_INIT_REQ, NO_PAYLOAD);/*这里发送消息给&theCm.task,也即上面赋值过的回调函数connectionBluestackHandler,第二个代表连接内部初始化请求此数值为1,第三个参数延时时间*/}
- 2.3.3 现在走进connectionBluestackHandler这个函数看怎样处理这个消息
/****************************************************************************NAME connectionBluestackHandlerDESCRIPTION This is the main task handler for all messages sent to the Connection Library task.RETURNS void*/void connectionBluestackHandler(Task task, MessageId id, Message message){ /* Get access to the Connection Library instance state */ /*获取这个传递过来的任务*/ connectionState *theCm = (connectionState *)task; connectionStates state = theCm->state; PRINT(("connectionBluestackHandler - Id = 0x%x\n",id)); /* Handle Bluestack primitives seperately */ switch (id) { case MESSAGE_BLUESTACK_DM_PRIM:/*8004*/ connectionBluestackHandlerDm(theCm, (DM_UPRIM_T *)message); break;#ifndef CL_EXCLUDE_RFCOMM case MESSAGE_BLUESTACK_RFCOMM_PRIM:/*8006*/ connectionBluestackHandlerRfcomm(theCm, (RFCOMM_UPRIM_T *)message); break;#endif#if !defined(CL_EXCLUDE_L2CAP) || !defined(DISABLE_BLE) case MESSAGE_BLUESTACK_L2CAP_PRIM:/*8005*/ connectionBluestackHandlerL2cap(theCm, (L2CA_UPRIM_T *)message); break;#endif#ifndef CL_EXCLUDE_SDP case MESSAGE_BLUESTACK_SDP_PRIM:/*8007*/ connectionBluestackHandlerSdp(theCm, (SDS_UPRIM_T *)message); break;#endif case MESSAGE_BLUESTACK_UDP_PRIM:/*8015*/ case MESSAGE_BLUESTACK_TCP_PRIM:/*8014*/ handleUnexpected(connectionUnhandledMessage, theCm->state, id); break;#ifndef CL_EXCLUDE_SDP /* CL_SDP_CLOSE_SEARCH_CFM Primitive arrived as a result of an internal call to close SDP search, can't avoid so ignore Handled as a special case to allow the compiler to generate better code for the previous switch statements. */ case CL_SDP_CLOSE_SEARCH_CFM: break;#endif /* Everything else must be internal connection library primitives */ default:/*可知1会进入这里*/ { switch (state)/*然会根据任务的状态判断,我们可以回过头去看看这个任务的状态在什么时间被赋值了,发现没有处理过所以为0,会进入connectionUninitialised这个值也为0*/ { case connectionReady: connectionBluestackHandlerReady(theCm, id, message); break; case connectionUninitialised: connectionBluestackHandlerUninitialised(theCm, id, message);/*注意传递过去的参数*/ break; case connectionInitialising: connectionBluestackHandlerInitialising(theCm, id, message); break; case connectionTestMode: connectionBluestackHandlerTestMode(theCm, id, message); break; } } }}
- 2.3.4 connectionBluestackHandlerUninitialised函数
static void connectionBluestackHandlerUninitialised(connectionState *theCm, MessageId id, Message message){ /* Depending upon the message id...*/ /*由前面可以知道此时相等*/ if (id == CL_INTERNAL_INIT_REQ) { PRINT(("CL_INTERNAL_INIT_REQ\n")); connectionHandleInternalInit(connectionInit);/*执行这个函数,注意参数为0*/ } else { /* Prims we are not handling - Not panicing the app in DEBUG Mode. Just Print this INFO and ignore it.*/ CL_DEBUG_INFO(("Ignored Unexpected Message - Code 0x%x State 0x%x MsgId 0x%x\n", connectionUnexpectedCmPrim, theCm->state, id)) }}
- 2.3.5 connectionHandleInternalInit函数
void connectionHandleInternalInit(connectionInitState state){ /* If we're ready to run, change state */ if(state == connectionInitComplete) { theCm.state = connectionReady; } else if (theCm.state != connectionInitialising)/*这个成立,此时状态为未初始化*/ { theCm.state = connectionInitialising;/*改变状态*/ /* Start a Timer to notify the Client if the initialisation fails */ /*等待一段时间发送CL_INTERNAL_INIT_TIMEOUT_IND这个消息此数值为0,还是向connectionBluestackHandler发送的,注意第三个参数,这个是个时间,很重要下面会分析到*/ MessageSendLater(&theCm.task, CL_INTERNAL_INIT_TIMEOUT_IND, NO_PAYLOAD, (uint32) INIT_TIMEOUT); } /* Check to see if all objects have been initialised */ if(state == connectionInitComplete) { /* Initialise auth requirements to unknown */ theCm.smState.authentication_requirements = AUTH_REQ_UNKNOWN; /* Some DM stuff can be initialised only after the DM register has happened so do it here */ connectionDmInfoInit(); /* Let the application we're ready to go */ connectionSendInitCfm(theCm.theAppTask, success, theCm.infoState.version); } else { /* Depending upon the previous object initialised, initialise the next one */ switch(state) { case connectionInit:/*此时会调用这个函数*/ connectionDmInit(); /*这个是个初始化,做什么的不了解*/ break; case connectionInitDm:#ifndef CL_EXCLUDE_RFCOMM connectionRfcInit(); #else connectionL2capInit();#endif break;#ifndef CL_EXCLUDE_RFCOMM case connectionInitRfc: connectionL2capInit(); break;#endif case connectionInitL2cap: connectionUdpInit(); break; case connectionInitUdp: connectionTcpInit(); break; case connectionInitTcp: connectionSdpInit(&theCm.sdpState); break; case connectionInitSdp: connectionVersionInit(); break; case connectionInitVer: connectionSmInit(theCm.infoState.version, &theCm.smState, theCm.flags); break; case connectionInitSm: theCm.smState.noDevices = connectionAuthInit(); break; case connectionInitComplete: /* We're ready! */ default: break; } }}
- 2.3.6 接下来第二次进入connectionBluestackHandler这个函数,只不过此时的状态已经更改为theCm.state = connectionInitialising;所以进入的函数为
case connectionInitialising:
connectionBluestackHandlerInitialising(theCm, id, message);
break; - 2.3.7 connectionBluestackHandlerInitialising函数分析,此时的id为CL_INTERNAL_INIT_TIMEOUT_IND
static void connectionBluestackHandlerInitialising(connectionState *theCm, MessageId id, Message message){ /* Depending upon the message id...*/ switch (id) { case CL_INTERNAL_INIT_CFM: PRINT(("CL_INTERNAL_INIT_CFM\n")); connectionHandleInternalInit(((CL_INTERNAL_INIT_CFM_T*)message)->state); break; case CL_INTERNAL_INIT_TIMEOUT_IND:/*所以会执行下面的语句*/ PRINT(("CL_INTERNAL_INIT_TIMEOUT_IND\n")); (void)MessageCancelFirst(&theCm->task, CL_INTERNAL_INIT_CFM); SET_CM_STATE(connectionUninitialised); connectionSendInitCfm(theCm->theAppTask, fail, bluetooth_unknown);/*这个函数是个重点,关注它的第一个参数为最重要的那个任务*/ break; case CL_INTERNAL_SM_INIT_REQ: PRINT(("CL_INTERNAL_SM_INIT_REQ\n")); handleSecurityInitReq(&theCm->infoState, (CL_INTERNAL_SM_INIT_REQ_T *)message); break; case CL_INTERNAL_DM_READ_LOCAL_VERSION_REQ: PRINT(("CL_INTERNAL_DM_READ_LOCAL_VERSION_REQ\n")); connectionHandleReadLocalVersionRequest(&theCm->infoState, (CL_INTERNAL_DM_READ_LOCAL_VERSION_REQ_T *)message); break; case CL_INTERNAL_DM_SET_BT_VERSION_REQ: PRINT(("CL_INTERNAL_DM_SET_BT_VERSION_REQ\n")); connectionHandleSetBtVersionReq(&theCm->infoState, (CL_INTERNAL_DM_SET_BT_VERSION_REQ_T *)message); break; default: /* Prims we are not handling - for now panic the app */ handleUnexpected(connectionUnhandledMessage, theCm->state, id); break; }}
- 2.3.8 回不去了 好像分析有误^0^………………..接着看connectionSendInitCfm函数
void connectionSendInitCfm(Task task, connection_lib_status status, cl_dm_bt_version version){ MAKE_CL_MESSAGE(CL_INIT_CFM); message->status = status;//这里这个是fail message->version = version;//版本的话没有bluetooth_unknown /*这个函数是重点,这个task是最重要的任务,所以会往上面返回一个没有初始化成功的标志*/ MessageSend(task, CL_INIT_CFM, message); /* Cancel initialisation timeout */ if(status == success) (void) MessageCancelFirst(connectionGetCmTask(), CL_INTERNAL_INIT_TIMEOUT_IND);}
汗啊,分析了一遍结果发现到头来初始化失败了啊!!
莫急,有没有注意到我上面说的那个时间很重要的参数,没错就是在这里,当这个时间到之后,确实会发送初始化失败,但是如果底层初始化成功的话这个消息将被取消,不会发往上面,其实程序看到这里的话,应该知道当状态变为初始化完成时,会向上面发送成功的标志,应该说流程大致有个印象,对于具体的其状态是怎样切换成初始化完成的,这个有待后面研究,目前我也不是很懂。
3.几个需要重要关注的地方
- 结构体的理解是个重点
- 连接库初始化的过程中状态的切换是个重点:这个没有解决!!!
百度文档搜索到一篇不错的文档:
注:参考文档,百度文档的对sink流程的分析–CSR ADK sink理解
0 0
- csr8670--sink工程的大致工作流程分析(以speaker为例)一
- csr8670--sink工程的大致工作流程分析(以speaker为例)一
- csr8670--sink工程的大致工作流程分析(以speaker为例)二
- csr8670--sink工程的大致工作流程分析(以speaker为例)二
- 基于ADK4.1下CSR8670跑系统默认SINK下的speaker工程
- hadoop大致的工作流程
- HBase1.0.0源码分析之请求处理流程分析以Put操作为例(一)
- G-sensor driver工作的大致流程
- G-sensor driver工作的大致流程
- ssh框架大致的工作流程
- Docker的性能损耗:以基因组分析流程为例
- 大致工作流程
- Binder客户端和驱动端通信流程实例分析----以acquireWakeLock()函数为例 (一)
- 传统Ajax的工作流程(以检测新用户id是否可用为例)
- IT工程的工作流程(漫画)
- magento ----后台grid模块的加载 --以news插件为例个人分析(一)
- HBase1.0.0源码分析之请求处理流程分析以Put操作为例(二)
- Struts2的执行流程解释以及源码分析(以登录 和自动登录实现 为例)
- SharePoint Server 2016 Beta 中已弃用的功能
- A应用中打开B应用
- couchbase 3.0.1 问题总结
- 2015总结
- 蓝桥--在线评测--入门训练
- csr8670--sink工程的大致工作流程分析(以speaker为例)一
- 扩大栈空间
- spring初始化refresh()方法中obtainFreshBeanFactory()源码走读。
- LeetCode_OJ【44】Wildcard Matching
- Android:RelativeLayout 属性
- 不兼容结构的协调——适配器模式(二):算法库适配器模式解决方案
- Tomcat 启动报错:host-manager does not exist or is not a readable directory
- 干掉头疼的finished with non-zero exit value 2
- Docker网络详解及pipework源码解读与实践