/********************************** (C) COPYRIGHT *******************************
* File Name          : peripheral.C
* Author             : WCH
* Version            : V1.0
* Date               : 2018/12/10
* Description        : 外设从机多连接应用程序，初始化广播连接参数，然后广播，连接主机后，
*                      请求更新连接参数，通过自定义服务传输数据           
*******************************************************************************/

/*********************************************************************
 * INCLUDES
 */
#include "CONFIG.h"
#include "CH57x_common.h"
#include "devinfoservice.h"
#include "gattprofile.h"
#include "peripheral.h"

/*********************************************************************
 * MACROS
 */

/*********************************************************************
 * CONSTANTS
 */

// How often to perform periodic event
#define SBP_PERIODIC_EVT_PERIOD               1600

// How often to perform read rssi event
#define SBP_READ_RSSI_EVT_PERIOD              /*3200*/4800

// Parameter update delay 
#define SBP_PARAM_UPDATE_DELAY                6400

// What is the advertising interval when device is discoverable (units of 625us, 80=50ms)
#define DEFAULT_ADVERTISING_INTERVAL          80

// Limited discoverable mode advertises for 30.72s, and then stops
// General discoverable mode advertises indefinitely
#define DEFAULT_DISCOVERABLE_MODE             GAP_ADTYPE_FLAGS_GENERAL

// Minimum connection interval (units of 1.25ms, 20=25ms) 
#define DEFAULT_DESIRED_MIN_CONN_INTERVAL     20

// Maximum connection interval (units of 1.25ms, 100=125ms)
#define DEFAULT_DESIRED_MAX_CONN_INTERVAL     100



// Slave latency to use parameter update
#define DEFAULT_DESIRED_SLAVE_LATENCY         0

// Supervision timeout value (units of 10ms, 100=1s)
#define DEFAULT_DESIRED_CONN_TIMEOUT          50

// Company Identifier: WCH  
#define WCH_COMPANY_ID                        0x07D7

/*********************************************************************
 * TYPEDEFS
 */

/*********************************************************************
 * GLOBAL VARIABLES
 */

/*********************************************************************
 * EXTERNAL VARIABLES
 */

/*********************************************************************
 * EXTERNAL FUNCTIONS
 */

/*********************************************************************
 * LOCAL VARIABLES
 */
static uint8 Peripheral_TaskID = INVALID_TASK_ID;   // Task ID for internal task/event processing


static uint8 advertData[] =
		{
			// Flags; this sets the device to use limited discoverable
			// mode (advertises for 30 seconds at a time) instead of general
			// discoverable mode (advertises indefinitely)
			0x02,   // length of this data
			GAP_ADTYPE_FLAGS,
			DEFAULT_DISCOVERABLE_MODE | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED,

			// service UUID, to notify central devices what services are included
			// in this peripheral
			0x03,   // length of this data
			GAP_ADTYPE_16BIT_MORE,      // some of the UUID's, but not all
			LO_UINT16( SIMPLEPROFILE_SERV_UUID ),
			HI_UINT16( SIMPLEPROFILE_SERV_UUID )
		};

// GAP - SCAN RSP data (max size = 31 bytes)
static uint8 scanRspData[31] =
{
  // complete name
  0x10,   // length of this data
  GAP_ADTYPE_LOCAL_NAME_COMPLETE,
  'B',   
  'L',   
  'V',   
  '-',   
  'C',   
  '1',   
  ' ',
  'R',   
  'C',   
  'U',
	':',
	'8',
  '8',
	'8',
	'8',
  // connection interval range
  0x05,   // length of this data
  GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE,
  LO_UINT16( DEFAULT_DESIRED_MIN_CONN_INTERVAL ),   // 100ms
  HI_UINT16( DEFAULT_DESIRED_MIN_CONN_INTERVAL ),
  LO_UINT16( DEFAULT_DESIRED_MAX_CONN_INTERVAL ),   // 1s
  HI_UINT16( DEFAULT_DESIRED_MAX_CONN_INTERVAL ),

  // Tx power level
//  0x02,   // length of this data
//  GAP_ADTYPE_POWER_LEVEL,
//  0       // 0dBm
};


