Cubietruck---26.android蓝牙分析4_pair分析

一. setting中的调用
1. 当在屏幕上点击搜索到的蓝牙设备时,会产生一个onClicked事件
在./device/softwinner/common/packages/TvdSettings/src/com/android/settings/bluetooth/BluetoothDevicePreference.java中
  1. void onClicked() {
  2.         int bondState = mCachedDevice.getBondState();

  3.         if (mCachedDevice.isConnected()) {
  4.             askDisconnect();
  5.         } else if (bondState == BluetoothDevice.BOND_BONDED) {
  6.             mCachedDevice.connect(true);
  7.         } else if (bondState == BluetoothDevice.BOND_NONE) {
  8.             pair();
  9.         }
  10.     }
会调用pair函数
  1. private void pair() {
  2.         if (!mCachedDevice.startPairing()) {
  3.             Utils.showError(getContext(), mCachedDevice.getName(),
  4.                     R.string.bluetooth_pairing_error_message);
  5.         }
  6.     }
mCachedDevice 是一个CachedBluetoothDevice
2. 在./device/softwinner/common/packages/TvdSettings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java中
  1. boolean startPairing() { 
  2.         if (mLocalAdapter.isDiscovering()) {
  3.             mLocalAdapter.cancelDiscovery();
  4.         }
  5.         if (!mDevice.createBond()) {
  6.             return false;
  7.         }
  8.         mConnectAfterPairing = true; // auto-connect after pairing
  9.         return true;
  10.     }
在pair时,如果正在搜索,则停止搜索,并调用  CachedBluetoothDevice的createBond,  mDevice 是一个 BluetoothDevice在framework层


二. framework层中的调用
在./frameworks/base/core/java/android/bluetooth/BluetoothDevice.java中
  1. public boolean createBond() {
  2.         if (sService == null) {
  3.             return false;
  4.         }
  5.         try {
  6.             return sService.createBond(this);
  7.         } catch (RemoteException e) {Log.e(TAG, "", e);}
  8.         return false;
  9.     }
调用了sService 的createBond, 其中sService是IBluetooth,要到packages层去了

三.packages中的调用
3.1 在./packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java中
的AdapterServiceBinder类中
  1. public boolean createBond(BluetoothDevice device) {
  2.     if (!Utils.checkCaller()) {
  3.         return false;
  4.     }

  5.     AdapterService service = getService();
  6.     if (service == null) return false;
  7.     return service.createBond(device);
  8. }
在AdapterService类中
  1. boolean createBond(BluetoothDevice device) {
  2.     enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
  3.     DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
  4.     if (deviceProp != null && deviceProp.getBondState() != BluetoothDevice.BOND_NONE) {
  5.         return false;
  6.     }
  7.     Message msg = mBondStateMachine.obtainMessage(BondStateMachine.CREATE_BOND);
  8.     msg.obj = device;
  9.     mBondStateMachine.sendMessage(msg);
  10.     return true;
  11. }
发送了一个CREATE_BOND的消息
3.2 在./packages/apps/Bluetooth/src/com/android/bluetooth/btservice/BondStateMachine.java中
  1. public boolean processMessage(Message msg) {
  2.      switch(msg.what) {
  3.       case CREATE_BOND:
  4.           createBond(dev, true);
  5.           break;
  6.      }
  7. }
在消息处理函数createBond中
  1. private boolean createBond(BluetoothDevice dev, boolean transition) {
  2.     if (dev.getBondState() == BluetoothDevice.BOND_NONE) {
  3.         byte[] addr = Utils.getBytesFromAddress(dev.getAddress());
  4.         if (!mAdapterService.createBondNative(addr)) {
  5.             sendIntent(dev, BluetoothDevice.BOND_NONE,
  6.                        BluetoothDevice.UNBOND_REASON_REMOVED);
  7.             return false;
  8.         } else if (transition) {
  9.             transitionTo(mPendingCommandState);
  10.         }
  11.         return true;
  12.     }
  13.     return false;
  14. }
看到 createBondNative这个函数,就知道要调用jni了。


