首先是确定与APP通信的BLE服务,这个服务如果不是公共服务,就定义私有服务,比如SDK里面的0X1800为公共服务,为显示电池电量等来用的。定义一个与APP通信的私有服务为0X2020。至于哪些为公共服务,可以查看BLE协议相关手册,除了公共服务以外其余皆为私有服务。平时我们在手机搜索到的BLE图标显示为键盘,手柄等等,就是因为搜索到的蓝牙定义的服务有公共服务,有什么公共服务,就显示为什么样的图标。
确定好私有服务0X2020,剩下的就是特征值了,一般定义3个特征值,一个用来写(0xa0a0),一个读(0xa0a1),一个Notify(0xa0a2),之后用gatt工具生成profile表格,替换掉sdk里面表格,到这里特征值和服务的工作已经做完。
接下去是sdk的读写回调,里面代码已经实现,需要做的是把自己定义的读写notify三个通道替换掉原来的。读回调,即app读蓝牙端数据后蓝牙给出怎样的结果,通道替换成0xa0a1即可。举例:用APP读取蓝牙端的音量,是通过0xa0a1这个通道来读取的,只要在回调中把音量放进去,APP即可读回蓝牙端音量。写回调:同理,在app发一个0x01过来,就会调用一次写回调函数。至于发送怎样的数据,跟读回调一个道理。接下去是notify,这个比较重要,这个通道是APP用来监听的通道,也是蓝牙端最常用的通道,蓝牙端想要主动发送数据到APP端就是通过这个通道来实现的,相关的代码在sdk里面已经实现了。
以下服务0XA035,写0XA040,读0XA041,Notify0XA042
#define ATT_CHARACTERISTIC_2A00_01_VALUE_HANDLE 0x0003
#define ATT_CHARACTERISTIC_a042_01_VALUE_HANDLE 0x0006 //蓝牙发送通道 需要client在该通道处于监听状态
#define ATT_CHARACTERISTIC_a042_01_CLIENT_CONFIGURATION_HANDLE 0x0007 //
#define ATT_CHARACTERISTIC_a040_01_VALUE_HANDLE 0x0009//client写通道
#define ATT_CHARACTERISTIC_a041_01_VALUE_HANDLE 0x000b // client读通道 蓝牙准备好数据给app读取
#define ATT_CHARACTERISTIC_a043_01_VALUE_HANDLE 0x000d // 没有用到的通道
#define ATT_CHARACTERISTIC_a043_01_CLIENT_CONFIGURATION_HANDLE 0x000e
static int att_write_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size)
{
int result = 0;
u16 tmp16;
u16 handle = att_handle;
// log_info("write_callback, handle= 0x%04x,size = %d\n", handle, buffer_size);
switch (handle) {
case ATT_CHARACTERISTIC_a042_01_CLIENT_CONFIGURATION_HANDLE:
case ATT_CHARACTERISTIC_a043_01_CLIENT_CONFIGURATION_HANDLE:
set_ble_work_state(BLE_ST_NOTIFY_IDICATE);
check_connetion_updata_deal();
log_info("\n------write ccc:%04x,%02x\n", handle, buffer[0]);
att_set_ccc_config(handle, buffer[0]);
break;
case ATT_CHARACTERISTIC_a040_01_VALUE_HANDLE:
if (buffer_size){
user_ble_rx_parse(buffer, buffer_size);
}
break;
default:
break;
}
return 0;
}
static uint16_t att_read_callback(hci_con_handle_t connection_handle,
uint16_t att_handle,
uint16_t offset,
uint8_t *buffer,
uint16_t buffer_size)
{
uint16_t att_value_len = 0;
uint16_t handle = att_handle;
u8* ptr = NULL;
// log_info("read_callback, handle= 0x%04x,buffer= %08x\n", handle, (u32)buffer);
switch (handle) {
case ATT_CHARACTERISTIC_a041_01_VALUE_HANDLE:
ptr = user_ble_app_read_cbk(&att_value_len);
if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) {
break;
}
if (buffer) {
memcpy(buffer, &ptr[offset], buffer_size);
att_value_len = buffer_size;
}
break;
default:
break;
}
return att_value_len;
}
/**
* \brief user_ble_tx_data
* \note ble数据直发
*
*/
static int ble_tx_data(u8 *tx_buf, u16 len)
{
u32 vaild_len = 0;
ble_user_cmd_prepare(BLE_CMD_ATT_VAILD_LEN, 1, &vaild_len);
if (len <= vaild_len) {
/// printf("ble send\n");
return app_send_user_data(ATT_CHARACTERISTIC_a042_01_VALUE_HANDLE, tx_buf, len, ATT_OP_AUTO_READ_CCC);
}
return APP_BLE_OPERATION_ERROR;
}
/**
* \brief user_ble_rx_parse
* \note ble原始数据解析
*
*/
void user_ble_rx_parse(u8 *rx_buf, u16 len)
{
u8 rx_user_data[128]={0};
u8 user_data_len = 0;
u16 command = 0;
u8 error_ack = 0xff;
user_uart_tx_data(rx_buf, len);/*!透传*/
bool check_result = ble_user_defined_protocol_check(rx_buf, len, rx_user_data, &user_data_len, &command);
if (check_result == TRUE)
{
ble_command_parse(command,rx_user_data);
}
else
{
printf("ble protocol check fail\n");
user_ble_app_rsp_package(command,&ble_rsp_error,1);
}
}
作者:渔夫与魔鬼的故事