蓝牙之十七-bluedroid scan流程

蓝牙扫描过程是指扫描蓝牙设备

app层

这里有两张截图

蓝牙之十七-bluedroid scan流程_第1张图片

第一张图显示的是安卓设置setting菜单栏中有Bluetooth这一项,点进去以后,点击右上角显示如下的截图。

蓝牙之十七-bluedroid scan流程_第2张图片

其中Refresh就是刷新设备列表,也就会扫描设备信息。

上图显示的三个菜单在BluetoothSettings.java文件。

    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        if (mLocalAdapter == null) return;
        // If the user is not allowed to configure bluetooth, do not show the menu.
        if (isUiRestricted()) return;

        boolean bluetoothIsEnabled = mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_ON;
        boolean isDiscovering = mLocalAdapter.isDiscovering();
        int textId = isDiscovering ? R.string.bluetooth_searching_for_devices :
            R.string.bluetooth_search_for_devices;
        menu.add(Menu.NONE, MENU_ID_SCAN, 0, textId)
                .setEnabled(bluetoothIsEnabled && !isDiscovering)
                .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
        menu.add(Menu.NONE, MENU_ID_RENAME_DEVICE, 0, R.string.bluetooth_rename_device)
                .setEnabled(bluetoothIsEnabled)
                .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
        menu.add(Menu.NONE, MENU_ID_SHOW_RECEIVED, 0, R.string.bluetooth_show_received_files)
                .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
        super.onCreateOptionsMenu(menu, inflater);
    }
当选择了Refresh项后,会触发如下操作:

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case MENU_ID_SCAN:
                if (mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_ON) {
                    MetricsLogger.action(getActivity(), MetricsLogger.ACTION_BLUETOOTH_SCAN);
                    startScanning();
                }
                return true;



    private void startScanning() {


        if (!mAvailableDevicesCategoryIsPresent) {
            getPreferenceScreen().addPreference(mAvailableDevicesCategory);
            mAvailableDevicesCategoryIsPresent = true;
        }

...
        mLocalManager.getCachedDeviceManager().clearNonBondedDevices();
        mAvailableDevicesCategory.removeAll();
        mInitialScanStarted = true;
        mLocalAdapter.startScanning(true);
    }
实际上调用了在frameworks层的一个BTlib实现相关功能;

    
public void startScanning(boolean force) {
        // Only start if we're not already scanning
        if (!mAdapter.isDiscovering()) {
            if (!force) {
                // Don't scan more than frequently than SCAN_EXPIRATION_MS,
                // unless forced
                if (mLastScan + SCAN_EXPIRATION_MS > System.currentTimeMillis()) {
                    return;
                }

                // If we are playing music, don't scan unless forced.
                A2dpProfile a2dp = mProfileManager.getA2dpProfile();
                if (a2dp != null && a2dp.isA2dpPlaying()) {
                    return;
                }
            }

            if (mAdapter.startDiscovery()) {
                mLastScan = System.currentTimeMillis();
            }
        }
    }

framework层

首先要求权限Manifest.permission.BLUETOOTH_ADMIN。

 private IBluetooth mService;   
 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
    public boolean startDiscovery() {
        if (getState() != STATE_ON) return false;
        try {
            synchronized(mManagerCallback) {
                if (mService != null) return mService.startDiscovery();
            }
        } catch (RemoteException e) {Log.e(TAG, "", e);}
        return false;
    }
mService用binder调用startDiscovery。

package中的BT service调用


public class AdapterService extends Service {
...
    private static class AdapterServiceBinder extends IBluetooth.Stub {
        private AdapterService mService;
        public boolean startDiscovery() {
            if (!Utils.checkCaller()) {
                Log.w(TAG, "startDiscovery() - Not allowed for non-active user");
                return false;
            }

            AdapterService service = getService();
            if (service == null) return false;
            return service.startDiscovery();
        }
    ...}
     boolean startDiscovery() {
        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                       "Need BLUETOOTH ADMIN permission");

        return startDiscoveryNative();
    }
}

