沁恒蓝牙芯片CH58X蓝牙从机的使用

        CH583 是集成 BLE 无线通讯的 32 位 RISC 微控制器。片上集成 2Mbps 低功耗蓝牙 BLE 通讯模块、2 个全速 USB 主机和设备控制器及收发器、2 个 SPI、4 个串口、ADC、触摸按键检测模块、RTC 等丰富的外设资源。外设资源相比国外的蓝牙IOT芯片来说丰富得多,而且价格上也很有优势,系列芯片还基本额外赠送USB外设(毕竟是USB串口接口转换芯片起家的)。编译器使用的也是国产免费编译器,不用再为KEIL IAR破解犯愁,配套使用的国产山河MounRiverStudio编译器是基于eclipse开源编译器进行二次开发的,目前国外不少芯片厂的自家编译器也大部分都是基于eclipse开发而来,如siliconlabs的ide也是。MounRiverStudio使用下来整体体验还不错。

有TI CC2530等相关开发经验的话上手这蓝牙芯片会感觉轻车熟路,开发起来快很多。

        蓝牙从机的功能比较简单,基本就广播,连接,配对,绑定,GATT注册读写这几个。

1、广播

  // Setup the GAP Peripheral Role Profile
  {
    //设置广播间隔,在低功耗应用中广播间隔适当调整可以降低平均耗电
    uint8 initial_advertising_enable = TRUE;
    uint16 desired_min_interval = DEFAULT_DESIRED_MIN_CONN_INTERVAL;
    uint16 desired_max_interval = DEFAULT_DESIRED_MAX_CONN_INTERVAL;
    
    //设置广播使能,广播扫描回应内容以及广播数据内容。如果做beacon应用的话只用关注广播内容。
    // Set the GAP Role Parameters
    GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &initial_advertising_enable );
    GAPRole_SetParameter( GAPROLE_SCAN_RSP_DATA, sizeof ( scanRspData ), scanRspData );
    GAPRole_SetParameter( GAPROLE_ADVERT_DATA, sizeof( advertData ), advertData );
    GAPRole_SetParameter( GAPROLE_MIN_CONN_INTERVAL, sizeof( uint16 ), &desired_min_interval );
    GAPRole_SetParameter( GAPROLE_MAX_CONN_INTERVAL, sizeof( uint16 ), &desired_max_interval );
  }

  // Set the GAP Characteristics
  GGS_SetParameter( GGS_DEVICE_NAME_ATT, GAP_DEVICE_NAME_LEN, attDeviceName );

  {
    uint16 advInt = DEFAULT_ADVERTISING_INTERVAL;

    // Set advertising interval
    GAP_SetParamValue( TGAP_DISC_ADV_INT_MIN, advInt );
    GAP_SetParamValue( TGAP_DISC_ADV_INT_MAX, advInt );

    // Enable scan req notify
    GAP_SetParamValue( TGAP_ADV_SCAN_REQ_NOTIFY, ENABLE );
  }

2、绑定配对相关

 // Setup the GAP Bond Manager
//绑定配对相关的配置,需要要开发设备的安全需求,IO功能进行设定
  {
    uint32 passkey = 0; // passkey "000000"
    uint8 pairMode = GAPBOND_PAIRING_MODE_WAIT_FOR_REQ;
    uint8 mitm = TRUE;
    uint8 bonding = TRUE;
    uint8 ioCap = GAPBOND_IO_CAP_DISPLAY_ONLY;
    GAPBondMgr_SetParameter( GAPBOND_PERI_DEFAULT_PASSCODE, sizeof ( uint32 ), &passkey );
    GAPBondMgr_SetParameter( GAPBOND_PERI_PAIRING_MODE, sizeof ( uint8 ), &pairMode );
    GAPBondMgr_SetParameter( GAPBOND_PERI_MITM_PROTECTION, sizeof ( uint8 ), &mitm );
    GAPBondMgr_SetParameter( GAPBOND_PERI_IO_CAPABILITIES, sizeof ( uint8 ), &ioCap );
    GAPBondMgr_SetParameter( GAPBOND_PERI_BONDING_ENABLED, sizeof ( uint8 ), &bonding );
  }

3、GATT注册读写相关

//GATT注册表,主要是配置service和char。不同service需要用不同的gattAttribute_t来定义
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 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 
      },
};


