最近入手了一款国产蓝牙soc,这里简单调一下串口透传,大体和CC2541的套路差不多。
在官方SDK的ble_simple_peripheral例程中,我首先在“simple_gatt_service.c”加入了一个char6的特征值用来做透传使用:
/******************************* Characteristic 6 defination *******************************/
// Characteristic 6 UUID: 0xFFF6
uint8_t sp_char6_uuid[UUID_SIZE_2] =
{
LO_UINT16(SP_CHAR6_UUID), HI_UINT16(SP_CHAR6_UUID)
};
// Characteristic 6 data
#define SP_CHAR6_VALUE_LEN 50
uint8_t sp_char6_value[SP_CHAR6_VALUE_LEN] = {0};
#define SP_CHAR6_CCC_LEN 2
uint8_t sp_char6_ccc[SP_CHAR6_CCC_LEN] = {0};
// Characteristic 6 User Description
#define SP_CHAR6_DESC_LEN 17
const uint8_t sp_char6_desc[SP_CHAR6_DESC_LEN] = "Characteristic 6";
并且在“simple_gatt_service.h”中添加一个“#define SP_CHAR6_UUID 0xFFF6”
然后在“simple_profile_att_table”表中添加我们自定义的char6:
/*********************************************************************************************************************************************************************/
// Characteristic 6 Declaration
[SP_IDX_CHAR6_DECLARATION] = {
{ UUID_SIZE_2, UUID16_ARR(GATT_CHARACTER_UUID) }, /* UUID */
GATT_PROP_READ, /* Permissions */
0, /* Max size of the value */
NULL, /* Value of the attribute */
},
// Characteristic 6 Value
[SP_IDX_CHAR6_VALUE] = {
{ UUID_SIZE_2, UUID16_ARR(SP_CHAR6_UUID) }, /* UUID */
GATT_PROP_READ | GATT_PROP_WRITE | GATT_PROP_NOTI, /* Permissions */
SP_CHAR6_VALUE_LEN, /* Max size of the value */
NULL, /* Value of the attribute */ /* Can assign a buffer here, or can be assigned in the application by user */
},
// Characteristic 6 client characteristic configuration
[SP_IDX_CHAR6_CFG] = {
{ UUID_SIZE_2, UUID16_ARR(GATT_CLIENT_CHAR_CFG_UUID) }, /* UUID */
GATT_PROP_READ | GATT_PROP_WRITE, /* Permissions */
SP_CHAR6_CCC_LEN, /* Max size of the value */
NULL, /* Value of the attribute */ /* Can assign a buffer here, or can be assigned in the application by user */
},
// Characteristic 6 User Description
[SP_IDX_CHAR6_USER_DESCRIPTION] = {
{ UUID_SIZE_2, UUID16_ARR(GATT_CHAR_USER_DESC_UUID) }, /* UUID */
GATT_PROP_READ, /* Permissions */
SP_CHAR6_DESC_LEN, /* Max size of the value */
(uint8_t *)sp_char6_desc, /* Value of the attribute */
},
};
至此,这个时候我们去编译完下载后,已经可以看到我们定义的特征值了。
当然,这个时候还无法实现我们想要的效果,还有两个函数需要修改,分别是“static void sp_gatt_read_cb(uint8_t *p_read, uint16_t *len, uint16_t att_idx)”和“static void sp_gatt_write_cb(uint8_t *write_buf, uint16_t len, uint16_t att_idx)”
我这里就先照抄了上面格式了。
/*********************************************************************
* @fn sp_gatt_read_cb
*
* @brief Simple Profile user application handles read request in this callback.
* 应用层在这个回调函数里面处理读的请求。
*
* @param p_read - the pointer to read buffer. NOTE: It's just a pointer from lower layer, please create the buffer in application layer.
* 指向读缓冲区的指针。 请注意这只是一个指针,请在应用程序中分配缓冲区. 为输出函数, 因此为指针的指针.
* len - the pointer to the length of read buffer. Application to assign it.
* 读缓冲区的长度,用户应用程序去给它赋值.
* att_idx - index of the attribute value in it's attribute table.
* Attribute的偏移量.
*
* @return 读请求的长度.
*/
static void sp_gatt_read_cb(uint8_t *p_read, uint16_t *len, uint16_t att_idx)
{
switch (att_idx)
{
case SP_IDX_CHAR1_VALUE:
for (int i = 0; i < SP_CHAR1_VALUE_LEN; i++)
sp_char1_value[i] = sp_char1_value[0] + i + 1;
memcpy(p_read, sp_char1_value, SP_CHAR1_VALUE_LEN);
*len = SP_CHAR1_VALUE_LEN;
break;
case SP_IDX_CHAR2_VALUE:
for (int i = 0; i < SP_CHAR2_VALUE_LEN; i++)
sp_char2_value[i] = sp_char2_value[0] + i + 1;
memcpy(p_read, sp_char2_value, SP_CHAR2_VALUE_LEN);
*len = SP_CHAR2_VALUE_LEN;
break;
case SP_IDX_CHAR4_CFG:
*len = 2;
memcpy(p_read, sp_char4_ccc, 2);
break;
case SP_IDX_CHAR5_VALUE:
for (int i = 0; i < SP_CHAR5_VALUE_LEN; i++)
sp_char5_value[i] = sp_char3_value[0] + i + 1;
memcpy(p_read, sp_char5_value, SP_CHAR5_VALUE_LEN);
*len = SP_CHAR5_VALUE_LEN;
break;
case SP_IDX_CHAR6_VALUE:
for (int i = 0; i < SP_CHAR6_VALUE_LEN; i++)
sp_char5_value[i] = sp_char3_value[0] + i + 1;
memcpy(p_read, sp_char5_value, SP_CHAR5_VALUE_LEN);
*len = SP_CHAR5_VALUE_LEN;
co_printf("Char6 Read: \r\n");
break;
default:
break;
}
//co_printf("Read request: len: %d value: 0x%x 0x%x \r\n", *len, (p_read)[0], (p_read)[*len-1]);
}
/*********************************************************************
* @fn sp_gatt_write_cb
*
* @brief Simple Profile user application handles write request in this callback.
* 应用层在这个回调函数里面处理写的请求。
*
* @param write_buf - the buffer for write
* 写操作的数据.
*
* len - the length of write buffer.
* 写缓冲区的长度.
* att_idx - index of the attribute value in it's attribute table.
* Attribute的偏移量.
*
* @return 写请求的长度.
*/
static void sp_gatt_write_cb(uint8_t *write_buf, uint16_t len, uint16_t att_idx)
{
for (int i = 0; i < len; i++)
{
//co_printf("Write request: len: %d, 0x%x \r\n", len, write_buf[i]);
if (att_idx == SP_IDX_CHAR1_VALUE)
memcpy(sp_char1_value, write_buf, len);
if (att_idx == SP_IDX_CHAR3_VALUE)
memcpy(sp_char3_value, write_buf, len);
if (att_idx == SP_IDX_CHAR5_VALUE)
memcpy(sp_char5_value, write_buf, len);
if (att_idx == SP_IDX_CHAR6_VALUE)
{
memcpy(sp_char6_value, write_buf, len); //这里可以去读取蓝牙调试助手发送来的数据
//co_printf("Char6 Write: \r\n");
//下面代码将收到的数据再发回去
//在接收到对端ntf使能的消息之后,通过调用gatt_notification()函数实现BLE peripheral端向手机端发送数据
gatt_ntf_t ntf_att;
ntf_att.att_idx = SP_IDX_CHAR6_VALUE;//0xfff0服务的第6个att:0xfff6
ntf_att.conidx = 0;//链接号,因为是单链接,所以这里可以写死为0
ntf_att.svc_id = sp_svc_id;//此GATT服务号
ntf_att.data_len = len;//Notification数据的长度,根据发送的数据实时调整
ntf_att.p_data = write_buf;//Notification数据的指针
gatt_notification(ntf_att);//peripheral端设备向手机端执行一次notification操作;
}
}
uint16_t uuid = BUILD_UINT16( simple_profile_att_table[att_idx].uuid.p_uuid[0], simple_profile_att_table[att_idx].uuid.p_uuid[1] );
if (uuid == GATT_CLIENT_CHAR_CFG_UUID)
{
//co_printf("Notification status changed\r\n");
if (att_idx == SP_IDX_CHAR4_CFG)
{
sp_char4_ccc[0] = write_buf[0];
sp_char4_ccc[1] = write_buf[1];
co_printf("Char4 ccc: 0x%x 0x%x \r\n", sp_char4_ccc[0], sp_char4_ccc[1]);
}
if (att_idx == SP_IDX_CHAR6_CFG)
{
sp_char6_ccc[0] = write_buf[0];
sp_char6_ccc[1] = write_buf[1];
co_printf("Char6 ccc: 0x%x 0x%x \r\n", sp_char6_ccc[0], sp_char6_ccc[1]);
}
}
}
下面将发送代码单独拎出来
//在接收到对端ntf使能的消息之后,通过调用gatt_notification()函数实现BLE peripheral端向手机端发送数据
gatt_ntf_t ntf_att;
ntf_att.att_idx = SP_IDX_CHAR6_VALUE;//0xfff0服务的第6个att:0xfff6
ntf_att.conidx = conn_idx;//链接号,因为是单链接,所以这里可以写死为0
ntf_att.svc_id = sp_svc_id;//此GATT服务号
ntf_att.data_len = 5;//Notification数据的长度,根据发送的数据实时调整
uint8_t ntf_data[] = "nihao";//虚拟数据,用户可根据需要替换成需要Notification的数据
ntf_att.p_data = ntf_data;//Notification数据的指针
gatt_notification(ntf_att);//peripheral端设备向手机端执行一次notification操作;
以上就是初步调试的过程了,如果需要使用的话还需要做修改,有什么错误的话欢迎指出。