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
原创粉丝点击