//GATT表注册到BLE STACK里,以及设置读写回调
bStatus_t SimpleProfile_AddService( uint32 services )
{
  uint8 status = SUCCESS;

  // Initialize Client Characteristic Configuration attributes
  GATTServApp_InitCharCfg( INVALID_CONNHANDLE, simpleProfileChar4Config );

  // Register with Link DB to receive link status change callback
  linkDB_Register( simpleProfile_HandleConnStatusCB );  
  
  if ( services & SIMPLEPROFILE_SERVICE )
  {
    // Register GATT attribute list and CBs with GATT Server App
    status = GATTServApp_RegisterService( simpleProfileAttrTbl, 
                                          GATT_NUM_ATTRS( simpleProfileAttrTbl ),
										  GATT_MAX_ENCRYPT_KEY_SIZE,
                                          &simpleProfileCBs );
  }

  return ( status );
}


//读写回调设置
// Simple Profile Service Callbacks
gattServiceCBs_t simpleProfileCBs =
{
  simpleProfile_ReadAttrCB,  // Read callback function pointer
  simpleProfile_WriteAttrCB, // Write callback function pointer
  NULL                       // Authorization callback function pointer
};


//实际的读写回调
static bStatus_t simpleProfile_ReadAttrCB( uint16 connHandle, gattAttribute_t *pAttr, 
                            uint8 *pValue, uint16 *pLen, uint16 offset, uint16 maxLen,uint8 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 those reads

      // characteristics 1 and 2 have read permissions
      // characteritisc 3 does not have read permissions; therefore it is not
      //   included here
      // characteristic 4 does not have read permissions, but because it
      //   can be sent as a notification, it is included here
      case SIMPLEPROFILE_CHAR1_UUID:
        *pLen = SIMPLEPROFILE_CHAR1_LEN;
        tmos_memcpy( pValue, pAttr->pValue, SIMPLEPROFILE_CHAR1_LEN );
        break;
      
      case SIMPLEPROFILE_CHAR2_UUID:
        *pLen = SIMPLEPROFILE_CHAR2_LEN;
        tmos_memcpy( pValue, pAttr->pValue, SIMPLEPROFILE_CHAR2_LEN );
        break;
      
      case SIMPLEPROFILE_CHAR4_UUID:
        *pLen = SIMPLEPROFILE_CHAR4_LEN;
        tmos_memcpy( pValue, pAttr->pValue, SIMPLEPROFILE_CHAR4_LEN );
        break;
      
      case SIMPLEPROFILE_CHAR5_UUID:
        *pLen = SIMPLEPROFILE_CHAR5_LEN;
        tmos_memcpy( pValue, pAttr->pValue, SIMPLEPROFILE_CHAR5_LEN );
        break;
        
      default:
        // Should never get here! (characteristics 3 and 4 do not have read permissions)
        *pLen = 0;
        status = ATT_ERR_ATTR_NOT_FOUND;
        break;
    }
  }
  else
  {
    // 128-bit UUID
    *pLen = 0;
    status = ATT_ERR_INVALID_HANDLE;
  }

  return ( status );
}

static bStatus_t simpleProfile_WriteAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
                                 uint8 *pValue, uint16 len, uint16 offset,uint8 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 SIMPLEPROFILE_CHAR1_UUID:
        //Validate the value
        // Make sure it's not a blob oper
        if ( offset == 0 )
        {
          if ( len > SIMPLEPROFILE_CHAR1_LEN )
          {
            status = ATT_ERR_INVALID_VALUE_SIZE;
          }
        }
        else
        {
          status = ATT_ERR_ATTR_NOT_LONG;
        }
        
        //Write the value
        if ( status == SUCCESS )
        {
          tmos_memcpy( pAttr->pValue, pValue, SIMPLEPROFILE_CHAR1_LEN );
          notifyApp = SIMPLEPROFILE_CHAR1;        
        }            
        break;
        
      case SIMPLEPROFILE_CHAR3_UUID:
        //Validate the value
        // Make sure it's not a blob oper
        if ( offset == 0 )
        {
          if ( len > SIMPLEPROFILE_CHAR3_LEN )
          {
            status = ATT_ERR_INVALID_VALUE_SIZE;
          }
        }
        else
        {
          status = ATT_ERR_ATTR_NOT_LONG;
        }
        
        //Write the value
        if ( status == SUCCESS )
        {
          tmos_memcpy( pAttr->pValue, pValue, SIMPLEPROFILE_CHAR3_LEN );
          notifyApp = SIMPLEPROFILE_CHAR3;        
        }            
        break;

      case GATT_CLIENT_CHAR_CFG_UUID:
        status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len,
                                                 offset, GATT_CLIENT_CFG_NOTIFY );
        break;
        
      default:
        // Should never get here! (characteristics 2 and 4 do not have write permissions)
        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 ) && simpleProfile_AppCBs && simpleProfile_AppCBs->pfnSimpleProfileChange )
  {
    simpleProfile_AppCBs->pfnSimpleProfileChange( notifyApp, pValue, len );
  }
  
  return ( status );
}