四. jni中的调用
在./packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp中
  1. static jboolean createBondNative(JNIEnv* env, jobject obj, jbyteArray address) {
  2.     jbyte *addr;
  3.     jboolean result = JNI_FALSE;

  4.     if (!sBluetoothInterface) return result;

  5.     addr = env->GetByteArrayElements(address, NULL);
  6.     int ret = sBluetoothInterface->create_bond((bt_bdaddr_t *)addr);
  7.     env->ReleaseByteArrayElements(address, addr, NULL);
  8.     result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
  9.     return result;
  10. }
其中这个sBluetoothInterface 是协议栈的接口

五.协议栈bluedroid中的调用
5.1 在./external/bluetooth/bluedroid/btif/src/bluetooth.c中
  1. static int create_bond(const bt_bdaddr_t *bd_addr)
  2. {
  3.     /* sanity check */
  4.     if (interface_ready() == FALSE)
  5.         return BT_STATUS_NOT_READY;
  6.     return btif_dm_create_bond(bd_addr);
  7. }
5.2 在./external/bluetooth/bluedroid/btif/src/btif_dm.c中
  1. bt_status_t btif_dm_create_bond(const bt_bdaddr_t *bd_addr)
  2. {
  3.     bdstr_t bdstr;
  4.     if (pairing_cb.state != BT_BOND_STATE_NONE)
  5.         return BT_STATUS_BUSY;
  6.     btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_CREATE_BOND,
  7.                           (char *)bd_addr, sizeof(bt_bdaddr_t), NULL);

  8.     return BT_STATUS_SUCCESS;
  9. }
具体的如何调用到了这个回调函数,参见附录1
5.3 在回调函数中进行具体的处理
在./external/bluetooth/bluedroid/btif/src/btif_dm.c中
  1. static void btif_dm_generic_evt(UINT16 event, char* p_param)
  2. {
  3.     switch(event)  //这个event就是发送的命令
  4.     {
  5.         case BTIF_DM_CB_CREATE_BOND:
  6.         {
  7.             btif_dm_cb_create_bond((bt_bdaddr_t *)p_param);
  8.         }
  9.         break;
  10.     }
  11. }
5.3.1 回调的具体处理
在./external/bluetooth/bluedroid/btif/src/btif_dm.c中
  1. static void btif_dm_cb_create_bond(bt_bdaddr_t *bd_addr)
  2. {
  3.     //状态由BT_BOND_STATE_NONE--> BT_BOND_STATE_BONDING,并通知上层
  4.     //这儿具体如何调用上层的过程,参见附录2
  5.     bond_state_changed(BT_STATUS_SUCCESS, bd_addr, BT_BOND_STATE_BONDING);
  6.     if (check_cod(bd_addr, COD_HID_POINTING)){
  7.         int status;
  8.         status = btif_hh_connect(bd_addr);
  9.         if(status != BT_STATUS_SUCCESS)
  10.             bond_state_changed(status, bd_addr, BT_BOND_STATE_NONE);
  11.     }
  12.     else
  13.     {
  14.         BTA_DmBond ((UINT8 *)bd_addr->address);
  15.     }
  16.     pairing_cb.is_local_initiated = TRUE;
  17. }
5.3.2 
在./external/bluetooth/bluedroid/bta/dm/bta_dm_api.c中
  1. void BTA_DmBond(BD_ADDR bd_addr)
  2. {
  3.     tBTA_DM_API_BOND *p_msg;

  4.     if ((p_msg = (tBTA_DM_API_BOND *) GKI_getbuf(sizeof(tBTA_DM_API_BOND))) != NULL)
  5.     {
  6.         p_msg->hdr.event = BTA_DM_API_BOND_EVT;
  7.         bdcpy(p_msg->bd_addr, bd_addr);
  8.         bta_sys_sendmsg(p_msg);
  9.     }
  10. }
在./external/bluetooth/bluedroid/bta/sys/bta_sys_main.c中
  1. void bta_sys_sendmsg(void *p_msg)
  2. {
  3.     GKI_send_msg(bta_sys_cb.task_id, p_bta_sys_cfg->mbox, p_msg);
  4. }