/************
**函  数：Set_BleDevice_Name
**作  用：修改蓝牙名称
**参  数：rspData: 存放扫描信息的buff  name：要修改的名字， len：名字的长度
**返回值：返回0成功
*************/
//uint8 Set_BleDevice_Name(uint8* name, u8 len)
//{
//	if(name == NULL || len == 0)   return 1;      //名字不能修改为空
//	if(dataFlash_save_t.bleName_len == len && memcmp(name, &dataFlash_save_t.scanRspData[2], len) == 0)   //蓝牙名未改变
//	{
//		return 2;      //名称相同
//	}
//	memset(dataFlash_save_t.scanRspData, 0, 31);
//	//memset(attDeviceName, 0, BLE_DEVICE_NAME_LEN);
//	if(len < BLE_DEVICE_NAME_LEN)
//	{
//		memcpy(&dataFlash_save_t.scanRspData[2], name, len);
//		//memcpy(attDeviceName, name, len);
//		dataFlash_save_t.scanRspData[0] = len +1;
//		dataFlash_save_t.bleName_len = len;
//	}
//	else
//	{
//		memcpy(&dataFlash_save_t.scanRspData[2], name, BLE_DEVICE_NAME_LEN);
//		//memcpy(attDeviceName, name, BLE_DEVICE_NAME_LEN);
//		dataFlash_save_t.scanRspData[0] = BLE_DEVICE_NAME_LEN + 1;
//		dataFlash_save_t.bleName_len = BLE_DEVICE_NAME_LEN;
//	}	
//	dataFlash_save_t.scanRspData[1] = GAP_ADTYPE_LOCAL_NAME_COMPLETE;
//	dataFlash_save_t.scanRspData[dataFlash_save_t.scanRspData[0]+1] = 0x05;   // length of this data
//	dataFlash_save_t.scanRspData[dataFlash_save_t.scanRspData[0]+2] = GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE;
//	dataFlash_save_t.scanRspData[dataFlash_save_t.scanRspData[0]+3] = LO_UINT16( DEFAULT_DESIRED_MIN_CONN_INTERVAL );
//	dataFlash_save_t.scanRspData[dataFlash_save_t.scanRspData[0]+4] = HI_UINT16( DEFAULT_DESIRED_MIN_CONN_INTERVAL );
//	dataFlash_save_t.scanRspData[dataFlash_save_t.scanRspData[0]+5] = LO_UINT16( DEFAULT_DESIRED_MAX_CONN_INTERVAL );
//	dataFlash_save_t.scanRspData[dataFlash_save_t.scanRspData[0]+6] = HI_UINT16( DEFAULT_DESIRED_MAX_CONN_INTERVAL );
//	dataFlash_save_t.scanRspData[dataFlash_save_t.scanRspData[0]+7] = 0x02;   // length of this data
//	dataFlash_save_t.scanRspData[dataFlash_save_t.scanRspData[0]+8] = GAP_ADTYPE_POWER_LEVEL;
//	dataFlash_save_t.scanRspData[dataFlash_save_t.scanRspData[0]+9] = 0;       // 0dBm
//	// Set the GAP Characteristics  写 GAP 服务参数
//  GGS_SetParameter( GGS_DEVICE_NAME_ATT, BLE_DEVICE_NAME_LEN, &dataFlash_save_t.scanRspData[2] );
//	GAPRole_SetParameter( GAPROLE_SCAN_RSP_DATA, sizeof ( dataFlash_save_t.scanRspData ), dataFlash_save_t.scanRspData );
//	
//	dataFlash_save_t.flash_save_flg = 1;     //标记需要保存
//	return 0;
//}





// Connection item list
/*static*/ peripheralConnItem_t peripheralConnList;

/*********************************************************************
 * LOCAL FUNCTIONS
 */
static void Peripheral_ProcessTMOSMsg( tmos_event_hdr_t *pMsg );
static void peripheralStateNotificationCB( gapRole_States_t newState ,gapRoleEvent_t * pEvent);
static void performPeriodicTask( void );
static void simpleProfileChangeCB( uint8 paramID );
static void peripheralParamUpdateCB( uint16 connHandle, uint16 connInterval, 
                                      uint16 connSlaveLatency, uint16 connTimeout );
static void peripheralInitConnItem( peripheralConnItem_t* peripheralConnList );
static void peripheralRssiCB( uint16 connHandle, int8  rssi );
//static void peripheralChar4Notify( uint8 *pValue, uint16 len );

/*********************************************************************
 * PROFILE CALLBACKS
 */

// 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          //参数更新完成回调
};

// GAP Bond Manager Callbacks
static gapBondCBs_t Peripheral_BondMgrCBs =
{
  NULL,                     // Passcode callback (not used by application)
  NULL                      // Pairing / Bonding state Callback (not used by application)
};

// Simple GATT Profile Callbacks
static simpleProfileCBs_t Peripheral_SimpleProfileCBs =
{
  simpleProfileChangeCB    // Charactersitic value change callback
};
/*********************************************************************
 * PUBLIC FUNCTIONS
 */