JNI层调用

static jboolean startDiscoveryNative(JNIEnv* env, jobject obj) {
    ALOGV("%s:",__FUNCTION__);

    jboolean result = JNI_FALSE;
    if (!sBluetoothInterface) return result;

    int ret = sBluetoothInterface->start_discovery();
    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
    return result;
}
sBluetoothInterface是bluetooth.default.so的接口,在前篇文章中有该接口对应方法所在的位置。

协议栈层

所在目录是/system/bt/,

再次把协议栈使用的简称再罗列一遍:

BTE(bluetooth embedded system):实现BT核心功能

BTA(bluetooth application layer):用于和android frameworks交流。

BTIF(bluetooth interface):dm(device management)

BTU(bluetooth upperlayer)

BTM(bluetooth manager)

btif/src/bluetooth.c

static int start_discovery(void)
{
    /* sanity check */
    if (interface_ready() == FALSE)
        return BT_STATUS_NOT_READY;

    return btif_dm_start_discovery();
}

btif/src/btif_dm.c

btif_dm_start_discovery

扫描分为BR/EDR类型的设备和BLE类型的设备。

BR/EDR类型设备扫描参数存在tBTA_DM_INQ结构体里,参数如下:

查询模式(general  or limited),

查询的长(以1.28s为单位,最长1.28*10s),

最大的查询响应量(0表示无限制响应)。

查询过滤类型(清除,按设备类型过滤,按设备地址过滤)。

如果是BLE类型的扫描还有如下参数需要设置一些其它的参数,这里以正常设备扫描流程说明过程。

这里将BR/EDR情况的参数设置罗列如下(dm 是device management简称):

inq_params.mode = BTA_DM_GENERAL_INQUIRY;
inq_params.duration = BTIF_DM_DEFAULT_INQ_MAX_DURATION;

inq_params.max_resps = BTIF_DM_DEFAULT_INQ_MAX_RESULTS;
inq_params.report_dup = TRUE;

inq_params.filter_type = BTA_DM_INQ_CLR;
 bt_status_t btif_dm_start_discovery(void)
{
    tBTA_DM_INQ inq_params;
    tBTA_SERVICE_MASK services = 0;
    tBTA_DM_BLE_PF_FILT_PARAMS adv_filt_param;
...
    inq_params.mode = BTA_DM_GENERAL_INQUIRY;

    inq_params.duration = BTIF_DM_DEFAULT_INQ_MAX_DURATION;

    inq_params.max_resps = BTIF_DM_DEFAULT_INQ_MAX_RESULTS;
    inq_params.report_dup = TRUE;

    inq_params.filter_type = BTA_DM_INQ_CLR;
    /* TODO: Filter device by BDA needs to be implemented here */

    /* Will be enabled to TRUE once inquiry busy level has been received */
    btif_dm_inquiry_in_progress = FALSE;
    /* find nearby devices */
    BTA_DmSearch(&inq_params, services, bte_search_devices_evt);

    return BT_STATUS_SUCCESS;
}

bta_dm_api.c

查找工作不在bta层进行,前面也说了,bta层是用于和framwork对接的,所以通过发送消息给btu层,让btu层完成工作。

void BTA_DmSearch(tBTA_DM_INQ *p_dm_inq, tBTA_SERVICE_MASK services, tBTA_DM_SEARCH_CBACK *p_cback)
{

    tBTA_DM_API_SEARCH    *p_msg;

    if ((p_msg = (tBTA_DM_API_SEARCH *) GKI_getbuf(sizeof(tBTA_DM_API_SEARCH))) != NULL)
    {
        memset(p_msg, 0, sizeof(tBTA_DM_API_SEARCH));

        p_msg->hdr.event = BTA_DM_API_SEARCH_EVT;
        memcpy(&p_msg->inq_params, p_dm_inq, sizeof(tBTA_DM_INQ));
        p_msg->services = services;
        p_msg->p_cback = p_cback;
        p_msg->rs_res  = BTA_DM_RS_NONE;
        bta_sys_sendmsg(p_msg);
    }

}
msg的header是BTA_DM_API_SEARCH_EVT。该消息被放到btu_bta_msg_queue队列。该消息队列的处理函数在注册这个函数可以看出。

  fixed_queue_register_dequeue(btu_bta_msg_queue,
      thread_get_reactor(bt_workqueue_thread),
      btu_bta_msg_ready,
      NULL);