又到了这个sendmsg,不过这次的跟上一次不一样的地方是参数task_id不是BTIF_TASK, 所以接收者不是btif_task而是btu_task
5.3.3 在./stack/btu/btu_task.c中
  1. BTU_API UINT32 btu_task (UINT32 param)
  2. {
  3.     if (event & TASK_MBOX_2_EVT_MASK)
  4.     {
  5.         while ((p_msg = (BT_HDR *) GKI_read_mbox(TASK_MBOX_2)) != NULL)
  6.         {
  7.             bta_sys_event(p_msg);
  8.         }
  9.     }
  10. }
在./bta/sys/bta_sys_main.c中
  1. BTA_API void bta_sys_event(BT_HDR *p_msg)
  2. {
  3.     UINT8 id;
  4.     BOOLEAN freebuf = TRUE;
  5.     id = (UINT8) (p_msg->event >> 8);
  6.     freebuf = (*bta_sys_cb.reg[id]->evt_hdlr)(p_msg);  
  7. }
会调用全局函数 bta_sys_cb . reg [ id ] - > evt_hdlr,这个东东是从哪儿来的呢?
5.4  bta_sys_cb . reg [ id ] - > evt_hdlr的由来
在bta/sys/bta_sys_main.c中
  1. void bta_sys_register(UINT8 id, const tBTA_SYS_REG *p_reg)
  2. {
  3.     bta_sys_cb.reg[id] = (tBTA_SYS_REG *) p_reg;
  4.     bta_sys_cb.is_reg[id] = TRUE;
  5. }
在bta/dm/bta_dm_api.c中
  1. static const tBTA_SYS_REG bta_dm_reg =
  2. {
  3.     bta_dm_sm_execute,
  4.     bta_dm_sm_disable
  5. };
通过bta_sys_register (BTA_ID_DM, &bta_dm_reg )注册的,
所以这儿的 bta_sys_cb . reg [ id ] - > evt_hdlr调用的就是bta_dm_sm_execute
5.5 bta_dm_sm_execute
在bta/dm/bta_dm_main.c中
  1. BOOLEAN bta_dm_sm_execute(BT_HDR *p_msg)
  2. {
  3.     UINT16 event = p_msg->event & 0x00ff;
  4.     if(event < BTA_DM_NUM_ACTIONS)
  5.     {
  6.         (*bta_dm_action[event])( (tBTA_DM_MSG*) p_msg);
  7.     }

  8.     return TRUE;
  9. }
bta_dm_action是一个函数指针的数组,此时event=10,在数组中是函数bta_dm_bond
5.6
在./bta/dm/bta_dm_act.c中
  1. void bta_dm_bond (tBTA_DM_MSG *p_data)
  2. {
  3.     tBTM_STATUS status;
  4.     tBTA_DM_SEC sec_event;
  5.     char *p_name;

  6.     status = BTM_SecBond ( p_data->bond.bd_addr, 0, NULL, 0 );
  7.     if (bta_dm_cb.p_sec_cback && (status != BTM_CMD_STARTED))
  8.     {
  9.         p_name = BTM_SecReadDevName(p_data->bond.bd_addr);
  10.         if (!p_name)
  11.             p_name = "";

  12.         memset(&sec_event, 0, sizeof(tBTA_DM_SEC));
  13.         bdcpy(sec_event.auth_cmpl.bd_addr, p_data->bond.bd_addr);
  14.         memcpy(sec_event.auth_cmpl.bd_name, p_name, (BD_NAME_LEN-1));
  15.         sec_event.auth_cmpl.bd_name[BD_NAME_LEN-1] = 0;
  16.         sec_event.auth_cmpl.fail_reason = HCI_ERR_ILLEGAL_COMMAND;
  17.         if (status == BTM_SUCCESS)
  18.             sec_event.auth_cmpl.success = TRUE;

  19.         bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event);
  20.     }

  21. }

5.6.1 在./stack/btm/btm_sec.c中
  1. tBTM_STATUS BTM_SecBond (BD_ADDR bd_addr, UINT8 pin_len, UINT8 *p_pin, UINT32 trusted_mask[])
  2. {
  3.     p_dev_rec = btm_find_or_alloc_dev (bd_addr);  //第一次配对时alloc一个device 
  4.     status = btm_sec_dd_create_conn(p_dev_rec);   //进入下一步
  5.     return status;
  6. }




在stack/l2cap/l2c_utils.c中 