/*********************************************************************
 * @fn      Peripheral_Init
 *
 * @brief   Initialization function for the Peripheral App Task.
 *          This is called during initialization and should contain
 *          any application specific initialization (ie. hardware
 *          initialization/setup, table initialization, power up
 *          notificaiton ... ).
 *
 * @param   task_id - the ID assigned by TMOS.  This ID should be
 *                    used to send messages and set timers.
 *
 * @return  none
 */
void Peripheral_Init( )
{
  Peripheral_TaskID = TMOS_ProcessEventRegister( Peripheral_ProcessEvent );
  
  // Setup the GAP Peripheral Role Profile 设置GAP外围角色配置文件
  {
    uint8 initial_advertising_enable = TRUE;
    uint16 desired_min_interval = DEFAULT_DESIRED_MIN_CONN_INTERVAL;   //最小连接间隔1（单位为1.25ms，20=25ms）
    uint16 desired_max_interval = DEFAULT_DESIRED_MAX_CONN_INTERVAL;   //最大连接间隔5（单位为1.25ms，100=25ms）
    
		// GAP - Advertisement data (max size = 31 bytes, though this is
		// best kept short to conserve power while advertisting)
		
		
    // Set the GAP Role Parameters 写 GAP Role 参数
    GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &initial_advertising_enable );
		
//    GAPRole_SetParameter( GAPROLE_SCAN_RSP_DATA, sizeof ( dataFlash_save_t.scanRspData ), dataFlash_save_t.scanRspData );
		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  写 GAP 服务参数
//  GGS_SetParameter( GGS_DEVICE_NAME_ATT, dataFlash_save_t.bleName_len, &dataFlash_save_t.scanRspData[2] );
		GGS_SetParameter( GGS_DEVICE_NAME_ATT, GAP_DEVICE_NAME_LEN, attDeviceName );

  // Set advertising interval
  {
    uint16 advInt = DEFAULT_ADVERTISING_INTERVAL;   //广播间隔
		//写 GAP 参数  
    GAP_SetParamValue( TGAP_DISC_ADV_INT_MIN, advInt );
    GAP_SetParamValue( TGAP_DISC_ADV_INT_MAX, advInt );
  }

  // Setup the GAP Bond Manager
  {
    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 );  //MITM保护的默认密码。长度为uint32。范围是0-999999。默认值为0。
    GAPBondMgr_SetParameter( GAPBOND_PERI_PAIRING_MODE, sizeof ( uint8 ), &pairMode );   //配对模式：@ref GAPBOND_Pairing_Mode_defined。读/写。大小是uint8。默认为GAPBOND_PAIRING_MODE_WAIT_REQ等待配对请求。
    GAPBondMgr_SetParameter( GAPBOND_PERI_MITM_PROTECTION, sizeof ( uint8 ), &mitm );     //密钥保护，读/写。大小是uint8。默认值为0（禁用）。此处打开
    GAPBondMgr_SetParameter( GAPBOND_PERI_IO_CAPABILITIES, sizeof ( uint8 ), &ioCap );    //I/O功能。读/写。大小是uint8。默认值为仅显示设备
    GAPBondMgr_SetParameter( GAPBOND_PERI_BONDING_ENABLED, sizeof ( uint8 ), &bonding );  //如果启用，将在配对过程中请求绑定。读/写。尺寸是uint8。默认值为0（禁用）。此处打开
  }

  // Initialize GATT attributes
  GGS_AddService( GATT_ALL_SERVICES );            // GAP
  GATTServApp_AddService( GATT_ALL_SERVICES );    // GATT attributes
  DevInfo_AddService();                           // Device Information Service
  SimpleProfile_AddService( GATT_ALL_SERVICES );  // Simple GATT Profile

  // Setup the SimpleProfile Characteristic Values
  {
//    uint8 charValue1[SIMPLEPROFILE_CHAR1_LEN] = { 1 };
//    uint8 charValue2[SIMPLEPROFILE_CHAR2_LEN] = {192,168,1,94};
    //uint8 charValue3[SIMPLEPROFILE_CHAR3_LEN] = { 3 };
//    uint8 charValue4[SIMPLEPROFILE_CHAR4_LEN] = { 4 };
//    uint8 charValue5[SIMPLEPROFILE_CHAR5_LEN] = { 1, 2, 3, 4, 5 };
		
//    SimpleProfile_SetParameter( SIMPLEPROFILE_CHAR1, SIMPLEPROFILE_CHAR1_LEN, charValue1 );
//    SimpleProfile_SetParameter( SIMPLEPROFILE_CHAR2, SIMPLEPROFILE_CHAR2_LEN, charValue2 );
    //SimpleProfile_SetParameter( SIMPLEPROFILE_CHAR3, SIMPLEPROFILE_CHAR3_LEN, charValue3 );
//    SimpleProfile_SetParameter( SIMPLEPROFILE_CHAR4, SIMPLEPROFILE_CHAR4_LEN, charValue4 );
//    SimpleProfile_SetParameter( SIMPLEPROFILE_CHAR5, SIMPLEPROFILE_CHAR5_LEN, charValue5 );
  }
  
  // Init Connection Item
  peripheralInitConnItem( &peripheralConnList );

  // Register callback with SimpleGATTprofile   //注册回调
  SimpleProfile_RegisterAppCBs( &Peripheral_SimpleProfileCBs );
 
	// Setup a delayed profile startup    //设置延迟的配置文件启动
  tmos_set_event( Peripheral_TaskID, SBP_START_DEVICE_EVT );
}

