一、简介
本文以SimpleBLEPeripheral工程为例,介绍如何在工程中添加一个自定义的服务。
二、实验平台
协议栈版本:ble_cc26xx_2_01_00_44423
编译软件:IAR Embedded Workbench for ARM Version 7.40
硬件平台:CC26xxDK开发板
仿真器:XDS100V3(香瓜)
手机平台:小米4S
APP:BLE读写器
三、版权声明
博主:甜甜的大香瓜
声明:喝水不忘挖井人,转载请注明出处。
原文地址:http://blog.csdn.NET/feilusia
联系方式:897503845@qq.com
香瓜BLE之CC2541群:127442605
香瓜BLE之CC2640群:557278427
香瓜单片机之职场交流群:450154342
五、基础知识
暂无
六、实验步骤
1、编写并添加自定义的服务
1)写一个服务源文件GUA_Profile.c(存放在“……\ble_cc26xx_2_01_00_44423\Projects\ble\SimpleBLEPeripheral\CC26xx\Source\Application\GUA”路径下)
- //******************************************************************************
- //name: GUA_profile.c
- //introduce: 香瓜自定义的服务,内含一个可读、可写、可通知的特征值
- //author: 甜甜的大香瓜
- //email: 897503845@qq.com
- //QQ group 香瓜BLE之CC2640(557278427)
- //changetime: 2016.08.27
- //******************************************************************************
- /*********************************************************************
- * INCLUDES
- */
- #include <string.h>
- #include "bcomdef.h"
- #include "OSAL.h"
- #include "linkdb.h"
- #include "att.h"
- #include "gatt.h"
- #include "gatt_uuid.h"
- #include "gattservapp.h"
- #include "gapbondmgr.h"
- #include "GUA_Profile.h"
- /*********************************************************************
- * MACROS
- */
- /*********************************************************************
- * CONSTANTS
- */
- #define SERVAPP_NUM_ATTR_SUPPORTED 5
- //属性在属性表中的偏移值
- #define ATTRTBL_GUA_CHAR1_IDX 2
- #define ATTRTBL_GUA_CHAR1_CCC_IDX 3
- /*********************************************************************
- * TYPEDEFS
- */
- /*********************************************************************
- * GLOBAL VARIABLES
- */
- // GUA Service UUID: 0xFFE0
- CONST uint8 GUAServUUID[ATT_BT_UUID_SIZE] =
- {
- LO_UINT16(GUAPROFILE_SERV_UUID), HI_UINT16(GUAPROFILE_SERV_UUID)
- };
- // GUA char1 UUID: 0xFFE1
- CONST uint8 GUAChar1UUID[ATT_BT_UUID_SIZE] =
- {
- LO_UINT16(GUAPROFILE_CHAR1_UUID), HI_UINT16(GUAPROFILE_CHAR1_UUID)
- };
- /*********************************************************************
- * EXTERNAL VARIABLES
- */
- /*********************************************************************
- * EXTERNAL FUNCTIONS
- */
- /*********************************************************************
- * LOCAL VARIABLES
- */
- static GUAProfileCBs_t *GUAProfile_AppCBs = NULL;
- /*********************************************************************
- * Profile Attributes - variables
- */
- // GUA Service attribute
- static CONST gattAttrType_t GUAProfile_Service = { ATT_BT_UUID_SIZE, GUAServUUID };
- // GUA Characteristic 1 Properties
- static uint8 GUAProfile_Char1_Props = GATT_PROP_READ | GATT_PROP_WRITE | GATT_PROP_NOTIFY;
- // GUA Characteristic 1 Value
- static uint8 GUAProfile_Char1[GUAPROFILE_CHAR1_LEN] = {0};
- // GUA Characteristic 1 Configs
- static gattCharCfg_t *GUAProfile_Char1_Config;
- // GUA Characteristic 1 User Description
- static uint8 GUAProfile_Char1_UserDesp[10] = "GUA Char1\0";
- /*********************************************************************
- * Profile Attributes - Table
- */
- static gattAttribute_t GUAProfileAttrTbl[SERVAPP_NUM_ATTR_SUPPORTED] =
- {
- // GUA Service
- {
- { ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */
- GATT_PERMIT_READ, /* permissions */
- 0, /* handle */
- (uint8 *)&GUAProfile_Service /* pValue */
- },
- // GUA Characteristic 1 Declaration
- {
- { ATT_BT_UUID_SIZE, characterUUID },
- GATT_PERMIT_READ,
- 0,
- &GUAProfile_Char1_Props
- },
- // GUA Characteristic 1 Value
- {
- { ATT_BT_UUID_SIZE, GUAChar1UUID },
- GATT_PERMIT_READ | GATT_PERMIT_WRITE,
- 0,
- GUAProfile_Char1
- },
- // GUA Characteristic 1 configuration
- {
- { ATT_BT_UUID_SIZE, clientCharCfgUUID },
- GATT_PERMIT_READ | GATT_PERMIT_WRITE,
- 0,
- (uint8 *)&GUAProfile_Char1_Config
- },
- // GUA Characteristic 1 User Description
- {
- { ATT_BT_UUID_SIZE, charUserDescUUID },
- GATT_PERMIT_READ,
- 0,
- GUAProfile_Char1_UserDesp
- },
- };
- /*********************************************************************
- * LOCAL FUNCTIONS
- */
- static uint8 GUAProfile_ReadAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
- uint8 *pValue, uint16 *pLen, uint16 offset, uint16 maxLen, uint8 method );
- static bStatus_t GUAProfile_WriteAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
- uint8 *pValue, uint16 len, uint16 offset, uint8 method );
- /*********************************************************************
- * PROFILE CALLBACKS
- */
- // GUAProfile Service Callbacks
- CONST gattServiceCBs_t GUAProfileCBs =
- {
- GUAProfile_ReadAttrCB, // Read callback function pointer
- GUAProfile_WriteAttrCB, // Write callback function pointer
- NULL // Authorization callback function pointer
- };
- /*********************************************************************
- * PUBLIC FUNCTIONS
- */
- /*********************************************************************
- * @fn GUAProfile_AddService
- *
- * @brief Initializes the GUA service by registering
- * GATT attributes with the GATT server.
- *
- * @param services - services to add. This is a bit map and can
- * contain more than one service.
- *
- * @return Success or Failure
- */
- bStatus_t GUAProfile_AddService( uint32 services )
- {
- uint8 status = SUCCESS;
- // Allocate Client Characteristic Configuration table
- GUAProfile_Char1_Config = (gattCharCfg_t *)ICall_malloc( sizeof(gattCharCfg_t) *
- linkDBNumConns );
- if ( GUAProfile_Char1_Config == NULL )
- {
- return ( bleMemAllocError );
- }
- // Initialize Client Characteristic Configuration attributes
- GATTServApp_InitCharCfg( INVALID_CONNHANDLE, GUAProfile_Char1_Config );
- if ( services & GUAPROFILE_SERVICE )
- {
- // Register GATT attribute list and CBs with GATT Server App
- status = GATTServApp_RegisterService( GUAProfileAttrTbl,
- GATT_NUM_ATTRS( GUAProfileAttrTbl ),
- GATT_MAX_ENCRYPT_KEY_SIZE,
- &GUAProfileCBs );
- }
- return ( status );
- }
- /*********************************************************************
- * @fn GUAProfile_RegisterAppCBs
- *
- * @brief Registers the application callback function. Only call
- * this function once.
- *
- * @param callbacks - pointer to application callbacks.
- *
- * @return SUCCESS or bleAlreadyInRequestedMode
- */
- bStatus_t GUAProfile_RegisterAppCBs( GUAProfileCBs_t *appCallbacks )
- {
- if ( appCallbacks )
- {
- GUAProfile_AppCBs = appCallbacks;
- return ( SUCCESS );
- }
- else
- {
- return ( bleAlreadyInRequestedMode );
- }
- }
- /*********************************************************************
- * @fn GUAProfile_SetParameter
- *
- * @brief Set a GUA Profile parameter.
- *
- * @param param - Profile parameter ID
- * @param len - length of data to right
- * @param pValue - pointer to data to write. This is dependent on
- * the parameter ID and WILL be cast to the appropriate
- * data type (example: data type of uint16 will be cast to
- * uint16 pointer).
- *
- * @return bStatus_t
- */
- bStatus_t GUAProfile_SetParameter( uint8 param, uint8 len, void *pValue )
- {
- bStatus_t ret = SUCCESS;
- switch ( param )
- {
- case GUAPROFILE_CHAR1:
- if ( len == GUAPROFILE_CHAR1_LEN )
- {
- VOID memcpy( GUAProfile_Char1, pValue, GUAPROFILE_CHAR1_LEN );
- }
- else
- {
- ret = bleInvalidRange;
- }
- break;
- default:
- ret = INVALIDPARAMETER;
- break;
- }
- return ( ret );
- }
- /*********************************************************************
- * @fn GUAProfile_GetParameter
- *
- * @brief Get a GUA Profile parameter.
- *
- * @param param - Profile parameter ID
- * @param pValue - pointer to data to put. This is dependent on
- * the parameter ID and WILL be cast to the appropriate
- * data type (example: data type of uint16 will be cast to
- * uint16 pointer).
- *
- * @return bStatus_t
- */
- bStatus_t GUAProfile_GetParameter( uint8 param, void *pValue )
- {
- bStatus_t ret = SUCCESS;
- switch ( param )
- {
- case GUAPROFILE_CHAR1:
- VOID memcpy( pValue, GUAProfile_Char1, GUAPROFILE_CHAR1_LEN );
- break;
- default:
- ret = INVALIDPARAMETER;
- break;
- }
- return ( ret );
- }
- /*********************************************************************
- * @fn GUAProfile_ReadAttrCB
- *
- * @brief Read an attribute.
- *
- * @param connHandle - connection message was received on
- * @param pAttr - pointer to attribute
- * @param pValue - pointer to data to be read
- * @param pLen - length of data to be read
- * @param offset - offset of the first octet to be read
- * @param maxLen - maximum length of data to be read
- *
- * @return Success or Failure
- */
- static uint8 GUAProfile_ReadAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
- uint8 *pValue, uint16 *pLen, uint16 offset, uint16 maxLen, uint8_t method )
- {
- bStatus_t status = SUCCESS;
- // If attribute permissions require authorization to read, return error
- if ( gattPermitAuthorRead( pAttr->permissions ) )
- {
- // Insufficient authorization
- return ( ATT_ERR_INSUFFICIENT_AUTHOR );
- }
- // Make sure it's not a blob operation (no attributes in the profile are long
- if ( offset > 0 )
- {
- return ( ATT_ERR_ATTR_NOT_LONG );
- }
- if ( pAttr->type.len == ATT_BT_UUID_SIZE )
- {
- // 16-bit UUID
- uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
- switch ( uuid )
- {
- // No need for "GATT_SERVICE_UUID" or "GATT_CLIENT_CHAR_CFG_UUID" cases;
- // gattserverapp handles this type for reads
- // GUA characteristic does not have read permissions, but because it
- // can be sent as a notification, it must be included here
- case GUAPROFILE_CHAR1_UUID:
- *pLen = GUAPROFILE_CHAR1_LEN;
- VOID memcpy( pValue, pAttr->pValue, GUAPROFILE_CHAR1_LEN );
- break;
- default:
- // Should never get here!
- *pLen = 0;
- status = ATT_ERR_ATTR_NOT_FOUND;
- break;
- }
- }
- else
- {
- // 128-bit UUID
- *pLen = 0;
- status = ATT_ERR_INVALID_HANDLE;
- }
- return ( status );
- }
- /*********************************************************************
- * @fn GUAProfile_WriteAttrCB
- *
- * @brief Validate attribute data prior to a write operation
- *
- * @param connHandle - connection message was received on
- * @param pAttr - pointer to attribute
- * @param pValue - pointer to data to be written
- * @param len - length of data
- * @param offset - offset of the first octet to be written
- *
- * @return Success or Failure
- */
- static bStatus_t GUAProfile_WriteAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
- uint8 *pValue, uint16 len, uint16 offset, uint8_t method )
- {
- bStatus_t status = SUCCESS;
- uint8 notifyApp = 0xFF;
- // If attribute permissions require authorization to write, return error
- if ( gattPermitAuthorWrite( pAttr->permissions ) )
- {
- // Insufficient authorization
- return ( ATT_ERR_INSUFFICIENT_AUTHOR );
- }
- if ( pAttr->type.len == ATT_BT_UUID_SIZE )
- {
- // 16-bit UUID
- uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
- switch ( uuid )
- {
- case GUAPROFILE_CHAR1_UUID:
- if ( offset == 0 )
- {
- if ( len != GUAPROFILE_CHAR1_LEN )
- {
- status = ATT_ERR_INVALID_VALUE_SIZE;
- }
- }
- else
- {
- status = ATT_ERR_ATTR_NOT_LONG;
- }
- //将接收到的数据写进特征值中,并且置标志位
- if ( status == SUCCESS )
- {
- VOID memcpy( pAttr->pValue, pValue, GUAPROFILE_CHAR1_LEN );
- notifyApp = GUAPROFILE_CHAR1;
- }
- break;
- case GATT_CLIENT_CHAR_CFG_UUID:
- //char1通道,则打开notify开关
- if ( pAttr->handle == GUAProfileAttrTbl[ATTRTBL_GUA_CHAR1_CCC_IDX].handle )//GUA CHAR1 NOTIFY
- {
- status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len,
- offset, GATT_CLIENT_CFG_NOTIFY );
- }
- else
- {
- status = ATT_ERR_INVALID_HANDLE;
- }
- break;
- default:
- status = ATT_ERR_ATTR_NOT_FOUND;
- break;
- }
- }
- else
- {
- // 128-bit UUID
- status = ATT_ERR_INVALID_HANDLE;
- }
- // If a charactersitic value changed then callback function to notify application of change
- if ( (notifyApp != 0xFF ) && GUAProfile_AppCBs && GUAProfile_AppCBs->pfnGUAProfileChange )
- {
- GUAProfile_AppCBs->pfnGUAProfileChange( notifyApp );
- }
- return ( status );
- }
- //******************************************************************************
- //name: GUAprofile_Notify
- //introduce: notify发送函数
- //parameter: param:特征值通道参数
- // connHandle:连接句柄
- // cpValue:要通知的数据,范围为0~SIMPLEPROFILE_CHAR6,最多20个字节
- //return: none
- //author: 甜甜的大香瓜
- //email: 897503845@qq.com
- //QQ group 香瓜BLE之CC2640(557278427)
- //changetime: 2016.08.27
- //******************************************************************************
- void GUAprofile_Notify( uint8 param, uint16 connHandle, uint8 *pValue, uint8 len)
- {
- attHandleValueNoti_t noti;
- uint16 value;
- switch ( param )
- {
- //特征值1
- case GUAPROFILE_CHAR1:
- {
- //读出CCC
- value = GATTServApp_ReadCharCfg( connHandle, GUAProfile_Char1_Config );
- //判断CCC是否被打开
- if ( value & GATT_CLIENT_CFG_NOTIFY )
- {
- //分配发送数据缓冲区
- noti.pValue = GATT_bm_alloc(connHandle, ATT_HANDLE_VALUE_NOTI, GUAPROFILE_CHAR1_LEN, NULL);
- //分配成功,则发送数据
- if(noti.pValue != NULL)
- {
- //填充数据
- noti.handle = GUAProfileAttrTbl[ATTRTBL_GUA_CHAR1_IDX].handle;
- noti.len = len;
- memcpy( noti.pValue, pValue, len);
- //发送数据
- if (GATT_Notification(connHandle, ¬i, FALSE) != SUCCESS)
- {
- GATT_bm_free((gattMsg_t *)¬i, ATT_HANDLE_VALUE_NOTI);
- }
- }
- }
- break;
- }
- default:
- break;
- }
- }
2)写一个服务头文件GUA_Profile.h(存放在“……\ble_cc26xx_2_01_00_44423\Projects\ble\SimpleBLEPeripheral\CC26xx\Source\Application\GUA”路径下)
- //******************************************************************************
- //name: GUA_profile.h
- //introduce: 香瓜自定义的服务,内含一个可读、可写、可通知的特征值
- //author: 甜甜的大香瓜
- //email: 897503845@qq.com
- //QQ group 香瓜BLE之CC2640(557278427)
- //changetime: 2016.08.27
- //******************************************************************************
- #ifndef GUA_PROFILE_H
- #define GUA_PROFILE_H
- #ifdef __cplusplus
- extern "C"
- {
- #endif
- /*********************************************************************
- * INCLUDES
- */
- /*********************************************************************
- * CONSTANTS
- */
- // Profile Parameters
- #define GUAPROFILE_CHAR1 0 // RW uint8 - Profile GUA Characteristic 1 value
- // GUA Service UUID
- #define GUAPROFILE_SERV_UUID 0xFFE0
- // GUA CHAR1 UUID
- #define GUAPROFILE_CHAR1_UUID 0xFFE1
- // GUA Profile Services bit fields
- #define GUAPROFILE_SERVICE 0x00000001
- // Length of GUA Characteristic 1 in bytes
- #define GUAPROFILE_CHAR1_LEN 20
- /*********************************************************************
- * TYPEDEFS
- */
- /*********************************************************************
- * MACROS
- */
- /*********************************************************************
- * Profile Callbacks
- */
- // Callback when a characteristic value has changed
- typedef void (*GUAProfileChange_t)( uint8 paramID );
- typedef struct
- {
- GUAProfileChange_t pfnGUAProfileChange; // Called when characteristic value changes
- } GUAProfileCBs_t;
- /*********************************************************************
- * API FUNCTIONS
- */
- /*
- * GUAProfile_AddService- Initializes the GUA service by registering
- * GATT attributes with the GATT server.
- *
- * @param services - services to add. This is a bit map and can
- * contain more than one service.
- */
- extern bStatus_t GUAProfile_AddService( uint32 services );
- /*
- * GUAProfile_RegisterAppCBs - Registers the application callback function.
- * Only call this function once.
- *
- * appCallbacks - pointer to application callbacks.
- */
- extern bStatus_t GUAProfile_RegisterAppCBs( GUAProfileCBs_t *appCallbacks );
- /*
- * GUAProfile_SetParameter - Set a Simple Key Profile parameter.
- *
- * param - Profile parameter ID
- * len - length of data to right
- * pValue - pointer to data to write. This is dependent on
- * the parameter ID and WILL be cast to the appropriate
- * data type (example: data type of uint16 will be cast to
- * uint16 pointer).
- */
- extern bStatus_t GUAProfile_SetParameter( uint8 param, uint8 len, void *pValue );
- /*
- * GUA_GetParameter - Get a Simple Key Profile parameter.
- *
- * param - Profile parameter ID
- * pValue - pointer to data to write. This is dependent on
- * the parameter ID and WILL be cast to the appropriate
- * data type (example: data type of uint16 will be cast to
- * uint16 pointer).
- */
- extern bStatus_t GUAProfile_GetParameter( uint8 param, void *pValue );
- //******************************************************************************
- //name: GUAprofile_Notify
- //introduce: notify发送函数
- //parameter: param:特征值通道参数
- // connHandle:连接句柄
- // cpValue:要通知的数据,范围为0~SIMPLEPROFILE_CHAR6,最多20个字节
- //return: none
- //author: 甜甜的大香瓜
- //email: 897503845@qq.com
- //QQ group 香瓜BLE之CC2640(557278427)
- //changetime: 2016.08.27
- extern void GUAprofile_Notify( uint8 param, uint16 connHandle, uint8 *pValue, uint8 len);
- /*********************************************************************
- *********************************************************************/
- #ifdef __cplusplus
- }
- #endif
- #endif /* GUA_PROFILE_H */
3)工程中添加GUA_Profile.c和GUA_Profile.h
4)在IAR设置中添加服务的文件路径
- $PROJ_DIR$/../../../Source/Application/GUA
2、在应用层中添加服务相关的代码
1)添加GUA_Profile头文件(SimpleBLEPeripheral.c中)
- //香瓜
- #include "GUA_Profile.h"
- //香瓜
2)服务初始化(SimpleBLEPeripheral.c的SimpleBLEPeripheral_Init中)
- //香瓜
- //增加服务
- GUAProfile_AddService(GATT_ALL_SERVICES);
- //初始化特征值
- uint8 GUAProfile_Char1Value[GUAPROFILE_CHAR1_LEN] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- GUAProfile_SetParameter( GUAPROFILE_CHAR1, GUAPROFILE_CHAR1_LEN, &GUAProfile_Char1Value );
- //添加回调函数
- VOID GUAProfile_RegisterAppCBs( &simpleBLEPeripheral_GUAProfileCBs );
- //香瓜
3)定义服务的回调函数及处理函数(SimpleBLEPeripheral.c中)
- //******************************************************************************
- //name: GUAProfileChangeCB
- //introduce: 应用层香瓜服务回调函数
- //parameter: paramID:特征值ID
- //return: none
- //author: 甜甜的大香瓜
- //email: 897503845@qq.com
- //QQ group 香瓜BLE之CC2640(557278427)
- //changetime: 2016.08.27
- //******************************************************************************
- static void GUAProfileChangeCB( uint8 paramID )
- {
- SimpleBLEPeripheral_enqueueMsg(SBP_GUA_CHAR_CHANGE_EVT, paramID);
- }
- //******************************************************************************
- //name: GUA_CharValueChangeEvt
- //introduce: 应用层香瓜服务的处理函数
- //parameter: paramID:特征值ID
- //return: none
- //author: 甜甜的大香瓜
- //email: 897503845@qq.com
- //QQ group 香瓜BLE之CC2640(557278427)
- //changetime: 2016.08.27
- //******************************************************************************
- static void GUA_CharValueChangeEvt(uint8_t paramID)
- {
- uint16 notify_Handle;
- uint8 bBuf[20] = {0};
- uint8 *p = bBuf;
- switch( paramID )
- {
- case GUAPROFILE_CHAR1:
- GAPRole_GetParameter( GAPROLE_CONNHANDLE, ¬ify_Handle); //获取Connection Handle
- for(uint8 i = 0; i < 20; i++) //写一个20字节的测试缓冲区的数据
- {
- *(p+i) = i;
- }
- GUAprofile_Notify(GUAPROFILE_CHAR1, notify_Handle, p, 20);
- break;
- default:
- // should not reach here!
- break;
- }
- }
4)声明服务的回调函数和处理函数(SimpleBLEPeripheral.c中)
- //香瓜
- static void GUAProfileChangeCB( uint8 paramID );
- static void GUA_CharValueChangeEvt(uint8_t paramID);
- //香瓜
5)注册回调函数(SimpleBLEPeripheral.c中)
- //香瓜
- // GUA Profile Callbacks
- static GUAProfileCBs_t simpleBLEPeripheral_GUAProfileCBs =
- {
- GUAProfileChangeCB // Charactersitic value change callback
- };
- //香瓜
6)添加香瓜服务处理事件(SimpleBLEPeripheral.c中)
①添加香瓜服务处理事件的宏定义
- #define SBP_GUA_CHAR_CHANGE_EVT 0x0010
②添加香瓜服务处理事件的处理部分(替换SimpleBLEPeripheral.c中的SimpleBLEPeripheral_processAppMsg函数)
- static void SimpleBLEPeripheral_processAppMsg(sbpEvt_t *pMsg)
- {
- switch (pMsg->hdr.event)
- {
- case SBP_STATE_CHANGE_EVT:
- SimpleBLEPeripheral_processStateChangeEvt((gaprole_States_t)pMsg->
- hdr.state);
- break;
- case SBP_CHAR_CHANGE_EVT:
- SimpleBLEPeripheral_processCharValueChangeEvt(pMsg->hdr.state);
- break;
- case SBP_GUA_CHAR_CHANGE_EVT:
- GUA_CharValueChangeEvt(pMsg->hdr.state);
- break;
- default:
- // Do nothing.
- break;
- }
- }
手机可能缓存了之前的代码(在更新过CC2541的代码之后,都需要清除手机端的缓存!!!),因此要清除缓存,清除缓存的方法如下:
方法一:关闭app、关闭蓝牙总开关、打开蓝牙总开关、打开app。
方法二:手机重启。
八、实验结果
注:香瓜在开发CC2541时常用的truthblue在读取特征值时会出错,比如char1(0x01)却读到7、8个字节的乱数据,暂用蓝牙读写器代替。