btu_task.c

void btu_bta_msg_ready(fixed_queue_t *queue, UNUSED_ATTR void *context) {
    BT_HDR *p_msg = (BT_HDR *)fixed_queue_dequeue(queue);
    bta_sys_event(p_msg);
}

上述的p_msg是workqueue中的message。

bta_sys_main.c

void bta_sys_event(BT_HDR *p_msg)
{
    UINT8       id;
    BOOLEAN     freebuf = TRUE;

    APPL_TRACE_EVENT("BTA got event 0x%x", p_msg->event);

    /* get subsystem id from event */
    id = (UINT8) (p_msg->event >> 8);

    /* verify id and call subsystem event handler */
    if ((id < BTA_ID_MAX) && (bta_sys_cb.reg[id] != NULL))
    {
        freebuf = (*bta_sys_cb.reg[id]->evt_hdlr)(p_msg);
    }
}
bta_sys_cb是函数指针集,


void bta_sys_register(UINT8 id, const tBTA_SYS_REG *p_reg)
{
    bta_sys_cb.reg[id] = (tBTA_SYS_REG *) p_reg;
    bta_sys_cb.is_reg[id] = TRUE;
}
这个函数指针的初始化在使能BT时会被初始化到。

static const tBTA_SYS_REG bta_dm_reg =
{
    bta_dm_sm_execute,
    bta_dm_sm_disable
};

static const tBTA_SYS_REG bta_dm_search_reg =
{
    bta_dm_search_sm_execute,
    bta_dm_search_sm_disable
};
tBTA_STATUS BTA_EnableBluetooth(tBTA_DM_SEC_CBACK *p_cback)
{

    tBTA_DM_API_ENABLE    *p_msg;

    /* Bluetooth disabling is in progress */
    if (bta_dm_cb.disabling)
        return BTA_FAILURE;

    memset(&bta_dm_cb, 0, sizeof(bta_dm_cb));

    bta_sys_register (BTA_ID_DM, &bta_dm_reg );
    bta_sys_register (BTA_ID_DM_SEARCH, &bta_dm_search_reg );
...
}
其调用bta_dm_search_sm_execute处理消息,sm的意思是statemachine,状态机管理穿插在整个蓝牙管理中。

bta_dm_main.c

BOOLEAN bta_dm_search_sm_execute(BT_HDR *p_msg)
{
    tBTA_DM_ST_TBL      state_table;
    UINT8               action;
    int                 i;

    APPL_TRACE_EVENT("bta_dm_search_sm_execute state:%d, event:0x%x",
        bta_dm_search_cb.state, p_msg->event);

    /* look up the state table for the current state */
    state_table = bta_dm_search_st_tbl[bta_dm_search_cb.state];

    bta_dm_search_cb.state = state_table[p_msg->event & 0x00ff][BTA_DM_SEARCH_NEXT_STATE];


    /* execute action functions */
    for (i = 0; i < BTA_DM_SEARCH_ACTIONS; i++)
    {
        if ((action = state_table[p_msg->event & 0x00ff][i]) != BTA_DM_SEARCH_IGNORE)
        {
            (*bta_dm_search_action[action])( (tBTA_DM_MSG*) p_msg);
        }
        else
        {
            break;
        }
    }
    return TRUE;
}
这个函数根据BT所处状态的不同,调用不同的函数。实际上调用的是bta_dm_search_action【0】,也即bta_dm_search_start

/* state table */
const tBTA_DM_ST_TBL bta_dm_search_st_tbl[] = {
    bta_dm_search_idle_st_table,
    bta_dm_search_search_active_st_table,
    bta_dm_search_search_cancelling_st_table,
    bta_dm_search_disc_active_st_table
};

