android bluedroid bt 读写特性值的流程

来源:互联网 发布:淘宝花呗还钱 编辑:程序博客网 时间:2024/06/03 11:19

这里我们以android 5.0来讲,当两个设备通过HOGP建立连接后,双方可以通过gatt read/write 读/写相关的特性值,

这里以write为例子,例如在APK里面调用如下的API接口,
framework/base/core/java/android/bluetooth/BluetoothGatt.java

/**
     * Writes a given characteristic and its values to the associated remote device.
     *
     * <p>Once the write operation has been completed, the
     * {@link BluetoothGattCallback#onCharacteristicWrite} callback is invoked,
     * reporting the result of the operation.
     *
     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
     *
     * @param characteristic Characteristic to write on the remote device
     * @return true, if the write operation was initiated successfully
     */
    public boolean writeCharacteristic(BluetoothGattCharacteristic characteristic) {
        if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) == 0
            && (characteristic.getProperties() &
                BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) == 0) return false;

        if (VDBG) Log.d(TAG, "writeCharacteristic() - uuid: " + characteristic.getUuid());
        if (mService == null || mClientIf == 0 || characteristic.getValue() == null) return false;

        BluetoothGattService service = characteristic.getService();
        if (service == null) return false;

        BluetoothDevice device = service.getDevice();
        if (device == null) return false;

        synchronized(mDeviceBusy) {
            if (mDeviceBusy) return false;
            mDeviceBusy = true;
        }

        try {
            mService.writeCharacteristic(mClientIf, device.getAddress(),
                service.getType(), service.getInstanceId(),
                new ParcelUuid(service.getUuid()), characteristic.getInstanceId(),
                new ParcelUuid(characteristic.getUuid()),
                characteristic.getWriteType(), AUTHENTICATION_NONE,
                characteristic.getValue());
        } catch (RemoteException e) {
            Log.e(TAG,"",e);
            mDeviceBusy = false;
            return false;
        }

        return true;
    }


mService为IBluetoothGatt mService的一个接口,那么它是在哪里实现的呢?

它是在package/app/bluetooth/src/com/android/bluetooth/GattService.java里面实现的,如下:

/**
     * Handlers for incoming service calls
     */
    private static class BluetoothGattBinder extends IBluetoothGatt.Stub implements IProfileServiceBinder {
        private GattService mService;

那么就会调用BluetoothGattBinder 的writeCharacteristic的方法,如下:



public void writeCharacteristic(int clientIf, String address, int srvcType,
                             int srvcInstanceId, ParcelUuid srvcId,
                             int charInstanceId, ParcelUuid charId,
                             int writeType, int authReq, byte[] value) {
            GattService service = getService();
            if (service == null) return;
            service.writeCharacteristic(clientIf, address, srvcType, srvcInstanceId,
                                       srvcId.getUuid(), charInstanceId,
                                       charId.getUuid(), writeType, authReq,
                                       value);
        }

那么会继续在调用GattService里面的writeCharacteristic方法,如下:

    void writeCharacteristic(int clientIf, String address, int srvcType,
                             int srvcInstanceId, UUID srvcUuid,
                             int charInstanceId, UUID charUuid, int writeType,
                             int authReq, byte[] value) {
        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
        if (isHidUuid(charUuid)) enforcePrivilegedPermission();

        if (VDBG) Log.d(TAG, "writeCharacteristic() - address=" + address);

        if (mReliableQueue.contains(address)) writeType = 3; // Prepared write

        Integer connId = mClientMap.connIdByAddress(clientIf, address);
        if (connId != null)
            gattClientWriteCharacteristicNative(connId, srvcType,
                srvcInstanceId, srvcUuid.getLeastSignificantBits(),
                srvcUuid.getMostSignificantBits(), charInstanceId,
                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
                writeType, authReq, value);
        else
            Log.e(TAG, "writeCharacteristic() - No connection for " + address + "...");
    }

接下来就会调用JNI的native方法,gattClientWriteCharacteristicNative,如下:


它是在package/app/bluetooth/jni/com_android_bluetooth_gatt.cpp

static void gattClientWriteCharacteristicNative(JNIEnv* env, jobject object,
    jint conn_id, jint  service_type, jint  service_id_inst_id,
    jlong service_id_uuid_lsb, jlong service_id_uuid_msb,
    jint  char_id_inst_id,
    jlong char_id_uuid_lsb, jlong char_id_uuid_msb,
    jint write_type, jint auth_req, jbyteArray value)
{
    if (!sGattIf) return;

    if (value == NULL) {
        warn("gattClientWriteCharacteristicNative() ignoring NULL array");
        return;
    }

    btgatt_srvc_id_t srvc_id;
    srvc_id.id.inst_id = (uint8_t) service_id_inst_id;
    srvc_id.is_primary = (service_type == BTGATT_SERVICE_TYPE_PRIMARY ? 1 : 0);
    set_uuid(srvc_id.id.uuid.uu, service_id_uuid_msb, service_id_uuid_lsb);

    btgatt_gatt_id_t char_id;
    char_id.inst_id = (uint8_t) char_id_inst_id;
    set_uuid(char_id.uuid.uu, char_id_uuid_msb, char_id_uuid_lsb);

    uint16_t len = (uint16_t) env->GetArrayLength(value);
    jbyte *p_value = env->GetByteArrayElements(value, NULL);
    if (p_value == NULL) return;

    sGattIf->client->write_characteristic(conn_id, &srvc_id, &char_id,
                                    write_type, len, auth_req, (char*)p_value);
    env->ReleaseByteArrayElements(value, p_value, 0);
}

JNI的这个接口会继续通过sGattIf->client的接口调用HAL层相关接口,接口定义如下:
在文件hardware/libhardware/include/hardware/bt_gatt_client.h文件里面,

/** Represents the standard BT-GATT client interface. */

typedef struct {
    /** Registers a GATT client application with the stack */
    bt_status_t (*register_client)( bt_uuid_t *uuid );

    /** Unregister a client application from the stack */
    bt_status_t (*unregister_client)(int client_if );

    /** Start or stop LE device scanning */
    bt_status_t (*scan)( bool start );

    /** Create a connection to a remote LE or dual-mode device */
    bt_status_t (*connect)( int client_if, const bt_bdaddr_t *bd_addr,
                         bool is_direct, int transport );

    /** Disconnect a remote device or cancel a pending connection */
    bt_status_t (*disconnect)( int client_if, const bt_bdaddr_t *bd_addr,
                    int conn_id);

    /** Start or stop advertisements to listen for incoming connections */
    bt_status_t (*listen)(int client_if, bool start);

    /** Clear the attribute cache for a given device */
    bt_status_t (*refresh)( int client_if, const bt_bdaddr_t *bd_addr );

    /**
     * Enumerate all GATT services on a connected device.
     * Optionally, the results can be filtered for a given UUID.
     */
    bt_status_t (*search_service)(int conn_id, bt_uuid_t *filter_uuid );

    /**
     * Enumerate included services for a given service.
     * Set start_incl_srvc_id to NULL to get the first included service.
     */
    bt_status_t (*get_included_service)( int conn_id, btgatt_srvc_id_t *srvc_id,
                                         btgatt_srvc_id_t *start_incl_srvc_id);

    /**
     * Enumerate characteristics for a given service.
     * Set start_char_id to NULL to get the first characteristic.
     */
    bt_status_t (*get_characteristic)( int conn_id,
                    btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *start_char_id);

    /**
     * Enumerate descriptors for a given characteristic.
     * Set start_descr_id to NULL to get the first descriptor.
     */
    bt_status_t (*get_descriptor)( int conn_id,
                    btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
                    btgatt_gatt_id_t *start_descr_id);

    /** Read a characteristic on a remote device */
    bt_status_t (*read_characteristic)( int conn_id,
                    btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
                    int auth_req );

    /** Write a remote characteristic */
    bt_status_t (*write_characteristic)(int conn_id,
                    btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
                    int write_type, int len, int auth_req,
                    char* p_value);

    /** Read the descriptor for a given characteristic */
    bt_status_t (*read_descriptor)(int conn_id,
                    btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
                    btgatt_gatt_id_t *descr_id, int auth_req);

    /** Write a remote descriptor for a given characteristic */
    bt_status_t (*write_descriptor)( int conn_id,
                    btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
                    btgatt_gatt_id_t *descr_id, int write_type, int len,
                    int auth_req, char* p_value);

    /** Execute a prepared write operation */
    bt_status_t (*execute_write)(int conn_id, int execute);

    /**
     * Register to receive notifications or indications for a given
     * characteristic
     */
    bt_status_t (*register_for_notification)( int client_if,
                    const bt_bdaddr_t *bd_addr, btgatt_srvc_id_t *srvc_id,
                    btgatt_gatt_id_t *char_id);

    /** Deregister a previous request for notifications/indications */
    bt_status_t (*deregister_for_notification)( int client_if,
                    const bt_bdaddr_t *bd_addr, btgatt_srvc_id_t *srvc_id,
                    btgatt_gatt_id_t *char_id);

    /** Request RSSI for a given remote device */
    bt_status_t (*read_remote_rssi)( int client_if, const bt_bdaddr_t *bd_addr);

    /** Setup scan filter params */
    bt_status_t (*scan_filter_param_setup)(btgatt_filt_param_setup_t filt_param);


    /** Configure a scan filter condition  */
    bt_status_t (*scan_filter_add_remove)(int client_if, int action, int filt_type,
                                   int filt_index, int company_id,
                                   int company_id_mask, const bt_uuid_t *p_uuid,
                                   const bt_uuid_t *p_uuid_mask, const bt_bdaddr_t *bd_addr,
                                   char addr_type, int data_len, char* p_data, int mask_len,
                                   char* p_mask);

    /** Clear all scan filter conditions for specific filter index*/
    bt_status_t (*scan_filter_clear)(int client_if, int filt_index);

    /** Enable / disable scan filter feature*/
    bt_status_t (*scan_filter_enable)(int client_if, bool enable);

    /** Determine the type of the remote device (LE, BR/EDR, Dual-mode) */
    int (*get_device_type)( const bt_bdaddr_t *bd_addr );

    /** Set the advertising data or scan response data */
    bt_status_t (*set_adv_data)(int client_if, bool set_scan_rsp, bool include_name,
                    bool include_txpower, int min_interval, int max_interval, int appearance,
                    uint16_t manufacturer_len, char* manufacturer_data,
                    uint16_t service_data_len, char* service_data,
                    uint16_t service_uuid_len, char* service_uuid);

    /** Configure the MTU for a given connection */
    bt_status_t (*configure_mtu)(int conn_id, int mtu);

    /** Request a connection parameter update */
    bt_status_t (*conn_parameter_update)(const bt_bdaddr_t *bd_addr, int min_interval,
                    int max_interval, int latency, int timeout);

    /** Sets the LE scan interval and window in units of N*0.625 msec */
    bt_status_t (*set_scan_parameters)(int client_if, int scan_interval, int scan_window);

    /* Setup the parameters as per spec, user manual specified values and enable multi ADV */
    bt_status_t (*multi_adv_enable)(int client_if, int min_interval,int max_interval,int adv_type,
                 int chnl_map, int tx_power, int timeout_s);

    /* Update the parameters as per spec, user manual specified values and restart multi ADV */
    bt_status_t (*multi_adv_update)(int client_if, int min_interval,int max_interval,int adv_type,
                 int chnl_map, int tx_power, int timeout_s);

    /* Setup the data for the specified instance */
    bt_status_t (*multi_adv_set_inst_data)(int client_if, bool set_scan_rsp, bool include_name,
                    bool incl_txpower, int appearance, int manufacturer_len,
                    char* manufacturer_data, int service_data_len,
                    char* service_data, int service_uuid_len, char* service_uuid);

    /* Disable the multi adv instance */
    bt_status_t (*multi_adv_disable)(int client_if);

    /* Configure the batchscan storage */
    bt_status_t (*batchscan_cfg_storage)(int client_if, int batch_scan_full_max,
        int batch_scan_trunc_max, int batch_scan_notify_threshold);

    /* Enable batchscan */
    bt_status_t (*batchscan_enb_batch_scan)(int client_if, int scan_mode,
        int scan_interval, int scan_window, int addr_type, int discard_rule);

    /* Disable batchscan */
    bt_status_t (*batchscan_dis_batch_scan)(int client_if);

    /* Read out batchscan reports */
    bt_status_t (*batchscan_read_reports)(int client_if, int scan_mode);

    /** Test mode interface */
    bt_status_t (*test_command)( int command, btgatt_test_params_t* params);

} btgatt_client_interface_t;

那么是哪里实现的这个相关的接口呢?

在文件system/bt/btif/src/btif_gatt_client.c中,

const btgatt_client_interface_t btgattClientInterface = {
    btif_gattc_register_app,
    btif_gattc_unregister_app,
    btif_gattc_scan,
    btif_gattc_open,
    btif_gattc_close,
    btif_gattc_listen,
    btif_gattc_refresh,
    btif_gattc_search_service,
    btif_gattc_get_included_service,
    btif_gattc_get_characteristic,
    btif_gattc_get_descriptor,
    btif_gattc_read_char,
    btif_gattc_write_char,
    btif_gattc_read_char_descr,
    btif_gattc_write_char_descr,
    btif_gattc_execute_write,
    btif_gattc_reg_for_notification,
    btif_gattc_dereg_for_notification,
    btif_gattc_read_remote_rssi,
    btif_gattc_scan_filter_param_setup,
    btif_gattc_scan_filter_add_remove,
    btif_gattc_scan_filter_clear,
    btif_gattc_scan_filter_enable,
    btif_gattc_get_device_type,
    btif_gattc_set_adv_data,
    btif_gattc_configure_mtu,
    btif_gattc_conn_parameter_update,
    btif_gattc_set_scan_parameters,
    btif_gattc_multi_adv_enable,
    btif_gattc_multi_adv_update,
    btif_gattc_multi_adv_setdata,
    btif_gattc_multi_adv_disable,
    btif_gattc_cfg_storage,
    btif_gattc_enb_batch_scan,
    btif_gattc_dis_batch_scan,
    btif_gattc_read_batch_scan_reports,
    btif_gattc_test_command
};

写特性值的方法如下:

static bt_status_t btif_gattc_write_char(int conn_id, btgatt_srvc_id_t* srvc_id,
                                         btgatt_gatt_id_t* char_id, int write_type,
                                         int len, int auth_req, char* p_value)
{
    CHECK_BTGATT_INIT();
    btif_gattc_cb_t btif_cb;
    btif_cb.conn_id = (uint16_t) conn_id;
    btif_cb.auth_req = (uint8_t) auth_req;
    btif_cb.write_type = (uint8_t) write_type;
    btif_cb.len = len > BTGATT_MAX_ATTR_LEN ? BTGATT_MAX_ATTR_LEN : len;
    memcpy(&btif_cb.srvc_id, srvc_id, sizeof(btgatt_srvc_id_t));
    memcpy(&btif_cb.char_id, char_id, sizeof(btgatt_gatt_id_t));
    memcpy(btif_cb.value, p_value, btif_cb.len);
    return btif_transfer_context(btgattc_handle_eventBTIF_GATTC_WRITE_CHAR,
                                 (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL);
}

红色字体btif_transfer_context的方法,是一个切换的到btif task上下文的方法

/*******************************************************************************
**
** Function         btif_transfer_context
**
** Description      This function switches context to btif task
**
**                  p_cback   : callback used to process message in btif context
**                  event     : event id of message
**                  p_params  : parameter area passed to callback (copied)
**                  param_len : length of parameter area
**                  p_copy_cback : If set this function will be invoked for deep copy
**
** Returns          void
**
*******************************************************************************/

bt_status_t btif_transfer_context (tBTIF_CBACK *p_cback, UINT16 event, char* p_params, int param_len, tBTIF_COPY_CBACK *p_copy_cback)
{
    tBTIF_CONTEXT_SWITCH_CBACK *p_msg;

    BTIF_TRACE_VERBOSE("btif_transfer_context event %d, len %d", event, param_len);

    /* allocate and send message that will be executed in btif context */
    if ((p_msg = (tBTIF_CONTEXT_SWITCH_CBACK *) GKI_getbuf(sizeof(tBTIF_CONTEXT_SWITCH_CBACK) + param_len)) != NULL)
    {
        p_msg->hdr.event = BT_EVT_CONTEXT_SWITCH_EVT; /* internal event */
        p_msg->p_cb = p_cback;

        p_msg->event = event;                         /* callback event */

        /* check if caller has provided a copy callback to do the deep copy */
        if (p_copy_cback)
        {
            p_copy_cback(event, p_msg->p_param, p_params);
        }
        else if (p_params)
        {
            memcpy(p_msg->p_param, p_params, param_len);  /* callback parameter data */
        }

        btif_sendmsg(p_msg);
        return BT_STATUS_SUCCESS;
    }
    else
    {
        /* let caller deal with a failed allocation */
        return BT_STATUS_NOMEM;
    }
}

这里通过btif_sendmsg来发送消息到消息队列,

/*******************************************************************************
**
** Function         btif_sendmsg
**
** Description      Sends msg to BTIF task
**
** Returns          void
**
*******************************************************************************/

void btif_sendmsg(void *p_msg)
{
    thread_post(bt_jni_workqueue_thread, bt_jni_msg_ready, p_msg);
}

这里调用thread_post方法来把消息入列至work_queue工作队列,

bool thread_post(thread_t *thread, thread_fn func, void *context) {
  assert(thread != NULL);
  assert(func != NULL);

  // TODO(sharvil): if the current thread == |thread| and we've run out
  // of queue space, we should abort this operation, otherwise we'll
  // deadlock.

  // Queue item is freed either when the queue itself is destroyed
  // or when the item is removed from the queue for dispatch.
  work_item_t *item = (work_item_t *)osi_malloc(sizeof(work_item_t));
  if (!item) {
    LOG_ERROR("%s unable to allocate memory: %s", __func__, strerror(errno));
    return false;
  }
  item->func = func;
  item->context = context;
  fixed_queue_enqueue(thread->work_queue, item);
  return true;
}

这里的work_queue消息队列是在btif_init_bluetooth()里面初始化的,

/*******************************************************************************
**
** Function         btif_init_bluetooth
**
** Description      Creates BTIF task and prepares BT scheduler for startup
**
** Returns          bt_status_t
**
*******************************************************************************/
bt_status_t btif_init_bluetooth() {
  bte_main_boot_entry();

  /* As part of the init, fetch the local BD ADDR */
  memset(&btif_local_bd_addr, 0, sizeof(bt_bdaddr_t));
  btif_fetch_local_bdaddr(&btif_local_bd_addr);

  bt_jni_workqueue_thread thread_new(BT_JNI_WORKQUEUE_NAME);
  if (bt_jni_workqueue_thread == NULL) {
    LOG_ERROR("%s Unable to create thread %s", __func__, BT_JNI_WORKQUEUE_NAME);
    goto error_exit;
  }

  // Associate this workqueue thread with jni.
  btif_transfer_context(btif_jni_associate, 0, NULL, 0, NULL);

  return BT_STATUS_SUCCESS;

error_exit:;
     thread_free(bt_jni_workqueue_thread);

     bt_jni_workqueue_thread = NULL;

     return BT_STATUS_FAIL;
}

btif_init_bluetooth()初始化的时候会将JNI与workqueue的thread关联起来,

当入列后,出列的时候就会调用如下的方法来处理,如下:

/*******************************************************************************
**
** Function         btif_task
**
** Description      BTIF task handler managing all messages being passed
**                  Bluetooth HAL and BTA.
**
** Returns          void
**
*******************************************************************************/
static void bt_jni_msg_ready(void *context) {
  BT_HDR *p_msg = (BT_HDR *)context;

  BTIF_TRACE_VERBOSE("btif task fetched event %x", p_msg->event);

  switch (p_msg->event) {
    case BT_EVT_CONTEXT_SWITCH_EVT:
      btif_context_switched(p_msg);
      break;
    default:
      BTIF_TRACE_ERROR("unhandled btif event (%d)", p_msg->event & BT_EVT_MASK);
      break;
  }
  GKI_freebuf(p_msg);
}

/*******************************************************************************
**
** Function         btif_context_switched
**
** Description      Callback used to execute transferred context callback
**
**                  p_msg : message to be executed in btif context
**
** Returns          void
**
*******************************************************************************/

static void btif_context_switched(void *p_msg)
{

    BTIF_TRACE_VERBOSE("btif_context_switched");

    tBTIF_CONTEXT_SWITCH_CBACK *p = (tBTIF_CONTEXT_SWITCH_CBACK *) p_msg;

    /* each callback knows how to parse the data */
    if (p->p_cb)
        p->p_cb(p->event, p->p_param);
}

从上面可以看出,
btgattc_handle_event来处理gatt的读写请求,

static void btgattc_handle_event(uint16_t event, char* p_param)
{
    tBTA_GATT_STATUS           status;
    tBT_UUID                   uuid;
    tBTA_GATT_SRVC_ID          srvc_id;
    tGATT_CHAR_PROP            out_char_prop;
    tBTA_GATTC_CHAR_ID         in_char_id;
    tBTA_GATTC_CHAR_ID         out_char_id;
    tBTA_GATTC_CHAR_DESCR_ID   in_char_descr_id;
    tBTA_GATTC_CHAR_DESCR_ID   out_char_descr_id;
    tBTA_GATTC_INCL_SVC_ID     in_incl_svc_id;
    tBTA_GATTC_INCL_SVC_ID     out_incl_svc_id;
    tBTA_GATT_UNFMT            descr_val;

    btif_gattc_cb_t* p_cb = (btif_gattc_cb_t*) p_param;
    if (!p_cb) return;

    LOG_VERBOSE("%s: Event %d", __FUNCTION__, event);

    switch (event)
    {
        case BTIF_GATTC_REGISTER_APP:
            btif_to_bta_uuid(&uuid, &p_cb->uuid);
            btif_gattc_incr_app_count();
            BTA_GATTC_AppRegister(&uuid, bta_gattc_cback);
            break;

        case BTIF_GATTC_UNREGISTER_APP:
            btif_gattc_clear_clientif(p_cb->client_if, TRUE);
            btif_gattc_decr_app_count();
            BTA_GATTC_AppDeregister(p_cb->client_if);
            break;

        case BTIF_GATTC_SCAN_START:
            btif_gattc_init_dev_cb();
            BTA_DmBleObserve(TRUE, 0, bta_scan_results_cb);
            break;

        case BTIF_GATTC_SCAN_STOP:
            BTA_DmBleObserve(FALSE, 0, 0);
            break;

        case BTIF_GATTC_OPEN:
        {
            // Ensure device is in inquiry database
            int addr_type = 0;
            int device_type = 0;
            tBTA_GATT_TRANSPORT transport = BTA_GATT_TRANSPORT_LE;

            if (btif_get_address_type(p_cb->bd_addr.address, &addr_type) &&
                btif_get_device_type(p_cb->bd_addr.address, &device_type) &&
                device_type != BT_DEVICE_TYPE_BREDR)
            {
                BTA_DmAddBleDevice(p_cb->bd_addr.address, addr_type, device_type);
            }

            // Mark background connections
            if (!p_cb->is_direct)
            {
                // Check if RPA offloading is supported, otherwise, do not start
                // background connection, since it will not connect after address
                // changes
                if ((p_cb->addr_type == BLE_ADDR_RANDOM)
                        && BTM_BLE_IS_RESOLVE_BDA(p_cb->bd_addr.address))
                {
                    tBTM_BLE_VSC_CB vnd_capabilities;
                    BTM_BleGetVendorCapabilities(&vnd_capabilities);
                    if (!vnd_capabilities.rpa_offloading)
                    {
                        HAL_CBACK(bt_gatt_callbacks, client->open_cb, 0, BT_STATUS_UNSUPPORTED,
                                        p_cb->client_if, &p_cb->bd_addr);
                        return;
                    }
                }
                BTA_DmBleSetBgConnType(BTM_BLE_CONN_AUTO, NULL);
            }

            switch(device_type)
            {
                case BT_DEVICE_TYPE_BREDR:
                    transport = BTA_GATT_TRANSPORT_BR_EDR;
                    break;

                case BT_DEVICE_TYPE_BLE:
                    transport = BTA_GATT_TRANSPORT_LE;
                    break;

                case BT_DEVICE_TYPE_DUMO:
                    if (p_cb->transport == GATT_TRANSPORT_LE)
                        transport = BTA_GATT_TRANSPORT_LE;
                    else
                        transport = BTA_GATT_TRANSPORT_BR_EDR;
                    break;
            }

            // Connect!
            BTIF_TRACE_DEBUG ("BTA_GATTC_Open Transport  = %d, dev type = %d",
                                transport, device_type);
            BTA_GATTC_Open(p_cb->client_if, p_cb->bd_addr.address, p_cb->is_direct, transport);
            break;
        }

        case BTIF_GATTC_CLOSE:
            // Disconnect established connections
            if (p_cb->conn_id != 0)
                BTA_GATTC_Close(p_cb->conn_id);
            else
                BTA_GATTC_CancelOpen(p_cb->client_if, p_cb->bd_addr.address, TRUE);

            // Cancel pending background connections (remove from whitelist)
            BTA_GATTC_CancelOpen(p_cb->client_if, p_cb->bd_addr.address, FALSE);
            break;

        case BTIF_GATTC_SEARCH_SERVICE:
        {
            if (p_cb->search_all)
            {
                BTA_GATTC_ServiceSearchRequest(p_cb->conn_id, NULL);
            } else {
                btif_to_bta_uuid(&uuid, &p_cb->uuid);
                BTA_GATTC_ServiceSearchRequest(p_cb->conn_id, &uuid);
            }
            break;
        }

        case BTIF_GATTC_GET_FIRST_CHAR:
        {
            btgatt_gatt_id_t char_id;
            btif_to_bta_srvc_id(&srvc_id, &p_cb->srvc_id);
            status = BTA_GATTC_GetFirstChar(p_cb->conn_id, &srvc_id, NULL,
                                            &out_char_id, &out_char_prop);

            if (status == 0)
                bta_to_btif_gatt_id(&char_id, &out_char_id.char_id);

            HAL_CBACK(bt_gatt_callbacks, client->get_characteristic_cb,
                p_cb->conn_id, status, &p_cb->srvc_id,
                &char_id, out_char_prop);
            break;
        }

        case BTIF_GATTC_GET_NEXT_CHAR:
        {
            btgatt_gatt_id_t char_id;
            btif_to_bta_srvc_id(&in_char_id.srvc_id, &p_cb->srvc_id);
            btif_to_bta_gatt_id(&in_char_id.char_id, &p_cb->char_id);

            status = BTA_GATTC_GetNextChar(p_cb->conn_id, &in_char_id, NULL,
                                            &out_char_id, &out_char_prop);

            if (status == 0)
                bta_to_btif_gatt_id(&char_id, &out_char_id.char_id);

            HAL_CBACK(bt_gatt_callbacks, client->get_characteristic_cb,
                p_cb->conn_id, status, &p_cb->srvc_id,
                &char_id, out_char_prop);
            break;
        }

        case BTIF_GATTC_GET_FIRST_CHAR_DESCR:
        {
            btgatt_gatt_id_t descr_id;
            btif_to_bta_srvc_id(&in_char_id.srvc_id, &p_cb->srvc_id);
            btif_to_bta_gatt_id(&in_char_id.char_id, &p_cb->char_id);

            status = BTA_GATTC_GetFirstCharDescr(p_cb->conn_id, &in_char_id, NULL,
                                                    &out_char_descr_id);

            if (status == 0)
                bta_to_btif_gatt_id(&descr_id, &out_char_descr_id.descr_id);

            HAL_CBACK(bt_gatt_callbacks, client->get_descriptor_cb,
                p_cb->conn_id, status, &p_cb->srvc_id,
                &p_cb->char_id, &descr_id);
            break;
        }

        case BTIF_GATTC_GET_NEXT_CHAR_DESCR:
        {
            btgatt_gatt_id_t descr_id;
            btif_to_bta_srvc_id(&in_char_descr_id.char_id.srvc_id, &p_cb->srvc_id);
            btif_to_bta_gatt_id(&in_char_descr_id.char_id.char_id, &p_cb->char_id);
            btif_to_bta_gatt_id(&in_char_descr_id.descr_id, &p_cb->descr_id);

            status = BTA_GATTC_GetNextCharDescr(p_cb->conn_id, &in_char_descr_id
                                        , NULL, &out_char_descr_id);

            if (status == 0)
                bta_to_btif_gatt_id(&descr_id, &out_char_descr_id.descr_id);

            HAL_CBACK(bt_gatt_callbacks, client->get_descriptor_cb,
                p_cb->conn_id, status, &p_cb->srvc_id,
                &p_cb->char_id, &descr_id);
            break;
        }

        case BTIF_GATTC_GET_FIRST_INCL_SERVICE:
        {
            btgatt_srvc_id_t incl_srvc_id;
            btif_to_bta_srvc_id(&srvc_id, &p_cb->srvc_id);

            status = BTA_GATTC_GetFirstIncludedService(p_cb->conn_id,
                        &srvc_id, NULL, &out_incl_svc_id);

            bta_to_btif_srvc_id(&incl_srvc_id, &out_incl_svc_id.incl_svc_id);

            HAL_CBACK(bt_gatt_callbacks, client->get_included_service_cb,
                p_cb->conn_id, status, &p_cb->srvc_id,
                &incl_srvc_id);
            break;
        }

        case BTIF_GATTC_GET_NEXT_INCL_SERVICE:
        {
            btgatt_srvc_id_t incl_srvc_id;
            btif_to_bta_srvc_id(&in_incl_svc_id.srvc_id, &p_cb->srvc_id);
            btif_to_bta_srvc_id(&in_incl_svc_id.incl_svc_id, &p_cb->incl_srvc_id);

            status = BTA_GATTC_GetNextIncludedService(p_cb->conn_id,
                        &in_incl_svc_id, NULL, &out_incl_svc_id);

            bta_to_btif_srvc_id(&incl_srvc_id, &out_incl_svc_id.incl_svc_id);

            HAL_CBACK(bt_gatt_callbacks, client->get_included_service_cb,
                p_cb->conn_id, status, &p_cb->srvc_id,
                &incl_srvc_id);
            break;
        }

        case BTIF_GATTC_READ_CHAR:
            btif_to_bta_srvc_id(&in_char_id.srvc_id, &p_cb->srvc_id);
            btif_to_bta_gatt_id(&in_char_id.char_id, &p_cb->char_id);

            BTA_GATTC_ReadCharacteristic(p_cb->conn_id, &in_char_id, p_cb->auth_req);
            break;

        case BTIF_GATTC_READ_CHAR_DESCR:
            btif_to_bta_srvc_id(&in_char_descr_id.char_id.srvc_id, &p_cb->srvc_id);
            btif_to_bta_gatt_id(&in_char_descr_id.char_id.char_id, &p_cb->char_id);
            btif_to_bta_gatt_id(&in_char_descr_id.descr_id, &p_cb->descr_id);

            BTA_GATTC_ReadCharDescr(p_cb->conn_id, &in_char_descr_id, p_cb->auth_req);
            break;

        case BTIF_GATTC_WRITE_CHAR:
            btif_to_bta_srvc_id(&in_char_id.srvc_id, &p_cb->srvc_id);
            btif_to_bta_gatt_id(&in_char_id.char_id, &p_cb->char_id);

            BTA_GATTC_WriteCharValue(p_cb->conn_id, &in_char_id,
                                     p_cb->write_type,
                                     p_cb->len,
                                     p_cb->value,
                                     p_cb->auth_req);
            break;

        case BTIF_GATTC_WRITE_CHAR_DESCR:
            btif_to_bta_srvc_id(&in_char_descr_id.char_id.srvc_id, &p_cb->srvc_id);
            btif_to_bta_gatt_id(&in_char_descr_id.char_id.char_id, &p_cb->char_id);
            btif_to_bta_gatt_id(&in_char_descr_id.descr_id, &p_cb->descr_id);

            descr_val.len = p_cb->len;
            descr_val.p_value = p_cb->value;

            BTA_GATTC_WriteCharDescr(p_cb->conn_id, &in_char_descr_id,
                                     p_cb->write_type, &descr_val,
                                     p_cb->auth_req);
            break;

        case BTIF_GATTC_EXECUTE_WRITE:
            BTA_GATTC_ExecuteWrite(p_cb->conn_id, p_cb->action);
            break;

        case BTIF_GATTC_REG_FOR_NOTIFICATION:
            btif_to_bta_srvc_id(&in_char_id.srvc_id, &p_cb->srvc_id);
            btif_to_bta_gatt_id(&in_char_id.char_id, &p_cb->char_id);

            status = BTA_GATTC_RegisterForNotifications(p_cb->client_if,
                                    p_cb->bd_addr.address, &in_char_id);

            HAL_CBACK(bt_gatt_callbacks, client->register_for_notification_cb,
                p_cb->conn_id, 1, status, &p_cb->srvc_id,
                &p_cb->char_id);
            break;

        case BTIF_GATTC_DEREG_FOR_NOTIFICATION:
            btif_to_bta_srvc_id(&in_char_id.srvc_id, &p_cb->srvc_id);
            btif_to_bta_gatt_id(&in_char_id.char_id, &p_cb->char_id);

            status = BTA_GATTC_DeregisterForNotifications(p_cb->client_if,
                                        p_cb->bd_addr.address, &in_char_id);

            HAL_CBACK(bt_gatt_callbacks, client->register_for_notification_cb,
                p_cb->conn_id, 0, status, &p_cb->srvc_id,
                &p_cb->char_id);
            break;

        case BTIF_GATTC_REFRESH:
            BTA_GATTC_Refresh(p_cb->bd_addr.address);
            break;

        case BTIF_GATTC_READ_RSSI:
            rssi_request_client_if = p_cb->client_if;
            BTM_ReadRSSI (p_cb->bd_addr.address, (tBTM_CMPL_CB *)btm_read_rssi_cb);
            break;

        case BTIF_GATTC_SCAN_FILTER_PARAM_SETUP:
        {
            btgatt_adv_filter_cb_t *p_adv_filt_cb = (btgatt_adv_filter_cb_t *) p_param;
            if (1 == p_adv_filt_cb->adv_filt_param.dely_mode)
               BTA_DmBleTrackAdvertiser(p_adv_filt_cb->client_if, bta_track_adv_event_cb);
            BTA_DmBleScanFilterSetup(p_adv_filt_cb->action, p_adv_filt_cb->filt_index,
                &p_adv_filt_cb->adv_filt_param, NULL, bta_scan_filt_param_setup_cb,
                p_adv_filt_cb->client_if);
            break;
        }

        case BTIF_GATTC_SCAN_FILTER_CONFIG:
        {
            btgatt_adv_filter_cb_t *p_adv_filt_cb = (btgatt_adv_filter_cb_t *) p_param;
            tBTA_DM_BLE_PF_COND_PARAM cond;
            memset(&cond, 0, sizeof(cond));

            switch (p_adv_filt_cb->filt_type)
            {
                case BTA_DM_BLE_PF_ADDR_FILTER: // 0
                    bdcpy(cond.target_addr.bda, p_adv_filt_cb->bd_addr.address);
                    cond.target_addr.type = p_adv_filt_cb->addr_type;
                    BTA_DmBleCfgFilterCondition(p_adv_filt_cb->action,
                                              p_adv_filt_cb->filt_type, p_adv_filt_cb->filt_index,
                                              &cond, bta_scan_filt_cfg_cb,
                                              p_adv_filt_cb->client_if);
                    break;

                case BTA_DM_BLE_PF_SRVC_DATA: // 1
                    BTA_DmBleCfgFilterCondition(p_adv_filt_cb->action,
                                            p_adv_filt_cb->filt_type, p_adv_filt_cb->filt_index,
                                            NULL, bta_scan_filt_cfg_cb, p_adv_filt_cb->client_if);
                    break;

                case BTA_DM_BLE_PF_SRVC_UUID: // 2
                {
                    tBTA_DM_BLE_PF_COND_MASK uuid_mask;

                    cond.srvc_uuid.p_target_addr = NULL;
                    cond.srvc_uuid.cond_logic = BTA_DM_BLE_PF_LOGIC_AND;
                    btif_to_bta_uuid(&cond.srvc_uuid.uuid, &p_adv_filt_cb->uuid);

                    cond.srvc_uuid.p_uuid_mask = NULL;
                    if (p_adv_filt_cb->has_mask)
                    {
                        btif_to_bta_uuid_mask(&uuid_mask, &p_adv_filt_cb->uuid_mask);
                        cond.srvc_uuid.p_uuid_mask = &uuid_mask;
                    }
                    BTA_DmBleCfgFilterCondition(p_adv_filt_cb->action,
                                              p_adv_filt_cb->filt_type, p_adv_filt_cb->filt_index,
                                              &cond, bta_scan_filt_cfg_cb,
                                              p_adv_filt_cb->client_if);
                    break;
                }

                case BTA_DM_BLE_PF_SRVC_SOL_UUID: // 3
                {
                    cond.solicitate_uuid.p_target_addr = NULL;
                    cond.solicitate_uuid.cond_logic = BTA_DM_BLE_PF_LOGIC_AND;
                    btif_to_bta_uuid(&cond.solicitate_uuid.uuid, &p_adv_filt_cb->uuid);
                    BTA_DmBleCfgFilterCondition(p_adv_filt_cb->action,
                                              p_adv_filt_cb->filt_type, p_adv_filt_cb->filt_index,
                                              &cond, bta_scan_filt_cfg_cb,
                                              p_adv_filt_cb->client_if);
                    break;
                }

                case BTA_DM_BLE_PF_LOCAL_NAME: // 4
                {
                    cond.local_name.data_len = p_adv_filt_cb->value_len;
                    cond.local_name.p_data = p_adv_filt_cb->value;
                    BTA_DmBleCfgFilterCondition(p_adv_filt_cb->action,
                                              p_adv_filt_cb->filt_type, p_adv_filt_cb->filt_index,
                                              &cond, bta_scan_filt_cfg_cb,
                                              p_adv_filt_cb->client_if);
                    break;
                }

                case BTA_DM_BLE_PF_MANU_DATA: // 5
                {
                    cond.manu_data.company_id = p_adv_filt_cb->conn_id;
                    cond.manu_data.company_id_mask = p_adv_filt_cb->company_id_mask;
                    cond.manu_data.data_len = p_adv_filt_cb->value_len;
                    cond.manu_data.p_pattern = p_adv_filt_cb->value;
                    cond.manu_data.p_pattern_mask = p_adv_filt_cb->value_mask;
                    BTA_DmBleCfgFilterCondition(p_adv_filt_cb->action,
                                              p_adv_filt_cb->filt_type, p_adv_filt_cb->filt_index,
                                              &cond, bta_scan_filt_cfg_cb,
                                              p_adv_filt_cb->client_if);
                    break;
                }

                case BTA_DM_BLE_PF_SRVC_DATA_PATTERN: //6
                {
                    cond.srvc_data.data_len = p_adv_filt_cb->value_len;
                    cond.srvc_data.p_pattern = p_adv_filt_cb->value;
                    cond.srvc_data.p_pattern_mask = p_adv_filt_cb->value_mask;
                    BTA_DmBleCfgFilterCondition(p_adv_filt_cb->action,
                                                p_adv_filt_cb->filt_type, p_adv_filt_cb->filt_index,
                                                &cond, bta_scan_filt_cfg_cb,
                                                p_adv_filt_cb->client_if);
                   break;
                }

                default:
                    LOG_ERROR("%s: Unknown filter type (%d)!", __FUNCTION__, p_cb->action);
                    break;
            }
            break;
        }

        case BTIF_GATTC_SCAN_FILTER_CLEAR:
        {
            btgatt_adv_filter_cb_t *p_adv_filt_cb = (btgatt_adv_filter_cb_t *) p_param;
            BTA_DmBleCfgFilterCondition(BTA_DM_BLE_SCAN_COND_CLEAR, BTA_DM_BLE_PF_TYPE_ALL,
                                        p_adv_filt_cb->filt_index, NULL, bta_scan_filt_cfg_cb,
                                        p_adv_filt_cb->client_if);
            break;
        }

        case BTIF_GATTC_SCAN_FILTER_ENABLE:
        {
            btgatt_adv_filter_cb_t *p_adv_filt_cb = (btgatt_adv_filter_cb_t *) p_param;
            BTA_DmEnableScanFilter(p_adv_filt_cb->action, bta_scan_filt_status_cb,
                                   p_adv_filt_cb->client_if);
            break;
        }

        case BTIF_GATTC_LISTEN:
#if (defined(BLE_PERIPHERAL_MODE_SUPPORT) && (BLE_PERIPHERAL_MODE_SUPPORT == TRUE))
            BTA_GATTC_Listen(p_cb->client_if, p_cb->start, NULL);
#else
            BTA_GATTC_Broadcast(p_cb->client_if, p_cb->start);
#endif
            break;

        case BTIF_GATTC_SET_ADV_DATA:
        {
            const btif_adv_data_t *p_adv_data = (btif_adv_data_t*) p_param;
            const int cbindex = CLNT_IF_IDX;
            if (cbindex >= 0 && btif_gattc_copy_datacb(cbindex, p_adv_data, false))
            {
                btgatt_multi_adv_common_data *p_multi_adv_data_cb = btif_obtain_multi_adv_data_cb();
                if (!p_adv_data->set_scan_rsp)
                {
                    BTA_DmBleSetAdvConfig(p_multi_adv_data_cb->inst_cb[cbindex].mask,
                        &p_multi_adv_data_cb->inst_cb[cbindex].data, bta_gattc_set_adv_data_cback);
                }
                else
                {
                    BTA_DmBleSetScanRsp(p_multi_adv_data_cb->inst_cb[cbindex].mask,
                        &p_multi_adv_data_cb->inst_cb[cbindex].data, bta_gattc_set_adv_data_cback);
                }
            }
            else
            {
                BTIF_TRACE_ERROR("%s:%s: failed to get instance data cbindex: %d",
                                 __func__, "BTIF_GATTC_SET_ADV_DATA", cbindex);
            }
            break;
        }

        case BTIF_GATTC_ADV_INSTANCE_ENABLE:
        {
            btgatt_multi_adv_inst_cb *p_inst_cb = (btgatt_multi_adv_inst_cb*) p_param;

            int cbindex = -1, arrindex = -1;

            arrindex = btif_multi_adv_add_instid_map(p_inst_cb->client_if,INVALID_ADV_INST, true);
            if (arrindex >= 0)
                cbindex = btif_gattc_obtain_idx_for_datacb(p_inst_cb->client_if, CLNT_IF_IDX);

            if (cbindex >= 0 && arrindex >= 0)
            {
                btgatt_multi_adv_common_data *p_multi_adv_data_cb = btif_obtain_multi_adv_data_cb();
                memcpy(&p_multi_adv_data_cb->inst_cb[cbindex].param,
                       &p_inst_cb->param, sizeof(tBTA_BLE_ADV_PARAMS));
                p_multi_adv_data_cb->inst_cb[cbindex].timeout_s = p_inst_cb->timeout_s;
                BTIF_TRACE_DEBUG("%s, client_if value: %d", __FUNCTION__,
                            p_multi_adv_data_cb->clntif_map[arrindex + arrindex]);
                BTA_BleEnableAdvInstance(&(p_multi_adv_data_cb->inst_cb[cbindex].param),
                    bta_gattc_multi_adv_cback,
                    &(p_multi_adv_data_cb->clntif_map[arrindex + arrindex]));
            }
            else
            {
                /* let the error propagate up from BTA layer */
                BTIF_TRACE_ERROR("%s invalid index in BTIF_GATTC_ENABLE_ADV",__FUNCTION__);
                BTA_BleEnableAdvInstance(&p_inst_cb->param, bta_gattc_multi_adv_cback, NULL);
            }
            break;
        }

        case BTIF_GATTC_ADV_INSTANCE_UPDATE:
        {
            btgatt_multi_adv_inst_cb *p_inst_cb = (btgatt_multi_adv_inst_cb*) p_param;
            int inst_id = btif_multi_adv_instid_for_clientif(p_inst_cb->client_if);
            int cbindex = btif_gattc_obtain_idx_for_datacb(p_inst_cb->client_if, CLNT_IF_IDX);
            if (inst_id >= 0 && cbindex >= 0 && NULL != p_inst_cb)
            {
                btgatt_multi_adv_common_data *p_multi_adv_data_cb = btif_obtain_multi_adv_data_cb();
                memcpy(&p_multi_adv_data_cb->inst_cb[cbindex].param, &p_inst_cb->param,
                        sizeof(tBTA_BLE_ADV_PARAMS));
                BTA_BleUpdateAdvInstParam((UINT8)inst_id,
                    &(p_multi_adv_data_cb->inst_cb[cbindex].param));
            }
            else
                BTIF_TRACE_ERROR("%s invalid index in BTIF_GATTC_UPDATE_ADV", __FUNCTION__);
            break;
        }

        case BTIF_GATTC_ADV_INSTANCE_SET_DATA:
        {
            btif_adv_data_t *p_adv_data = (btif_adv_data_t*) p_param;
            int cbindex = btif_gattc_obtain_idx_for_datacb(p_adv_data->client_if, CLNT_IF_IDX);
            int inst_id = btif_multi_adv_instid_for_clientif(p_adv_data->client_if);
            if (inst_id >= 0 && cbindex >= 0 && btif_gattc_copy_datacb(cbindex, p_adv_data, true))
            {
                btgatt_multi_adv_common_data *p_multi_adv_data_cb =
                    btif_obtain_multi_adv_data_cb();
                BTA_BleCfgAdvInstData(
                    (UINT8)inst_id,
                    p_multi_adv_data_cb->inst_cb[cbindex].is_scan_rsp,
                    p_multi_adv_data_cb->inst_cb[cbindex].mask,
                    &p_multi_adv_data_cb->inst_cb[cbindex].data);
            }
            else
            {
                BTIF_TRACE_ERROR(
                    "%s:%s: failed to get invalid instance data: inst_id:%d "
                    "cbindex:%d",
                    __func__, "BTIF_GATTC_ADV_INSTANCE_SET_DATA", inst_id, cbindex);
            }
            break;
        }

        case BTIF_GATTC_ADV_INSTANCE_DISABLE:
        {
            btgatt_multi_adv_inst_cb *p_inst_cb = (btgatt_multi_adv_inst_cb*) p_param;
            int inst_id = btif_multi_adv_instid_for_clientif(p_inst_cb->client_if);
            if (inst_id >=0)
                BTA_BleDisableAdvInstance((UINT8)inst_id);
            else
                BTIF_TRACE_ERROR("%s invalid instance ID in BTIF_GATTC_DISABLE_ADV",__FUNCTION__);
            break;
        }

        case BTIF_GATTC_CONFIGURE_MTU:
            BTA_GATTC_ConfigureMTU(p_cb->conn_id, p_cb->len);
            break;

        case BTIF_GATTC_CONN_PARAM_UPDT:
        {
            btif_conn_param_cb_t *p_conn_param_cb = (btif_conn_param_cb_t*) p_param;
            if (BTA_DmGetConnectionState(p_conn_param_cb->bd_addr.address))
            {
                BTA_DmBleUpdateConnectionParams(p_conn_param_cb->bd_addr.address,
                               p_conn_param_cb->min_interval, p_conn_param_cb->max_interval,
                               p_conn_param_cb->latency, p_conn_param_cb->timeout);
            } else {
                BTA_DmSetBlePrefConnParams(p_conn_param_cb->bd_addr.address,
                               p_conn_param_cb->min_interval, p_conn_param_cb->max_interval,
                               p_conn_param_cb->latency, p_conn_param_cb->timeout);
            }
            break;
        }

        case BTIF_GATTC_SET_SCAN_PARAMS:
        {
            BTA_DmSetBleScanParams(p_cb->client_if, p_cb->scan_interval, p_cb->scan_window,
                                   BTM_BLE_SCAN_MODE_ACTI, bta_scan_param_setup_cb);
            break;
        }

        case BTIF_GATTC_CONFIG_STORAGE_PARAMS:
        {
            btgatt_batch_track_cb_t *p_scan_track_cb = (btgatt_batch_track_cb_t *) p_param;
            BTA_DmBleSetStorageParams(p_scan_track_cb->batch_scan_full_max,
               p_scan_track_cb->batch_scan_trunc_max, p_scan_track_cb->batch_scan_notify_threshold,
               bta_batch_scan_setup_cb, bta_batch_scan_threshold_cb, bta_batch_scan_reports_cb,
               (tBTA_DM_BLE_REF_VALUE) p_scan_track_cb->client_if);
            break;
        }

        case BTIF_GATTC_ENABLE_BATCH_SCAN:
        {
            btgatt_batch_track_cb_t *p_scan_track_cb = (btgatt_batch_track_cb_t *) p_param;
            BTA_DmBleEnableBatchScan(p_scan_track_cb->scan_mode, p_scan_track_cb->scan_interval,
               p_scan_track_cb->scan_window, p_scan_track_cb->discard_rule,
               p_scan_track_cb->addr_type, p_scan_track_cb->client_if);
            break;
        }

        case BTIF_GATTC_DISABLE_BATCH_SCAN:
        {
            btgatt_batch_track_cb_t *p_scan_track_cb = (btgatt_batch_track_cb_t *) p_param;
            BTA_DmBleDisableBatchScan(p_scan_track_cb->client_if);
            break;
        }

        case BTIF_GATTC_READ_BATCH_SCAN_REPORTS:
        {
            btgatt_batch_track_cb_t *p_scan_track_cb = (btgatt_batch_track_cb_t *) p_param;
            BTA_DmBleReadScanReports(p_scan_track_cb->scan_mode, p_scan_track_cb->client_if);
            break;
        }

        default:
            LOG_ERROR("%s: Unknown event (%d)!", __FUNCTION__, event);
            break;
    }

    btgattc_free_event_data(event, p_param);
}

这样就调用到BTA里面的GATTC里面的,BTA_GATTC_WriteCharValue(),

/*******************************************************************************
**
** Function         BTA_GATTC_WriteCharValue
**
** Description      This function is called to write characteristic value.
**
** Parameters       conn_id - connection ID.
**                    p_char_id - characteristic ID to write.
**                    write_type - type of write.
**                  len: length of the data to be written.
**                  p_value - the value to be written.
**
** Returns          None
**
*******************************************************************************/
void BTA_GATTC_WriteCharValue ( UINT16 conn_id,
                                tBTA_GATTC_CHAR_ID *p_char_id,
                                tBTA_GATTC_WRITE_TYPE  write_type,
                                UINT16 len,
                                UINT8 *p_value,
                                tBTA_GATT_AUTH_REQ auth_req)
{
    tBTA_GATTC_API_WRITE  *p_buf;

    if ((p_buf = (tBTA_GATTC_API_WRITE *) GKI_getbuf((UINT16)(sizeof(tBTA_GATTC_API_WRITE) + len))) != NULL)
    {
        memset(p_buf, 0, sizeof(tBTA_GATTC_API_WRITE) + len);

        p_buf->hdr.event = BTA_GATTC_API_WRITE_EVT;
        p_buf->hdr.layer_specific = conn_id;
        p_buf->auth_req = auth_req;

        memcpy(&p_buf->srvc_id, &p_char_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID));
        memcpy(&p_buf->char_id, &p_char_id->char_id, sizeof(tBTA_GATT_ID));

        p_buf->write_type = write_type;
        p_buf->len = len;

        if (p_value && len > 0)
        {
            p_buf->p_value = (UINT8 *)(p_buf + 1);
            memcpy(p_buf->p_value, p_value, len);
        }

        bta_sys_sendmsg(p_buf);
    }
    return;
}

这样就到了BTA里面的处理流程了,通过bta_sys_sendmsg()发送消息到队列后,

bta_gattc_hdl_event()来处理,这里有一些事件是它处理的,还有一些事件需要通过它的状态机
来处理,比如: BTA_GATTC_API_WRITE_EVT,如下:


BOOLEAN bta_gattc_hdl_event(BT_HDR *p_msg)
{
    tBTA_GATTC_CB *p_cb = &bta_gattc_cb;
    tBTA_GATTC_CLCB *p_clcb = NULL;
    tBTA_GATTC_RCB      *p_clreg;
    BOOLEAN             rt = TRUE;
#if BTA_GATT_DEBUG == TRUE
    APPL_TRACE_DEBUG("bta_gattc_hdl_event: Event [%s]", gattc_evt_code(p_msg->event));
#endif
    switch (p_msg->event)
    {
        case BTA_GATTC_API_DISABLE_EVT:
            bta_gattc_disable(p_cb);
            break;

        case BTA_GATTC_API_REG_EVT:
            bta_gattc_register(p_cb, (tBTA_GATTC_DATA *) p_msg);
            break;

        case BTA_GATTC_INT_START_IF_EVT:
            bta_gattc_start_if(p_cb, (tBTA_GATTC_DATA *) p_msg);
            break;

        case BTA_GATTC_API_DEREG_EVT:
            p_clreg = bta_gattc_cl_get_regcb(((tBTA_GATTC_DATA *)p_msg)->api_dereg.client_if);
            bta_gattc_deregister(p_cb, p_clreg);
            break;

        case BTA_GATTC_API_OPEN_EVT:
            bta_gattc_process_api_open(p_cb, (tBTA_GATTC_DATA *) p_msg);
            break;

        case BTA_GATTC_API_CANCEL_OPEN_EVT:
            bta_gattc_process_api_open_cancel(p_cb, (tBTA_GATTC_DATA *) p_msg);
            break;

        case BTA_GATTC_API_REFRESH_EVT:
            bta_gattc_process_api_refresh(p_cb, (tBTA_GATTC_DATA *) p_msg);
            break;

#if BLE_INCLUDED == TRUE
        case BTA_GATTC_API_LISTEN_EVT:
            bta_gattc_listen(p_cb, (tBTA_GATTC_DATA *) p_msg);
            break;
        case BTA_GATTC_API_BROADCAST_EVT:
            bta_gattc_broadcast(p_cb, (tBTA_GATTC_DATA *) p_msg);
            break;
#endif

        case BTA_GATTC_ENC_CMPL_EVT:
            bta_gattc_process_enc_cmpl(p_cb, (tBTA_GATTC_DATA *) p_msg);
            break;

        default:
            if (p_msg->event == BTA_GATTC_INT_CONN_EVT)
                p_clcb = bta_gattc_find_int_conn_clcb((tBTA_GATTC_DATA *) p_msg);
            else if (p_msg->event == BTA_GATTC_INT_DISCONN_EVT)
                p_clcb = bta_gattc_find_int_disconn_clcb((tBTA_GATTC_DATA *) p_msg);
            else
                p_clcb = bta_gattc_find_clcb_by_conn_id(p_msg->layer_specific);

            if (p_clcb != NULL)
            {
                rt = bta_gattc_sm_execute(p_clcb, p_msg->event, (tBTA_GATTC_DATA *) p_msg);
            }
            else
            {
                APPL_TRACE_DEBUG("Ignore unknown conn ID: %d", p_msg->layer_specific);
            }

            break;
    }


    return rt;
}

如下:
BOOLEAN bta_gattc_sm_execute(tBTA_GATTC_CLCB *p_clcb, UINT16 event, tBTA_GATTC_DATA *p_data)
{
    tBTA_GATTC_ST_TBL     state_table;
    UINT8               action;
    int                 i;
    BOOLEAN             rt = TRUE;
#if BTA_GATT_DEBUG == TRUE
    tBTA_GATTC_STATE in_state = p_clcb->state;
    UINT16         in_event = event;
    APPL_TRACE_DEBUG("bta_gattc_sm_execute: State 0x%02x [%s], Event 0x%x[%s]", in_state,
                      gattc_state_code(in_state),
                      in_event,
                      gattc_evt_code(in_event));
#endif


    /* look up the state table for the current state */
    state_table = bta_gattc_st_tbl[p_clcb->state];

    event &= 0x00FF;

    /* set next state */
    p_clcb->state = state_table[event][BTA_GATTC_NEXT_STATE];

    /* execute action functions */
    for (i = 0; i < BTA_GATTC_ACTIONS; i++)
    {
        if ((action = state_table[event][i]) != BTA_GATTC_IGNORE)
        {
            (*bta_gattc_action[action])(p_clcb, p_data);
            if (p_clcb->p_q_cmd == p_data) {
                /* buffer is queued, don't free in the bta dispatcher.
                 * we free it ourselves when a completion event is received.
                 */
                rt = FALSE;
            }
        }
        else
        {
            break;
        }
    }

#if BTA_GATT_DEBUG == TRUE
    if (in_state != p_clcb->state)
    {
        APPL_TRACE_DEBUG("GATTC State Change: [%s] -> [%s] after Event [%s]",
                          gattc_state_code(in_state),
                          gattc_state_code(p_clcb->state),
                          gattc_evt_code(in_event));
    }
#endif
    return rt;
}

当前的状态是connect状态,那么state_table的表就是bta_gattc_st_connected这个表,

/* state table for open state */
static const UINT8 bta_gattc_st_connected[][BTA_GATTC_NUM_COLS] =
{
/* Event                            Action 1                            Next state */
/* BTA_GATTC_API_OPEN_EVT           */   {BTA_GATTC_OPEN,               BTA_GATTC_CONN_ST},
/* BTA_GATTC_INT_OPEN_FAIL_EVT      */   {BTA_GATTC_IGNORE,             BTA_GATTC_CONN_ST},
/* BTA_GATTC_API_CANCEL_OPEN_EVT    */   {BTA_GATTC_CANCEL_OPEN_ERROR, BTA_GATTC_CONN_ST},
/* BTA_GATTC_INT_CANCEL_OPEN_OK_EVT */   {BTA_GATTC_IGNORE,            BTA_GATTC_CONN_ST},

/* BTA_GATTC_API_READ_EVT           */   {BTA_GATTC_READ,               BTA_GATTC_CONN_ST},
/* BTA_GATTC_API_WRITE_EVT          */   {BTA_GATTC_WRITE,              BTA_GATTC_CONN_ST},
/* BTA_GATTC_API_EXEC_EVT           */   {BTA_GATTC_EXEC,               BTA_GATTC_CONN_ST},
/* BTA_GATTC_API_CFG_MTU_EVT        */   {BTA_GATTC_CFG_MTU,            BTA_GATTC_CONN_ST},

/* BTA_GATTC_API_CLOSE_EVT          */   {BTA_GATTC_CLOSE,              BTA_GATTC_IDLE_ST},

/* BTA_GATTC_API_SEARCH_EVT         */   {BTA_GATTC_SEARCH,             BTA_GATTC_CONN_ST},
/* BTA_GATTC_API_CONFIRM_EVT        */   {BTA_GATTC_CONFIRM,            BTA_GATTC_CONN_ST},
/* BTA_GATTC_API_READ_MULTI_EVT     */   {BTA_GATTC_READ_MULTI,         BTA_GATTC_CONN_ST},
/* BTA_GATTC_API_REFRESH_EVT        */   {BTA_GATTC_IGNORE,             BTA_GATTC_CONN_ST},

/* BTA_GATTC_INT_CONN_EVT           */   {BTA_GATTC_IGNORE,             BTA_GATTC_CONN_ST},
/* BTA_GATTC_INT_DISCOVER_EVT       */   {BTA_GATTC_START_DISCOVER,     BTA_GATTC_DISCOVER_ST},
/* BTA_GATTC_DISCOVER_CMPL_EVT       */  {BTA_GATTC_IGNORE,             BTA_GATTC_CONN_ST},
/* BTA_GATTC_OP_CMPL_EVT            */   {BTA_GATTC_OP_CMPL,            BTA_GATTC_CONN_ST},

/* BTA_GATTC_INT_DISCONN_EVT        */   {BTA_GATTC_CLOSE,              BTA_GATTC_IDLE_ST},

/* ===> for cache loading, saving   */
/* BTA_GATTC_START_CACHE_EVT        */   {BTA_GATTC_CACHE_OPEN,         BTA_GATTC_DISCOVER_ST},
/* BTA_GATTC_CI_CACHE_OPEN_EVT      */   {BTA_GATTC_IGNORE,             BTA_GATTC_CONN_ST},
/* BTA_GATTC_CI_CACHE_LOAD_EVT      */   {BTA_GATTC_IGNORE,             BTA_GATTC_CONN_ST},
/* BTA_GATTC_CI_CACHE_SAVE_EVT      */   {BTA_GATTC_IGNORE,             BTA_GATTC_CONN_ST}
};

那么对应表里面的action就是BTA_GATTC_WRITE,这个枚举对应的方法如下:bta_gattc_write()

/* state machine action enumeration list */
enum
{
    BTA_GATTC_OPEN,
    BTA_GATTC_OPEN_FAIL,
    BTA_GATTC_OPEN_ERROR,
    BTA_GATTC_CANCEL_OPEN,
    BTA_GATTC_CANCEL_OPEN_OK,
    BTA_GATTC_CANCEL_OPEN_ERROR,
    BTA_GATTC_CONN,
    BTA_GATTC_START_DISCOVER,
    BTA_GATTC_DISC_CMPL,

    BTA_GATTC_Q_CMD,
    BTA_GATTC_CLOSE,
    BTA_GATTC_CLOSE_FAIL,
    BTA_GATTC_READ,
    BTA_GATTC_WRITE,

    BTA_GATTC_OP_CMPL,
    BTA_GATTC_SEARCH,
    BTA_GATTC_FAIL,
    BTA_GATTC_CONFIRM,
    BTA_GATTC_EXEC,
    BTA_GATTC_READ_MULTI,
    BTA_GATTC_CI_OPEN,
    BTA_GATTC_CI_LOAD,
    BTA_GATTC_CI_SAVE,
    BTA_GATTC_CACHE_OPEN,
    BTA_GATTC_IGNORE_OP_CMPL,
    BTA_GATTC_DISC_CLOSE,
    BTA_GATTC_RESTART_DISCOVER,
    BTA_GATTC_CFG_MTU,

    BTA_GATTC_IGNORE
};
/* type for action functions */
typedef void (*tBTA_GATTC_ACTION)(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);

/* action function list */
const tBTA_GATTC_ACTION bta_gattc_action[] =
{
    bta_gattc_open,
    bta_gattc_open_fail,
    bta_gattc_open_error,
    bta_gattc_cancel_open,
    bta_gattc_cancel_open_ok,
    bta_gattc_cancel_open_error,
    bta_gattc_conn,
    bta_gattc_start_discover,
    bta_gattc_disc_cmpl,

    bta_gattc_q_cmd,
    bta_gattc_close,
    bta_gattc_close_fail,
    bta_gattc_read,
    bta_gattc_write,

    bta_gattc_op_cmpl,
    bta_gattc_search,
    bta_gattc_fail,
    bta_gattc_confirm,
    bta_gattc_execute,
    bta_gattc_read_multi,
    bta_gattc_ci_open,
    bta_gattc_ci_load,
    bta_gattc_ci_save,
    bta_gattc_cache_open,
    bta_gattc_ignore_op_cmpl,
    bta_gattc_disc_close,
    bta_gattc_restart_discover,
    bta_gattc_cfg_mtu
};

具体方法如下:
/*******************************************************************************
**
** Function         bta_gattc_write
**
** Description      Write an attribute
**
** Returns          None.
**
*******************************************************************************/
void bta_gattc_write(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
{
    UINT16              handle = 0;
    tGATT_VALUE         attr = {0};
    tBTA_GATTC_OP_CMPL  op_cmpl;
    tBTA_GATT_STATUS    status = BTA_GATT_OK;

    if (bta_gattc_enqueue(p_clcb, p_data))
    {
        if ((handle = bta_gattc_id2handle(p_clcb->p_srcb,
                                          &p_data->api_write.srvc_id,
                                          &p_data->api_write.char_id,
                                          p_data->api_write.p_descr_type)) == 0)
        {
            status = BTA_GATT_ERROR;
        }
        else
        {
            attr.handle= handle;
            attr.offset = p_data->api_write.offset;
            attr.len    = p_data->api_write.len;
            attr.auth_req = p_data->api_write.auth_req;

            if (p_data->api_write.p_value)
                memcpy(attr.value, p_data->api_write.p_value, p_data->api_write.len);

            status = GATTC_Write(p_clcb->bta_conn_id, p_data->api_write.write_type, &attr);
        }

        /* write fail */
        if (status != BTA_GATT_OK)
        {
            memset(&op_cmpl, 0, sizeof(tBTA_GATTC_OP_CMPL));

            op_cmpl.status  = status;
            op_cmpl.op_code = GATTC_OPTYPE_WRITE;
            op_cmpl.p_cmpl  = NULL;

            bta_gattc_sm_execute(p_clcb, BTA_GATTC_OP_CMPL_EVT, (tBTA_GATTC_DATA *)&op_cmpl);
        }
    }
}

那么继续,这里会调用协议栈里面的方法了,GATTC_Write()

/*******************************************************************************
**
** Function         GATTC_Write
**
** Description      This function is called to write the value of an attribute to
**                  the server.
**
** Parameters       conn_id: connection identifier.
**                  type    - attribute write type.
**                  p_write  - write operation parameters.
**
** Returns          GATT_SUCCESS if command started successfully.
**
*******************************************************************************/
tGATT_STATUS GATTC_Write (UINT16 conn_id, tGATT_WRITE_TYPE type, tGATT_VALUE *p_write)
{
    tGATT_STATUS status = GATT_SUCCESS;
    tGATT_CLCB      *p_clcb;
    tGATT_VALUE     *p;
    tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
    UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
    tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);

    if ( (p_tcb == NULL) || (p_reg==NULL) || (p_write == NULL) ||
         ((type != GATT_WRITE) && (type != GATT_WRITE_PREPARE) && (type != GATT_WRITE_NO_RSP)) )
    {
        GATT_TRACE_ERROR("GATT_Write Illegal param: conn_id %d, type 0%d,", conn_id, type);
        return GATT_ILLEGAL_PARAMETER;
    }

    if (gatt_is_clcb_allocated(conn_id))
    {
        GATT_TRACE_ERROR("GATTC_Write GATT_BUSY conn_id = %d", conn_id);
        return GATT_BUSY;
    }

    if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL )
    {
        p_clcb->operation  = GATTC_OPTYPE_WRITE;
        p_clcb->op_subtype = type;
        p_clcb->auth_req = p_write->auth_req;

        if (( p_clcb->p_attr_buf = (UINT8 *)GKI_getbuf((UINT16)sizeof(tGATT_VALUE))) != NULL)
        {
            memcpy(p_clcb->p_attr_buf, (void *)p_write, sizeof(tGATT_VALUE));

            p =  (tGATT_VALUE *)p_clcb->p_attr_buf;
            if (type == GATT_WRITE_PREPARE)
            {
                p_clcb->start_offset = p_write->offset;
                p->offset = 0;
            }

            if (gatt_security_check_start(p_clcb) == FALSE)
            {
                status = GATT_NO_RESOURCES;
            }
        }
        else
        {
            status = GATT_NO_RESOURCES;
        }

        if (status == GATT_NO_RESOURCES)
            gatt_clcb_dealloc(p_clcb);
    }
    else
    {
        status = GATT_NO_RESOURCES;
    }
    return status;
}
这里的type是APP调用的时候,设定的就是GATT_WRITE_PREPARE,

关于协议栈里面的实现,暂不表述




0 0
原创粉丝点击