CH577F-BLE Notihy

news/2025/2/12 20:57:18/

一、前言

最近玩了一下CH577的蓝牙,这里记录一下
在这里插入图片描述

二、准备

  1. 使用CH的EVT,从机用 BLE\Peripheral ,主机用 BLE\Central,注意使用官网最新的,因为一直有进行更新,我前段时间拿的,使能notify是没有对应的参考的。
    这里上一下链接:
    CH官网,下载EVT即可

  2. 关于GATT和ATT,可以参考下面资料
    资料1
    资料2
    这篇比较简单易懂

三、程序

1、主机

对于主机,需要修改下面这些部分

  1. MAC地址,注意这里的MAC和从机要相反!
// Peer device address
static uint8 PeerAddrDef[B_ADDR_LEN] = { 0x02,0x02,0x03,0xE4,0xC2,0x84 };
  1. 对于广播数据,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;}
}
  1. 对于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, &centralBondCB, &centralRoleCB );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;
}
  1. 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的配置,来对应改动即可

需要修改下面这些地方

  1. 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
    ```
    
  2. 需要NOTIFY的特征值(CHAR1,4)的特征值偏移,用于发送数据时用
    在ATT表中 从 0 开始数即可

// Position of simpleProfilechar4 value in attribute array
#define SIMPLEPROFILE_CHAR1_VALUE_POS            2
#define SIMPLEPROFILE_CHAR4_VALUE_POS            12
  1. 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 },
};
  1. 修改一下CHAR1的Props为notify
// Simple Profile Characteristic 1 Properties
static uint8 simpleProfileChar1Props = GATT_PROP_READ | GATT_PROP_WRITE|GATT_PROP_NOTIFY;
  1. 增加CHAR1的配置数据
static gattCharCfg_t simpleProfileChar1Config[4];
  1. 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. 链接状态改变时,也加一下
/*********************************************************************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 );}}
}
  1. 增加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, &noti ) != SUCCESS ){GATT_bm_free( (gattMsg_t *)&noti, 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

  1. 从机
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..
  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
  1. 截图

在这里插入图片描述


http://www.ppmy.cn/news/504931.html

相关文章

74HC245的作用

74HC245的作用&#xff1a;信号功率放大。 第1脚DIR&#xff0c;为输入输出端口转换用&#xff0c;DIR“1”高电平时信号由“A”端输入“B”端输出&#xff0c;DIR“0”低电平时信号由“B”端输入“A”端输出。 第2~9脚“A”信号输入输出端&#xff0c;A1B1、、、、、、A8B8&am…

HCIA-H12-811(1-50)

1、 在VRP平台上&#xff0c;可以通过下面哪种方式访向上条历史命令&#xff1f;&#xff08; &#xff09; A、Ctr1U B、Ctr1P C、左光标 D、上光标 试题答案&#xff1a;[[D]] 试题解析&#xff1a; 在VRP系统中&#xff0c;ctrlU为自定义快捷键&#xff0c;ctrlP为显…

PCB设计系列文章-印刷电路发展历史

目录 概要 整体架构流程 技术名词解释 技术细节 小结 概要 现在&#xff0e;通信产品&#xff0e;计算机和其他几乎全部的电子产品&#xff0c;都使用了印刷电路。印刷电路技术的发展和完善&#xff0c;为改变世界面貌的发明--集成电路的问世&#xff0c;创造了条件。随着科学技…

【计算机网络自顶向下】简答题习题总结(三)

文章目录 第三章 传输层UDP用户数据报协议可靠数据传输原理面向连接传输TCP流量控制可靠数据传输机制 题目 第三章 传输层 传输层服务&#xff1a;在两个不同的主机的运行应用程序之间提供逻辑通信 在接收主机多路分解 将接收到的数据段传递给正确的套接字【多路分解】 在发送…

steam API

api文档&#xff1a; https://wiki.teamfortress.com/wiki/WebAPI/GetAppList https://developer.valvesoftware.com/wiki/Steam_Web_API#GetGlobalAchievementPercentagesForApp_.28v0001.29 https://partner.steamgames.com/doc/webapi_overview/oauth#RetrieveSteamID https…

解决安装Steam提示steam需要在线更新问题

解决安装Steam提示steam需要在线更新问题 解决方法&#xff1a; 参考&#xff1a;https://tieba.baidu.com/p/5252799864?pn1贴吧里楼主的方法&#xff0c; 该重启重启&#xff0c;再以管理员身份运行就好了&#xff0c;我也是试了3、4次才更新的。

FreeRTOS 创建任务

例子&#xff1a;创建一个任务&#xff0c;并在任务里面翻转LED 灯 1. 函数原型 BaseType_t xTaskCreate(TaskFunction_t pxTaskCode,const char * const pcName,const uint16_t usStackDepth,void * const pvParameters,UBaseType_t uxPriority,TaskHandle_t * const pxCreat…

steam++工具箱

「Steam」是一个包含多种Steam工具功能的工具箱&#xff0c;此工具的大部分功能都是需要您下载安装Steam才能使用&#xff0c;也可以加速其他平台 简直国内steam玩家的福利&#xff0c;特此推荐 当然最大的优点莫过于开源&#xff0c;开源意味着可控与安全&#xff0c;如果有能…