一、前言
最近玩了一下CH577的蓝牙,这里记录一下
二、准备
-
使用CH的EVT,从机用 BLE\Peripheral ,主机用 BLE\Central,注意使用官网最新的,因为一直有进行更新,我前段时间拿的,使能notify是没有对应的参考的。
这里上一下链接:
CH官网,下载EVT即可 -
关于GATT和ATT,可以参考下面资料
资料1
资料2
这篇比较简单易懂
三、程序
1、主机
对于主机,需要修改下面这些部分
- MAC地址,注意这里的MAC和从机要相反!
// Peer device address
static uint8 PeerAddrDef[B_ADDR_LEN] = { 0x02,0x02,0x03,0xE4,0xC2,0x84 };
- 对于广播数据,MAC的发现,在下面函数中实现
/*********************************************************************5. @fn centralEventCB6. 7. @brief Central event callback function.7. 9. @param pEvent - pointer to event structure8. 11. @return none*/
static void centralEventCB( gapRoleEvent_t *pEvent )
{switch ( pEvent->gap.opcode ){case GAP_DEVICE_INIT_DONE_EVENT: {PRINT( "Discovering...\n" );GAPRole_CentralStartDiscovery( DEFAULT_DISCOVERY_MODE,DEFAULT_DISCOVERY_ACTIVE_SCAN,DEFAULT_DISCOVERY_WHITE_LIST ); }break;case GAP_DEVICE_INFO_EVENT:{// Add device to listcentralAddDeviceInfo( pEvent->deviceInfo.addr, pEvent->deviceInfo.addrType ); }break;case GAP_DEVICE_DISCOVERY_EVENT:{uint8 i; // See if peer device has been discovered for ( i = 0; i < centralScanRes; i++ ){if ( tmos_memcmp( PeerAddrDef, centralDevList[i].addr , B_ADDR_LEN ) )break;}// Peer device not foundif(i == centralScanRes){PRINT( "Device not found...\n" );centralScanRes = 0;GAPRole_CentralStartDiscovery( DEFAULT_DISCOVERY_MODE,DEFAULT_DISCOVERY_ACTIVE_SCAN,DEFAULT_DISCOVERY_WHITE_LIST ); PRINT( "Discovering...\n" );} // Peer device foundelse{PRINT( "Device found...\n" ); GAPRole_CentralEstablishLink( DEFAULT_LINK_HIGH_DUTY_CYCLE,DEFAULT_LINK_WHITE_LIST,centralDevList[i].addrType, centralDevList[i].addr );// Start establish link timeout eventtmos_start_task( centralTaskId, ESTABLISH_LINK_TIMEOUT_EVT, ESTABLISH_LINK_TIMEOUT);PRINT( "Connecting...\n" ); } }break;case GAP_LINK_ESTABLISHED_EVENT:{tmos_stop_task( centralTaskId, ESTABLISH_LINK_TIMEOUT_EVT );if ( pEvent->gap.hdr.status == SUCCESS ){centralState = BLE_STATE_CONNECTED;centralConnHandle = pEvent->linkCmpl.connectionHandle;centralProcedureInProgress = TRUE; // Initiate service discoverytmos_start_task( centralTaskId, START_SVC_DISCOVERY_EVT, DEFAULT_SVC_DISCOVERY_DELAY);// See if initiate connect parameter updateif ( centralParamUpdate ){tmos_start_task( centralTaskId, START_PARAM_UPDATE_EVT, DEFAULT_PARAM_UPDATE_DELAY);}// See if start RSSI pollingif ( centralRssi ){tmos_start_task( centralTaskId, START_READ_RSSI_EVT, DEFAULT_RSSI_PERIOD ); }PRINT( "Connected...\n" );}else{PRINT( "Connect Failed...Reason:%X\n",pEvent->gap.hdr.status );PRINT( "Discovering...\n" );centralScanRes = 0;GAPRole_CentralStartDiscovery( DEFAULT_DISCOVERY_MODE,DEFAULT_DISCOVERY_ACTIVE_SCAN,DEFAULT_DISCOVERY_WHITE_LIST ); }}break;case GAP_LINK_TERMINATED_EVENT:{centralState = BLE_STATE_IDLE;centralConnHandle = GAP_CONNHANDLE_INIT;centralDiscState = BLE_DISC_STATE_IDLE;centralCharHdl = 0;centralScanRes = 0;centralProcedureInProgress = FALSE;tmos_stop_task( centralTaskId, START_READ_RSSI_EVT ); PRINT( "Disconnected...Reason:%x\n", pEvent->linkTerminate.reason );PRINT( "Discovering...\n" );GAPRole_CentralStartDiscovery( DEFAULT_DISCOVERY_MODE,DEFAULT_DISCOVERY_ACTIVE_SCAN,DEFAULT_DISCOVERY_WHITE_LIST ); }break;case GAP_LINK_PARAM_UPDATE_EVENT:{PRINT( "Param Update...\n" );}break;default:break;}
}
-
对于GATT服务发现,在下面中完成,其实这里就是采用 GATT_ReadUsingCharUUID 来找特征的句柄 需要指定一下开头和结尾的HDL
需要注意:
(1). 若要发现多个服务,则要多建几个 centralDiscState 状态,在 pMsg->msg.readByTypeRsp.numPairs = 0时再切下一个状态
(2). 若要打开多个notify,需要调用多次 GATT_WriteCharValue ,这里必须采用任务来打开,不能马上打开,否则不生效,另外调用这些蓝牙的操作,不能在相同时间内操作多个,否则前面的也不生效
(3). 注意采用 GATT_ReadUsingCharUUID 方法(UUID已知)来发现特征值,得到的HDL,是特征值 数值的HDL
(4). 在采用 GATT_CLIENT_CHAR_CFG_UUID 这个UUID来获取CCC的时候,每读取完一个,需要 将当前的CCC的HDL+1作为 req.startHandle 来发现下一个CCC的HDL
/********************************************************************** @fn centralGATTDiscoveryEvent** @brief Process GATT discovery event** @return none*/
static void centralGATTDiscoveryEvent( gattMsgEvent_t *pMsg )
{attReadByTypeReq_t req;if ( centralDiscState == BLE_DISC_STATE_SVC ){// Service found, store handlesif ( pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&pMsg->msg.findByTypeValueRsp.numInfo > 0 ){centralSvcStartHdl = ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo,0);centralSvcEndHdl = ATT_GRP_END_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo,0);// Display Profile Service handle rangePRINT("Found Profile Service handle : %x ~ %x \n",centralSvcStartHdl,centralSvcEndHdl);}// If procedure completeif ( ( pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP && pMsg->hdr.status == bleProcedureComplete ) ||( pMsg->method == ATT_ERROR_RSP ) ){if ( centralSvcStartHdl != 0 ){// Discover characteristiccentralDiscState = BLE_DISC_STATE_CHAR;req.startHandle = centralSvcStartHdl;req.endHandle = centralSvcEndHdl;req.type.len = ATT_BT_UUID_SIZE;req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR1_UUID);req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR1_UUID);GATT_ReadUsingCharUUID( centralConnHandle, &req, centralTaskId );}}}else if ( centralDiscState == BLE_DISC_STATE_CHAR ){// Characteristic found, store handleif ( pMsg->method == ATT_READ_BY_TYPE_RSP && pMsg->msg.readByTypeRsp.numPairs > 0 ){centralCharHdl = BUILD_UINT16( pMsg->msg.readByTypeRsp.pDataList[0],pMsg->msg.readByTypeRsp.pDataList[1] );// Start do read or writetmos_start_task( centralTaskId, START_READ_OR_WRITE_EVT, DEFAULT_READ_OR_WRITE_DELAY);// Display Characteristic 1 handlePRINT("Found Characteristic 1 handle : %x \n",centralCharHdl); }if ( ( pMsg->method == ATT_READ_BY_TYPE_RSP && pMsg->hdr.status == bleProcedureComplete ) ||( pMsg->method == ATT_ERROR_RSP ) ){// Discover characteristiccentralDiscState = BLE_DISC_STATE_CCCD;req.startHandle = centralSvcStartHdl;req.endHandle = centralSvcEndHdl;req.type.len = ATT_BT_UUID_SIZE;req.type.uuid[0] = LO_UINT16(GATT_CLIENT_CHAR_CFG_UUID);req.type.uuid[1] = HI_UINT16(GATT_CLIENT_CHAR_CFG_UUID);GATT_ReadUsingCharUUID( centralConnHandle, &req, centralTaskId );}} else if ( centralDiscState == BLE_DISC_STATE_CCCD ){// Characteristic found, store handleif ( pMsg->method == ATT_READ_BY_TYPE_RSP && pMsg->msg.readByTypeRsp.numPairs > 0 ){centralCCCDHdl = BUILD_UINT16( pMsg->msg.readByTypeRsp.pDataList[0],pMsg->msg.readByTypeRsp.pDataList[1] );centralProcedureInProgress = FALSE;// Start do write CCCDtmos_start_task( centralTaskId, START_WRITE_CCCD_EVT, DEFAULT_WRITE_CCCD_DELAY);// Display Characteristic 1 handlePRINT("Found client characteristic configuration handle : %x \n",centralCCCDHdl); }else{// Discover characteristiccentralDiscState = BLE_DISC_STATE_CCCD;req.startHandle = centralCCCDHdl+1;//偏移来找....不然找到还是第一个....req.endHandle = centralSvcEndHdl;req.type.len = ATT_BT_UUID_SIZE;req.type.uuid[0] = LO_UINT16(GATT_CLIENT_CHAR_CFG_UUID);req.type.uuid[1] = HI_UINT16(GATT_CLIENT_CHAR_CFG_UUID);GATT_ReadUsingCharUUID( centralConnHandle, &req, centralTaskId );centralDiscState = BLE_DISC_STATE_CCCD2;}}else if ( centralDiscState == BLE_DISC_STATE_CCCD2 ){// Characteristic found, store handleif ( pMsg->method == ATT_READ_BY_TYPE_RSP && pMsg->msg.readByTypeRsp.numPairs > 0 ){centralCCCDHd2 = BUILD_UINT16( pMsg->msg.readByTypeRsp.pDataList[0],pMsg->msg.readByTypeRsp.pDataList[1] );centralProcedureInProgress = FALSE;// Start do write CCCDtmos_start_task( centralTaskId, START_WRITE_CCCD2_EVT, DEFAULT_WRITE_CCCD_DELAY);//注意换一个EVT。。上面第一个EVT 1600个时基后才写// Display Characteristic 1 handlePRINT("Found client characteristic configuration handle : %x \n",centralCCCDHd2); }centralDiscState = BLE_DISC_STATE_IDLE;}}
对于用户定义的任务,在下面实现
/*********************************************************************1. @fn Central_ProcessEvent2. 3. @brief Central Application Task event processor. This function3. is called to process all events for the task. Events4. include timers, messages and any other user defined events.5. 7. @param task_id - The TMOS assigned task ID.6. @param events - events to process. This is a bit map and can7. contain more than one event.8. 11. @return events not processed*/
uint16 Central_ProcessEvent( uint8 task_id, uint16 events )
{if ( events & SYS_EVENT_MSG ){uint8 *pMsg;if ( (pMsg = tmos_msg_receive( centralTaskId )) != NULL ){central_ProcessTMOSMsg( (tmos_event_hdr_t *)pMsg );// Release the TMOS messagetmos_msg_deallocate( pMsg );}// return unprocessed eventsreturn (events ^ SYS_EVENT_MSG);}if ( events & START_DEVICE_EVT ){// Start the DeviceGAPRole_CentralStartDevice( centralTaskId, ¢ralBondCB, ¢ralRoleCB );return ( events ^ START_DEVICE_EVT );}if ( events & ESTABLISH_LINK_TIMEOUT_EVT ){GAPRole_TerminateLink( INVALID_CONNHANDLE );return ( events ^ ESTABLISH_LINK_TIMEOUT_EVT );}if ( events & START_SVC_DISCOVERY_EVT ){// start service discoverycentralStartDiscovery( );return ( events ^ START_SVC_DISCOVERY_EVT );}if ( events & START_PARAM_UPDATE_EVT ){// start connect parameter updateGAPRole_UpdateLink( centralConnHandle,DEFAULT_UPDATE_MIN_CONN_INTERVAL,DEFAULT_UPDATE_MAX_CONN_INTERVAL,DEFAULT_UPDATE_SLAVE_LATENCY,DEFAULT_UPDATE_CONN_TIMEOUT );return ( events ^ START_PARAM_UPDATE_EVT );}if ( events & START_READ_OR_WRITE_EVT ){ if( centralProcedureInProgress == FALSE ){if( centralDoWrite ){// Do a writeattWriteReq_t req;req.cmd = FALSE;req.sig = FALSE;req.handle = centralCharHdl;req.len = 1;req.pValue = GATT_bm_alloc(centralConnHandle,ATT_WRITE_REQ,req.len,NULL,0);if ( req.pValue != NULL ){*req.pValue = centralCharVal;if( GATT_WriteCharValue(centralConnHandle,&req,centralTaskId) == SUCCESS ){ centralProcedureInProgress = TRUE;centralDoWrite = !centralDoWrite;tmos_start_task( centralTaskId, START_READ_OR_WRITE_EVT, DEFAULT_READ_OR_WRITE_DELAY);}else{GATT_bm_free((gattMsg_t *)&req, ATT_WRITE_REQ);}} }else{// Do a readattReadReq_t req; req.handle = centralCharHdl; if( GATT_ReadCharValue( centralConnHandle, &req, centralTaskId ) == SUCCESS ){centralProcedureInProgress = TRUE;centralDoWrite = !centralDoWrite;}}}return ( events ^ START_READ_OR_WRITE_EVT );}if ( events & START_WRITE_CCCD_EVT ){ if( centralProcedureInProgress == FALSE ){// Do a writeattWriteReq_t req;req.cmd = FALSE;req.sig = FALSE;req.handle = centralCCCDHdl;req.len = 2;req.pValue = GATT_bm_alloc(centralConnHandle,ATT_WRITE_REQ,req.len,NULL,0);if ( req.pValue != NULL ){req.pValue[0] = 1;req.pValue[1] = 0;if( GATT_WriteCharValue(centralConnHandle,&req,centralTaskId) == SUCCESS ){ centralProcedureInProgress = TRUE;}else{GATT_bm_free((gattMsg_t *)&req, ATT_WRITE_REQ);}}}return ( events ^ START_WRITE_CCCD_EVT );}if ( events & START_WRITE_CCCD2_EVT ){ if( centralProcedureInProgress == FALSE ){// Do a writeattWriteReq_t req;req.cmd = FALSE;req.sig = FALSE;req.handle = centralCCCDHd2;//用第二个hdl。。req.len = 2;req.pValue = GATT_bm_alloc(centralConnHandle,ATT_WRITE_REQ,req.len,NULL,0);if ( req.pValue != NULL ){req.pValue[0] = 1;req.pValue[1] = 0;if( GATT_WriteCharValue(centralConnHandle,&req,centralTaskId) == SUCCESS ){ centralProcedureInProgress = TRUE;}else{GATT_bm_free((gattMsg_t *)&req, ATT_WRITE_REQ);}}}return ( events ^ START_WRITE_CCCD2_EVT );}if ( events & START_READ_RSSI_EVT ){GAPRole_ReadRssiCmd(centralConnHandle);tmos_start_task( centralTaskId, START_READ_RSSI_EVT, DEFAULT_RSSI_PERIOD ); return (events ^ START_READ_RSSI_EVT);}// Discard unknown eventsreturn 0;
}
- GATT的写入读取NOTIFY
这里可以将handle打出来
/*********************************************************************10. @fn centralProcessGATTMsg11. 12. @brief Process GATT messages13. 14. @return none*/
static void centralProcessGATTMsg( gattMsgEvent_t *pMsg )
{if ( centralState != BLE_STATE_CONNECTED ){// In case a GATT message came after a connection has dropped,// ignore the messagereturn;}if ( ( pMsg->method == ATT_EXCHANGE_MTU_RSP ) ||( ( pMsg->method == ATT_ERROR_RSP ) &&( pMsg->msg.errorRsp.reqOpcode == ATT_EXCHANGE_MTU_REQ ) ) ){if ( pMsg->method == ATT_ERROR_RSP ){uint8 status = pMsg->msg.errorRsp.errCode;PRINT( "Exchange MTU Error: %x\n", status );}centralProcedureInProgress = FALSE;}if ( pMsg->method == ATT_MTU_UPDATED_EVENT ){PRINT("MTU: %x\n",pMsg->msg.mtuEvt.MTU);} if ( ( pMsg->method == ATT_READ_RSP ) ||( ( pMsg->method == ATT_ERROR_RSP ) &&( pMsg->msg.errorRsp.reqOpcode == ATT_READ_REQ ) ) ){if ( pMsg->method == ATT_ERROR_RSP ){uint8 status = pMsg->msg.errorRsp.errCode;PRINT( "Read Error: %x\n", status );}else{// After a successful read, display the read valuePRINT("Read rsp: %x\n",*pMsg->msg.readRsp.pValue);}centralProcedureInProgress = FALSE;}else if ( ( pMsg->method == ATT_WRITE_RSP ) ||( ( pMsg->method == ATT_ERROR_RSP ) &&( pMsg->msg.errorRsp.reqOpcode == ATT_WRITE_REQ ) ) ){if ( pMsg->method == ATT_ERROR_RSP ){uint8 status = pMsg->msg.errorRsp.errCode;PRINT( "Write Error: %x\n", status );}else{// Write successPRINT( "Write success \n" ); }centralProcedureInProgress = FALSE; }else if ( pMsg->method == ATT_HANDLE_VALUE_NOTI ){PRINT("Receive hdl %x noti: %x\n",pMsg->msg.handleValueNoti.handle,*pMsg->msg.handleValueNoti.pValue);}else if ( centralDiscState != BLE_DISC_STATE_IDLE ){centralGATTDiscoveryEvent( pMsg );}GATT_bm_free(&pMsg->msg, pMsg->method);
}
2、从机
为了做测试,将CHAR1增加一个NOTIFY属性,CHAR4就已经是notify属性的,按照CHAR4来修改来一下CHAR1
可以参考 CHAR4的配置,来对应改动即可
需要修改下面这些地方
-
MAC地址,注意这里的MAC和主机要相反!
打开 BLE_MAC 宏
```c
/*********************************************************************
* GLOBAL TYPEDEFS
*/
__align(4) u32 MEM_BUF[BLE_MEMHEAP_SIZE/4];#if (defined (BLE_MAC)) && (BLE_MAC == TRUE) u8C MacAddr[6] = {0x84,0xC2,0xE4,0x03,0x02,0x02}; #endif ```
-
需要NOTIFY的特征值(CHAR1,4)的特征值偏移,用于发送数据时用
在ATT表中 从 0 开始数即可
// Position of simpleProfilechar4 value in attribute array
#define SIMPLEPROFILE_CHAR1_VALUE_POS 2
#define SIMPLEPROFILE_CHAR4_VALUE_POS 12
- ATT表增加特征配置项
/********************************************************************** Profile Attributes - Table*/static gattAttribute_t simpleProfileAttrTbl[] =
{// Simple Profile Service{ { ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */GATT_PERMIT_READ, /* permissions */0, /* handle */(uint8 *)&simpleProfileService /* pValue */},// Characteristic 1 Declaration{ { ATT_BT_UUID_SIZE, characterUUID },GATT_PERMIT_READ, 0,&simpleProfileChar1Props },// Characteristic Value 1{ { ATT_BT_UUID_SIZE, simpleProfilechar1UUID },GATT_PERMIT_READ | GATT_PERMIT_WRITE, 0, simpleProfileChar1 },// Characteristic 1 configuration 我增加的 { { ATT_BT_UUID_SIZE, clientCharCfgUUID },GATT_PERMIT_READ | GATT_PERMIT_WRITE, 0, (uint8 *)simpleProfileChar1Config },// Characteristic 1 User Description{ { ATT_BT_UUID_SIZE, charUserDescUUID },GATT_PERMIT_READ, 0, simpleProfileChar1UserDesp }, // Characteristic 2 Declaration{ { ATT_BT_UUID_SIZE, characterUUID },GATT_PERMIT_READ, 0,&simpleProfileChar2Props },// Characteristic Value 2{ { ATT_BT_UUID_SIZE, simpleProfilechar2UUID },GATT_PERMIT_READ, 0, simpleProfileChar2 },// Characteristic 2 User Description{ { ATT_BT_UUID_SIZE, charUserDescUUID },GATT_PERMIT_READ, 0, simpleProfileChar2UserDesp }, // Characteristic 3 Declaration{ { ATT_BT_UUID_SIZE, characterUUID },GATT_PERMIT_READ, 0,&simpleProfileChar3Props },// Characteristic Value 3{ { ATT_BT_UUID_SIZE, simpleProfilechar3UUID },GATT_PERMIT_WRITE, 0, simpleProfileChar3 },// Characteristic 3 User Description{ { ATT_BT_UUID_SIZE, charUserDescUUID },GATT_PERMIT_READ, 0, simpleProfileChar3UserDesp },// Characteristic 4 Declaration{ { ATT_BT_UUID_SIZE, characterUUID },GATT_PERMIT_READ, 0,&simpleProfileChar4Props },// Characteristic Value 4{ { ATT_BT_UUID_SIZE, simpleProfilechar4UUID },0, 0, simpleProfileChar4 },// Characteristic 4 configuration{ { ATT_BT_UUID_SIZE, clientCharCfgUUID },GATT_PERMIT_READ | GATT_PERMIT_WRITE, 0, (uint8 *)simpleProfileChar4Config },// Characteristic 4 User Description{ { ATT_BT_UUID_SIZE, charUserDescUUID },GATT_PERMIT_READ, 0, simpleProfileChar4UserDesp },// Characteristic 5 Declaration{ { ATT_BT_UUID_SIZE, characterUUID },GATT_PERMIT_READ, 0,&simpleProfileChar5Props },// Characteristic Value 5{ { ATT_BT_UUID_SIZE, simpleProfilechar5UUID },GATT_PERMIT_AUTHEN_READ, 0, simpleProfileChar5 },// Characteristic 5 User Description{ { ATT_BT_UUID_SIZE, charUserDescUUID },GATT_PERMIT_READ, 0, simpleProfileChar5UserDesp },
};
- 修改一下CHAR1的Props为notify
// Simple Profile Characteristic 1 Properties
static uint8 simpleProfileChar1Props = GATT_PROP_READ | GATT_PROP_WRITE|GATT_PROP_NOTIFY;
- 增加CHAR1的配置数据
static gattCharCfg_t simpleProfileChar1Config[4];
- profile 中,初始化CHAR1的配置
/*********************************************************************1. @fn SimpleProfile_AddService2. 3. @brief Initializes the Simple Profile service by registering4. GATT attributes with the GATT server.5. 6. @param services - services to add. This is a bit map and can7. contain more than one service.8. 9. @return Success or Failure*/
bStatus_t SimpleProfile_AddService( uint32 services )
{uint8 status = SUCCESS;// Initialize Client Characteristic Configuration attributesGATTServApp_InitCharCfg( INVALID_CONNHANDLE, simpleProfileChar4Config );GATTServApp_InitCharCfg( INVALID_CONNHANDLE, simpleProfileChar1Config );// Register with Link DB to receive link status change callbacklinkDB_Register( simpleProfile_HandleConnStatusCB ); if ( services & SIMPLEPROFILE_SERVICE ){// Register GATT attribute list and CBs with GATT Server Appstatus = GATTServApp_RegisterService( simpleProfileAttrTbl, GATT_NUM_ATTRS( simpleProfileAttrTbl ),GATT_MAX_ENCRYPT_KEY_SIZE,&simpleProfileCBs );}return ( status );
}
- 链接状态改变时,也加一下
/*********************************************************************1. @fn simpleProfile_HandleConnStatusCB2. 3. @brief Simple Profile link status change handler function.4. 5. @param connHandle - connection handle6. @param changeType - type of change7. 8. @return none*/
static void simpleProfile_HandleConnStatusCB( uint16 connHandle, uint8 changeType )
{ // Make sure this is not loopback connectionif ( connHandle != LOOPBACK_CONNHANDLE ){// Reset Client Char Config if connection has droppedif ( ( changeType == LINKDB_STATUS_UPDATE_REMOVED ) ||( ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) && ( !linkDB_Up( connHandle ) ) ) ){ GATTServApp_InitCharCfg( connHandle, simpleProfileChar4Config );GATTServApp_InitCharCfg( connHandle, simpleProfileChar1Config );}}
}
- 增加notify的方法
我这里取巧了,只是用于测试, simpleProfile_Notify 这个函数是在用户定义的任务周期函数里面定义的,这里间隔发送 CHAR1 和 CHAR4
再强调: 调用这些蓝牙的操作,不能在相同时间内操作多个,否则前面的也不生效,例如下面同时notify CHAR1 和 CHAR4 ,则CHAR1是不会生效的!
/********************************************************************** @fn simpleProfile_Notify** @brief Send a notification containing a heart rate* measurement.** @param connHandle - connection handle* @param pNoti - pointer to notification structure** @return Success or Failure*/
bStatus_t simpleProfile_Notify( uint16 connHandle, attHandleValueNoti_t *pNoti )
{static char flag = 0;flag = !flag;// If notifications enabledif(flag == 0){uint16 value = GATTServApp_ReadCharCfg( connHandle, simpleProfileChar4Config );if ( value & GATT_CLIENT_CFG_NOTIFY ){printf("noti char 4..\n");// Set the handlepNoti->handle = simpleProfileAttrTbl[SIMPLEPROFILE_CHAR4_VALUE_POS].handle;// Send the notificationreturn GATT_Notification( connHandle, pNoti, FALSE );// GATT_Notification( connHandle, pNoti, FALSE );}}else{uint16 value2 = GATTServApp_ReadCharCfg( connHandle, simpleProfileChar1Config );printf("noti char 1..\n");// If notifications enabledif ( value2 & GATT_CLIENT_CFG_NOTIFY ){// Set the handlepNoti->handle = simpleProfileAttrTbl[SIMPLEPROFILE_CHAR1_VALUE_POS].handle;// Send the notification//return GATT_Notification( connHandle, pNoti, FALSE );GATT_Notification( connHandle, pNoti, FALSE );}}return bleIncorrectMode;
}
用户任务
/********************************************************************** @fn performPeriodicTask** @brief Perform a periodic application task. This function gets* called every five seconds as a result of the SBP_PERIODIC_EVT* TMOS event. In this example, the value of the third* characteristic in the SimpleGATTProfile service is retrieved* from the profile, and then copied into the value of the* the fourth characteristic.** @param none** @return none*/
static void performPeriodicTask( void )
{uint8 notiData[SIMPLEPROFILE_CHAR4_LEN] = { 0x88 };peripheralChar4Notify( notiData, SIMPLEPROFILE_CHAR4_LEN );
}/********************************************************************** @fn peripheralChar4Notify** @brief Prepare and send simpleProfileChar4 notification** @param pValue - data to notify* len - length of data** @return none*/
static void peripheralChar4Notify( uint8 *pValue, uint16 len )
{attHandleValueNoti_t noti;noti.len = len;noti.pValue = GATT_bm_alloc( peripheralConnList.connHandle, ATT_HANDLE_VALUE_NOTI, noti.len, NULL, 0 );tmos_memcpy( noti.pValue, pValue, noti.len );if( simpleProfile_Notify( peripheralConnList.connHandle, ¬i ) != SUCCESS ){GATT_bm_free( (gattMsg_t *)¬i, ATT_HANDLE_VALUE_NOTI );}
}/********************************************************************** @fn Peripheral_ProcessEvent** @brief Peripheral Application Task event processor. This function* is called to process all events for the task. Events* include timers, messages and any other user defined events.** @param task_id - The TMOS assigned task ID.* @param events - events to process. This is a bit map and can* contain more than one event.** @return events not processed*/
uint16 Peripheral_ProcessEvent( uint8 task_id, uint16 events )
{// VOID task_id; // TMOS required parameter that isn't used in this functionif ( events & SYS_EVENT_MSG ){uint8 *pMsg;if ( (pMsg = tmos_msg_receive( Peripheral_TaskID )) != NULL ){Peripheral_ProcessTMOSMsg( (tmos_event_hdr_t *)pMsg );// Release the TMOS messagetmos_msg_deallocate( pMsg );}// return unprocessed eventsreturn (events ^ SYS_EVENT_MSG);}if ( events & SBP_START_DEVICE_EVT ){// Start the DeviceGAPRole_PeripheralStartDevice( Peripheral_TaskID, &Peripheral_BondMgrCBs, &Peripheral_PeripheralCBs );return ( events ^ SBP_START_DEVICE_EVT );}if ( events & SBP_PERIODIC_EVT ){// Restart timerif ( SBP_PERIODIC_EVT_PERIOD ){tmos_start_task( Peripheral_TaskID, SBP_PERIODIC_EVT, SBP_PERIODIC_EVT_PERIOD );}// Perform periodic application task 就是这里调用norifyperformPeriodicTask();return (events ^ SBP_PERIODIC_EVT);}if ( events & SBP_PARAM_UPDATE_EVT ){// Send connect param update requestGAPRole_PeripheralConnParamUpdateReq( peripheralConnList.connHandle,DEFAULT_DESIRED_MIN_CONN_INTERVAL,DEFAULT_DESIRED_MAX_CONN_INTERVAL,DEFAULT_DESIRED_SLAVE_LATENCY,DEFAULT_DESIRED_CONN_TIMEOUT,Peripheral_TaskID);return (events ^ SBP_PARAM_UPDATE_EVT);}if ( events & SBP_READ_RSSI_EVT ){GAPRole_ReadRssiCmd(peripheralConnList.connHandle);tmos_start_task( Peripheral_TaskID, SBP_READ_RSSI_EVT, SBP_READ_RSSI_EVT_PERIOD ); return (events ^ SBP_READ_RSSI_EVT);} // Discard unknown eventsreturn 0;
}
3、LOG
- 从机
noti char 1..
RSSI -52 dB Conn 1
noti char 4..
noti char 1..
noti char 4..
Disconnected.. Reason:8
Advertising..
Conn 1 - Int 3d
Connected..
noti char 1..
noti char 1..
RSSI -55 dB Conn 1
Update 1 - Int 3c
status = 0..
noti char 1..
status = 0..
noti char 4..
RSSI -51 dB Conn 1
noti char 1..
Update 1 - Int 8
noti char 4..
noti char 1..
RSSI -50 dB Conn 1
noti char 4..
noti char 1..
noti char 4..
RSSI -50 dB Conn 1
noti char 1..
noti char 4..
noti char 1..
RSSI -49 dB Conn 1
noti char 4..
noti char 1..
- 主机
CH57x_BLE_LIB_V1.60
Discovering...
Device 1 - Addr 9e b6 28 63 48 4d
Device 2 - Addr e5 b9 9c 48 b 72
Device 3 - Addr e3 7 ca b6 e3 2f
Device 4 - Addr 25 a3 22 e6 3a 9
Device 5 - Addr 4e 3 d2 96 4b 75
Device 6 - Addr ca 30 74 4e d7 76
Device 7 - Addr 90 e2 f3 38 c1 a4
Device 8 - Addr 61 59 99 c4 a 24
Device 9 - Addr ff 72 94 78 39 5d
Device 10 - Addr f5 aa 91 49 b5 5c
Device not found...
Discovering...
Device 1 - Addr e3 7 ca b6 e3 2f
Device 2 - Addr ca 30 74 4e d7 76
Device 3 - Addr 25 a3 22 e6 3a 9
Device 4 - Addr e5 b9 9c 48 b 72
Device 5 - Addr 82 47 dd 48 de 4b
Device 6 - Addr 9e b6 28 63 48 4d
Device 7 - Addr 61 59 99 c4 a 24
Device 8 - Addr 4e 3 d2 96 4b 75
Device not found...
Discovering...
Device 1 - Addr 25 a3 22 e6 3a 9
Device 2 - Addr e3 7 ca b6 e3 2f
Device 3 - Addr e5 b9 9c 48 b 72
Device 4 - Addr 4e 3 d2 96 4b 75
Device 5 - Addr ca 30 74 4e d7 76
Device 6 - Addr 82 47 dd 48 de 4b
Device 7 - Addr 56 8d 6d 14 cd 45
Device 8 - Addr ff 72 94 78 39 5d
Device 9 - Addr f5 aa 91 49 b5 5c
Device 10 - Addr a d6 6c 38 c1 a4
Device not found...
Discovering...
Device 1 - Addr e5 b9 9c 48 b 72
Device 2 - Addr 82 47 dd 48 de 4b
Device 3 - Addr 61 59 99 c4 a 24
Device 4 - Addr e3 7 ca b6 e3 2f
Device 5 - Addr 4e 3 d2 96 4b 75
Device 6 - Addr ca 30 74 4e d7 76
Device 7 - Addr 25 a3 22 e6 3a 9
Device 8 - Addr f9 69 64 38 c1 a4
Device 9 - Addr 56 8d 6d 14 cd 45
Device 10 - Addr f5 aa 91 49 b5 5c
Device not found...
Discovering...
Device 1 - Addr e3 7 ca b6 e3 2f
Device 2 - Addr f5 aa 91 49 b5 5c
Device 3 - Addr e5 b9 9c 48 b 72
Device 4 - Addr 25 a3 22 e6 3a 9
Device 5 - Addr ca 30 74 4e d7 76
Device 6 - Addr 2 2 3 e4 c2 84
Device 7 - Addr 9e b6 28 63 48 4d
Device 8 - Addr ff 72 94 78 39 5d
Device 9 - Addr 4e 3 d2 96 4b 75
Device 10 - Addr f9 69 64 38 c1 a4
Device found...
Connecting...
Connected...
Found Profile Service handle : 21 ~ ffff
Found Characteristic 1 handle : 23
RSSI : -40 dB
Found client characteristic configuration handle : 24
Found client characteristic configuration handle : 2e
Param Update...
Write success
RSSI : -38 dB
Receive hdl 23 noti: 88
Write success
Receive hdl 2d noti: 88
Receive hdl 23 noti: 88
RSSI : -37 dB
Param Update...
Receive hdl 2d noti: 88
Receive hdl 23 noti: 88
RSSI : -36 dB
Receive hdl 2d noti: 88
Receive hdl 23 noti: 88
RSSI : -41 dB
Receive hdl 2d noti: 88
Receive hdl 23 noti: 88
- 截图