/*********************************************************************
 * @fn      peripheralInitConnItem
 *
 * @brief   Init Connection Item
 *
 * @param   peripheralConnList -
 *
 * @return  NULL
 */
static void peripheralInitConnItem( peripheralConnItem_t* peripheralConnList )
{
  peripheralConnList->connHandle = GAP_CONNHANDLE_INIT;
  peripheralConnList->connInterval = 0;
  peripheralConnList->connSlaveLatency = 0;
  peripheralConnList->connTimeout = 0;
}

/*********************************************************************
 * @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 function

  if ( events & SYS_EVENT_MSG ){
    uint8 *pMsg;

    if ( (pMsg = tmos_msg_receive( Peripheral_TaskID )) != NULL ){
      Peripheral_ProcessTMOSMsg( (tmos_event_hdr_t *)pMsg );
      // Release the TMOS message
      tmos_msg_deallocate( pMsg );
    }
    // return unprocessed events
    return (events ^ SYS_EVENT_MSG);
  }

  if ( events & SBP_START_DEVICE_EVT ){
	// Start the Device
    GAPRole_PeripheralStartDevice( Peripheral_TaskID, &Peripheral_BondMgrCBs, &Peripheral_PeripheralCBs );
    return ( events ^ SBP_START_DEVICE_EVT );
  }

  if ( events & SBP_PERIODIC_EVT )
  {
   // Restart timer
//    if ( SBP_PERIODIC_EVT_PERIOD ){
//      tmos_start_task( Peripheral_TaskID, SBP_PERIODIC_EVT, SBP_PERIODIC_EVT_PERIOD );
//    }
    // Perform periodic application task  执行定期应用任务
    //performPeriodicTask();                //定期发送通知
    return (events ^ SBP_PERIODIC_EVT);
  }
  
  if ( events & SBP_PARAM_UPDATE_EVT )    //参数更新
  {
    // Send connect param update request  //发送连接参数更新请求
    GAPRole_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 events
  return 0;
}

/*********************************************************************
 * @fn      Peripheral_ProcessTMOSMsg
 *
 * @brief   Process an incoming task message.
 *
 * @param   pMsg - message to process
 *
 * @return  none
 */
static void Peripheral_ProcessTMOSMsg( tmos_event_hdr_t *pMsg )
{
  switch ( pMsg->event ){
		default:
			break;
  }
}

/*********************************************************************
 * @fn      Peripheral_LinkEstablished
 *
 * @brief   Process link established.
 *
 * @param   pEvent - event to process
 *
 * @return  none
 */
static void Peripheral_LinkEstablished( gapRoleEvent_t * pEvent )
{
  gapEstLinkReqEvent_t *event = (gapEstLinkReqEvent_t *) pEvent;
  
  // See if already connected
  if( peripheralConnList.connHandle != GAP_CONNHANDLE_INIT )
  {
    GAPRole_TerminateLink( pEvent->linkCmpl.connectionHandle );
    PRINT( "Connection max...\n" );
  }
  else
  {
    peripheralConnList.connHandle = event->connectionHandle;
    peripheralConnList.connInterval = event->connInterval;
    peripheralConnList.connSlaveLatency = event->connLatency;
    peripheralConnList.connTimeout = event->connTimeout;
    
    // Set timer for periodic event
    tmos_start_task( Peripheral_TaskID, SBP_PERIODIC_EVT, SBP_PERIODIC_EVT_PERIOD );

    // Set timer for param update event
    tmos_start_task( Peripheral_TaskID, SBP_PARAM_UPDATE_EVT, SBP_PARAM_UPDATE_DELAY );
    
    // Start read rssi
    tmos_start_task( Peripheral_TaskID, SBP_READ_RSSI_EVT, SBP_READ_RSSI_EVT_PERIOD );
    
    printf("Conn %x - Int %x \n", event->connectionHandle, event->connInterval);                   
  }        
}

