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_event, BTIF_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
- android bluedroid bt 读写特性值的流程
- Android bt hid(bluedroid)和linux HID-subsystem
- Bluedroid的启动与enable流程
- Android Wifi BT的工作流程和porting(精)
- Android Wifi BT的工作流程和porting(精)
- Android BlueDroid(一):BlueDroid概述
- Android BlueDroid(一):BlueDroid概述
- Android BlueDroid(一):BlueDroid概述
- Android BlueDroid(一):BlueDroid概述
- Android BlueDroid(一):BlueDroid概述
- Android BlueDroid(一):BlueDroid概述
- Android BlueDroid(一):BlueDroid概述
- Android BlueDroid(一):BlueDroid概述
- BlueDroid 蓝牙启动流程分析
- Android BlueDroid(二)
- Android BlueDroid(三)
- android bluedroid调试
- android bluedroid架构
- LogUtils工具栏
- hjr学习-通信原理(一):通信基础
- oralce表空间创建修改删除
- C语言头文件#include<sys/types.h>的作用
- 02_下载
- android bluedroid bt 读写特性值的流程
- fdisk
- mac ox 搭建red5流媒体服务器(含Demo)--学习记录
- 我就是说点实话
- gerrit服务器新建库
- js加载页面资源
- adb client, adb server, adbd原理浅析(附带我的操作过程)
- java的第一章节
- spring的事务隔离机制