附一: 协议栈中消息的传递
btif_dm_create_bond 中调用了函数btif_transfer_context来发送CREATE_BOND命令
 btif_transfer_context ( btif_dm_generic_evt ,  BTIF_DM_CB_CREATE_BOND ,
                           ( char  * ) bd_addr ,  sizeof ( bt_bdaddr_t ) ,   NULL ) ;
其中btif_dm_generic_evt 是回调函数,
BTIF_DM_CB_CREATE_BOND 是命令
( char  * ) bd_addr 是参数
1.1 stack中消息的发送与处理过程
在./external/bluetooth/bluedroid/btif/src/btif_core.c中
  1. bt_status_t btif_transfer_context (tBTIF_CBACK *p_cback, UINT16 event, char* p_params, int param_len, tBTIF_COPY_CBACK *p_copy_cback)
  2. {
  3.     tBTIF_CONTEXT_SWITCH_CBACK *p_msg;
  4.     //第1步获取msg的buffer
  5.     if ((p_msg = (tBTIF_CONTEXT_SWITCH_CBACK *) GKI_getbuf(sizeof(tBTIF_CONTEXT_SWITCH_CBACK) + param_len)) != NULL)
  6.     {
  7.         //第2步组成一个msg
  8.         p_msg->hdr.event = BT_EVT_CONTEXT_SWITCH_EVT
  9.         p_msg->p_cb = p_cback;
  10.         p_msg->event = event; 
  11.         if (p_copy_cback)
  12.         {
  13.             p_copy_cback(event, p_msg->p_param, p_params);
  14.         }
  15.         else if (p_params)
  16.         {
  17.             memcpy(p_msg->p_param, p_params, param_len); /* callback parameter data */
  18.         }
  19.         /第3步,最后一步发送    
  20.         btif_sendmsg(p_msg);
  21.         return BT_STATUS_SUCCESS;
  22.     }
  23.     else
  24.     {
  25.         return BT_STATUS_NOMEM;
  26.     }
  27. }
1.2 进入core
在 ./external/bluetooth/bluedroid/btif/src/btif_core.c中
  1. void btif_sendmsg(void *p_msg)
  2. {
  3.     GKI_send_msg(BTIF_TASK, BTU_BTIF_MBOX, p_msg);
  4. }
1.3 组成命令,并发送//这个event就是发送的命令
在./external/bluetooth/bluedroid/gki/common/gki_buffer.c中
  1. void GKI_send_msg (UINT8 task_id, UINT8 mbox, void *msg)
  2. {
  3.     BUFFER_HDR_T *p_hdr;
  4.     tGKI_COM_CB *p_cb = &gki_cb.com;

  5.     p_hdr = (BUFFER_HDR_T *) ((UINT8 *) msg - BUFFER_HDR_SIZE);
  6.     GKI_disable();
  7.     if (p_cb->OSTaskQFirst[task_id][mbox])
  8.         p_cb->OSTaskQLast[task_id][mbox]->p_next = p_hdr;
  9.     else
  10.         p_cb->OSTaskQFirst[task_id][mbox] = p_hdr;

  11.     p_cb->OSTaskQLast[task_id][mbox] = p_hdr;
  12.     p_hdr->p_next = NULL;
  13.     p_hdr->status = BUF_STATUS_QUEUED;
  14.     p_hdr->task_id = task_id;
  15.     GKI_enable();
  16.     GKI_send_event(task_id, (UINT16)EVENT_MASK(mbox));
  17.     return;
  18. }
1.4 具体的发送过程
这儿说是发送,并不是发送msg,而是向接收者发送了一个信号。
在./external/bluetooth/bluedroid/gki/ulinux/gki_ulinux.c中
  1. UINT8 GKI_send_event (UINT8 task_id, UINT16 event)
  2. {
  3.     if (task_id < GKI_MAX_TASKS)
  4.     {
  5.         pthread_mutex_lock(&gki_cb.os.thread_evt_mutex[task_id]);
  6.         gki_cb.com.OSWaitEvt[task_id] |= event;
  7.         pthread_cond_signal(&gki_cb.os.thread_evt_cond[task_id]);
  8.         pthread_mutex_unlock(&gki_cb.os.thread_evt_mutex[task_id]);
  9.         return ( GKI_SUCCESS );
  10.     }
  11.     return (GKI_FAILURE);
  12. }