bta_dm_act.c

这里忽略BLE情况。

void bta_dm_search_start (tBTA_DM_MSG *p_data)
{
    tBTM_INQUIRY_CMPL result;


    APPL_TRACE_DEBUG("%s avoid_scatter=%d", __func__, p_bta_dm_cfg->avoid_scatter);

    if (p_bta_dm_cfg->avoid_scatter &&
        (p_data->search.rs_res == BTA_DM_RS_NONE) && bta_dm_check_av(BTA_DM_API_SEARCH_EVT))
    {
        memcpy(&bta_dm_cb.search_msg, &p_data->search, sizeof(tBTA_DM_API_SEARCH));
        return;
    }

    BTM_ClearInqDb(NULL);//清楚查询的db(database)
    /* save search params */
    bta_dm_search_cb.p_search_cback = p_data->search.p_cback;
    bta_dm_search_cb.services = p_data->search.services;

    result.status = BTM_StartInquiry(   (tBTM_INQ_PARMS*)&p_data->search.inq_params,
                        bta_dm_inq_results_cb,
                        (tBTM_CMPL_CB*) bta_dm_inq_cmpl_cb);

    APPL_TRACE_EVENT("%s status=%d", __func__, result.status);
    if (result.status != BTM_CMD_STARTED)
    {
        result.num_resp = 0;
        bta_dm_inq_cmpl_cb ((void *)&result);
    }
}

BTM_StartInquiry中的第一个参数中inq_params,也就是btif_dm_start_discovery发送的参数。

btm_inq.c

这个函数的查询过程包括BLE和BR/EDR两种模式的查询。重点还是BR/EDR模式。

