您的位置:首页 > 产品设计 > UI/UE

蓝牙之十七-bluedroid scan流程

2016-10-16 22:35 519 查看
蓝牙扫描过程是指扫描蓝牙设备

app层

这里有两张截图



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



其中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实现相关功能;

</frameworks/base/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java>
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调用

</packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java>
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是函数指针集,

<bta_sys_main.c>
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

<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