4、设备状态变化回调相关

// GAP Role Callbacks
static gapRolesCBs_t Peripheral_PeripheralCBs =
{
  peripheralStateNotificationCB,  // Profile State Change Callbacks
  peripheralRssiCB,                   // When a valid RSSI is read from controller (not used by application)
	peripheralParamUpdateCB
};

static void peripheralStateNotificationCB( gapRole_States_t newState, gapRoleEvent_t * pEvent )
{
  switch ( newState&GAPROLE_STATE_ADV_MASK )
  {
    case GAPROLE_STARTED:
      PRINT( "Initialized..\n" );
      break;

    case GAPROLE_ADVERTISING:
      if( pEvent->gap.opcode == GAP_LINK_TERMINATED_EVENT )
      {
        Peripheral_LinkTerminated( pEvent );
        PRINT( "Disconnected.. Reason:%x\n",pEvent->linkTerminate.reason );
        PRINT( "Advertising..\n" );
      }
      else if( pEvent->gap.opcode == GAP_MAKE_DISCOVERABLE_DONE_EVENT )
      {
        PRINT( "Advertising..\n" );
      }
      break;

    case GAPROLE_CONNECTED:
      if( pEvent->gap.opcode == GAP_LINK_ESTABLISHED_EVENT )
      {
        Peripheral_LinkEstablished( pEvent );
        PRINT( "Connected..\n" );
      }
      break;

    case GAPROLE_CONNECTED_ADV:
      if( pEvent->gap.opcode == GAP_MAKE_DISCOVERABLE_DONE_EVENT )
      {
        PRINT( "Connected Advertising..\n" );
      }
      break;      
    
    case GAPROLE_WAITING:
      if( pEvent->gap.opcode == GAP_END_DISCOVERABLE_DONE_EVENT )
      {
        PRINT( "Waiting for advertising..\n" );
      }
      else if( pEvent->gap.opcode == GAP_LINK_TERMINATED_EVENT )
      {
        Peripheral_LinkTerminated( pEvent );
        PRINT( "Disconnected.. Reason:%x\n",pEvent->linkTerminate.reason );
      }
      else if( pEvent->gap.opcode == GAP_LINK_ESTABLISHED_EVENT )
			{
				if( pEvent->gap.hdr.status != SUCCESS )
				{
					PRINT( "Waiting for advertising..\n" );
				}
				else
				{
					PRINT( "Error..\n" );
				}
			}
			else
			{
				PRINT( "Error..%x\n",pEvent->gap.opcode );
			}
      break;

    case GAPROLE_ERROR:
			PRINT( "Error..\n" );
      break;

    default:
      break;
  }
}

5、对于需要主动上报的char

//要能notify前提需要先配置2902为notify enable。BLE规范默认notify disable,需要每次连接上主机去是能,或者绑定的话就不用每次连接去使能
static void peripheralChar4Notify( uint8 *pValue, uint16 len )
{
  attHandleValueNoti_t noti;
  if( len > (peripheralMTU-3) )
  {
    printf("Too large noti\n");
    return;
  }
  noti.len = len;
  noti.pValue = GATT_bm_alloc( peripheralConnList.connHandle, ATT_HANDLE_VALUE_NOTI, noti.len, NULL, 0 );
  if( noti.pValue )
  {
    tmos_memcpy( noti.pValue, pValue, noti.len );
    if( simpleProfile_Notify( peripheralConnList.connHandle, ¬i ) != SUCCESS )
    {
      GATT_bm_free( (gattMsg_t *)¬i, ATT_HANDLE_VALUE_NOTI );
    }
  }
}

你可能感兴趣的:(BLE,物联网,蓝牙)