1.5 接收者
因为GKI_send_msg(BTIF_TASK, BTU_BTIF_MBOX, p_msg);发送的task是BTIF_TASK
所以在./external/bluetooth/bluedroid/btif/src/btif_core.c中
  1. static void btif_task(UINT32 params)
  2. {
  3.     UINT16 event;
  4.     BT_HDR *p_msg;
  5.     btif_associate_evt();
  6.     for(;;)
  7.     {
  8.         //上面的pthread_cond_signal,把下面的wait打断
  9.         event = GKI_wait(0xFFFF, 0);
  10.                 
  11.         if(event & TASK_MBOX_1_EVT_MASK)
  12.         {//这个event就是发送的命令
  13.             while((p_msg = GKI_read_mbox(BTU_BTIF_MBOX)) != NULL)
  14.             {
  15.                 switch (p_msg->event)
  16.                 {  
  17.                     case BT_EVT_CONTEXT_SWITCH_EVT:  //执行到这儿
  18.                         btif_context_switched(p_msg);
  19.                         break;
  20.                     default:
  21.                         break;
  22.                 }
  23.                 GKI_freebuf(p_msg);
  24.             }
  25.         }
  26.     }

  27.     btif_disassociate_evt();
  28. }
1.6 最后调用回调函数
在./external/bluetooth/bluedroid/btif/src/btif_core.c中
  1. static void btif_context_switched(void *p_msg)
  2. {
  3.     tBTIF_CONTEXT_SWITCH_CBACK *p;

  4.     BTIF_TRACE_VERBOSE0("btif_context_switched");

  5.     p = (tBTIF_CONTEXT_SWITCH_CBACK *) p_msg;
  6.     //调用回调函数 
  7.     if (p->p_cb)
  8.         p->p_cb(p->event, p->p_param);
  9. }
1.7 在回调函数中进行具体的处理
在./external/bluetooth/bluedroid/btif/src/btif_dm.c中
  1. static void btif_dm_generic_evt(UINT16 event, char* p_param)
  2. {
  3.     switch(event) //这个event就是发送的命令
  4.     {
  5.         case BTIF_DM_CB_CREATE_BOND:
  6.         {
  7.             btif_dm_cb_create_bond((bt_bdaddr_t *)p_param);
  8.         }
  9.         break;
  10.     }
  11. }
1.8 
根据task_id来区分是发送给btif_task还是btu_task


2.5 总结一下


附三: 
在stack/hcic/hcicmds.c中
  1. BOOLEAN btsnd_hcic_delete_stored_key (BD_ADDR bd_addr, BOOLEAN delete_all_flag)
  2. {
  3.     BT_HDR *p;
  4.     UINT8 *pp;

  5.     = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_DELETE_STORED_KEY); //获取buffer
  6.     pp = (UINT8 *)(+ 1);

  7.     p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_DELETE_STORED_KEY;
  8.     p->offset = 0;

  9.     UINT16_TO_STREAM (pp, HCI_DELETE_STORED_LINK_KEY);
  10.     UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_DELETE_STORED_KEY);

  11.     BDADDR_TO_STREAM (pp, bd_addr);
  12.     UINT8_TO_STREAM (pp, delete_all_flag);

  13.     btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
  14.     return (TRUE);
  15. }

在stack/btu/btu_hcif.c中
  1. void btu_hcif_send_cmd (UINT8 controller_id, BT_HDR *p_buf)
  2. {
  3.     if (controller_id == LOCAL_BR_EDR_CONTROLLER_ID)
  4.         HCI_CMD_TO_LOWER(p_buf);
  5. }
#define HCI_CMD_TO_LOWER(p)         bte_main_hci_send((BT_HDR *)(p), BT_EVT_TO_LM_HCI_CMD);
在main/bte_main.c 中
  1. void bte_main_hci_send (BT_HDR *p_msg, UINT16 event)
  2. {
  3.     UINT16 sub_event = event & BT_SUB_EVT_MASK; /* local controller ID */
  4.     p_msg->event = event;
  5.     if((sub_event == LOCAL_BR_EDR_CONTROLLER_ID) ||  (sub_event == LOCAL_BLE_CONTROLLER_ID))
  6.     {
  7.         if (bt_hc_if)
  8.         {
  9.             bt_hc_if->transmit_buf((TRANSAC)p_msg, (char *) (p_msg + 1), p_msg->len);
  10.         }
  11.         else
  12.             GKI_freebuf(p_msg);
  13.     }    
  14. }