tBTM_STATUS BTM_StartInquiry (tBTM_INQ_PARMS *p_inqparms, tBTM_INQ_RESULTS_CB *p_results_cb,
                              tBTM_CMPL_CB *p_cmpl_cb)
{
    tBTM_STATUS  status = BTM_CMD_STARTED;
    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;

    BTM_TRACE_API ("BTM_StartInquiry: mode: %d, dur: %d, rsps: %d, flt: %d",
                        p_inqparms->mode, p_inqparms->duration, p_inqparms->max_resps,
                        p_inqparms->filter_cond_type);

    /* Only one active inquiry is allowed in this implementation.
       Also do not allow an inquiry if the inquiry filter is being updated */
    if (p_inq->inq_active || p_inq->inqfilt_active)
    {
        {
            return (BTM_BUSY);
            BTM_TRACE_API("BTM_StartInquiry: return BUSY");
        }
    }
    else
        p_inq->scan_type = INQ_GENERAL;

        /*** Make sure the device is ready ***/
    if (!BTM_IsDeviceUp())
        return (BTM_WRONG_MODE);

    if ((p_inqparms->mode & BTM_BR_INQUIRY_MASK)!= BTM_GENERAL_INQUIRY &&
        (p_inqparms->mode & BTM_BR_INQUIRY_MASK)!= BTM_LIMITED_INQUIRY
        )
        return (BTM_ILLEGAL_VALUE);


    /* Save the inquiry parameters to be used upon the completion of setting/clearing the inquiry filter */
    p_inq->inqparms = *p_inqparms;

    /* Initialize the inquiry variables */
    p_inq->state = BTM_INQ_ACTIVE_STATE;
    p_inq->p_inq_cmpl_cb = p_cmpl_cb;
    p_inq->p_inq_results_cb = p_results_cb;
    p_inq->inq_cmpl_info.num_resp = 0;         /* Clear the results counter */
    p_inq->inq_active = p_inqparms->mode;

    BTM_TRACE_DEBUG("BTM_StartInquiry: p_inq->inq_active = 0x%02x", p_inq->inq_active);


/* start LE inquiry here if requested */
#if BLE_INCLUDED == TRUE
    if ((p_inqparms->mode & BTM_BLE_INQUIRY_MASK)
#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)
        &&(p_inq->next_state==BTM_BLE_ONE || p_inq->next_state==BTM_BLE_TWO ||
           p_inq->next_state==BTM_NO_INTERLEAVING)
#endif
        )

    {
#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)
        p_inq->inq_active = (p_inqparms->mode & BTM_BLE_INQUIRY_MASK);
        BTM_TRACE_API("BTM:Starting LE Scan with duration %d and activeMode:0x%02x",
                       p_inqparms->duration, (p_inqparms->mode & BTM_BLE_INQUIRY_MASK));
#endif
        if (!controller_get_interface()->supports_ble())
        {
            p_inq->inqparms.mode &= ~ BTM_BLE_INQUIRY_MASK;
            status = BTM_ILLEGAL_VALUE;
        }
        /* BLE for now does not support filter condition for inquiry */
        else if ((status = btm_ble_start_inquiry((UINT8)(p_inqparms->mode & BTM_BLE_INQUIRY_MASK),
                                            p_inqparms->duration)) != BTM_CMD_STARTED)
        {
            BTM_TRACE_ERROR("Err Starting LE Inquiry.");
            p_inq->inqparms.mode &= ~ BTM_BLE_INQUIRY_MASK;
        }
#if (!defined(BTA_HOST_INTERLEAVE_SEARCH) || BTA_HOST_INTERLEAVE_SEARCH == FALSE)
        p_inqparms->mode &= ~BTM_BLE_INQUIRY_MASK;
#endif

#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)
        if(p_inq->next_state==BTM_NO_INTERLEAVING)
        {
            p_inq->next_state=BTM_FINISH;
        }
        else
        {
            BTM_TRACE_API("BTM:Interleaving: started LE scan, Advancing to next state: %d",
                           p_inq->next_state+1);
            p_inq->next_state+=1;
        }
        /* reset next_state if status <> BTM_Started */
        if(status!=BTM_CMD_STARTED)
            p_inq->next_state=BTM_BR_ONE;

        /* if interleave scan..return here */
        return status;
#endif


        BTM_TRACE_DEBUG("BTM_StartInquiry: mode = %02x", p_inqparms->mode);
    }
#endif /* end of BLE_INCLUDED */

    /* we're done with this routine if BR/EDR inquiry is not desired. */
    if ((p_inqparms->mode & BTM_BR_INQUIRY_MASK) == BTM_INQUIRY_NONE)
        return status;

    /* BR/EDR inquiry portion */
#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)
    if((p_inq->next_state==BTM_BR_ONE || p_inq->next_state==BTM_BR_TWO ||
        p_inq->next_state==BTM_NO_INTERLEAVING ))
    {
        p_inq->inq_active = (p_inqparms->mode & BTM_BR_INQUIRY_MASK);
#endif
    /* If a filter is specified, then save it for later and clear the current filter.
       The setting of the filter is done upon completion of clearing of the previous
       filter.
    */
    switch (p_inqparms->filter_cond_type)
    {
    case BTM_CLR_INQUIRY_FILTER:
        p_inq->state = BTM_INQ_SET_FILT_STATE;
        break;

    case BTM_FILTER_COND_DEVICE_CLASS:
    case BTM_FILTER_COND_BD_ADDR:
        /* The filter is not being used so simply clear it;
            the inquiry can start after this operation */
        p_inq->state = BTM_INQ_CLR_FILT_STATE;
        p_inqparms->filter_cond_type = BTM_CLR_INQUIRY_FILTER;
        /* =============>>>> adding LE filtering here ????? */
        break;

    default:
        return (BTM_ILLEGAL_VALUE);
    }

    /* Before beginning the inquiry the current filter must be cleared, so initiate the command */
    if ((status = btm_set_inq_event_filter (p_inqparms->filter_cond_type,
                                            &p_inqparms->filter_cond)) != BTM_CMD_STARTED)
        p_inq->state = BTM_INQ_INACTIVE_STATE;

#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)
        if (p_inq->next_state==BTM_NO_INTERLEAVING)
            p_inq->next_state=BTM_FINISH;
        else
        {
            BTM_TRACE_API("BTM:Interleaving: Started BTM inq, Advancing to next state: %d",
                           p_inq->next_state+1);
            p_inq->next_state+=1;
        }
     }
     if (status!=BTM_CMD_STARTED)
     {
         /* Some error beginning the scan process.
            Reset the next_state parameter.. Do we need to reset the inq_active also?
         */
        BTM_TRACE_API("BTM:Interleaving: Error in Starting inquiry, status: 0x%02x", status);
        p_inq->next_state=BTM_BR_ONE;
     }
#endif


    return (status);
}