/*********************************************************************
 * @fn      Peripheral_LinkTerminated
 *
 * @brief   Process link terminated.
 *
 * @param   pEvent - event to process
 *
 * @return  none
 */
static void Peripheral_LinkTerminated( gapRoleEvent_t * pEvent )
{
  gapTerminateLinkEvent_t *event = (gapTerminateLinkEvent_t *) pEvent;
  
  if( event->connectionHandle == peripheralConnList.connHandle )
  {
    peripheralConnList.connHandle = GAP_CONNHANDLE_INIT;
    peripheralConnList.connInterval = 0;
    peripheralConnList.connSlaveLatency = 0;
    peripheralConnList.connTimeout = 0;
    tmos_stop_task( Peripheral_TaskID, SBP_PERIODIC_EVT );
    tmos_stop_task( Peripheral_TaskID, SBP_READ_RSSI_EVT );
    
    // Restart advertising
    {
      uint8 advertising_enable = TRUE;
      GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &advertising_enable );
    }
  }
  else
  {
    PRINT("ERR..\n");
  }      
}

/*********************************************************************
 * @fn      peripheralRssiCB
 *
 * @brief   RSSI callback.
 *
 * @param   connHandle - connection handle
 * @param   rssi - RSSI
 *
 * @return  none
 */
static void peripheralRssiCB( uint16 connHandle, int8 rssi )
{
  PRINT( "RSSI -%d dB Conn  %x \n", -rssi, connHandle);
}

/*********************************************************************
 * @fn      peripheralParamUpdateCB
 *
 * @brief   Parameter update complete callback
 *
 * @param   connHandle - connect handle
 *          connInterval - connect interval
 *          connSlaveLatency - connect slave latency
 *          connTimeout - connect timeout
 *          
 * @return  none
 */
static void peripheralParamUpdateCB( uint16 connHandle, uint16 connInterval, 
                                      uint16 connSlaveLatency, uint16 connTimeout )
{
  if( connHandle == peripheralConnList.connHandle )
  {
    peripheralConnList.connInterval = connInterval;
    peripheralConnList.connSlaveLatency = connSlaveLatency;
    peripheralConnList.connTimeout = connTimeout;

    printf("Update %x - Int %x \n", connHandle, connInterval);
  }
  else
  {
    PRINT("ERR..\n");
  }
}

/*********************************************************************
 * @fn      peripheralStateNotificationCB
 *
 * @brief   Notification from the profile of a state change.
 *
 * @param   newState - new state
 *
 * @return  none
 */
static void peripheralStateNotificationCB( gapRole_States_t newState, gapRoleEvent_t * pEvent )
{
  switch ( newState )
  {
    case GAPROLE_STARTED:
      PRINT( "Initialized..\n" );
      break;

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

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

    case GAPROLE_CONNECTED_ADV:                             //
      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 );
      }
      break;

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

    default:
      break;
  }
}

/*********************************************************************
 * @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 )
{
	static uint8 count = 0;
  uint8 notiData[SIMPLEPROFILE_CHAR4_LEN] = "Notify:";
	sprintf((char*)&notiData[7], "%d", ++count);
  peripheralChar4Notify( notiData, strlen((char*)notiData) );
}

/*********************************************************************
 * @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      simpleProfileChangeCB
 *
 * @brief   Callback from SimpleBLEProfile indicating a value change
 *
 * @param   paramID - parameter ID of the value that was changed.
 *
 * @return  none
 */
static void simpleProfileChangeCB( uint8 paramID )
{

  switch( paramID )
  {
    case SIMPLEPROFILE_CHAR1:
		{
			uint8 newValue[SIMPLEPROFILE_CHAR1_LEN];
      SimpleProfile_GetParameter( SIMPLEPROFILE_CHAR1, newValue );
			PRINT("profile ChangeCB CHAR1.. \n");
      break;
		}

    case SIMPLEPROFILE_CHAR3:
		{
			uint8 newValue[GAP_DEVICE_NAME_LEN];
      SimpleProfile_GetParameter( SIMPLEPROFILE_CHAR3, newValue );
			PRINT("profile ChangeCB CHAR3..\n");
      break;
		}

    default:
      // should not reach here!
      break;
  }
}

/*********************************************************************
*********************************************************************/