在hci/src/bt_hci_bdroid.c中
  1. static int transmit_buf(TRANSAC transac, char *p_buf, int len)
  2. {
  3.     utils_enqueue(&tx_q, (void *) transac);
  4.     bthc_signal_event(HC_EVENT_TX);
  5.     return BT_HC_STATUS_SUCCESS;
  6. }
发送了一个 HC_EVENT_TX 信号

那么是谁来接收这个HC_EVENT_TX命令呢?
在hci/src/bt_hci_bdroid.c中
  1. static void *bt_hc_worker_thread(void *arg)
  2. {
  3.     if (events & HC_EVENT_TX)
  4.     {
  5.         tx_cmd_pkts_pending = FALSE;
  6.         HC_BT_HDR * sending_msg_que[64];
  7.         int sending_msg_count = 0;
  8.         utils_lock();
  9.         p_next_msg = tx_q.p_first;
  10.         while (p_next_msg && sending_msg_count < (int)sizeof(sending_msg_que)/sizeof(sending_msg_que[0]))
  11.         {
  12.             if ((p_next_msg->event & MSG_EVT_MASK)==MSG_STACK_TO_HC_HCI_CMD)
  13.             {
  14.                 if ((tx_cmd_pkts_pending == TRUE) || (num_hci_cmd_pkts <= 0))
  15.                 {
  16.                     tx_cmd_pkts_pending = TRUE;
  17.                     p_next_msg = utils_getnext(p_next_msg);
  18.                     continue;
  19.                 }
  20.             }

  21.             p_msg = p_next_msg;
  22.             p_next_msg = utils_getnext(p_msg);
  23.             utils_remove_from_queue_unlocked(&tx_q, p_msg);
  24.             sending_msg_que[sending_msg_count++] = p_msg;
  25.         }
  26.         utils_unlock();
  27.         int i;
  28.         for(= 0; i < sending_msg_count; i++)
  29.             p_hci_if->send(sending_msg_que[i]);
  30.         if (tx_cmd_pkts_pending == TRUE)
  31.             BTHCDBG("Used up Tx Cmd credits");
  32.         }
  33. }

其中p_hci_if的初始化是在hci/src/bt_hci_bdroid.c中
  1. static int init(const bt_hc_callbacks_t* p_cb, unsigned char *local_bdaddr)
  2. {

  3. #ifdef HCI_USE_MCT              //MCT: Multi-Channels Transport
  4.     extern tHCI_IF hci_mct_func_table;
  5.     p_hci_if = &hci_mct_func_table;
  6. #elif defined HCI_USE_RTK_H5
  7.     extern tHCI_IF hci_h5_func_table;
  8.     p_hci_if = &hci_h5_func_table;
  9. #else
  10.     extern tHCI_IF hci_h4_func_table;
  11.     p_hci_if = &hci_h4_func_table;      //这儿是用的这个
  12. #endif

  13.     p_hci_if->init();
  14. }



在hci/src/userial.c中
  1. uint16_t userial_write(uint16_t msg_id, uint8_t *p_data, uint16_t len)
  2. {
  3.     int ret, total = 0;

  4.     while(len != 0)
  5.     {
  6.         ret = write(userial_cb.fd, p_data+total, len);
  7.         total += ret;
  8.         len -= ret;
  9.     }

  10.     return ((uint16_t)total);
  11. }

在hci/src/userial.c中,初始化了userial_cb . fd
  1. uint8_t userial_open(uint8_t port)
  2. {
  3.     bt_vnd_if->op(BT_VND_OP_USERIAL_OPEN, &fd_array); //向libbt_verder.so发消息
  4.     userial_cb.fd = fd_array[0];
  5. }



  1. root@android:/ # ls /dev/ttyS2 -
  2. crw-rw---- bluetooth net_bt_stack 250, 2 2014-08-19 15:30 ttyS2


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值