该函数判断是否支持BLE扫描,如果支持调用btm_ble_start_inquiry进行BLE模式扫描,对于BR/EDR模式,则调用btm_set_inq_event_filter进行扫描。

btm_inq.c

static tBTM_STATUS btm_set_inq_event_filter (UINT8 filter_cond_type,
                                             tBTM_INQ_FILT_COND *p_filt_cond)
{
    UINT8    condition_length = DEV_CLASS_LEN * 2;
    UINT8    condition_buf[DEV_CLASS_LEN * 2];
    UINT8   *p_cond = condition_buf;                    /* points to the condition to pass to HCI */

#if (BTM_INQ_DEBUG == TRUE)
    BTM_TRACE_DEBUG ("btm_set_inq_event_filter: filter type %d [Clear-0, COD-1, BDADDR-2]",
        filter_cond_type);
    BTM_TRACE_DEBUG ("                       condition [%02x%02x%02x %02x%02x%02x]",
               p_filt_cond->bdaddr_cond[0], p_filt_cond->bdaddr_cond[1], p_filt_cond->bdaddr_cond[2],
               p_filt_cond->bdaddr_cond[3], p_filt_cond->bdaddr_cond[4], p_filt_cond->bdaddr_cond[5]);
#endif

    /* Load the correct filter condition to pass to the lower layer */
    switch (filter_cond_type)
    {
    case BTM_FILTER_COND_DEVICE_CLASS:
        /* copy the device class and device class fields into contiguous memory to send to HCI */
        memcpy (condition_buf, p_filt_cond->cod_cond.dev_class, DEV_CLASS_LEN);
        memcpy (&condition_buf[DEV_CLASS_LEN],
                p_filt_cond->cod_cond.dev_class_mask, DEV_CLASS_LEN);

        /* condition length should already be set as the default */
        break;

    case BTM_FILTER_COND_BD_ADDR:
        p_cond = p_filt_cond->bdaddr_cond;

        /* condition length should already be set as the default */
        break;

    case BTM_CLR_INQUIRY_FILTER:
        condition_length = 0;
        break;

    default:
        return (BTM_ILLEGAL_VALUE);     /* Bad parameter was passed in */
    }

    btm_cb.btm_inq_vars.inqfilt_active = TRUE;

    /* Filter the inquiry results for the specified condition type and value */
    if (btsnd_hcic_set_event_filter(HCI_FILTER_INQUIRY_RESULT, filter_cond_type,
                                    p_cond, condition_length))

        return (BTM_CMD_STARTED);
    else
        return (BTM_NO_RESOURCES);
}
这个函数根据条件设置查询的过滤项。

hci和tty通信

LOCAL_BR_EDR_CONTROLLER_ID选定扫描使用的BT主机控制器。

btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);

      ---》transmit_command

          ----》packet_fragmenter->fragment_and_dispatch(wait_entry->command)

                 ---》transmit_fragment

                        -》transmit_data

                             -》write(uart_fd, data + transmitted_length, length); ---uart_fd是打开的串口描述符。


static uint16_t transmit_data(serial_data_type_t type, uint8_t *data, uint16_t length) {
  assert(data != NULL);
  assert(length > 0);

  if (type < DATA_TYPE_COMMAND || type > DATA_TYPE_SCO) {
    LOG_ERROR("%s invalid data type: %d", __func__, type);
    return 0;
  }

  // Write the signal byte right before the data
  --data;
  uint8_t previous_byte = *data;
  *(data) = type;
  ++length;

  uint16_t transmitted_length = 0;
  while (length > 0) {
    ssize_t ret = write(uart_fd, data + transmitted_length, length);
    switch (ret) {
      case -1:
        LOG_ERROR("In %s, error writing to the uart serial port: %s", __func__, strerror(errno));
        goto done;
      case 0:
        // If we wrote nothing, don't loop more because we
        // can't go to infinity or beyond
        goto done;
      default:
        transmitted_length += ret;
        length -= ret;
        break;
    }
  }

done:;
  // Be nice and restore the old value of that byte
  *(data) = previous_byte;

  // Remove the signal byte from our transmitted length, if it was actually written
  if (transmitted_length > 0)
    --transmitted_length;

  return transmitted_length;
}

有发送就有对应的接收

--》【hal->read_data】--》


hci_layer.c


static const hci_hal_callbacks_t hal_callbacks = {
  hal_says_data_ready
};

  hal->init(&hal_callbacks, thread);


hal = hci_hal_get_interface();

hci_hal_h4.c

这里的串口号,和写操作的uart_fd是一样的,创建的uart_stream是串口的数据的读者对象。

static bool hal_open() {
  LOG_INFO("%s", __func__);
  // TODO(zachoverflow): close if already open / or don't reopen (maybe at the hci layer level)

  int fd_array[CH_MAX];
  int number_of_ports = vendor->send_command(VENDOR_OPEN_USERIAL, &fd_array);

  if (number_of_ports != 1) {
    LOG_ERROR("%s opened the wrong number of ports: got %d, expected 1.", __func__, number_of_ports);
    goto error;
  }

  uart_fd = fd_array[0];
  if (uart_fd == INVALID_FD) {
    LOG_ERROR("%s unable to open the uart serial port.", __func__);
    goto error;
  }

  uart_stream = eager_reader_new(uart_fd, &allocator_malloc, HCI_HAL_SERIAL_BUFFER_SIZE, SIZE_MAX, "hci_single_channel");
  if (!uart_stream) {
    LOG_ERROR("%s unable to create eager reader for the uart serial port.", __func__);
    goto error;
  }

  stream_has_interpretation = false;
  stream_corruption_detected = false;
  stream_corruption_bytes_to_ignore = 0;
  eager_reader_register(uart_stream, thread_get_reactor(thread), event_uart_has_bytes, NULL);

  // Raise thread priorities to keep up with audio
  thread_set_priority(thread, HCI_THREAD_PRIORITY);
  thread_set_priority(eager_reader_get_read_thread(uart_stream), HCI_THREAD_PRIORITY);

  return true;

error:
  interface.close();
  return false;
}
该读者对象被eager_reader_register注册,并被放在名为“hci_thread”的线程上,并在数据来临时,通过event_uart_has_bytes通知上层数据来了。

该函数的data_ready是在hal层init时上层回调函数hal_says_data_ready,这样将数据向上层传送。

// See what data is waiting, and notify the upper layer
static void event_uart_has_bytes(eager_reader_t *reader, UNUSED_ATTR void *context) {
  if (stream_has_interpretation) {
    callbacks->data_ready(current_data_type);
  } else {
    uint8_t type_byte;
    if (eager_reader_read(reader, &type_byte, 1, true) == 0) {
      LOG_ERROR("%s could not read HCI message type", __func__);
      return;
    }

    if (stream_corrupted_during_le_scan_workaround(type_byte))
      return;

    if (type_byte < DATA_TYPE_ACL || type_byte > DATA_TYPE_EVENT) {
      LOG_ERROR("%s Unknown HCI message type. Dropping this byte 0x%x, min %x, max %x", __func__, type_byte, DATA_TYPE_ACL, DATA_TYPE_EVENT);
      return;
    }

    stream_has_interpretation = true;
    current_data_type = type_byte;
  }
}
这个函数将收到的数据reassamble,并且进一步向上层传输。

蓝牙之十七-bluedroid scan流程_第3张图片

你可能感兴趣的:(蓝牙)