This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC2652R: Cannot establish a solid connection between CC2652 and CC2640

Part Number: CC2652R
Other Parts Discussed in Thread: CC2640, CC2640R2F, SYSCONFIG

I have the LAUCHXL-CC2652 as a master and CC2640 as a slave. 

But every time I try to connect CC2640, the connection will be broken after 30 seconds about. It seems that the master cannot receive the connection event from the slave or the slave cannot receive the connection event from the master. Is it true that connection event is sent in SimpleCentral_taskFxn(uintptr_t a0, uintptr_t a1) only? Can they send a connection event in whatever functions I'm calling?

I'm not very clear about how to establish a connection between two BLE devices. Is it OK if I call SimpleCentral_doSelectConn(0) to exchange MTU in case GAP_LINK_ESTABLISHED_EVENT in function SimpleCentral_processGapMsg(gapEventHdr_t *pMsg)?

And should I update the params of the link?

Here is the code of LAUCHXL-CC2652

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

 @file  simple_central.c

 @brief This file contains the Simple Central sample application for use
        with the CC2650 Bluetooth Low Energy Protocol Stack.

 Group: WCS, BTS
 Target Device: cc13xx_cc26xx

 ******************************************************************************
 
 Copyright (c) 2013-2022, Texas Instruments Incorporated
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:

 *  Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.

 *  Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.

 *  Neither the name of Texas Instruments Incorporated nor the names of
    its contributors may be used to endorse or promote products derived
    from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

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

/*********************************************************************
 * INCLUDES
 */
#include <string.h>

#include <ti/sysbios/knl/Task.h>
#include <ti/sysbios/knl/Clock.h>
#include <ti/sysbios/knl/Event.h>
#include <ti/sysbios/knl/Queue.h>

#include <ti/display/Display.h>

#include "bcomdef.h"

#include <ti/drivers/GPIO.h>
#include <icall.h>
#include "util.h"
/* This Header file contains all BLE API and icall structure definition */
#include "icall_ble_api.h"
#include "osal_list.h"
#include "board_key.h"
#include <ti_drivers_config.h>

#include "ti_ble_config.h"
#include "ble_user_config.h"

#include "simple_gatt_profile.h"

#include <menu/two_btn_menu.h>
#include "simple_central.h"
#include "simple_central_menu.h"

//Author: Wang Jieqiong
#include "usrs.h"
Clock_Struct uart_clock;
Clock_Struct startDiscClock;

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

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

// Application events
#define SC_EVT_KEY_CHANGE          0x01
#define SC_EVT_SCAN_ENABLED        0x02
#define SC_EVT_SCAN_DISABLED       0x03
#define SC_EVT_ADV_REPORT          0x04
#define SC_EVT_SVC_DISC            0x05
#define SC_EVT_READ_RSSI           0x06
#define SC_EVT_PAIR_STATE          0x07
#define SC_EVT_PASSCODE_NEEDED     0x08
#define SC_EVT_READ_RPA            0x09
#define SC_EVT_INSUFFICIENT_MEM    0x0A

// Simple Central Task Events
#define SC_ICALL_EVT                         ICALL_MSG_EVENT_ID  // Event_Id_31
#define SC_QUEUE_EVT                         UTIL_QUEUE_EVENT_ID // Event_Id_30

#define SC_ALL_EVENTS                        (SC_ICALL_EVT           | \
                                              SC_QUEUE_EVT)

// Default connection interval when connecting to more then 8 connections and autoconnenct enabled
#define DEFAULT_MULTICON_INTERVAL            200 //250 ms (200 frames of 1.25ms)

// Default connection supervision timeout when connnecting to more then 8 connections and autoconnenct enabled
#define DEFAULT_MULTICON_LSTO                3200 // 32 secs

// Supervision timeout conversion rate to miliseconds
#define CONN_TIMEOUT_MS_CONVERSION            10

// Task configuration
#define SC_TASK_PRIORITY                     1

#ifndef SC_TASK_STACK_SIZE
#define SC_TASK_STACK_SIZE                   1024
#endif

// Size of string-converted device address ("0xXXXXXXXXXXXX")
#define SC_ADDR_STR_SIZE     15

// Row numbers for two-button menu
#define SC_ROW_SEPARATOR     (TBM_ROW_APP + 0)
#define SC_ROW_CUR_CONN      (TBM_ROW_APP + 1)
#define SC_ROW_ANY_CONN      (TBM_ROW_APP + 2)
#define SC_ROW_NON_CONN      (TBM_ROW_APP + 3)
#define SC_ROW_NUM_CONN      (TBM_ROW_APP + 4)
#define SC_ROW_IDA           (TBM_ROW_APP + 5)
#define SC_ROW_RPA           (TBM_ROW_APP + 6)
#define SC_ROW_AC            (TBM_ROW_APP + 8)

// Spin if the expression is not true
#define SIMPLECENTRAL_ASSERT(expr) if (!(expr)) SimpleCentral_spin();

// Timeout for the initiator to cancel connection if not successful
#define CONNECTION_TIMEOUT                   3000

// Auto connect chosen group
#define GROUP_NAME_LENGTH                    4

//Member defalult status when initalized
#define GROUP_MEMBER_INITIALIZED             0x00

//Member connected
#define GROUP_MEMBER_CONNECTED               0x01

//Default connection handle which is set when group member is created
#define GROUP_INITIALIZED_CONNECTION_HANDLE  0xFFFF

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

// Auto connect availble groups
enum
{
  AUTOCONNECT_DISABLE = 0,              // Disable
  AUTOCONNECT_GROUP_A = 1,              // Group A
  AUTOCONNECT_GROUP_B = 2               // Group B
};

// Discovery states
enum
{
  BLE_DISC_STATE_IDLE,                // Idle
  BLE_DISC_STATE_MTU,                 // Exchange ATT MTU size
  BLE_DISC_STATE_SVC,                 // Service discovery
  BLE_DISC_STATE_CHAR                 // Characteristic discovery
};

// App event passed from profiles.
typedef struct
{
  appEvtHdr_t hdr; // event header
  uint8_t *pData;  // event data
} scEvt_t;

// Scanned device information record
typedef struct
{
  uint8_t addrType;         // Peer Device's Address Type
  uint8_t addr[B_ADDR_LEN]; // Peer Device Address
} scanRec_t;

// Connected device information
typedef struct
{
  uint16_t connHandle;        // Connection Handle
  uint16_t charHandle;        // Characteristic Handle
  uint8_t  addr[B_ADDR_LEN];  // Peer Device Address
  Clock_Struct *pRssiClock;   // pointer to clock struct
} connRec_t;

// Container to store paring state info when passing from gapbondmgr callback
// to app event. See the pfnPairStateCB_t documentation from the gapbondmgr.h
// header file for more information on each parameter.
typedef struct
{
  uint16_t connHandle;
  uint8_t  status;
} scPairStateData_t;

// Container to store passcode data when passing from gapbondmgr callback
// to app event. See the pfnPasscodeCB_t documentation from the gapbondmgr.h
// header file for more information on each parameter.
typedef struct
{
  uint8_t deviceAddr[B_ADDR_LEN];
  uint16_t connHandle;
  uint8_t uiInputs;
  uint8_t uiOutputs;
  uint32_t numComparison;
} scPasscodeData_t;

typedef struct  
{
	osal_list_elem elem;
	uint8_t  addr[B_ADDR_LEN];  // member's BDADDR
	uint8_t  addrType;          // member's Address Type
	uint16_t connHandle;        // member's connection handle
	uint8_t  status;            // bitwise status flag 
} groupListElem_t;

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

// Display Interface
Display_Handle dispHandle = NULL;

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

#define APP_EVT_EVENT_MAX 0xA
char *appEventStrings[] = {
  "APP_EVT_ZERO              ",
  "APP_EVT_KEY_CHANGE        ",
  "APP_EVT_SCAN_ENABLED      ",
  "APP_EVT_SCAN_DISABLED     ",
  "APP_EVT_ADV_REPORT        ",
  "APP_EVT_SVC_DISC          ",
  "APP_EVT_READ_RSSI         ",
  "APP_EVT_PAIR_STATE        ",
  "APP_EVT_PASSCODE_NEEDED   ",
  "APP_EVT_READ_RPA          ",
  "APP_EVT_INSUFFICIENT_MEM  ",
};

/*********************************************************************
 * LOCAL VARIABLES
 */

// Entity ID globally used to check for source and/or destination of messages
static ICall_EntityID selfEntity;

// Event globally used to post local events and pend on system and
// local events.
static ICall_SyncHandle syncEvent;

// Queue object used for app messages
static Queue_Struct appMsg;
static Queue_Handle appMsgQueue;

// Task configuration
Task_Struct scTask;
#if defined __TI_COMPILER_VERSION__
#pragma DATA_ALIGN(scTaskStack, 8)
#else
#pragma data_alignment=8
#endif
uint8_t scTaskStack[SC_TASK_STACK_SIZE];

#if (DEFAULT_DEV_DISC_BY_SVC_UUID == TRUE)
// Number of scan results filtered by Service UUID
static uint8_t numScanRes = 0;

// Scan results filtered by Service UUID
static scanRec_t scanList[DEFAULT_MAX_SCAN_RES];
#endif // DEFAULT_DEV_DISC_BY_SVC_UUID

// Number of connected devices
static uint8_t numConn = 0;

// List of connections
static connRec_t connList[MAX_NUM_BLE_CONNS];

// Connection handle of current connection
static uint16_t scConnHandle = LINKDB_CONNHANDLE_INVALID;

// Accept or reject L2CAP connection parameter update request
static bool acceptParamUpdateReq = true;

// Discovery state
static uint8_t discState = BLE_DISC_STATE_IDLE;

// Discovered service start and end handle
static uint16_t svcStartHdl = 0;
static uint16_t svcEndHdl = 0;

// Value to write
static uint8_t charVal = 0;

// Maximum PDU size (default = 27 octets)
static uint16_t scMaxPduSize;

// Clock instance for RPA read events.
static Clock_Struct clkRpaRead;

// Address mode
static GAP_Addr_Modes_t addrMode = DEFAULT_ADDRESS_MODE;

// Current Random Private Address
static uint8 rpa[B_ADDR_LEN] = {0};

// Auto connect Disabled/Enabled {0 - Disabled, 1- Group A , 2-Group B, ...}
uint8_t autoConnect = AUTOCONNECT_GROUP_A;

//AutoConnect Group list
static osal_list_list groupList;

//AutoConnect ADV data filter according to local name short
//static uint8_t acGroup[4] = {
//  0x03,
//  GAP_ADTYPE_LOCAL_NAME_SHORT,
//  'G',
//  'A'
// };

static uint8_t acGroup[4] = {
  0x02,
  GAP_ADTYPE_FLAGS,
  GAP_ADTYPE_FLAGS_GENERAL | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED,

  // service UUID, to notify central devices what services are included
  // in this peripheral
#if !defined(FEATURE_OAD) || defined(FEATURE_OAD_ONCHIP)
  0x03,   // length of this data
#else //OAD for external flash
  0x05,  // length of this data
#endif //FEATURE_OAD
  GAP_ADTYPE_16BIT_MORE,      // some of the UUID's, but not all
#ifdef FEATURE_OAD
  LO_UINT16(OAD_SERVICE_UUID),
  HI_UINT16(OAD_SERVICE_UUID),
#endif //FEATURE_OAD
#ifndef FEATURE_OAD_ONCHIP
  LO_UINT16(SIMPLEPROFILE_SERV_UUID),
  HI_UINT16(SIMPLEPROFILE_SERV_UUID)
#endif //FEATURE_OAD_ONCHIP
 };

//Number of group members found
static uint8_t numGroupMembers = 0;

//Connection in progress to avoid double initiate
static groupListElem_t *memberInProg;

/*********************************************************************
 * LOCAL FUNCTIONS
 */
static void SimpleCentral_init(void);
static void SimpleCentral_taskFxn(uintptr_t a0, uintptr_t a1);

static uint8_t SimpleCentral_isMember(uint8_t *advData , uint8_t *groupName , uint8_t len);
static void SimpleCentral_autoConnect(void);

static void SimpleCentral_handleKeys(uint8_t keys);
static uint8_t SimpleCentral_processStackMsg(ICall_Hdr *pMsg);
static void SimpleCentral_processGapMsg(gapEventHdr_t *pMsg);
static void SimpleCentral_processGATTMsg(gattMsgEvent_t *pMsg);
static void SimpleCentral_processAppMsg(scEvt_t *pMsg);
static void SimpleCentral_processGATTDiscEvent(gattMsgEvent_t *pMsg);
static void SimpleCentral_startSvcDiscovery(void);
#if (DEFAULT_DEV_DISC_BY_SVC_UUID == TRUE)
static bool SimpleCentral_findSvcUuid(uint16_t uuid, uint8_t *pData,
                                      uint16_t dataLen);
static void SimpleCentral_addScanInfo(uint8_t *pAddr, uint8_t addrType);
#endif // DEFAULT_DEV_DISC_BY_SVC_UUID
static uint8_t SimpleCentral_addConnInfo(uint16_t connHandle, uint8_t *pAddr);
static uint8_t SimpleCentral_removeConnInfo(uint16_t connHandle);
static uint8_t SimpleCentral_getConnIndex(uint16_t connHandle);
#ifndef Display_DISABLE_ALL
static char* SimpleCentral_getConnAddrStr(uint16_t connHandle);
#endif
static void SimpleCentral_processPairState(uint8_t state,
                                           scPairStateData_t* pPairStateData);
static void SimpleCentral_processPasscode(scPasscodeData_t *pData);

static void SimpleCentral_processCmdCompleteEvt(hciEvt_CmdComplete_t *pMsg);
static status_t SimpleCentral_StartRssi();
static status_t SimpleCentral_CancelRssi(uint16_t connHandle);

static void SimpleCentral_passcodeCb(uint8_t *deviceAddr, uint16_t connHandle,
                                     uint8_t uiInputs, uint8_t uiOutputs,
                                     uint32_t numComparison);
static void SimpleCentral_pairStateCb(uint16_t connHandle, uint8_t state,
                                      uint8_t status);

static void SimpleCentral_keyChangeHandler(uint8 keys);
static void SimpleCentral_clockHandler(UArg arg);

static status_t SimpleCentral_enqueueMsg(uint8_t event, uint8_t status,
                                        uint8_t *pData);

static void SimpleCentral_scanCb(uint32_t evt, void* msg, uintptr_t arg);
static void SimpleCentral_menuSwitchCb(tbmMenuObj_t* pMenuObjCurr,
                                       tbmMenuObj_t* pMenuObjNext);

/*********************************************************************
 * EXTERN FUNCTIONS
 */
extern void AssertHandler(uint8 assertCause, uint8 assertSubcause);

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

// Bond Manager Callbacks
static gapBondCBs_t bondMgrCBs =
{
  SimpleCentral_passcodeCb, // Passcode callback
  SimpleCentral_pairStateCb // Pairing/Bonding state Callback
};

/*********************************************************************
 * PUBLIC FUNCTIONS
 */
/*********************************************************************
 * @fn		SimpleCentral_isMember
 *
 * @brief	Check if Advertiser is part of the group according to its Adv Data
 *
 * @param	advData   - pointer to adv data
 *          groupNmae - group name which need to be compared with
 *          len       - length of the group name
 *
 * @return  TRUE: part of the group
 *          FALSE: not part of the group
 */

static uint8_t SimpleCentral_isMember(uint8_t *advData , uint8_t *groupName , uint8_t len)
{
  if (osal_memcmp((uint8_t *)advData, (uint8_t *)groupName, len))
  {
    return TRUE;
  }
  return FALSE;
}

/*********************************************************************
 * @fn		SimpleCentral_autoConnect
 *
 * @brief	Check if Advertiser is part of the group according to its Adv Data
 *
 * @param   none
 *
 * @return  none
 */

static void SimpleCentral_autoConnect(void) 
{
  status_t status;
  int len = 9;
  size_t  bytesWritten;

  if (memberInProg == NULL)
  {
    if (numConn < MAX_NUM_BLE_CONNS)
    {
	  groupListElem_t *tempMember = (groupListElem_t *)osal_list_head(&groupList);
      //If group member is not connected
      if ((tempMember != NULL) && (!(tempMember->status & GROUP_MEMBER_CONNECTED)))
      {
        //Initiate a connection
        status = GapInit_connect(tempMember->addrType & MASK_ADDRTYPE_ID,tempMember->addr, DEFAULT_INIT_PHY, CONNECTION_TIMEOUT);
        if (status != SUCCESS)
        {
          //Couldn't create connection remove element from list and free the memory.
//          char *str = "AutoConnect Failed. The status is 0";
//          str[35] = status + '0';
//          Uart_SendMsg(UART_HEADER_STR,36, str);
          osal_list_remove(&groupList, (osal_list_elem *)tempMember);
          ICall_free(tempMember);
        }
    	else
    	{
          //Save pointer to connection in progress untill connection is established.
		  memberInProg = tempMember;
//		  Uart_SendMsg(UART_HEADER_HEX,6, tempMember->addr);
        }
	  }
    }
    else
    {
      Display_printf(dispHandle, SC_ROW_NON_CONN, 0, "AutoConnect turned off: Max connection reached.");
    }
  }
}

/*********************************************************************
 * @fn      SimpleCentral_spin
 *
 * @brief   Spin forever
 *
 * @param   none
 */
static void SimpleCentral_spin(void)
{
  volatile uint8_t x;
//  Uart_SendMsg(UART_HEADER_STR,9, "Spinning!");
  while(1)
  {
    x++;
  }
}

/*********************************************************************
 * @fn      SimpleCentral_createTask
 *
 * @brief   Task creation function for the Simple Central.
 *
 * @param   none
 *
 * @return  none
 */
void SimpleCentral_createTask(void)
{
  Task_Params taskParams;

  // Configure task
  Task_Params_init(&taskParams);
  taskParams.stack = scTaskStack;
  taskParams.stackSize = SC_TASK_STACK_SIZE;
  taskParams.priority = SC_TASK_PRIORITY;

  Task_construct(&scTask, SimpleCentral_taskFxn, &taskParams, NULL);
}

/*********************************************************************
 * @fn      SimpleCentral_Init
 *
 * @brief   Initialization function for the Simple Central App Task.
 *          This is called during initialization and should contain
 *          any application specific initialization (ie. hardware
 *          initialization/setup, table initialization, power up
 *          notification).
 *
 * @param   none
 *
 * @return  none
 */

static void SimpleCentral_init(void)
{
  uint8_t i;

  BLE_LOG_INT_TIME(0, BLE_LOG_MODULE_APP, "APP : ---- init ", SC_TASK_PRIORITY);
  // Create the menu
  SimpleCentral_buildMenu();

  // ******************************************************************
  // N0 STACK API CALLS CAN OCCUR BEFORE THIS CALL TO ICall_registerApp
  // ******************************************************************
  // Register the current thread as an ICall dispatcher application
  // so that the application can send and receive messages.
  ICall_registerApp(&selfEntity, &syncEvent);

  // Create an RTOS queue for message from profile to be sent to app.
  appMsgQueue = Util_constructQueue(&appMsg);

  // Initialize internal data
  for (i = 0; i < MAX_NUM_BLE_CONNS; i++)
  {
    connList[i].connHandle = LINKDB_CONNHANDLE_INVALID;
    connList[i].pRssiClock = NULL;
  }

  Board_initKeys(SimpleCentral_keyChangeHandler);

  GGS_SetParameter(GGS_DEVICE_NAME_ATT, GAP_DEVICE_NAME_LEN,
                   (void *)attDeviceName);

  //Set default values for Data Length Extension
  //Extended Data Length Feature is already enabled by default
  //in build_config.opt in stack project.
  {
    //Change initial values of RX/TX PDU and Time, RX is set to max. by default(251 octets, 2120us)
    #define APP_SUGGESTED_RX_PDU_SIZE 251     //default is 251 octets(RX)
    #define APP_SUGGESTED_RX_TIME     17000   //default is 17000us(RX)
    #define APP_SUGGESTED_TX_PDU_SIZE 27      //default is 27 octets(TX)
    #define APP_SUGGESTED_TX_TIME     328     //default is 328us(TX)

    //This API is documented in hci.h
    //See the LE Data Length Extension section in the BLE5-Stack User's Guide for information on using this command:
    //http://software-dl.ti.com/lprf/ble5stack-latest/
//    HCI_EXT_SetMaxDataLenCmd(APP_SUGGESTED_TX_PDU_SIZE, APP_SUGGESTED_TX_TIME, APP_SUGGESTED_RX_PDU_SIZE, APP_SUGGESTED_RX_TIME);
      HCI_LE_WriteSuggestedDefaultDataLenCmd(APP_SUGGESTED_RX_PDU_SIZE, APP_SUGGESTED_TX_TIME);
      HCI_LE_SetDefaultPhyCmd(LL_PHY_USE_ANY_PHY, LL_PHY_2_MBPS, LL_PHY_2_MBPS);
  }

  // Initialize GATT Client
  VOID GATT_InitClient("");

  // Register to receive incoming ATT Indications/Notifications
  GATT_RegisterForInd(selfEntity);

  // Initialize GATT attributes
//  GGS_AddService(GAP_SERVICE);               // GAP
  GGS_AddService(GATT_ALL_SERVICES);
  GATTServApp_AddService(GATT_ALL_SERVICES); // GATT attributes

  // Register for GATT local events and ATT Responses pending for transmission
  GATT_RegisterForMsgs(selfEntity);

  // Set Bond Manager parameters
  setBondManagerParameters();

  // Start Bond Manager and register callback
  // This must be done before initialing the GAP layer
  VOID GAPBondMgr_Register(&bondMgrCBs);

  // Accept all parameter update requests
  GAP_SetParamValue(GAP_PARAM_LINK_UPDATE_DECISION, GAP_UPDATE_REQ_ACCEPT_ALL);

  // Register with GAP for HCI/Host messages (for RSSI)
  GAP_RegisterForMsgs(selfEntity);

  BLE_LOG_INT_TIME(0, BLE_LOG_MODULE_APP, "APP : ---- call GAP_DeviceInit", GAP_PROFILE_CENTRAL);
  // Initialize GAP layer for Central role and register to receive GAP events
  GAP_DeviceInit(GAP_PROFILE_CENTRAL, selfEntity, addrMode, &pRandomAddress);

  dispHandle = Display_open(Display_Type_ANY, NULL);

  // Disable all items in the main menu
  tbm_setItemStatus(&scMenuMain, SC_ITEM_NONE, SC_ITEM_ALL);
  // Initialize Two-button Menu
  tbm_initTwoBtnMenu(dispHandle, &scMenuMain, 5, SimpleCentral_menuSwitchCb);
  Display_printf(dispHandle, SC_ROW_SEPARATOR, 0, "====================");

  //Author: Wang Jieqiong
  UART2_Params_init(&uart_params);
  uart_params.writeMode = UART2_Mode_CALLBACK;
  uart_params.writeCallback = UART_WRITE_CALLBACK;
  uart_params.baudRate = 256000;
  uart = UART2_open(CONFIG_UART2_0, &uart_params);
  LED_init();
  LED_Params LED_params;
  LED_Params_init(&LED_params);
  led_red = LED_open(CONFIG_LED_0, &LED_params);
  led_green = LED_open(CONFIG_LED_1, &LED_params);

  if(!uart){
      while(1);
  }
//  LED_setOn(led_green, 100);

  Util_constructClock(&uart_clock, SimpleCentral_clockHandler,
                      UART_PERIOD, 0, true, SC_EVT_UART_WRITE);
  Util_constructClock(&startDiscClock, SimpleCentral_clockHandler,
                      DEFAULT_SVC_DISCOVERY_DELAY, 0, false, SC_EVT_START_DISCOVERY);
//  Util_startClock(&uart_clock);

  //
} //SimpleCentral_init()

//UART2_Callback UART_WRITE_CALLBACK(UART2_Handle handle, void *buf, size_t count, void *userArg, int_fast16_t status){
//
//}
/*********************************************************************
 * @fn      SimpleCentral_taskFxn
 *
 * @brief   Application task entry point for the Simple Central.
 *
 * @param   none
 *
 * @return  events not processed
 */
static void SimpleCentral_taskFxn(uintptr_t a0, uintptr_t a1)
{
  // Initialize application
  SimpleCentral_init();
//  Uart_SendMsg(UART_HEADER_STR,50,  "====================================================");
  // Application main loop
  for (;;)
  {
    uint32_t events;

    events = Event_pend(syncEvent, Event_Id_NONE, SC_ALL_EVENTS | SC_UART_EVT,
                        ICALL_TIMEOUT_FOREVER);

    if (events)
    {
      ICall_EntityID dest;
      ICall_ServiceEnum src;
      ICall_HciExtEvt *pMsg = NULL;

      if (ICall_fetchServiceMsg(&src, &dest,
                                (void **)&pMsg) == ICALL_ERRNO_SUCCESS)
      {
        uint8 safeToDealloc = TRUE;

        if ((src == ICALL_SERVICE_CLASS_BLE) && (dest == selfEntity))
        {
          ICall_Stack_Event *pEvt = (ICall_Stack_Event *)pMsg;

          // Check for BLE stack events first
          if (pEvt->signature != 0xffff)
          {
            // Process inter-task message
            safeToDealloc = SimpleCentral_processStackMsg((ICall_Hdr *)pMsg);
          }
        }

        if (pMsg && safeToDealloc)
        {
          ICall_freeMsg(pMsg);
        }
      }

      // If RTOS queue is not empty, process app message
      if (events & SC_QUEUE_EVT)
      {
        scEvt_t *pMsg;
        while ((pMsg = (scEvt_t *)Util_dequeueMsg(appMsgQueue)))
        {
          // Process message
          SimpleCentral_processAppMsg(pMsg);

          // Free the space from the message
          ICall_free(pMsg);
        }
      }//events & SC_QUEUE_EVT

      if(events & SC_UART_EVT){
//          SimpleCentral_doSelectConn(0);
//          Uart_SendMsg(UART_HEADER_STR,14, "Clock working.");

//          led_red_status = !led_red_status;
          Util_startClock(&uart_clock);
      }
    }
  }
}

/*********************************************************************
 * @fn      SimpleCentral_processStackMsg
 *
 * @brief   Process an incoming task message.
 *
 * @param   pMsg - message to process
 *
 * @return  TRUE if safe to deallocate incoming message, FALSE otherwise.
 */
static uint8_t SimpleCentral_processStackMsg(ICall_Hdr *pMsg)
{
  uint8_t safeToDealloc = TRUE;

  BLE_LOG_INT_INT(0, BLE_LOG_MODULE_APP, "APP : Stack msg status=%d, event=0x%x\n", pMsg->status, pMsg->event);

  switch (pMsg->event)
  {
    case GAP_MSG_EVENT:
      SimpleCentral_processGapMsg((gapEventHdr_t*) pMsg);
      break;

    case GATT_MSG_EVENT:
      SimpleCentral_processGATTMsg((gattMsgEvent_t *)pMsg);
      break;

    case HCI_GAP_EVENT_EVENT:
    {
      // Process HCI message
      switch (pMsg->status)
      {
        case HCI_COMMAND_COMPLETE_EVENT_CODE:
          SimpleCentral_processCmdCompleteEvt((hciEvt_CmdComplete_t *) pMsg);
          break;

        case HCI_BLE_HARDWARE_ERROR_EVENT_CODE:
          AssertHandler(HAL_ASSERT_CAUSE_HARDWARE_ERROR,0);
          break;

        // HCI Commands Events
        case HCI_COMMAND_STATUS_EVENT_CODE:
          {
            hciEvt_CommandStatus_t *pMyMsg = (hciEvt_CommandStatus_t *)pMsg;
            switch ( pMyMsg->cmdOpcode )
            {
              case HCI_LE_SET_PHY:
                {
                  if (pMyMsg->cmdStatus ==
                      HCI_ERROR_CODE_UNSUPPORTED_REMOTE_FEATURE)
                  {
                    Display_printf(dispHandle, SC_ROW_CUR_CONN, 0,
                            "PHY Change failure, peer does not support this");
                  }
                  else
                  {
                    Display_printf(dispHandle, SC_ROW_CUR_CONN, 0,
                                   "PHY Update Status: 0x%02x",
                                   pMyMsg->cmdStatus);
                  }
                }
                break;
              case HCI_DISCONNECT:
                break;

              default:
                {
                  Display_printf(dispHandle, SC_ROW_NON_CONN, 0,
                                 "Unknown Cmd Status: 0x%04x::0x%02x",
                                 pMyMsg->cmdOpcode, pMyMsg->cmdStatus);
                }
              break;
            }
          }
          break;

        // LE Events
        case HCI_LE_EVENT_CODE:
        {
          hciEvt_BLEPhyUpdateComplete_t *pPUC
            = (hciEvt_BLEPhyUpdateComplete_t*) pMsg;

          if (pPUC->BLEEventCode == HCI_BLE_PHY_UPDATE_COMPLETE_EVENT)
          {
            if (pPUC->status != SUCCESS)
            {
              Display_printf(dispHandle, SC_ROW_ANY_CONN, 0,
                             "%s: PHY change failure",
                             SimpleCentral_getConnAddrStr(pPUC->connHandle));
            }
            else
            {
              Display_printf(dispHandle, SC_ROW_ANY_CONN, 0,
                             "%s: PHY updated to %s",
                             SimpleCentral_getConnAddrStr(pPUC->connHandle),
              // Only symmetrical PHY is supported.
              // rxPhy should be equal to txPhy.
                                (pPUC->rxPhy == PHY_UPDATE_COMPLETE_EVENT_1M) ? "1 Mbps" :
                                (pPUC->rxPhy == PHY_UPDATE_COMPLETE_EVENT_2M) ? "2 Mbps" :
                                (pPUC->rxPhy == PHY_UPDATE_COMPLETE_EVENT_CODED) ? "CODED" : "Unexpected PHY Value");
            }
          }

          break;
        }

        default:
          break;
      }

      break;
    }

    case L2CAP_SIGNAL_EVENT:
      // place holder for L2CAP Connection Parameter Reply
      break;

    default:
      break;
  }

  return (safeToDealloc);
}

/*********************************************************************
 * @fn      SimpleCentral_processAppMsg
 *
 * @brief   Scanner application event processing function.
 *
 * @param   pMsg - pointer to event structure
 *
 * @return  none
 */
static void SimpleCentral_processAppMsg(scEvt_t *pMsg)
{
  bool safeToDealloc = TRUE;

  if (pMsg->hdr.event <= APP_EVT_EVENT_MAX)
  {
    BLE_LOG_INT_STR(0, BLE_LOG_MODULE_APP, "APP : App msg status=%d, event=%s\n", 0, appEventStrings[pMsg->hdr.event]);
  }
  else
  {
    BLE_LOG_INT_INT(0, BLE_LOG_MODULE_APP, "APP : App msg status=%d, event=0x%x\n", 0, pMsg->hdr.event);
  }

  switch (pMsg->hdr.event)
  {
    case SC_EVT_KEY_CHANGE:
      SimpleCentral_handleKeys(pMsg->hdr.state);
      break;

    case SC_EVT_ADV_REPORT:
    {
//      Uart_SendMsg(UART_HEADER_STR,17, "SC_EVT_ADV_REPORT");

      GapScan_Evt_AdvRpt_t* pAdvRpt = (GapScan_Evt_AdvRpt_t*) (pMsg->pData);
//      Uart_SendMsg(UART_HEADER_HEX, B_ADDR_LEN, pAdvRpt->addr);
      //Auto connect is enabled
      if (autoConnect) 
      {
        if (numGroupMembers == MAX_NUM_BLE_CONNS)
        {
          GapScan_disable("");
          break;
		}
        //Check if advertiser is part of the group

        if (SimpleCentral_isMember(pAdvRpt->pData , acGroup, GROUP_NAME_LENGTH))
	    {
     	  groupListElem_t *tempMember;
     	  //Traverse list to search if advertiser already in list.
  	      for (tempMember = (groupListElem_t *)osal_list_head(&groupList); tempMember != NULL; tempMember = (groupListElem_t *)osal_list_next((osal_list_elem *)tempMember)) 
  	      {
            if (osal_memcmp((uint8_t *)tempMember->addr ,(uint8_t *)pAdvRpt->addr,B_ADDR_LEN))
            {
              break;
            }
          }
          //If tempMemer is NULL this meams advertiser not in list.
          if (tempMember == NULL)
          {
            groupListElem_t *groupMember = (groupListElem_t *)ICall_malloc(sizeof(groupListElem_t));
            if (groupMember != NULL)
            {
              //Copy member's details into Member's list.
//              Uart_SendMsg(UART_HEADER_HEX, B_ADDR_LEN, pAdvRpt->addr);
              osal_memcpy((uint8_t *)groupMember->addr , (uint8_t *)pAdvRpt->addr,B_ADDR_LEN);
              groupMember->addrType = pAdvRpt->addrType;
              groupMember->status = GROUP_MEMBER_INITIALIZED;
              groupMember->connHandle = GROUP_INITIALIZED_CONNECTION_HANDLE;
              //Add group member into list.
              osal_list_putHead(&groupList,(osal_list_elem *)groupMember);
			  numGroupMembers++;

            }
            else
            {
              Display_printf(dispHandle, SC_ROW_AC, 0, "AutoConnect: Allocation failed!");
              break;
            }
          }
        }
      }
#if (DEFAULT_DEV_DISC_BY_SVC_UUID == TRUE)
      if (SimpleCentral_findSvcUuid(SIMPLEPROFILE_SERV_UUID,
                                    pAdvRpt->pData, pAdvRpt->dataLen))
      {
        SimpleCentral_addScanInfo(pAdvRpt->addr, pAdvRpt->addrType);
        Display_printf(dispHandle, SC_ROW_NON_CONN, 0, "Discovered: %s",
                       Util_convertBdAddr2Str(pAdvRpt->addr));
      }
#else // !DEFAULT_DEV_DISC_BY_SVC_UUID
      Display_printf(dispHandle, SC_ROW_NON_CONN, 0, "Discovered: %s",
                     Util_convertBdAddr2Str(pAdvRpt->addr));
#endif // DEFAULT_DEV_DISC_BY_SVC_UUID

      // Free report payload data
      if (pAdvRpt->pData != NULL)
      {
        ICall_free(pAdvRpt->pData);
      }
      break;
    }

    case SC_EVT_SCAN_ENABLED:
      // Disable everything but "Stop Discovering" on the menu
      tbm_setItemStatus(&scMenuMain, SC_ITEM_STOPDISC,
                        (SC_ITEM_ALL & ~SC_ITEM_STOPDISC));
      Display_printf(dispHandle, SC_ROW_NON_CONN, 0, "Discovering...");
      LED_startBlinking(led_green, 100, LED_BLINK_FOREVER);
      break;

    case SC_EVT_SCAN_DISABLED:
    {
//      Uart_SendMsg(UART_HEADER_STR,14, "scan disabled.");
        LED_stopBlinking(led_green);
      uint16_t itemsToEnable = SC_ITEM_STARTDISC | SC_ITEM_SCANPHY;
      if (osal_list_head(&groupList) == NULL){
          SimpleCentral_doDiscoverDevices(0);
          return;
      }
      if (autoConnect)
      {
        itemsToEnable |= SC_ITEM_AUTOCONNECT;
		if (numGroupMembers < MAX_NUM_BLE_CONNS)
        {
           Display_printf(dispHandle, SC_ROW_AC, 0, "AutoConnect: Not all members found, only %d members were found",numGroupMembers);
        }
		else
		{
		  Display_printf(dispHandle, SC_ROW_AC, 0, "AutoConnect: Number of members in the group %d",numGroupMembers);
		  SimpleCentral_autoConnect();
          if (numConn > 0)
	      {
	        // Also enable "Work with"
	        itemsToEnable |= SC_ITEM_SELECTCONN;
	      }
        }
		// Enable "Discover Devices", "Set Scanning PHY", and possibly
	    // "Connect to" and/or "Work with".
	    // Disable "Stop Discovering".
  	    tbm_setItemStatus(&scMenuMain, itemsToEnable, SC_ITEM_STOPDISC);
	  }
      else
      {
	      uint8_t numReport;
	      uint8_t i;
	      static uint8_t* pAddrs = NULL;
	      uint8_t* pAddrTemp;
#if (DEFAULT_DEV_DISC_BY_SVC_UUID == TRUE)
	      numReport = numScanRes;
#else // !DEFAULT_DEV_DISC_BY_SVC_UUID
	      GapScan_Evt_AdvRpt_t advRpt;

	      numReport = ((GapScan_Evt_End_t*) (pMsg->pData))->numReport;
#endif // DEFAULT_DEV_DISC_BY_SVC_UUID

	      Display_printf(dispHandle, SC_ROW_NON_CONN, 0,
	                     "%d devices discovered", numReport);

	      if (numReport > 0)
	      {
	        // Also enable "Connect to"
	        itemsToEnable |= SC_ITEM_CONNECT;
	      }

	      if (numConn > 0)
	      {
	        // Also enable "Work with"
	        itemsToEnable |= SC_ITEM_SELECTCONN;
	      }

	      // Enable "Discover Devices", "Set Scanning PHY", and possibly
	      // "Connect to" and/or "Work with".
	      // Disable "Stop Discovering".
	      tbm_setItemStatus(&scMenuMain, itemsToEnable, SC_ITEM_STOPDISC);

	      // Allocate buffer to display addresses
	      if (pAddrs != NULL)
	      {
	        // A scan has been done previously, release the previously allocated buffer
	        ICall_free(pAddrs);
	      }
	      pAddrs = ICall_malloc(numReport * SC_ADDR_STR_SIZE);
	      if (pAddrs == NULL)
	      {
	        numReport = 0;
	      }

	      TBM_SET_NUM_ITEM(&scMenuConnect, numReport);

	      if (pAddrs != NULL)
	      {
	        pAddrTemp = pAddrs;
	        for (i = 0; i < numReport; i++, pAddrTemp += SC_ADDR_STR_SIZE)
	        {
	  #if (DEFAULT_DEV_DISC_BY_SVC_UUID == TRUE)
	          // Get the address from the list, convert it to string, and
	          // copy the string to the address buffer
	          memcpy(pAddrTemp, Util_convertBdAddr2Str(scanList[i].addr),
	                 SC_ADDR_STR_SIZE);
	  #else // !DEFAULT_DEV_DISC_BY_SVC_UUID
	          // Get the address from the report, convert it to string, and
	          // copy the string to the address buffer
	          GapScan_getAdvReport(i, &advRpt);
	          memcpy(pAddrTemp, Util_convertBdAddr2Str(advRpt.addr),
	                 SC_ADDR_STR_SIZE);
	  #endif // DEFAULT_DEV_DISC_BY_SVC_UUID

	          // Assign the string to the corresponding action description of the menu
	          TBM_SET_ACTION_DESC(&scMenuConnect, i, pAddrTemp);
	        }

	        // Disable any non-active scan results
	        for (; i < DEFAULT_MAX_SCAN_RES; i++)
	        {
	          tbm_setItemStatus(&scMenuConnect, TBM_ITEM_NONE, (1 << i));
	        }

	        // Note: pAddrs is not freed since it will be used by the two button menu
	        // to display the discovered address.
	        // This implies that at least the last discovered addresses
	        // will be maintained until a new scan is done.
	      }
	      break;
	    }
    }
    case SC_EVT_SVC_DISC:
//      Uart_SendMsg(UART_HEADER_STR, 14, "SC_EVT_SVC_DISC");
      SimpleCentral_startSvcDiscovery();
      break;

    case SC_EVT_READ_RSSI:
    {
      uint8_t connIndex = pMsg->hdr.state;
      uint16_t connHandle = connList[connIndex].connHandle;
//      Uart_SendMsg(UART_HEADER_STR, 16, "SC_EVT_READ_RSSI");
      // If link is still valid
      if (connHandle != LINKDB_CONNHANDLE_INVALID)
      {
//        char ch[] = "Rssi clock started and conindex is 0";
//        ch[35] += connIndex;
//        Uart_SendMsg(UART_HEADER_STR, 36, ch);
        // Restart timer
        Util_startClock(connList[connIndex].pRssiClock);
//        Uart_SendMsg(UART_HEADER_STR, 11, "111111111111");
        // Read RSSI
//        VOID HCI_ReadRssiCmd(connHandle);
        hciStatus_t rssiStatus = HCI_ReadRssiCmd(connHandle);
//        ch[35]  = rssiStatus + '0';
//        Uart_SendMsg(UART_HEADER_STR, 36, ch);
      }

      break;
    }

    // Pairing event
    case SC_EVT_PAIR_STATE:
    {
      SimpleCentral_processPairState(pMsg->hdr.state,
                                     (scPairStateData_t*) (pMsg->pData));
      break;
    }

    // Passcode event
    case SC_EVT_PASSCODE_NEEDED:
    {
      SimpleCentral_processPasscode((scPasscodeData_t *)(pMsg->pData));
      break;
    }

    case SC_EVT_READ_RPA:
    {
      uint8_t* pRpaNew;

      // Read the current RPA.
      pRpaNew = GAP_GetDevAddress(FALSE);

      if (memcmp(pRpaNew, rpa, B_ADDR_LEN))
      {
        // If the RPA has changed, update the display
        Display_printf(dispHandle, SC_ROW_RPA, 0, "RP Addr: %s",
                       Util_convertBdAddr2Str(pRpaNew));
        memcpy(rpa, pRpaNew, B_ADDR_LEN);
      }
      break;
    }

    // Insufficient memory
    case SC_EVT_INSUFFICIENT_MEM:
    {
      // We are running out of memory.
      Display_printf(dispHandle, SC_ROW_ANY_CONN, 0, "Insufficient Memory");

      // We might be in the middle of scanning, try stopping it.
      GapScan_disable("");
      break;
    }

    default:
      // Do nothing.
      break;
  }

  if ((safeToDealloc == TRUE) && (pMsg->pData != NULL))
  {
    ICall_free(pMsg->pData);
  }
}

/*********************************************************************
 * @fn      SimpleCentral_processGapMsg
 *
 * @brief   GAP message processing function.
 *
 * @param   pMsg - pointer to event message structure
 *
 * @return  none
 */
static void SimpleCentral_processGapMsg(gapEventHdr_t *pMsg)
{
  switch (pMsg->opcode)
  {
    case GAP_DEVICE_INIT_DONE_EVENT:
    {
      uint8_t temp8;
      uint16_t temp16;
      gapDeviceInitDoneEvent_t *pPkt = (gapDeviceInitDoneEvent_t *)pMsg;

      BLE_LOG_INT_TIME(0, BLE_LOG_MODULE_APP, "APP : ---- got GAP_DEVICE_INIT_DONE_EVENT", 0);
      // Setup scanning
      // For more information, see the GAP section in the User's Guide:
      // http://software-dl.ti.com/lprf/ble5stack-latest/

      // Register callback to process Scanner events
      GapScan_registerCb(SimpleCentral_scanCb, NULL);

      // Set Scanner Event Mask
      GapScan_setEventMask(GAP_EVT_SCAN_ENABLED | GAP_EVT_SCAN_DISABLED |
                           GAP_EVT_ADV_REPORT);

      // Set Scan PHY parameters
      GapScan_setPhyParams(DEFAULT_SCAN_PHY, DEFAULT_SCAN_TYPE,
                           DEFAULT_SCAN_INTERVAL, DEFAULT_SCAN_WINDOW);

      // Set Advertising report fields to keep
      temp16 = ADV_RPT_FIELDS;
      GapScan_setParam(SCAN_PARAM_RPT_FIELDS, &temp16);
      // Set Scanning Primary PHY
      temp8 = DEFAULT_SCAN_PHY;
      GapScan_setParam(SCAN_PARAM_PRIM_PHYS, &temp8);
      // Set LL Duplicate Filter
      temp8 = SCANNER_DUPLICATE_FILTER;
      GapScan_setParam(SCAN_PARAM_FLT_DUP, &temp8);

      // Set PDU type filter -
      // Only 'Connectable' and 'Complete' packets are desired.
      // It doesn't matter if received packets are
      // whether Scannable or Non-Scannable, whether Directed or Undirected,
      // whether Scan_Rsp's or Advertisements, and whether Legacy or Extended.
      temp16 = SCAN_FLT_PDU_CONNECTABLE_ONLY | SCAN_FLT_PDU_COMPLETE_ONLY;
      BLE_LOG_INT_TIME(0, BLE_LOG_MODULE_APP, "APP : ---- GapScan_setParam", 0);
      GapScan_setParam(SCAN_PARAM_FLT_PDU_TYPE, &temp16);

	  // Set initiating PHY parameters
      GapInit_setPhyParam(DEFAULT_INIT_PHY, INIT_PHYPARAM_CONN_INT_MIN,
						  INIT_PHYPARAM_MIN_CONN_INT);
	  GapInit_setPhyParam(DEFAULT_INIT_PHY, INIT_PHYPARAM_CONN_INT_MAX,
						  INIT_PHYPARAM_MAX_CONN_INT);

      scMaxPduSize = pPkt->dataPktLen;

      // Enable "Discover Devices", "Set Scanning PHY", "AutoConnect" , and "Set Address Type"
      // in the main menu
      tbm_setItemStatus(&scMenuMain,
                        SC_ITEM_STARTDISC | SC_ITEM_SCANPHY | SC_ITEM_AUTOCONNECT, SC_ITEM_NONE);

      Display_printf(dispHandle, SC_ROW_NON_CONN, 0, "Initialized");
      Display_printf(dispHandle, SC_ROW_NUM_CONN, 0, "Num Conns: %d", numConn);

      // Display device address
      Display_printf(dispHandle, SC_ROW_IDA, 0, "%s Addr: %s",
                     (addrMode <= ADDRMODE_RANDOM) ? "Dev" : "ID",
                     Util_convertBdAddr2Str(pPkt->devAddr));

      if (addrMode > ADDRMODE_RANDOM)
      {
        // Update the current RPA.
        memcpy(rpa, GAP_GetDevAddress(FALSE), B_ADDR_LEN);

        Display_printf(dispHandle, SC_ROW_RPA, 0, "RP Addr: %s",
                       Util_convertBdAddr2Str(rpa));

        // Create one-shot clock for RPA check event.
        Util_constructClock(&clkRpaRead, SimpleCentral_clockHandler,
                            READ_RPA_PERIOD, 0, true, SC_EVT_READ_RPA);
      }
      SimpleCentral_doDiscoverDevices(0);
      break;
    }

    case GAP_CONNECTING_CANCELLED_EVENT:
    {
//      Uart_SendMsg(UART_HEADER_STR, 30, "GAP_CONNECTING_CANCELLED_EVENT");
      uint16_t itemsToEnable = SC_ITEM_SCANPHY | SC_ITEM_STARTDISC |
                               SC_ITEM_CONNECT | SC_ITEM_AUTOCONNECT;
	  if (autoConnect)
      {
        if (memberInProg != NULL)
		{
          //Remove node from member's group and free its memory.
          osal_list_remove(&groupList, (osal_list_elem *)memberInProg);
          ICall_free(memberInProg);  
  		  numGroupMembers--;
          memberInProg = NULL;
	    }
		Display_printf(dispHandle, SC_ROW_AC, 0, "AutoConnect: Number of members in the group %d",numGroupMembers);
		//Keep on connecting to the remaining members in the list
        SimpleCentral_autoConnect();
      }

      if (numConn > 0)
      {
        itemsToEnable |= SC_ITEM_SELECTCONN;
      }

      Display_printf(dispHandle, SC_ROW_NON_CONN, 0,
                     "Conneting attempt cancelled");

      // Enable "Discover Devices", "Connect To", and "Set Scanning PHY"
      // and disable everything else.
      tbm_setItemStatus(&scMenuMain,
                        itemsToEnable, SC_ITEM_ALL & ~itemsToEnable);

      break;
    }

    case GAP_LINK_ESTABLISHED_EVENT:
    {
      LED_setOn(led_green, 100);
      uint16_t connHandle = ((gapEstLinkReqEvent_t*) pMsg)->connectionHandle;
      uint8_t* pAddr = ((gapEstLinkReqEvent_t*) pMsg)->devAddr;
      BLE_LOG_INT_TIME(0, BLE_LOG_MODULE_APP, "APP : ---- got GAP_LINK_ESTABLISHED_EVENT", 0);
//      Uart_SendMsg(UART_HEADER_STR,9, "connected");
      if (autoConnect)
      {
        if (memberInProg != NULL)
		{
  		  if (osal_memcmp((uint8_t *)pAddr, (uint8_t *)memberInProg->addr, B_ADDR_LEN))
  		  {
            //Move the connected member to the tail of the list.
            osal_list_remove(&groupList,(osal_list_elem *)memberInProg);
            osal_list_put(&groupList,(osal_list_elem *)memberInProg);
            //Set the connected bit.;
  		    memberInProg->status |= GROUP_MEMBER_CONNECTED;
            //Store the connection handle.
            memberInProg->connHandle = connHandle;
  		    memberInProg = NULL;
  		  }
  	    }
	  }
      uint8_t  connIndex;
      uint32_t itemsToDisable = SC_ITEM_STOPDISC | SC_ITEM_CANCELCONN;
      uint8_t* pStrAddr;
      uint8_t i;
      uint8_t numConnectable = 0;
      uint8_t pairMode = 0;

      // Add this connection info to the list
      connIndex = SimpleCentral_addConnInfo(connHandle, pAddr);

      // connIndex cannot be equal to or greater than MAX_NUM_BLE_CONNS
      SIMPLECENTRAL_ASSERT(connIndex < MAX_NUM_BLE_CONNS);

      connList[connIndex].charHandle = 0;

      pStrAddr = (uint8_t*) Util_convertBdAddr2Str(connList[connIndex].addr);

      Display_printf(dispHandle, SC_ROW_NON_CONN, 0, "Connected to %s", pStrAddr);
      Display_printf(dispHandle, SC_ROW_NUM_CONN, 0, "Num Conns: %d", numConn);

      // Disable "Connect To" until another discovery is performed
      itemsToDisable |= SC_ITEM_CONNECT;

      // If we already have maximum allowed number of connections,
      // disable device discovery and additional connection making.
      if (numConn >= MAX_NUM_BLE_CONNS)
      {
        itemsToDisable |= SC_ITEM_SCANPHY | SC_ITEM_STARTDISC;
      }

      for (i = 0; i < TBM_GET_NUM_ITEM(&scMenuConnect); i++)
      {
        if (!memcmp(TBM_GET_ACTION_DESC(&scMenuConnect, i), pStrAddr,
            SC_ADDR_STR_SIZE))
        {
          // Disable this device from the connection choices
          tbm_setItemStatus(&scMenuConnect, SC_ITEM_NONE, 1 << i);
        }
        else if (TBM_IS_ITEM_ACTIVE(&scMenuConnect, i))
        {
          numConnectable++;
        }
      }

      // Enable/disable Main menu items properly
      tbm_setItemStatus(&scMenuMain,
                        SC_ITEM_ALL & ~(itemsToDisable), itemsToDisable);

      GAPBondMgr_GetParameter(GAPBOND_PAIRING_MODE, &pairMode);

      if ((autoConnect) && (pairMode != GAPBOND_PAIRING_MODE_INITIATE))
      {
//          Uart_SendMsg(UART_HEADER_STR,20, "What are you doing1?");
		  SimpleCentral_autoConnect();
      }
      scConnHandle = connHandle;
      SimpleCentral_doSelectConn(0);
//      Util_startClock(&uart_clock);
//      SimpleCentral_autoConnect();
//      SimpleCentral_doRssiRead(2);
      break;
    }

    case GAP_LINK_TERMINATED_EVENT:
    {
      LED_setOff(led_green);
//      Uart_SendMsg(UART_HEADER_STR, 15, "link terminated.");

	  uint8_t connIndex;
      BLE_LOG_INT_STR(0, BLE_LOG_MODULE_APP, "APP : GAP msg status=%d, opcode=%s\n", 0, "GAP_LINK_TERMINATED_EVENT");
      uint32_t itemsToEnable = SC_ITEM_STARTDISC | SC_ITEM_SCANPHY | SC_ITEM_AUTOCONNECT;
      uint8_t* pStrAddr;
      uint8_t i;
      uint8_t numConnectable = 0;
      uint16_t connHandle = ((gapTerminateLinkEvent_t*) pMsg)->connectionHandle;
      if (autoConnect)
      {
        groupListElem_t *tempMember;
        //Traverse from tail to head because of the sorting which put the connected at the end of the list.
		for (tempMember = (groupListElem_t *)osal_list_tail(&groupList); tempMember != NULL; tempMember = (groupListElem_t *)osal_list_prev((osal_list_elem *)tempMember)) 
        {
          if (tempMember->connHandle == connHandle)
          {
            //Move disconnected member to the head of the list for next connection.
            osal_list_remove(&groupList,(osal_list_elem *)tempMember);
            osal_list_putHead(&groupList,(osal_list_elem *)tempMember);
            //Clear the connected flag.
            tempMember->status &= ~GROUP_MEMBER_CONNECTED;
            //Clear the connnection handle.
            tempMember->connHandle = GROUP_INITIALIZED_CONNECTION_HANDLE;   
          }
        }
      }
      // Cancel timers
      SimpleCentral_CancelRssi(connHandle);
	  
	  // Mark this connection deleted in the connected device list.
      connIndex = SimpleCentral_removeConnInfo(connHandle);
      if (autoConnect)
      {
//        Uart_SendMsg(UART_HEADER_STR,20, "What are you doing2?");

//	    SimpleCentral_autoConnect();
      }
      // connIndex cannot be equal to or greater than MAX_NUM_BLE_CONNS
      SIMPLECENTRAL_ASSERT(connIndex < MAX_NUM_BLE_CONNS);

      pStrAddr = (uint8_t*) Util_convertBdAddr2Str(connList[connIndex].addr);

      Display_printf(dispHandle, SC_ROW_NON_CONN, 0, "%s is disconnected",
                     pStrAddr);
      Display_printf(dispHandle, SC_ROW_NUM_CONN, 0, "Num Conns: %d", numConn);

      for (i = 0; i < TBM_GET_NUM_ITEM(&scMenuConnect); i++)
      {
        if (!memcmp(TBM_GET_ACTION_DESC(&scMenuConnect, i), pStrAddr,
                     SC_ADDR_STR_SIZE))
        {
          // Enable this device in the connection choices
          tbm_setItemStatus(&scMenuConnect, 1 << i, SC_ITEM_NONE);
        }

        if (TBM_IS_ITEM_ACTIVE(&scMenuConnect, i))
        {
          numConnectable++;
        }
      }

      if (numConn > 0)
      {
        // There still is an active connection to select
        itemsToEnable |= SC_ITEM_SELECTCONN;
      }

      // Enable/disable items properly.
      tbm_setItemStatus(&scMenuMain,
                        itemsToEnable, SC_ITEM_ALL & ~itemsToEnable);

      // If we are in the context which the teminated connection was associated
      // with, go to main menu.
      if (connHandle == scConnHandle)
      {
        tbm_goTo(&scMenuMain);
      }

      break;
    }

    case GAP_UPDATE_LINK_PARAM_REQ_EVENT:
    {
//      Uart_SendMsg(UART_HEADER_STR, 31, "GAP_UPDATE_LINK_PARAM_REQ_EVENT");
	  gapUpdateLinkParamReqReply_t rsp;
      gapUpdateLinkParamReq_t *pReq;

      pReq = &((gapUpdateLinkParamReqEvent_t *)pMsg)->req;

      rsp.connectionHandle = pReq->connectionHandle;
      rsp.signalIdentifier = pReq->signalIdentifier;

      if (acceptParamUpdateReq)
      {
        rsp.intervalMin = pReq->intervalMin;
        rsp.intervalMax = pReq->intervalMax;
        rsp.connLatency = pReq->connLatency;
        rsp.connTimeout = pReq->connTimeout;
        rsp.accepted = TRUE;
      }
      else
      {
        // Reject the request.
        rsp.accepted = FALSE;
      }

      // Send Reply
      VOID GAP_UpdateLinkParamReqReply(&rsp);

	  if (autoConnect)
      {
//	    Uart_SendMsg(UART_HEADER_STR,20, "What are you doing3?");
        SimpleCentral_autoConnect();
      }

      break;
    }

    case GAP_LINK_PARAM_UPDATE_EVENT:
    {
//      Uart_SendMsg(UART_HEADER_STR, 27, "GAP_LINK_PARAM_UPDATE_EVENT");
      gapLinkUpdateEvent_t *pPkt = (gapLinkUpdateEvent_t *)pMsg;
      // Get the address from the connection handle
      linkDBInfo_t linkInfo;

      BLE_LOG_INT_STR(0, BLE_LOG_MODULE_APP, "APP : GAP msg status=%d, opcode=%s\n", 0, "GAP_LINK_PARAM_UPDATE_EVENT");
      if (linkDB_GetInfo(pPkt->connectionHandle, &linkInfo) ==  SUCCESS)
      {
        if(pPkt->status == SUCCESS)
        {
          Display_printf(dispHandle, SC_ROW_CUR_CONN, 0,
                         "Updated: %s, connTimeout:%d",
                         Util_convertBdAddr2Str(linkInfo.addr),
                         linkInfo.connTimeout*CONN_TIMEOUT_MS_CONVERSION);
        }
        else
        {
          // Display the address of the connection update failure
          Display_printf(dispHandle, SC_ROW_CUR_CONN, 0,
                         "Update Failed 0x%h: %s", pPkt->opcode,
                         Util_convertBdAddr2Str(linkInfo.addr));
        }
      }
      
      if (autoConnect)
      {
//        Uart_SendMsg(UART_HEADER_STR,20, "What are you doing4?");
        SimpleCentral_autoConnect();
      }

      break;
    }

#if defined ( NOTIFY_PARAM_UPDATE_RJCT )

    case GAP_LINK_PARAM_UPDATE_REJECT_EVENT:
    {
      linkDBInfo_t linkInfo;
      gapLinkUpdateEvent_t *pPkt = (gapLinkUpdateEvent_t *)pMsg;

      // Get the address from the connection handle
      linkDB_GetInfo(pPkt->connectionHandle, &linkInfo);

      // Display the address of the connection update failure
      Display_printf(dispHandle, SC_ROW_CUR_CONN, 0,
                     "Peer Device's Update Request Rejected 0x%h: %s", pPkt->opcode,
                     Util_convertBdAddr2Str(linkInfo.addr));

      break;
    }
#endif

    default:
      break;
  }
}

/*********************************************************************
 * @fn      SimpleCentral_handleKeys
 *
 * @brief   Handles all key events for this device.
 *
 * @param   keys - bit field for key events. Valid entries:
 *                 KEY_LEFT
 *                 KEY_RIGHT
 *
 * @return  none
 */
static void SimpleCentral_handleKeys(uint8_t keys)
{
  if (keys & KEY_LEFT)
  {
    // Check if the key is still pressed. Workaround for possible bouncing.
    if (GPIO_read(CONFIG_GPIO_BTN1) == 0)
    {
      tbm_buttonLeft();
    }
  }
  else if (keys & KEY_RIGHT)
  {
    // Check if the key is still pressed. Workaround for possible bouncing.
    if (GPIO_read(CONFIG_GPIO_BTN2) == 0)
    {
      tbm_buttonRight();
    }
  }
}
/*********************************************************************
 * @fn      SimpleCentral_processGATTMsg
 *
 * @brief   Process GATT messages and events.
 *
 * @return  none
 */
static void SimpleCentral_processGATTMsg(gattMsgEvent_t *pMsg)
{
  if (linkDB_Up(pMsg->connHandle))
  {
    // See if GATT server was unable to transmit an ATT response
    if (pMsg->hdr.status == blePending)
    {
//      Uart_SendMsg(UART_HEADER_STR, 20, "GATTMsg() -> Pending");
      // No HCI buffer was available. App can try to retransmit the response
      // on the next connection event. Drop it for now.
      Display_printf(dispHandle, SC_ROW_CUR_CONN, 0,
                     "ATT Rsp dropped %d", pMsg->method);
    }
    else if ((pMsg->method == ATT_READ_RSP)   ||
             ((pMsg->method == ATT_ERROR_RSP) &&
              (pMsg->msg.errorRsp.reqOpcode == ATT_READ_REQ)))
    {
      if (pMsg->method == ATT_ERROR_RSP)
      {
//        Uart_SendMsg(UART_HEADER_STR, 23, "GATTMsg() -> Read Error");
        Display_printf(dispHandle, SC_ROW_CUR_CONN, 0,
                       "Read Error %d", pMsg->msg.errorRsp.errCode);
      }
      else
      {
//        Uart_SendMsg(UART_HEADER_STR, 21, "GATTMsg() -> Read rsp");
        // After a successful read, display the read value
        Display_printf(dispHandle, SC_ROW_CUR_CONN, 0,
                       "Read rsp: 0x%02x", pMsg->msg.readRsp.pValue[0]);
      }
    }
    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)
      {
        Display_printf(dispHandle, SC_ROW_CUR_CONN, 0,
                       "Write Error %d", pMsg->msg.errorRsp.errCode);
//        Uart_SendMsg(UART_HEADER_STR, 24, "GATTMsg() -> Write Error");
      }
      else
      {
        // After a successful write, display the value that was written and
        // increment value
        Display_printf(dispHandle, SC_ROW_CUR_CONN, 0,
                       "Write sent: 0x%02x", charVal);
//        Uart_SendMsg(UART_HEADER_STR, 23, "GATTMsg() -> Write sent");
      }

      tbm_goTo(&scMenuPerConn);
    }
    else if (pMsg->method == ATT_FLOW_CTRL_VIOLATED_EVENT)
    {
      // ATT request-response or indication-confirmation flow control is
      // violated. All subsequent ATT requests or indications will be dropped.
      // The app is informed in case it wants to drop the connection.

      // Display the opcode of the message that caused the violation.
      Display_printf(dispHandle, SC_ROW_CUR_CONN, 0,
                     "FC Violated: %d", pMsg->msg.flowCtrlEvt.opcode);
//      Uart_SendMsg(UART_HEADER_STR, 24, "GATTMsg() -> FC Violated");
    }
    else if (pMsg->method == ATT_MTU_UPDATED_EVENT)
    {
      // MTU size updated
      Display_printf(dispHandle, SC_ROW_CUR_CONN, 0,
                     "MTU Size: %d", pMsg->msg.mtuEvt.MTU);
//      Uart_SendMsg(UART_HEADER_STR, 21, "GATTMsg() -> MTU Size");
    }else if(pMsg->method == ATT_HANDLE_VALUE_NOTI){
        LED_write(led_red, led_red_status);
        led_red_status = !led_red_status;
        ;
//        Uart_SendMsg(UART_HEADER_STR, 19, "GATTMsg() -> NOTIFY");
//        Uart_SendMsg(UART_HEADER_HEX, pMsg->msg.handleValueNoti.len, pMsg->msg.handleValueNoti.pValue);
    }
    else if (discState != BLE_DISC_STATE_IDLE)
    {
      SimpleCentral_processGATTDiscEvent(pMsg);
    }
  } // else - in case a GATT message came after a connection has dropped, ignore it.

  // Needed only for ATT Protocol messages
  GATT_bm_free(&pMsg->msg, pMsg->method);
}

/*********************************************************************
 * @fn      SimpleCentral_processCmdCompleteEvt
 *
 * @brief   Process an incoming OSAL HCI Command Complete Event.
 *
 * @param   pMsg - message to process
 *
 * @return  none
 */
static void SimpleCentral_processCmdCompleteEvt(hciEvt_CmdComplete_t *pMsg)
{
  switch (pMsg->cmdOpcode)
  {
    case HCI_READ_RSSI:
    {
#ifndef Display_DISABLE_ALL
      uint16_t connHandle = BUILD_UINT16(pMsg->pReturnParam[1],
                                         pMsg->pReturnParam[2]);
      int8 rssi = (int8)pMsg->pReturnParam[3];
//      char *str = "Rssi is 0";
//      str[8] += rssi;
//      Uart_SendMsg(UART_HEADER_STR,9, str);
	  Display_printf(dispHandle, SC_ROW_ANY_CONN, 0, "%s: RSSI %d dBm",
                   SimpleCentral_getConnAddrStr(connHandle), rssi);

#endif
      break;
    }
    default:
      break;
  }
}

/*********************************************************************
 * @fn      SimpleCentral_StartRssi
 *
 * @brief   Start periodic RSSI reads on the current link.
 *
 * @return  SUCCESS: RSSI Read timer started
 *          bleIncorrectMode: Aready started
 *          bleNoResources: No resources
 */
static status_t SimpleCentral_StartRssi(void)
{
//    Uart_SendMsg(UART_HEADER_STR, 26, "SimpleCentral_StartRssi()");
  uint8_t connIndex = SimpleCentral_getConnIndex(scConnHandle);
//  char *str = "The index of connection is 0";
//  str[27] += connIndex;
//  Uart_SendMsg(UART_HEADER_STR,28, str);
  // connIndex cannot be equal to or greater than MAX_NUM_BLE_CONNS
  SIMPLECENTRAL_ASSERT(connIndex < MAX_NUM_BLE_CONNS);
//  Uart_SendMsg(UART_HEADER_STR, 31, "SimpleCentral_StartRssi() exit");
  // If already running
  if (connList[connIndex].pRssiClock != NULL)
  {
    return bleIncorrectMode;
  }

  // Create a clock object and start
  connList[connIndex].pRssiClock
    = (Clock_Struct*) ICall_malloc(sizeof(Clock_Struct));

  if (connList[connIndex].pRssiClock)
  {
    Util_constructClock(connList[connIndex].pRssiClock,
                        SimpleCentral_clockHandler,
                        DEFAULT_RSSI_PERIOD, 0, true,
                        (connIndex << 8) | SC_EVT_READ_RSSI);
  }
  else
  {
    return bleNoResources;
  }

  return SUCCESS;
}

/*********************************************************************
 * @fn      SimpleCentral_CancelRssi
 *
 * @brief   Cancel periodic RSSI reads on a link.
 *
 * @param   connection handle
 *
 * @return  SUCCESS: Operation successful
 *          bleIncorrectMode: Has not started
 */
static status_t SimpleCentral_CancelRssi(uint16_t connHandle)
{
//    Uart_SendMsg(UART_HEADER_STR, 27, "SimpleCentral_CancelRssi()");
  uint8_t connIndex = SimpleCentral_getConnIndex(connHandle);

  // connIndex cannot be equal to or greater than MAX_NUM_BLE_CONNS
  SIMPLECENTRAL_ASSERT(connIndex < MAX_NUM_BLE_CONNS);

  // If already running
  if (connList[connIndex].pRssiClock == NULL)
  {
    return bleIncorrectMode;
  }

  // Stop timer
  Util_stopClock(connList[connIndex].pRssiClock);

  // Destroy the clock object
  Clock_destruct(connList[connIndex].pRssiClock);

  // Free clock struct
  ICall_free(connList[connIndex].pRssiClock);
  connList[connIndex].pRssiClock = NULL;

  Display_clearLine(dispHandle, SC_ROW_ANY_CONN);
//  Uart_SendMsg(UART_HEADER_STR, 32, "SimpleCentral_CancelRssi() exit");
  return SUCCESS;
}

/*********************************************************************
 * @fn      SimpleCentral_processPairState
 *
 * @brief   Process the new paring state.
 *
 * @return  none
 */
static void SimpleCentral_processPairState(uint8_t state,
                                           scPairStateData_t* pPairData)
{
//  Uart_SendMsg(UART_HEADER_STR, 33, "SimpleCentral_processPairState()");
  uint8_t status = pPairData->status;
  uint8_t pairMode = 0;

  if (state == GAPBOND_PAIRING_STATE_STARTED)
  {
    Display_printf(dispHandle, SC_ROW_CUR_CONN, 0, "Pairing started");
  }
  else if (state == GAPBOND_PAIRING_STATE_COMPLETE)
  {
    if (status == SUCCESS)
    {
      linkDBInfo_t linkInfo;

      Display_printf(dispHandle, SC_ROW_CUR_CONN, 0, "Pairing success");

      if (linkDB_GetInfo(pPairData->connHandle, &linkInfo) == SUCCESS)
      {
        // If the peer was using private address, update with ID address
        if ((linkInfo.addrType == ADDRTYPE_PUBLIC_ID ||
             linkInfo.addrType == ADDRTYPE_RANDOM_ID) &&
             !Util_isBufSet(linkInfo.addrPriv, 0, B_ADDR_LEN))
        {
          // Update the address of the peer to the ID address
          Display_printf(dispHandle, SC_ROW_NON_CONN, 0, "Addr updated: %s",
                         Util_convertBdAddr2Str(linkInfo.addr));

          // Update the connection list with the ID address
          uint8_t i = SimpleCentral_getConnIndex(pPairData->connHandle);

          SIMPLECENTRAL_ASSERT(i < MAX_NUM_BLE_CONNS);
          memcpy(connList[i].addr, linkInfo.addr, B_ADDR_LEN);
        }
      }
    }
    else
    {
      Display_printf(dispHandle, SC_ROW_CUR_CONN, 0, "Pairing fail: %d", status);
    }

    GAPBondMgr_GetParameter(GAPBOND_PAIRING_MODE, &pairMode);

    if ((autoConnect) && (pairMode == GAPBOND_PAIRING_MODE_INITIATE))
    {
	  SimpleCentral_autoConnect();
    }
  }
  else if (state == GAPBOND_PAIRING_STATE_ENCRYPTED)
  {
    if (status == SUCCESS)
    {
      Display_printf(dispHandle, SC_ROW_CUR_CONN, 0, "Encryption success");
    }
    else
    {
      Display_printf(dispHandle, SC_ROW_CUR_CONN, 0, "Encryption failed: %d", status);
    }

    GAPBondMgr_GetParameter(GAPBOND_PAIRING_MODE, &pairMode);

    if ((autoConnect) && (pairMode == GAPBOND_PAIRING_MODE_INITIATE))
    {
      SimpleCentral_autoConnect();
    }
  }
  else if (state == GAPBOND_PAIRING_STATE_BOND_SAVED)
  {
    if (status == SUCCESS)
    {
      Display_printf(dispHandle, SC_ROW_CUR_CONN, 0, "Bond save success");
    }
    else
    {
      Display_printf(dispHandle, SC_ROW_CUR_CONN, 0, "Bond save failed: %d", status);
    }
  }
//  Uart_SendMsg(UART_HEADER_STR, 38, "SimpleCentral_processPairState() exit");
}

/*********************************************************************
 * @fn      SimpleCentral_processPasscode
 *
 * @brief   Process the Passcode request.
 *
 * @return  none
 */
static void SimpleCentral_processPasscode(scPasscodeData_t *pData)
{
  // Display passcode to user
  if (pData->uiOutputs != 0)
  {
    Display_printf(dispHandle, SC_ROW_CUR_CONN, 0, "Passcode: %d",
                   B_APP_DEFAULT_PASSCODE);
  }

  // Send passcode response
  GAPBondMgr_PasscodeRsp(pData->connHandle, SUCCESS, B_APP_DEFAULT_PASSCODE);
}

/*********************************************************************
 * @fn      SimpleCentral_startSvcDiscovery
 *
 * @brief   Start service discovery.
 *
 * @return  none
 */
static void SimpleCentral_startSvcDiscovery(void)
{
  attExchangeMTUReq_t req;

  // Initialize cached handles
  svcStartHdl = svcEndHdl = 0;

  discState = BLE_DISC_STATE_MTU;

  // Discover GATT Server's Rx MTU size
  req.clientRxMTU = scMaxPduSize - L2CAP_HDR_SIZE;

  // ATT MTU size should be set to the minimum of the Client Rx MTU
  // and Server Rx MTU values

  bStatus_t res =  GATT_ExchangeMTU(scConnHandle, &req, selfEntity);
  LED_setOn(led_red, 100);
//  if(res == SUCCESS){
//      Uart_SendMsg(UART_HEADER_STR, 19, "ExchangeMTU SUCCESS");
//  }else{
//      uint8_t res_p[] = {0x00, 0x11, 0x22, 0x33};
//      res_p[3] = res;
//      Uart_SendMsg(UART_HEADER_HEX, 4, res_p);
//  }
}

/*********************************************************************
 * @fn      SimpleCentral_processGATTDiscEvent
 *
 * @brief   Process GATT discovery event
 *
 * @return  none
 */
static void SimpleCentral_processGATTDiscEvent(gattMsgEvent_t *pMsg)
{
  if (discState == BLE_DISC_STATE_MTU)
  {
//    Uart_SendMsg(UART_HEADER_STR, 20, "GATTDiscEvent -> MTU");
    // MTU size response received, discover simple service
    if (pMsg->method == ATT_EXCHANGE_MTU_RSP)
    {
      uint8_t uuid[ATT_BT_UUID_SIZE] = { LO_UINT16(SIMPLEPROFILE_SERV_UUID),
                                         HI_UINT16(SIMPLEPROFILE_SERV_UUID) };

      discState = BLE_DISC_STATE_SVC;

      // Discovery simple service
//      VOID GATT_DiscPrimaryServiceByUUID(pMsg->connHandle, uuid,
//                                         ATT_BT_UUID_SIZE, selfEntity);

      bStatus_t res = GATT_DiscPrimaryServiceByUUID(pMsg->connHandle, uuid,
                                           ATT_BT_UUID_SIZE, selfEntity);
    }else{
//        Uart_SendMsg(UART_HEADER_STR, 23+4, "GATTDiscEvent -> MTU : None");
    }
  }
  else if (discState == BLE_DISC_STATE_SVC)
  {
//      Uart_SendMsg(UART_HEADER_STR, 20, "GATTDiscEvent -> SVC");
    // Service found, store handles
    if (pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
        pMsg->msg.findByTypeValueRsp.numInfo > 0)
    {
      svcStartHdl = ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
      svcEndHdl = ATT_GRP_END_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
    }

    // If procedure complete
    if (((pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP) &&
         (pMsg->hdr.status == bleProcedureComplete))  ||
        (pMsg->method == ATT_ERROR_RSP))
    {
      if (svcStartHdl != 0)
      {
        attReadByTypeReq_t req;

        // Discover characteristic
        discState = BLE_DISC_STATE_CHAR;

        req.startHandle = svcStartHdl;
        req.endHandle = svcEndHdl;
        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);

        VOID GATT_DiscCharsByUUID(pMsg->connHandle, &req, selfEntity);
      }
    }
  }
  else if (discState == BLE_DISC_STATE_CHAR)
  {
//      Uart_SendMsg(UART_HEADER_STR, 21, "GATTDiscEvent -> CHAR");
    // Characteristic found, store handle
    if ((pMsg->method == ATT_READ_BY_TYPE_RSP) &&
        (pMsg->msg.readByTypeRsp.numPairs > 0))
    {
      uint8_t connIndex = SimpleCentral_getConnIndex(scConnHandle);

      // connIndex cannot be equal to or greater than MAX_NUM_BLE_CONNS
      SIMPLECENTRAL_ASSERT(connIndex < MAX_NUM_BLE_CONNS);

 	  // Store the handle of the simpleprofile characteristic 1 value
      connList[connIndex].charHandle
        = BUILD_UINT16(pMsg->msg.readByTypeRsp.pDataList[3],
                       pMsg->msg.readByTypeRsp.pDataList[4]);

      Display_printf(dispHandle, SC_ROW_CUR_CONN, 0, "Simple Svc Found");

      // Now we can use GATT Read/Write
      tbm_setItemStatus(&scMenuPerConn,
                        SC_ITEM_GATTREAD | SC_ITEM_GATTWRITE, SC_ITEM_NONE);
    }

    discState = BLE_DISC_STATE_IDLE;
  }
}

#if (DEFAULT_DEV_DISC_BY_SVC_UUID == TRUE)
/*********************************************************************
 * @fn      SimpleCentral_findSvcUuid
 *
 * @brief   Find a given UUID in an advertiser's service UUID list.
 *
 * @return  TRUE if service UUID found
 */
static bool SimpleCentral_findSvcUuid(uint16_t uuid, uint8_t *pData,
                                      uint16_t dataLen)
{
  uint8_t adLen;
  uint8_t adType;
  uint8_t *pEnd;

  if (dataLen > 0)
  {
    pEnd = pData + dataLen - 1;

    // While end of data not reached
    while (pData < pEnd)
    {
      // Get length of next AD item
      adLen = *pData++;
      if (adLen > 0)
      {
        adType = *pData;

        // If AD type is for 16-bit service UUID
        if ((adType == GAP_ADTYPE_16BIT_MORE) ||
            (adType == GAP_ADTYPE_16BIT_COMPLETE))
        {
          pData++;
          adLen--;

          // For each UUID in list
          while (adLen >= 2 && pData < pEnd)
          {
            // Check for match
            if ((pData[0] == LO_UINT16(uuid)) && (pData[1] == HI_UINT16(uuid)))
            {
              // Match found
              return TRUE;
            }

            // Go to next
            pData += 2;
            adLen -= 2;
          }

          // Handle possible erroneous extra byte in UUID list
          if (adLen == 1)
          {
            pData++;
          }
        }
        else
        {
          // Go to next item
          pData += adLen;
        }
      }
    }
  }

  // Match not found
  return FALSE;
}

/*********************************************************************
 * @fn      SimpleCentral_addScanInfo
 *
 * @brief   Add a device to the scanned device list
 *
 * @return  none
 */
static void SimpleCentral_addScanInfo(uint8_t *pAddr, uint8_t addrType)
{
  uint8_t i;

  // If result count not at max
  if (numScanRes < DEFAULT_MAX_SCAN_RES)
  {
    // Check if device is already in scan results
    for (i = 0; i < numScanRes; i++)
    {
      if (memcmp(pAddr, scanList[i].addr , B_ADDR_LEN) == 0)
      {
        return;
      }
    }

    // Add addr to scan result list
    memcpy(scanList[numScanRes].addr, pAddr, B_ADDR_LEN);
    scanList[numScanRes].addrType = addrType;

    // Increment scan result count
    numScanRes++;
  }
}
#endif // DEFAULT_DEV_DISC_BY_SVC_UUID

/*********************************************************************
 * @fn      SimpleCentral_addConnInfo
 *
 * @brief   Add a device to the connected device list
 *
 * @return  index of the connected device list entry where the new connection
 *          info is put in.
 *          if there is no room, MAX_NUM_BLE_CONNS will be returned.
 */
static uint8_t SimpleCentral_addConnInfo(uint16_t connHandle, uint8_t *pAddr)
{
  uint8_t i;

  for (i = 0; i < MAX_NUM_BLE_CONNS; i++)
  {
    if (connList[i].connHandle == LINKDB_CONNHANDLE_INVALID)
    {
      // Found available entry to put a new connection info in
      connList[i].connHandle = connHandle;
      memcpy(connList[i].addr, pAddr, B_ADDR_LEN);
      numConn++;

      break;
    }
  }

  return i;
}

/*********************************************************************
 * @fn      SimpleCentral_removeConnInfo
 *
 * @brief   Remove a device from the connected device list
 *
 * @return  index of the connected device list entry where the new connection
 *          info is removed from.
 *          if connHandle is not found, MAX_NUM_BLE_CONNS will be returned.
 */
static uint8_t SimpleCentral_removeConnInfo(uint16_t connHandle)
{
  uint8_t i;

  for (i = 0; i < MAX_NUM_BLE_CONNS; i++)
  {
    if (connList[i].connHandle == connHandle)
    {
      // Found the entry to mark as deleted
      connList[i].connHandle = LINKDB_CONNHANDLE_INVALID;
      numConn--;

      break;
    }
  }

  return i;
}

/*********************************************************************
 * @fn      SimpleCentral_getConnIndex
 *
 * @brief   Find index in the connected device list by connHandle
 *
 * @return  the index of the entry that has the given connection handle.
 *          if there is no match, MAX_NUM_BLE_CONNS will be returned.
 */
static uint8_t SimpleCentral_getConnIndex(uint16_t connHandle)
{
  uint8_t i;

  for (i = 0; i < MAX_NUM_BLE_CONNS; i++)
  {
    if (connList[i].connHandle == connHandle)
    {
      break;
    }
  }
//  Uart_SendMsg(UART_HEADER_STR, 20, "Get connection index");
//  str1[13] = i + '0';
  return i;
}

#ifndef Display_DISABLE_ALL
/*********************************************************************
 * @fn      SimpleCentral_getConnAddrStr
 *
 * @brief   Return, in string form, the address of the peer associated with
 *          the connHandle.
 *
 * @return  A null-terminated string of the address.
 *          if there is no match, NULL will be returned.
 */
static char* SimpleCentral_getConnAddrStr(uint16_t connHandle)
{
  uint8_t i;

  for (i = 0; i < MAX_NUM_BLE_CONNS; i++)
  {
    if (connList[i].connHandle == connHandle)
    {
      return Util_convertBdAddr2Str(connList[i].addr);
    }
  }

  return NULL;
}
#endif

/*********************************************************************
 * @fn      SimpleCentral_pairStateCb
 *
 * @brief   Pairing state callback.
 *
 * @return  none
 */
static void SimpleCentral_pairStateCb(uint16_t connHandle, uint8_t state,
                                      uint8_t status)
{
  scPairStateData_t *pData;

  // Allocate space for the event data.
  if ((pData = ICall_malloc(sizeof(scPairStateData_t))))
  {
    pData->connHandle = connHandle;
    pData->status = status;

    // Queue the event.
    if(SimpleCentral_enqueueMsg(SC_EVT_PAIR_STATE, state, (uint8_t*) pData) != SUCCESS)
    {
      ICall_free(pData);
    }
  }
}

/*********************************************************************
* @fn      SimpleCentral_passcodeCb
*
* @brief   Passcode callback.
*
* @param   deviceAddr - pointer to device address
*
* @param   connHandle - the connection handle
*
* @param   uiInputs - pairing User Interface Inputs
*
* @param   uiOutputs - pairing User Interface Outputs
*
* @param   numComparison - numeric Comparison 20 bits
*
* @return  none
*/
static void SimpleCentral_passcodeCb(uint8_t *deviceAddr, uint16_t connHandle,
                                  uint8_t uiInputs, uint8_t uiOutputs,
                                  uint32_t numComparison)
{
  scPasscodeData_t *pData = ICall_malloc(sizeof(scPasscodeData_t));

  // Allocate space for the passcode event.
  if (pData)
  {
    pData->connHandle = connHandle;
    memcpy(pData->deviceAddr, deviceAddr, B_ADDR_LEN);
    pData->uiInputs = uiInputs;
    pData->uiOutputs = uiOutputs;
    pData->numComparison = numComparison;

    // Enqueue the event.
    if (SimpleCentral_enqueueMsg(SC_EVT_PASSCODE_NEEDED, 0,(uint8_t *) pData) != SUCCESS)
    {
      ICall_free(pData);
    }
  }
}

/*********************************************************************
 * @fn      SimpleCentral_keyChangeHandler
 *
 * @brief   Key event handler function
 *
 * @param   a0 - ignored
 *
 * @return  none
 */
static void SimpleCentral_keyChangeHandler(uint8 keys)
{
  SimpleCentral_enqueueMsg(SC_EVT_KEY_CHANGE, keys, NULL);
}

/*********************************************************************
 * @fn      SimpleCentral_clockHandler
 *
 * @brief   clock handler function
 *
 * @param   arg - argument from the clock initiator
 *
 * @return  none
 */
void SimpleCentral_clockHandler(UArg arg)
{
  uint8_t evtId = (uint8_t) (arg & 0xFF);

  switch (evtId)
  {
    case SC_EVT_READ_RSSI:
      SimpleCentral_enqueueMsg(SC_EVT_READ_RSSI, (uint8_t) (arg >> 8) , NULL);
      break;

    case SC_EVT_READ_RPA:
      // Restart timer
      Util_startClock(&clkRpaRead);
      // Let the application handle the event
      SimpleCentral_enqueueMsg(SC_EVT_READ_RPA, 0, NULL);
      break;

    case SC_EVT_UART_WRITE:
        Event_post(syncEvent, SC_UART_EVT);
        break;
    case SC_EVT_START_DISCOVERY:
        SimpleCentral_enqueueMsg(SC_EVT_SVC_DISC, 0, NULL);
    default:
      break;
  }
}

/*********************************************************************
 * @fn      SimpleCentral_enqueueMsg
 *
 * @brief   Creates a message and puts the message in RTOS queue.
 *
 * @param   event - message event.
 * @param   state - message state.
 * @param   pData - message data pointer.
 *
 * @return  TRUE or FALSE
 */
static status_t SimpleCentral_enqueueMsg(uint8_t event, uint8_t state,
                                           uint8_t *pData)
{
  uint8_t success;
  scEvt_t *pMsg = ICall_malloc(sizeof(scEvt_t));

  // Create dynamic pointer to message.
  if (pMsg)
  {
    pMsg->hdr.event = event;
    pMsg->hdr.state = state;
    pMsg->pData = pData;

    // Enqueue the message.
    success = Util_enqueueMsg(appMsgQueue, syncEvent, (uint8_t *)pMsg);
    return (success) ? SUCCESS : FAILURE;
  }

  return(bleMemAllocError);
}

/*********************************************************************
 * @fn      SimpleCentral_scanCb
 *
 * @brief   Callback called by GapScan module
 *
 * @param   evt - event
 * @param   msg - message coming with the event
 * @param   arg - user argument
 *
 * @return  none
 */
void SimpleCentral_scanCb(uint32_t evt, void* pMsg, uintptr_t arg)
{
  uint8_t event;

  if (evt & GAP_EVT_ADV_REPORT)
  {
    event = SC_EVT_ADV_REPORT;
  }
  else if (evt & GAP_EVT_SCAN_ENABLED)
  {
    event = SC_EVT_SCAN_ENABLED;
  }
  else if (evt & GAP_EVT_SCAN_DISABLED)
  {
    event = SC_EVT_SCAN_DISABLED;
  }
  else if (evt & GAP_EVT_INSUFFICIENT_MEMORY)
  {
    event = SC_EVT_INSUFFICIENT_MEM;
  }
  else
  {
    return;
  }

  if(SimpleCentral_enqueueMsg(event, SUCCESS, pMsg) != SUCCESS)
  {
    ICall_free(pMsg);
  }
}

/*********************************************************************
 * @fn      SimpleCentral_doAutoConnect
 *
 * @brief   Enable/Disable AutoConnect.
 *
 * @param   index - 0 : Disable AutoConnect
 *                  1 : Enable Group A
 *                  2 : Enable Group B
 *
 * @return  always true
 */
bool SimpleCentral_doAutoConnect(uint8_t index)
{
    if (index == 1)
    {
      if ((autoConnect) && (autoConnect != AUTOCONNECT_GROUP_A))
      {
        groupListElem_t *tempMember;
        //Traverse list to search if advertiser already in list.
        for (tempMember = (groupListElem_t *)osal_list_head(&groupList); tempMember != NULL; tempMember = (groupListElem_t *)osal_list_next((osal_list_elem *)tempMember)) 
        {
          osal_list_remove(&groupList,(osal_list_elem *)tempMember);
          ICall_free(tempMember);
        }
		numGroupMembers = 0;
      }	
	  Display_printf(dispHandle, SC_ROW_AC, 0, "AutoConnect enabled: Group A");
      autoConnect = AUTOCONNECT_GROUP_A;
      acGroup[3] = 'A';
    }
    else if (index == 2)
    {
      if ((autoConnect) && (autoConnect != AUTOCONNECT_GROUP_B))
      {
        groupListElem_t *tempMember;
        //Traverse list to search if advertiser already in list.
        for (tempMember = (groupListElem_t *)osal_list_head(&groupList); tempMember != NULL; tempMember = (groupListElem_t *)osal_list_next((osal_list_elem *)tempMember)) 
        {
          osal_list_remove(&groupList,(osal_list_elem *)tempMember);
          ICall_free(tempMember);
        }
		numGroupMembers = 0;
      }
      Display_printf(dispHandle, SC_ROW_AC, 0, "AutoConnect enabled: Group B");
      autoConnect = AUTOCONNECT_GROUP_B;
      acGroup[3] = 'B';
    }
    else
    {
      autoConnect = AUTOCONNECT_DISABLE;
      groupListElem_t *tempMember;
      //Traverse list to search if advertiser already in list.
      for (tempMember = (groupListElem_t *)osal_list_head(&groupList); tempMember != NULL; tempMember = (groupListElem_t *)osal_list_next((osal_list_elem *)tempMember)) 
      {
        osal_list_remove(&groupList,(osal_list_elem *)tempMember);
        ICall_free(tempMember);
      }
	  numGroupMembers = 0;
      Display_printf(dispHandle, SC_ROW_AC, 0, "AutoConnect disabled");
    }
    if ((autoConnect) && (MAX_NUM_BLE_CONNS > 8))
    {
	  //Disable accepting L2CAP param upadte request
      acceptParamUpdateReq = false;
	  //Disable all parameter update requests
	  GAP_SetParamValue(GAP_PARAM_LINK_UPDATE_DECISION, GAP_UPDATE_REQ_DENY_ALL);
	  //Set connection interval and supervision timeout
      GapInit_setPhyParam(INIT_PHY_1M | INIT_PHY_2M | INIT_PHY_CODED,INIT_PHYPARAM_CONN_INT_MAX,DEFAULT_MULTICON_INTERVAL);
      GapInit_setPhyParam(INIT_PHY_1M | INIT_PHY_2M | INIT_PHY_CODED,INIT_PHYPARAM_CONN_INT_MIN,DEFAULT_MULTICON_INTERVAL);
	  GapInit_setPhyParam(INIT_PHY_1M | INIT_PHY_2M | INIT_PHY_CODED,INIT_PHYPARAM_SUP_TIMEOUT,DEFAULT_MULTICON_LSTO);
    }
 
    tbm_goTo(&scMenuMain);
    
    return (true);
}

/*********************************************************************
 * @fn      SimpleCentral_doSetScanPhy
 *
 * @brief   Set PHYs for scanning.
 *
 * @param   index - 0: 1M PHY
 *                  1: CODED PHY (Long range)
 *
 * @return  always true
 */
bool SimpleCentral_doSetScanPhy(uint8_t index)
{
  uint8_t temp8;

  if (index == 0)
  {
    temp8 = SCAN_PRIM_PHY_1M;
  }
  else
  {
    temp8 = SCAN_PRIM_PHY_CODED;
  }

  // Set scanning primary PHY
  GapScan_setParam(SCAN_PARAM_PRIM_PHYS, &temp8);

  Display_printf(dispHandle, SC_ROW_NON_CONN, 0, "Primary Scan PHY: %s",
                 TBM_GET_ACTION_DESC(&scMenuScanPhy, index));

  tbm_goTo(&scMenuMain);

  return (true);
}

/*********************************************************************
 * @fn      SimpleCentral_doDiscoverDevices
 *
 * @brief   Enables scanning
 *
 * @param   index - item index from the menu
 *
 * @return  always true
 */
bool SimpleCentral_doDiscoverDevices(uint8_t index)
{
  (void) index;

#if (DEFAULT_DEV_DISC_BY_SVC_UUID == TRUE)
  // Scanning for DEFAULT_SCAN_DURATION x 10 ms.
  // The stack does not need to record advertising reports
  // since the application will filter them by Service UUID and save.
  // Reset number of scan results to 0 before starting scan
  numScanRes = 0;
  GapScan_enable(0, DEFAULT_SCAN_DURATION, 0);
#else // !DEFAULT_DEV_DISC_BY_SVC_UUID
  // Scanning for DEFAULT_SCAN_DURATION x 10 ms.
  // Let the stack record the advertising reports as many as up to DEFAULT_MAX_SCAN_RES.
  GapScan_enable(0, DEFAULT_SCAN_DURATION, DEFAULT_MAX_SCAN_RES);
#endif // DEFAULT_DEV_DISC_BY_SVC_UUID

  // Enable only "Stop Discovering" and disable all others in the main menu
  tbm_setItemStatus(&scMenuMain, SC_ITEM_STOPDISC,
                    (SC_ITEM_ALL & ~SC_ITEM_STOPDISC));

  return (true);
}

/*********************************************************************
 * @fn      SimpleCentral_doStopDiscovering
 *
 * @brief   Stop on-going scanning
 *
 * @param   index - item index from the menu
 *
 * @return  always true
 */
bool SimpleCentral_doStopDiscovering(uint8_t index)
{
  (void) index;

  GapScan_disable("");

  return (true);
}

/*********************************************************************
 * @fn      SimpleCentral_doEstablishLink
 *
 * @brief   Establish a link to a peer device
 *
 * @param   index - item index from the menu
 *
 * @return  always true
 */
bool SimpleCentral_doConnect(uint8_t index)
{
#if (DEFAULT_DEV_DISC_BY_SVC_UUID == TRUE)
  GapInit_connect(scanList[index].addrType & MASK_ADDRTYPE_ID,
                  scanList[index].addr, DEFAULT_INIT_PHY, 0);
#else // !DEFAULT_DEV_DISC_BY_SVC_UUID
  GapScan_Evt_AdvRpt_t advRpt;

  GapScan_getAdvReport(index, &advRpt);

  GapInit_connect(advRpt.addrType & MASK_ADDRTYPE_ID,
                  advRpt.addr, DEFAULT_INIT_PHY, 0);
#endif // DEFAULT_DEV_DISC_BY_SVC_UUID

  // Enable only "Cancel Connecting" and disable all others in the main menu
  tbm_setItemStatus(&scMenuMain, SC_ITEM_CANCELCONN,
                    (SC_ITEM_ALL & ~SC_ITEM_CANCELCONN));

  Display_printf(dispHandle, SC_ROW_NON_CONN, 0, "Connecting...");

  tbm_goTo(&scMenuMain);

  return (true);
}

/*********************************************************************
 * @fn      SimpleCentral_doCancelConnecting
 *
 * @brief   Cancel on-going connection attempt
 *
 * @param   index - item index from the menu
 *
 * @return  always true
 */
bool SimpleCentral_doCancelConnecting(uint8_t index)
{
  (void) index;
//  Uart_SendMsg(UART_HEADER_STR, 15, "CancelConnecting");
  GapInit_cancelConnect("");

  return (true);
}

/*********************************************************************
 * @fn      SimpleCentral_doSelectConn
 *
 * @brief   Select a connection to communicate with
 *
 * @param   index - item index from the menu
 *
 * @return  always true
 */
bool SimpleCentral_doSelectConn(uint8_t index)
{
  uint32_t itemsToDisable = SC_ITEM_NONE;

  // index cannot be equal to or greater than MAX_NUM_BLE_CONNS
  SIMPLECENTRAL_ASSERT(index < MAX_NUM_BLE_CONNS);

  scConnHandle = connList[index].connHandle;

  if (connList[index].charHandle == 0)
  {
    // Initiate service discovery
    SimpleCentral_enqueueMsg(SC_EVT_SVC_DISC, 0, NULL);

    // Diable GATT Read/Write until simple service is found
    itemsToDisable = SC_ITEM_GATTREAD | SC_ITEM_GATTWRITE;
  }

  // Set the menu title and go to this connection's context
  TBM_SET_TITLE(&scMenuPerConn, TBM_GET_ACTION_DESC(&scMenuSelectConn, index));

  // Set RSSI items properly depending on current state
  if (connList[index].pRssiClock == NULL)
  {
    tbm_setItemStatus(&scMenuPerConn,
                      SC_ITEM_STRTRSSI, SC_ITEM_STOPRSSI | itemsToDisable);
  }
  else
  {
    tbm_setItemStatus(&scMenuPerConn,
                      SC_ITEM_STOPRSSI, SC_ITEM_STRTRSSI | itemsToDisable);
  }

  // Clear non-connection-related message
  Display_clearLine(dispHandle, SC_ROW_NON_CONN);

  tbm_goTo(&scMenuPerConn);

  return (true);
}

/*********************************************************************
 * @fn      SimpleCentral_doGattRead
 *
 * @brief   GATT Read
 *
 * @param   index - item index from the menu
 *
 * @return  always true
 */
bool SimpleCentral_doGattRead(uint8_t index)
{
  attReadReq_t req;
//  Uart_SendMsg(UART_HEADER_STR, 27, "SimpleCentral_doGattRead()");
  uint8_t connIndex = SimpleCentral_getConnIndex(scConnHandle);

  // connIndex cannot be equal to or greater than MAX_NUM_BLE_CONNS
  SIMPLECENTRAL_ASSERT(connIndex < MAX_NUM_BLE_CONNS);

  req.handle = connList[connIndex].charHandle;
  GATT_ReadCharValue(scConnHandle, &req, selfEntity);
//  Uart_SendMsg(UART_HEADER_STR, 32, "SimpleCentral_doGattRead() exit");
  return (true);
}

/*********************************************************************
 * @fn      SimpleCentral_doGattWrite
 *
 * @brief   GATT Write
 *
 * @param   index - item index from the menu
 *
 * @return  always true
 */
bool SimpleCentral_doGattWrite(uint8_t index)
{
//  Uart_SendMsg(UART_HEADER_STR, 28, "SimpleCentral_doGattWrite()");
  status_t status;
  uint8_t charVals[4] = { 0x00, 0x55, 0xAA, 0xFF }; // Should be consistent with
                                                    // those in scMenuGattWrite

  attWriteReq_t req;

  req.pValue = GATT_bm_alloc(scConnHandle, ATT_WRITE_REQ, 1, NULL);

  if ( req.pValue != NULL )
  {
    uint8_t connIndex = SimpleCentral_getConnIndex(scConnHandle);

    // connIndex cannot be equal to or greater than MAX_NUM_BLE_CONNS
    SIMPLECENTRAL_ASSERT(connIndex < MAX_NUM_BLE_CONNS);

    req.handle = connList[connIndex].charHandle;
    req.len = 1;
    charVal = charVals[index];    
    req.pValue[0] = charVal;
    req.sig = 0;
    req.cmd = 0;

    status = GATT_WriteCharValue(scConnHandle, &req, selfEntity);
    if ( status != SUCCESS )
    {
      GATT_bm_free((gattMsg_t *)&req, ATT_WRITE_REQ);
    }
  }
//  Uart_SendMsg(UART_HEADER_STR, 33, "SimpleCentral_doGattWrite() exit");
  return (true);
}

/*********************************************************************
 * @fn      SimpleCentral_doRssiRead
 *
 * @brief   Toggle RSSI Read
 *
 * @param   index - item index from the menu
 *
 * @return  always true
 */
bool SimpleCentral_doRssiRead(uint8_t index)
{
  status_t status;

  if ((1 << index) == SC_ITEM_STRTRSSI)
  {
//    Uart_SendMsg(UART_HEADER_STR,18, "Start to read rssi");
    if ((status = SimpleCentral_StartRssi()) == SUCCESS)
    {
//      Uart_SendMsg(UART_HEADER_STR,17, "Rssi read started");
      tbm_setItemStatus(&scMenuPerConn, SC_ITEM_STOPRSSI, SC_ITEM_STRTRSSI);
    }else{
//        Uart_SendMsg(UART_HEADER_STR,16, "Rssi read failed");
    }
  }
  else // SC_ITEM_STOP_RSSI
  {
//    Uart_SendMsg(UART_HEADER_STR,17, "Stop reading rssi");
    if ((status = SimpleCentral_CancelRssi(scConnHandle)) == SUCCESS)
    {
      tbm_setItemStatus(&scMenuPerConn, SC_ITEM_STRTRSSI, SC_ITEM_STOPRSSI);
    }
  }

  return ((status == SUCCESS) ? true : false);
}

/*********************************************************************
 * @fn      SimpleCentral_doConnUpdate
 *
 * @brief   Initiate Connection Update procedure
 *
 * @param   index - item index from the menu
 *
 * @return  always true
 */
bool SimpleCentral_doConnUpdate(uint8_t index)
{
  gapUpdateLinkParamReq_t params;

  (void) index;

  params.connectionHandle = scConnHandle;
  params.intervalMin = DEFAULT_UPDATE_MIN_CONN_INTERVAL;
  params.intervalMax = DEFAULT_UPDATE_MAX_CONN_INTERVAL;
  params.connLatency = DEFAULT_UPDATE_SLAVE_LATENCY;

  linkDBInfo_t linkInfo;
  if (linkDB_GetInfo(scConnHandle, &linkInfo) == SUCCESS)
  {
    if (linkInfo.connTimeout == DEFAULT_UPDATE_CONN_TIMEOUT)
    {
      params.connTimeout = DEFAULT_UPDATE_CONN_TIMEOUT + 200;
    }
    else
    {
      params.connTimeout = DEFAULT_UPDATE_CONN_TIMEOUT;
    }
    GAP_UpdateLinkParamReq(&params);

    Display_printf(dispHandle, SC_ROW_CUR_CONN, 0, "Param update Request:connTimeout =%d",
                    params.connTimeout*CONN_TIMEOUT_MS_CONVERSION);
  }
  else
  {
    Display_printf(dispHandle, SC_ROW_CUR_CONN, 0,
                   "update :%s, Unable to find link information",
                    Util_convertBdAddr2Str(linkInfo.addr));
  }
  return (true);
}

/*********************************************************************
 * @fn      SimpleCentral_doSetConnPhy
 *
 * @brief   Set Connection PHY preference.
 *
 * @param   index - 0: 1M PHY
 *                  1: 2M PHY
 *                  2: 1M + 2M PHY
 *                  3: CODED PHY (Long range)
 *                  4: 1M + 2M + CODED PHY
 *
 * @return  always true
 */
bool SimpleCentral_doSetConnPhy(uint8_t index)
{
  static uint8_t phy[] = {
    HCI_PHY_1_MBPS, HCI_PHY_2_MBPS, HCI_PHY_1_MBPS | HCI_PHY_2_MBPS,
    HCI_PHY_CODED, HCI_PHY_1_MBPS | HCI_PHY_2_MBPS | HCI_PHY_CODED,
  };

  // Set Phy Preference on the current connection. Apply the same value
  // for RX and TX. For more information, see the LE 2M PHY section in the User's Guide:
  // http://software-dl.ti.com/lprf/ble5stack-latest/
  // Note PHYs are already enabled by default in build_config.opt in stack project.
  HCI_LE_SetPhyCmd(scConnHandle, 0, phy[index], phy[index], 0);

  Display_printf(dispHandle, SC_ROW_CUR_CONN, 0, "PHY preference: %s",
                 TBM_GET_ACTION_DESC(&scMenuConnPhy, index));

  return (true);
}

/*********************************************************************
 * @fn      SimpleCentral_doDisconnect
 *
 * @brief   Disconnect the specified link
 *
 * @param   index - item index from the menu
 *
 * @return  always true
 */
bool SimpleCentral_doDisconnect(uint8_t index)
{
  (void) index;
//  Uart_SendMsg(UART_HEADER_STR, 10, "Disconnect");
  GAP_TerminateLinkReq(scConnHandle, HCI_DISCONNECT_REMOTE_USER_TERM);

  return (true);
}

/*********************************************************************
 * @fn      SimpleCentral_menuSwitchCb
 *
 * @brief   Detect menu context switching
 *
 * @param   pMenuObjCurr - the current menu object
 * @param   pMenuObjNext - the menu object the context is about to switch to
 *
 * @return  none
 */
static void SimpleCentral_menuSwitchCb(tbmMenuObj_t* pMenuObjCurr,
                                       tbmMenuObj_t* pMenuObjNext)
{
  uint8_t i, j;

  // interested in only the events of
  // entering scMenuConnect, scMenuSelectConn, and scMenuMain for now
  if (pMenuObjNext == &scMenuConnect)
  {
    
    uint32_t itemsToDisable = SC_ITEM_NONE;

    for (i = 0; i < TBM_GET_NUM_ITEM(&scMenuConnect); i++)
    {
      for (j = 0; j < MAX_NUM_BLE_CONNS; j++)
      {
        if ((connList[j].connHandle != LINKDB_CONNHANDLE_INVALID) &&
            !memcmp(TBM_GET_ACTION_DESC(&scMenuConnect, i),
                    Util_convertBdAddr2Str(connList[j].addr),
                    SC_ADDR_STR_SIZE))
        {
          // Already connected. Add to the set to be disabled.
          itemsToDisable |= (1 << i);
        }
      }
    }

    // Eventually only non-connected device addresses will be displayed.
    tbm_setItemStatus(&scMenuConnect,
                      SC_ITEM_ALL & ~itemsToDisable, itemsToDisable);
  }
  else if (pMenuObjNext == &scMenuSelectConn)
  {
    static uint8_t* pAddrs;
    uint8_t* pAddrTemp;

    if (pAddrs != NULL)
    {
      ICall_free(pAddrs);
    }

    // Allocate buffer to display addresses
    pAddrs = ICall_malloc(numConn * SC_ADDR_STR_SIZE);

    if (pAddrs == NULL)
    {
      TBM_SET_NUM_ITEM(&scMenuSelectConn, 0);
    }
    else
    {
      TBM_SET_NUM_ITEM(&scMenuSelectConn, MAX_NUM_BLE_CONNS);

      pAddrTemp = pAddrs;

      // Add active connection info to the menu object
      for (i = 0; i < MAX_NUM_BLE_CONNS; i++)
      {
        if (connList[i].connHandle != LINKDB_CONNHANDLE_INVALID)
        {
          // This connection is active. Set the corresponding menu item with
          // the address of this connection and enable the item.
          memcpy(pAddrTemp, Util_convertBdAddr2Str(connList[i].addr),
                 SC_ADDR_STR_SIZE);
          TBM_SET_ACTION_DESC(&scMenuSelectConn, i, pAddrTemp);
          tbm_setItemStatus(&scMenuSelectConn, (1 << i), SC_ITEM_NONE);
          pAddrTemp += SC_ADDR_STR_SIZE;
        }
        else
        {
          // This connection is not active. Disable the corresponding menu item.
          tbm_setItemStatus(&scMenuSelectConn, SC_ITEM_NONE, (1 << i));
        }
      }
    }
  }
  else if (pMenuObjNext == &scMenuMain)
  {
    // Now we are not in a specific connection's context
    scConnHandle = LINKDB_CONNHANDLE_INVALID;

    // Clear connection-related message
    Display_clearLine(dispHandle, SC_ROW_CUR_CONN);
  }
}


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

And the code of CC2640

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

 @file       simple_peripheral.c

 @brief This file contains the Simple Peripheral sample application for use
        with the CC2650 Bluetooth Low Energy Protocol Stack.

 Group: CMCU, SCS
 Target Device: CC2640R2

 ******************************************************************************
 
 Copyright (c) 2013-2017, Texas Instruments Incorporated
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:

 *  Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.

 *  Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.

 *  Neither the name of Texas Instruments Incorporated nor the names of
    its contributors may be used to endorse or promote products derived
    from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

 ******************************************************************************
 Release Name: simplelink_cc2640r2_sdk_1_40_00_45
 Release Date: 2017-07-20 17:16:59
 *****************************************************************************/

/*********************************************************************
 * INCLUDES
 */
#include <string.h>

#include <ti/sysbios/knl/Task.h>
#include <ti/sysbios/knl/Clock.h>
#include <ti/sysbios/knl/Event.h>
#include <ti/sysbios/knl/Queue.h>
#include <ti/display/Display.h>

#if defined( USE_FPGA ) || defined( DEBUG_SW_TRACE )
#include <driverlib/ioc.h>
#endif // USE_FPGA | DEBUG_SW_TRACE

#include <icall.h>
#include "util.h"
/* This Header file contains all BLE API and icall structure definition */
#include "icall_ble_api.h"

#include "devinfoservice.h"
#include "simple_gatt_profile.h"

#if defined(FEATURE_OAD) || defined(IMAGE_INVALIDATE)
#include "oad_target.h"
#include "oad.h"
#endif //FEATURE_OAD || IMAGE_INVALIDATE

#include "peripheral.h"

#ifdef USE_RCOSC
#include "rcosc_calibration.h"
#endif //USE_RCOSC


#include "board.h"

#if !defined(Display_DISABLE_ALL)
#include "board_key.h"
#include <menu/two_btn_menu.h>

#include "simple_peripheral_menu.h"
#endif  // !Display_DISABLE_ALL

#include "simple_peripheral.h"

#include "usrs.h"
Clock_Struct noti_clock;
/*********************************************************************
 * CONSTANTS
 */

// Advertising interval when device is discoverable (units of 625us, 160=100ms)
#define DEFAULT_ADVERTISING_INTERVAL          160

// General discoverable mode: advertise indefinitely
#define DEFAULT_DISCOVERABLE_MODE             GAP_ADTYPE_FLAGS_GENERAL

#ifndef FEATURE_OAD
// Minimum connection interval (units of 1.25ms, 80=100ms) for automatic
// parameter update request
#define DEFAULT_DESIRED_MIN_CONN_INTERVAL     80

// Maximum connection interval (units of 1.25ms, 800=1000ms) for automatic
// parameter update request
#define DEFAULT_DESIRED_MAX_CONN_INTERVAL     800

#else // FEATURE_OAD
// Increase the the connection interval to allow for higher throughput for OAD

// Minimum connection interval (units of 1.25ms, 8=10ms) for automatic
// parameter update request
#define DEFAULT_DESIRED_MIN_CONN_INTERVAL     8

// Maximum connection interval (units of 1.25ms, 8=10ms) for automatic
// parameter update request
#define DEFAULT_DESIRED_MAX_CONN_INTERVAL     8
#endif // FEATURE_OAD

// Slave latency to use for automatic parameter update request
#define DEFAULT_DESIRED_SLAVE_LATENCY         0

// Supervision timeout value (units of 10ms, 1000=10s) for automatic parameter
// update request
#define DEFAULT_DESIRED_CONN_TIMEOUT          3200//1000

// After the connection is formed, the peripheral waits until the central
// device asks for its preferred connection parameters
#define DEFAULT_ENABLE_UPDATE_REQUEST         GAPROLE_LINK_PARAM_UPDATE_WAIT_REMOTE_PARAMS

// Connection Pause Peripheral time value (in seconds)
#define DEFAULT_CONN_PAUSE_PERIPHERAL         1//6

// How often to perform periodic event (in msec)
#define SBP_PERIODIC_EVT_PERIOD               5000

// Application specific event ID for HCI Connection Event End Events
#define SBP_HCI_CONN_EVT_END_EVT              0x0001

// Type of Display to open
#if !defined(Display_DISABLE_ALL)
  #if defined(BOARD_DISPLAY_USE_LCD) && (BOARD_DISPLAY_USE_LCD!=0)
    #define SBP_DISPLAY_TYPE Display_Type_LCD
  #elif defined (BOARD_DISPLAY_USE_UART) && (BOARD_DISPLAY_USE_UART!=0)
    #define SBP_DISPLAY_TYPE Display_Type_UART
  #else // !BOARD_DISPLAY_USE_LCD && !BOARD_DISPLAY_USE_UART
    #define SBP_DISPLAY_TYPE 0 // Option not supported
  #endif // BOARD_DISPLAY_USE_LCD && BOARD_DISPLAY_USE_UART
#else // BOARD_DISPLAY_USE_LCD && BOARD_DISPLAY_USE_UART
  #define SBP_DISPLAY_TYPE 0 // No Display
#endif // !Display_DISABLE_ALL

#ifdef FEATURE_OAD
// The size of an OAD packet.
#define OAD_PACKET_SIZE                       ((OAD_BLOCK_SIZE) + 2)
#endif // FEATURE_OAD

// Task configuration
#define SBP_TASK_PRIORITY                     1

#ifndef SBP_TASK_STACK_SIZE
#define SBP_TASK_STACK_SIZE                   644
#endif

// Application events
#define SBP_STATE_CHANGE_EVT                  0x0001
#define SBP_CHAR_CHANGE_EVT                   0x0002
#define SBP_KEY_CHANGE_EVT                    0x0004

// Internal Events for RTOS application
#define SBP_ICALL_EVT                         ICALL_MSG_EVENT_ID // Event_Id_31
#define SBP_QUEUE_EVT                         UTIL_QUEUE_EVENT_ID // Event_Id_30
#define SBP_PERIODIC_EVT                      Event_Id_00

#ifdef FEATURE_OAD
// Additional Application Events for OAD
#define SBP_QUEUE_PING_EVT                    Event_Id_01

// Bitwise OR of all events to pend on with OAD
#define SBP_ALL_EVENTS                        (SBP_ICALL_EVT        | \
                                               SBP_QUEUE_EVT        | \
                                               SBP_PERIODIC_EVT     | \
                                               SBP_QUEUE_PING_EVT)
#else
// Bitwise OR of all events to pend on
#define SBP_ALL_EVENTS                        (SBP_ICALL_EVT        | \
                                               SBP_QUEUE_EVT        | \
                                               SBP_PERIODIC_EVT)
#endif /* FEATURE_OAD */

// Row numbers for two-button menu
#define SBP_ROW_RESULT        TBM_ROW_APP
#define SBP_ROW_STATUS_1      (TBM_ROW_APP + 1)
#define SBP_ROW_STATUS_2      (TBM_ROW_APP + 2)
#define SBP_ROW_ROLESTATE     (TBM_ROW_APP + 3)
#define SBP_ROW_BDADDR        (TBM_ROW_APP + 4)

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

// App event passed from profiles.
typedef struct
{
  appEvtHdr_t hdr;  // event header.
} sbpEvt_t;

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

// Display Interface
Display_Handle dispHandle = NULL;

/*********************************************************************
 * LOCAL VARIABLES
 */

// Entity ID globally used to check for source and/or destination of messages
static ICall_EntityID selfEntity;

// Event globally used to post local events and pend on system and
// local events.
static ICall_SyncHandle syncEvent;

// Clock instances for internal periodic events.
static Clock_Struct periodicClock;

// Queue object used for app messages
static Queue_Struct appMsg;
static Queue_Handle appMsgQueue;

#if defined(FEATURE_OAD)
// Event data from OAD profile.
static Queue_Struct oadQ;
static Queue_Handle hOadQ;
#endif //FEATURE_OAD

// Task configuration
Task_Struct sbpTask;
Char sbpTaskStack[SBP_TASK_STACK_SIZE];

// Scan response data (max size = 31 bytes)
static uint8_t scanRspData[] =
{
  // complete name
  0x14,   // length of this data
  GAP_ADTYPE_LOCAL_NAME_COMPLETE,
  'S',
  'i',
  'm',
  'p',
  'l',
  'e',
  'B',
  'L',
  'E',
  'P',
  'e',
  'r',
  'i',
  'p',
  'h',
  'e',
  'r',
  'a',
  'l',

  // 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
};

// Advertisement data (max size = 31 bytes, though this is
// best kept short to conserve power while advertising)
static uint8_t advertData[] =
{
  // Flags: this field sets the device to use general discoverable
  // mode (advertises indefinitely) instead of general
  // discoverable mode (advertise for 30 seconds at a time)
  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
#if !defined(FEATURE_OAD) || defined(FEATURE_OAD_ONCHIP)
  0x03,   // length of this data
#else //OAD for external flash
  0x05,  // length of this data
#endif //FEATURE_OAD
  GAP_ADTYPE_16BIT_MORE,      // some of the UUID's, but not all
#ifdef FEATURE_OAD
  LO_UINT16(OAD_SERVICE_UUID),
  HI_UINT16(OAD_SERVICE_UUID),
#endif //FEATURE_OAD
#ifndef FEATURE_OAD_ONCHIP
  LO_UINT16(SIMPLEPROFILE_SERV_UUID),
  HI_UINT16(SIMPLEPROFILE_SERV_UUID)
#endif //FEATURE_OAD_ONCHIP
};

// GAP GATT Attributes
static uint8_t attDeviceName[GAP_DEVICE_NAME_LEN] = "Simple Peripheral";

// Globals used for ATT Response retransmission
static gattMsgEvent_t *pAttRsp = NULL;
static uint8_t rspTxRetry = 0;

/*********************************************************************
 * LOCAL FUNCTIONS
 */

static void SimpleBLEPeripheral_init( void );
static void SimpleBLEPeripheral_taskFxn(UArg a0, UArg a1);

static uint8_t SimpleBLEPeripheral_processStackMsg(ICall_Hdr *pMsg);
static uint8_t SimpleBLEPeripheral_processGATTMsg(gattMsgEvent_t *pMsg);
static void SimpleBLEPeripheral_processAppMsg(sbpEvt_t *pMsg);
static void SimpleBLEPeripheral_processStateChangeEvt(gaprole_States_t newState);
static void SimpleBLEPeripheral_processCharValueChangeEvt(uint8_t paramID);
static void SimpleBLEPeripheral_performPeriodicTask(void);
static void SimpleBLEPeripheral_clockHandler(UArg arg);

static void SimpleBLEPeripheral_sendAttRsp(void);
static void SimpleBLEPeripheral_freeAttRsp(uint8_t status);

static void SimpleBLEPeripheral_stateChangeCB(gaprole_States_t newState);
#ifndef FEATURE_OAD_ONCHIP
static void SimpleBLEPeripheral_charValueChangeCB(uint8_t paramID);
#endif //!FEATURE_OAD_ONCHIP
static void SimpleBLEPeripheral_enqueueMsg(uint8_t event, uint8_t state);

#ifdef FEATURE_OAD
void SimpleBLEPeripheral_processOadWriteCB(uint8_t event, uint16_t connHandle,
                                           uint8_t *pData);
#endif //FEATURE_OAD

#if !defined(Display_DISABLE_ALL)
void SimpleBLEPeripheral_keyChangeHandler(uint8 keys);
static void SimpleBLEPeripheral_handleKeys(uint8_t keys);
#endif  // !Display_DISABLE_ALL

/*********************************************************************
 * EXTERN FUNCTIONS
 */
extern void AssertHandler(uint8 assertCause, uint8 assertSubcause);

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

// Peripheral GAPRole Callbacks
static gapRolesCBs_t SimpleBLEPeripheral_gapRoleCBs =
{
  SimpleBLEPeripheral_stateChangeCB     // GAPRole State Change Callbacks
};

// GAP Bond Manager Callbacks
// These are set to NULL since they are not needed. The application
// is set up to only perform justworks pairing.
static gapBondCBs_t simpleBLEPeripheral_BondMgrCBs =
{
  NULL, // Passcode callback
  NULL  // Pairing / Bonding state Callback
};

// Simple GATT Profile Callbacks
#ifndef FEATURE_OAD_ONCHIP
static simpleProfileCBs_t SimpleBLEPeripheral_simpleProfileCBs =
{
  SimpleBLEPeripheral_charValueChangeCB // Simple GATT Characteristic value change callback
};
#endif //!FEATURE_OAD_ONCHIP

#ifdef FEATURE_OAD
static oadTargetCBs_t simpleBLEPeripheral_oadCBs =
{
  SimpleBLEPeripheral_processOadWriteCB // OAD Profile Characteristic value change callback.
};
#endif //FEATURE_OAD

/*********************************************************************
 * PUBLIC FUNCTIONS
 */

/*********************************************************************
 * @fn      SimpleBLEPeripheral_createTask
 *
 * @brief   Task creation function for the Simple Peripheral.
 *
 * @param   None.
 *
 * @return  None.
 */
void SimpleBLEPeripheral_createTask(void)
{
  Task_Params taskParams;

  // Configure task
  Task_Params_init(&taskParams);
  taskParams.stack = sbpTaskStack;
  taskParams.stackSize = SBP_TASK_STACK_SIZE;
  taskParams.priority = SBP_TASK_PRIORITY;

  Task_construct(&sbpTask, SimpleBLEPeripheral_taskFxn, &taskParams, NULL);
}

/*********************************************************************
 * @fn      SimpleBLEPeripheral_init
 *
 * @brief   Called during initialization and contains application
 *          specific initialization (ie. hardware initialization/setup,
 *          table initialization, power up notification, etc), and
 *          profile initialization/setup.
 *
 * @param   None.
 *
 * @return  None.
 */
static void SimpleBLEPeripheral_init(void)
{
  // ******************************************************************
  // N0 STACK API CALLS CAN OCCUR BEFORE THIS CALL TO ICall_registerApp
  // ******************************************************************
  // Register the current thread as an ICall dispatcher application
  // so that the application can send and receive messages.
  ICall_registerApp(&selfEntity, &syncEvent);

#ifdef USE_RCOSC
  RCOSC_enableCalibration();
#endif // USE_RCOSC

#if defined( USE_FPGA )
  // configure RF Core SMI Data Link
  IOCPortConfigureSet(IOID_12, IOC_PORT_RFC_GPO0, IOC_STD_OUTPUT);
  IOCPortConfigureSet(IOID_11, IOC_PORT_RFC_GPI0, IOC_STD_INPUT);

  // configure RF Core SMI Command Link
  IOCPortConfigureSet(IOID_10, IOC_IOCFG0_PORT_ID_RFC_SMI_CL_OUT, IOC_STD_OUTPUT);
  IOCPortConfigureSet(IOID_9, IOC_IOCFG0_PORT_ID_RFC_SMI_CL_IN, IOC_STD_INPUT);

  // configure RF Core tracer IO
  IOCPortConfigureSet(IOID_8, IOC_PORT_RFC_TRC, IOC_STD_OUTPUT);
#else // !USE_FPGA
  #if defined( DEBUG_SW_TRACE )
    // configure RF Core tracer IO
    IOCPortConfigureSet(IOID_8, IOC_PORT_RFC_TRC, IOC_STD_OUTPUT | IOC_CURRENT_4MA | IOC_SLEW_ENABLE);
  #endif // DEBUG_SW_TRACE
#endif // USE_FPGA

  // Create an RTOS queue for message from profile to be sent to app.
  appMsgQueue = Util_constructQueue(&appMsg);

  // Create one-shot clocks for internal periodic events.
  Util_constructClock(&periodicClock, SimpleBLEPeripheral_clockHandler,
                      SBP_PERIODIC_EVT_PERIOD, 0, false, SBP_PERIODIC_EVT);

  dispHandle = Display_open(SBP_DISPLAY_TYPE, NULL);

  // Set GAP Parameters: After a connection was established, delay in seconds
  // before sending when GAPRole_SetParameter(GAPROLE_PARAM_UPDATE_ENABLE,...)
  // uses GAPROLE_LINK_PARAM_UPDATE_INITIATE_BOTH_PARAMS or
  // GAPROLE_LINK_PARAM_UPDATE_INITIATE_APP_PARAMS
  // For current defaults, this has no effect.
  GAP_SetParamValue(TGAP_CONN_PAUSE_PERIPHERAL, DEFAULT_CONN_PAUSE_PERIPHERAL);

  // Setup the Peripheral GAPRole Profile. For more information see the User's Guide:
  // http://software-dl.ti.com/lprf/ble5stack-docs-latest/html/ble-stack/gaprole.html
  {
    // Device starts advertising upon initialization of GAP
    uint8_t initialAdvertEnable = TRUE;

    // By setting this to zero, the device will go into the waiting state after
    // being discoverable for 30.72 second, and will not being advertising again
    // until re-enabled by the application
    uint16_t advertOffTime = 0;

    uint8_t enableUpdateRequest = DEFAULT_ENABLE_UPDATE_REQUEST;
    uint16_t desiredMinInterval = DEFAULT_DESIRED_MIN_CONN_INTERVAL;
    uint16_t desiredMaxInterval = DEFAULT_DESIRED_MAX_CONN_INTERVAL;
    uint16_t desiredSlaveLatency = DEFAULT_DESIRED_SLAVE_LATENCY;
    uint16_t desiredConnTimeout = DEFAULT_DESIRED_CONN_TIMEOUT;

    // Set the Peripheral GAPRole Parameters
    GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t),
                         &initialAdvertEnable);
    GAPRole_SetParameter(GAPROLE_ADVERT_OFF_TIME, sizeof(uint16_t),
                         &advertOffTime);

    GAPRole_SetParameter(GAPROLE_SCAN_RSP_DATA, sizeof(scanRspData),
                         scanRspData);
    GAPRole_SetParameter(GAPROLE_ADVERT_DATA, sizeof(advertData), advertData);

    GAPRole_SetParameter(GAPROLE_PARAM_UPDATE_ENABLE, sizeof(uint8_t),
                         &enableUpdateRequest);
    GAPRole_SetParameter(GAPROLE_MIN_CONN_INTERVAL, sizeof(uint16_t),
                         &desiredMinInterval);
    GAPRole_SetParameter(GAPROLE_MAX_CONN_INTERVAL, sizeof(uint16_t),
                         &desiredMaxInterval);
    GAPRole_SetParameter(GAPROLE_SLAVE_LATENCY, sizeof(uint16_t),
                         &desiredSlaveLatency);
    GAPRole_SetParameter(GAPROLE_TIMEOUT_MULTIPLIER, sizeof(uint16_t),
                         &desiredConnTimeout);
  }

  // Set the Device Name characteristic in the GAP GATT Service
  // For more information, see the section in the User's Guide:
  // http://software-dl.ti.com/lprf/ble5stack-docs-latest/html/ble-stack/gaprole.html
  GGS_SetParameter(GGS_DEVICE_NAME_ATT, GAP_DEVICE_NAME_LEN, attDeviceName);

  // Set GAP Parameters to set the advertising interval
  // For more information, see the GAP section of the User's Guide:
  // http://software-dl.ti.com/lprf/ble5stack-docs-latest/html/ble-stack/gatt.html#gap-gatt-service-ggs
  {
    // Use the same interval for general and limited advertising.
    // Note that only general advertising will occur based on the above configuration
    uint16_t advInt = DEFAULT_ADVERTISING_INTERVAL;

    GAP_SetParamValue(TGAP_LIM_DISC_ADV_INT_MIN, advInt);
    GAP_SetParamValue(TGAP_LIM_DISC_ADV_INT_MAX, advInt);
    GAP_SetParamValue(TGAP_GEN_DISC_ADV_INT_MIN, advInt);
    GAP_SetParamValue(TGAP_GEN_DISC_ADV_INT_MAX, advInt);
  }

  // Setup the GAP Bond Manager. For more information see the section in the
  // User's Guide:
  // http://software-dl.ti.com/lprf/ble5stack-docs-latest/html/ble-stack/gapbondmngr.html#
  {
    // Hard code the passkey that will be used for pairing. The GAPBondMgr will
    // use this key instead of issuing a callback to the application. This only
    // works if both sides of the connection know to use this same key at
    // compile-time.
    uint32_t passkey = 0; // passkey "000000"
    // Don't send a pairing request after connecting; the peer device must
    // initiate pairing
    uint8_t pairMode = GAPBOND_PAIRING_MODE_WAIT_FOR_REQ;
    // Use authenticated pairing: require passcode.
    uint8_t mitm = TRUE;
    // This device only has display capabilities. Therefore, it will display the
    // passcode during pairing. However, since the default passcode is being
    // used, there is no need to display anything.
    uint8_t ioCap = GAPBOND_IO_CAP_DISPLAY_ONLY;
    // Request bonding (storing long-term keys for re-encryption upon subsequent
    // connections without repairing)
    uint8_t bonding = TRUE;

    GAPBondMgr_SetParameter(GAPBOND_DEFAULT_PASSCODE, sizeof(uint32_t),
                            &passkey);
    GAPBondMgr_SetParameter(GAPBOND_PAIRING_MODE, sizeof(uint8_t), &pairMode);
    GAPBondMgr_SetParameter(GAPBOND_MITM_PROTECTION, sizeof(uint8_t), &mitm);
    GAPBondMgr_SetParameter(GAPBOND_IO_CAPABILITIES, sizeof(uint8_t), &ioCap);
    GAPBondMgr_SetParameter(GAPBOND_BONDING_ENABLED, sizeof(uint8_t), &bonding);
  }

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

#ifndef FEATURE_OAD_ONCHIP
  SimpleProfile_AddService(GATT_ALL_SERVICES); // Simple GATT Profile
#endif //!FEATURE_OAD_ONCHIP

#ifdef FEATURE_OAD
  VOID OAD_addService();                       // OAD Profile
  OAD_register((oadTargetCBs_t *)&simpleBLEPeripheral_oadCBs);
  hOadQ = Util_constructQueue(&oadQ);
#endif //FEATURE_OAD

#ifdef IMAGE_INVALIDATE
  Reset_addService();
#endif //IMAGE_INVALIDATE


#ifndef FEATURE_OAD_ONCHIP
  // Setup the SimpleProfile Characteristic Values
  // For more information, see the sections in the User's Guide:
  // http://software-dl.ti.com/lprf/ble5stack-docs-latest/html/ble-stack/gatt.html#
  // http://software-dl.ti.com/lprf/ble5stack-docs-latest/html/ble-stack/gatt.html#gattservapp-module
  {
    uint8_t charValue1 = 1;
    uint8_t charValue2 = 2;
    uint8_t charValue3 = 3;
    uint8_t charValue4 = 4;
    uint8_t charValue5[SIMPLEPROFILE_CHAR5_LEN] = { 1, 2, 3, 4, 5 };

    SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR1, sizeof(uint8_t),
                               &charValue1);
    SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR2, sizeof(uint8_t),
                               &charValue2);
    SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR3, sizeof(uint8_t),
                               &charValue3);
    SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR4, sizeof(uint8_t),
                               &charValue4);
    SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR5, SIMPLEPROFILE_CHAR5_LEN,
                               charValue5);
  }

  // Register callback with SimpleGATTprofile
  SimpleProfile_RegisterAppCBs(&SimpleBLEPeripheral_simpleProfileCBs);
#endif //!FEATURE_OAD_ONCHIP

  // Start Bond Manager and register callback
  VOID GAPBondMgr_Register(&simpleBLEPeripheral_BondMgrCBs);

  // Register with GAP for HCI/Host messages. This is needed to receive HCI
  // events. For more information, see the section in the User's Guide:
  // http://software-dl.ti.com/lprf/ble5stack-docs-latest/html/ble-stack/hci.html
  GAP_RegisterForMsgs(selfEntity);

  // Register for GATT local events and ATT Responses pending for transmission
  GATT_RegisterForMsgs(selfEntity);

  // Set default values for Data Length Extension
  // This should be included only if Extended Data Length Feature is enabled
  // in build_config.opt in stack project.
  {
    //Set initial values to maximum, RX is set to max. by default(251 octets, 2120us)
    #define APP_SUGGESTED_PDU_SIZE 251 //default is 27 octets(TX)
    #define APP_SUGGESTED_TX_TIME 2120 //default is 328us(TX)

    // This API is documented in hci.h
    // See BLE5-Stack User's Guide for information on using this command:
    // http://software-dl.ti.com/lprf/ble5stack-docs-latest/html/ble-stack/data-length-extensions.html
    // HCI_LE_WriteSuggestedDefaultDataLenCmd(APP_SUGGESTED_PDU_SIZE, APP_SUGGESTED_TX_TIME);
  }

#if defined (BLE_V42_FEATURES) && (BLE_V42_FEATURES & PRIVACY_1_2_CFG)
  // Initialize GATT Client
  GATT_InitClient();

  // This line masks the Resolvable Private Address Only (RPAO) Characteristic
  // in the GAP GATT Server from being detected by remote devices. This value
  // cannot be toggled without power cycling but should remain consistent across
  // power-cycles. Removing this command when Privacy is used will cause this
  // device to be treated in Network Privacy Mode by bonded devices - this means
  // that after disconnecting they will not respond to this device's PDUs which
  // contain its Identity Address.
  // Devices wanting to use Network Privacy Mode with other BT5 devices, this
  // line should be commented out.
  GGS_SetParamValue(GGS_DISABLE_RPAO_CHARACTERISTIC);
#endif // BLE_V42_FEATURES & PRIVACY_1_2_CFG

#if !defined(Display_DISABLE_ALL)
  // Set the title of the main menu
  #if defined FEATURE_OAD
    #if defined (HAL_IMAGE_A)
      TBM_SET_TITLE(&sbpMenuMain, "BLE Peripheral A");
    #else
      TBM_SET_TITLE(&sbpMenuMain, "BLE Peripheral B");
    #endif // HAL_IMAGE_A
  #else
    TBM_SET_TITLE(&sbpMenuMain, "BLE Peripheral");
  #endif // FEATURE_OAD

  // Initialize Two-Button Menu module
  tbm_setItemStatus(&sbpMenuMain, TBM_ITEM_NONE, TBM_ITEM_ALL);
  tbm_initTwoBtnMenu(dispHandle, &sbpMenuMain, 3, NULL);

  // Init key debouncer
  Board_initKeys(SimpleBLEPeripheral_keyChangeHandler);
#endif  // !Display_DISABLE_ALL

#if !defined (USE_LL_CONN_PARAM_UPDATE)
  // Get the currently set local supported LE features
  // The will result in a HCI_LE_READ_LOCAL_SUPPORTED_FEATURES event that
  // will get received in the main task processing loop. At this point,
  // feature bits can be set / cleared and the features can be updated.
  HCI_LE_ReadLocalSupportedFeaturesCmd();
#endif // !defined (USE_LL_CONN_PARAM_UPDATE)

  // Start the GAPRole
  VOID GAPRole_StartDevice(&SimpleBLEPeripheral_gapRoleCBs);
  HCI_EXT_SetTxPowerCmd(HCI_EXT_TX_POWER_5_DBM);

  Uart_Ini();
  led_handle = PIN_open(&led_pins, led_cfg);
  Util_constructClock(&noti_clock, SimpleBLEPeripheral_clockHandler,  SBP_NOTI_EVT_PERIOD, 0, false, SBP_NOTI_EVT);
//  PIN_setOutputValue(led_handle, LED1, 1);
}

void SimplePeripheral_SendNotify(){
    uint16_t connectionHandle;
    GAPRole_GetParameter(GAPROLE_CONNHANDLE, &connectionHandle);
    if(connectionHandle == INVALID_CONNHANDLE){
        return;
    }

    attHandleValueNoti_t noti;
    noti.handle = 0x29; //simpleProfileAttrTbl[11].handle;
    uint16_t len_msg = 9;
    noti.len = len_msg;

    bStatus_t status;
    noti.pValue = (uint8 *)GATT_bm_alloc(connectionHandle, ATT_HANDLE_VALUE_NOTI, len_msg, &len_msg );
    if(noti.pValue!=NULL){
        for(int i = 0;i < 9; i++){
            noti.pValue[i] = i;
        }
        status = GATT_Notification( connectionHandle, &noti, 0);
        if ( status != SUCCESS ){ //if noti not sent
            GATT_bm_free( (gattMsg_t *)&noti, ATT_HANDLE_VALUE_NOTI );
        }
    }
    else{
        GATT_bm_free( (gattMsg_t *)&noti, ATT_HANDLE_VALUE_NOTI );
        status = bleNoResources;
        // bleNoResources was returned
        asm(" NOP ");
    }
}

/*********************************************************************
 * @fn      SimpleBLEPeripheral_taskFxn
 *
 * @brief   Application task entry point for the Simple Peripheral.
 *
 * @param   a0, a1 - not used.
 *
 * @return  None.
 */
static void SimpleBLEPeripheral_taskFxn(UArg a0, UArg a1)
{
  // Initialize application
  SimpleBLEPeripheral_init();

  // Application main loop
  for (;;)
  {
    uint32_t events;

    // Waits for an event to be posted associated with the calling thread.
    // Note that an event associated with a thread is posted when a
    // message is queued to the message receive queue of the thread
    events = Event_pend(syncEvent, Event_Id_NONE, SBP_ALL_EVENTS | SBP_NOTI_EVT,
                        ICALL_TIMEOUT_FOREVER);

    if (events)
    {
      ICall_EntityID dest;
      ICall_ServiceEnum src;
      ICall_HciExtEvt *pMsg = NULL;

      // Fetch any available messages that might have been sent from the stack
      if (ICall_fetchServiceMsg(&src, &dest,
                                (void **)&pMsg) == ICALL_ERRNO_SUCCESS)
      {
        uint8 safeToDealloc = TRUE;

        if ((src == ICALL_SERVICE_CLASS_BLE) && (dest == selfEntity))
        {
          ICall_Stack_Event *pEvt = (ICall_Stack_Event *)pMsg;

          // Check for BLE stack events first
          if (pEvt->signature == 0xffff)
          {
            // The GATT server might have returned a blePending as it was trying
            // to process an ATT Response. Now that we finished with this
            // connection event, let's try sending any remaining ATT Responses
            // on the next connection event.
            if (pEvt->event_flag & SBP_HCI_CONN_EVT_END_EVT)
            {
              // Try to retransmit pending ATT Response (if any)
              SimpleBLEPeripheral_sendAttRsp();
            }
          }
          else
          {
            // Process inter-task message
            safeToDealloc = SimpleBLEPeripheral_processStackMsg((ICall_Hdr *)pMsg);
          }
        }

        if (pMsg && safeToDealloc)
        {
          ICall_freeMsg(pMsg);
        }
      }

      // If RTOS queue is not empty, process app message.
      if (events & SBP_QUEUE_EVT)
      {
        while (!Queue_empty(appMsgQueue))
        {
          sbpEvt_t *pMsg = (sbpEvt_t *)Util_dequeueMsg(appMsgQueue);
          if (pMsg)
          {
            // Process message.
            SimpleBLEPeripheral_processAppMsg(pMsg);

            // Free the space from the message.
            ICall_free(pMsg);
          }
        }
      }

      if (events & SBP_PERIODIC_EVT)
      {
        Util_startClock(&periodicClock);

        // Perform periodic application task
        SimpleBLEPeripheral_performPeriodicTask();
      }

      if(events & SBP_NOTI_EVT){
          Util_startClock(&noti_clock);
          SimplePeripheral_SendNotify();
      }
#ifdef FEATURE_OAD
      if (events & SBP_QUEUE_PING_EVT)
      {
        while (!Queue_empty(hOadQ))
        {
          oadTargetWrite_t *oadWriteEvt = Queue_get(hOadQ);

          // Identify new image.
          if (oadWriteEvt->event == OAD_WRITE_IDENTIFY_REQ)
          {
            OAD_imgIdentifyWrite(oadWriteEvt->connHandle, oadWriteEvt->pData);
          }
          // Write a next block request.
          else if (oadWriteEvt->event == OAD_WRITE_BLOCK_REQ)
          {
            OAD_imgBlockWrite(oadWriteEvt->connHandle, oadWriteEvt->pData);
          }

          // Free buffer.
          ICall_free(oadWriteEvt);
        }
      }
#endif //FEATURE_OAD
    }
  }
}

/*********************************************************************
 * @fn      SimpleBLEPeripheral_processStackMsg
 *
 * @brief   Process an incoming stack message.
 *
 * @param   pMsg - message to process
 *
 * @return  TRUE if safe to deallocate incoming message, FALSE otherwise.
 */
static uint8_t SimpleBLEPeripheral_processStackMsg(ICall_Hdr *pMsg)
{
  uint8_t safeToDealloc = TRUE;

  switch (pMsg->event)
  {
    case GATT_MSG_EVENT:
      // Process GATT message
      safeToDealloc = SimpleBLEPeripheral_processGATTMsg((gattMsgEvent_t *)pMsg);
      break;

    case HCI_GAP_EVENT_EVENT:
      {

        // Process HCI message
        switch(pMsg->status)
        {
          case HCI_COMMAND_COMPLETE_EVENT_CODE:
            // Process HCI Command Complete Event
            {

#if !defined (USE_LL_CONN_PARAM_UPDATE)
              // This code will disable the use of the LL_CONNECTION_PARAM_REQ
              // control procedure (for connection parameter updates, the
              // L2CAP Connection Parameter Update procedure will be used
              // instead). To re-enable the LL_CONNECTION_PARAM_REQ control
              // procedures, define the symbol USE_LL_CONN_PARAM_UPDATE
              // The L2CAP Connection Parameter Update procedure is used to
              // support a delta between the minimum and maximum connection
              // intervals required by some iOS devices.

              // Parse Command Complete Event for opcode and status
              hciEvt_CmdComplete_t* command_complete = (hciEvt_CmdComplete_t*) pMsg;
              uint8_t   pktStatus = command_complete->pReturnParam[0];

              //find which command this command complete is for
              switch (command_complete->cmdOpcode)
              {
                case HCI_LE_READ_LOCAL_SUPPORTED_FEATURES:
                  {
                    if (pktStatus == SUCCESS)
                    {
                      uint8_t featSet[8];

                      // Get current feature set from received event (bits 1-9
                      // of the returned data
                      memcpy( featSet, &command_complete->pReturnParam[1], 8 );

                      // Clear bit 1 of byte 0 of feature set to disable LL
                      // Connection Parameter Updates
                      CLR_FEATURE_FLAG( featSet[0], LL_FEATURE_CONN_PARAMS_REQ );

                      // Update controller with modified features
                      HCI_EXT_SetLocalSupportedFeaturesCmd( featSet );
                    }
                  }
                  break;

                default:
                  //do nothing
                  break;
              }
#endif // !defined (USE_LL_CONN_PARAM_UPDATE)

            }
            break;

          case HCI_BLE_HARDWARE_ERROR_EVENT_CODE:
            AssertHandler(HAL_ASSERT_CAUSE_HARDWARE_ERROR,0);
            break;

          // LE Events
          case HCI_LE_EVENT_CODE:
            {
              hciEvt_BLEPhyUpdateComplete_t *pPUC
                = (hciEvt_BLEPhyUpdateComplete_t*) pMsg;

              // A Phy Update Has Completed or Failed
              if (pPUC->BLEEventCode == HCI_BLE_PHY_UPDATE_COMPLETE_EVENT)
              {
                if (pPUC->status != SUCCESS)
                {
                  Display_print0(dispHandle, SBP_ROW_STATUS_1, 0,
                                 "PHY Change failure");
                }
                else
                {
                  Display_print0(dispHandle, SBP_ROW_STATUS_1, 0,
                                 "PHY Update Complete");
                  // Only symmetrical PHY is supported.
                  // rxPhy should be equal to txPhy.
                  Display_print1(dispHandle, SBP_ROW_STATUS_2, 0,
                                 "Current PHY: %s",
                                 (pPUC->rxPhy == HCI_PHY_1_MBPS) ? "1 Mbps" :

// Note: BLE_V50_FEATURES is always defined and long range phy (PHY_LR_CFG) is
//       defined in build_config.opt
#if (BLE_V50_FEATURES & PHY_LR_CFG)
                                   ((pPUC->rxPhy == HCI_PHY_2_MBPS) ? "2 Mbps" :
                                       "Coded:S2"));
#else  // !PHY_LR_CFG
                                   "2 Mbps");
#endif // PHY_LR_CFG
                }
              }
            }
            break;

          default:
            break;
        }
      }
      break;

      default:
        // do nothing
        break;

    }

  return (safeToDealloc);
}

/*********************************************************************
 * @fn      SimpleBLEPeripheral_processGATTMsg
 *
 * @brief   Process GATT messages and events.
 *
 * @return  TRUE if safe to deallocate incoming message, FALSE otherwise.
 */
static uint8_t SimpleBLEPeripheral_processGATTMsg(gattMsgEvent_t *pMsg)
{
  // See if GATT server was unable to transmit an ATT response
  if (pMsg->hdr.status == blePending)
  {
      PIN_setOutputValue(led_handle, LED4, 1);
    // No HCI buffer was available. Let's try to retransmit the response
    // on the next connection event.
    if (HCI_EXT_ConnEventNoticeCmd(pMsg->connHandle, selfEntity,
                                   SBP_HCI_CONN_EVT_END_EVT) == SUCCESS)
    {
      // First free any pending response
      SimpleBLEPeripheral_freeAttRsp(FAILURE);

      // Hold on to the response message for retransmission
      pAttRsp = pMsg;

      // Don't free the response message yet
      return (FALSE);
    }
  }
  else if (pMsg->method == ATT_FLOW_CTRL_VIOLATED_EVENT)
  {
      PIN_setOutputValue(led_handle, LED3, 1);
    // ATT request-response or indication-confirmation flow control is
    // violated. All subsequent ATT requests or indications will be dropped.
    // The app is informed in case it wants to drop the connection.

    // Display the opcode of the message that caused the violation.
    Display_print1(dispHandle, SBP_ROW_RESULT, 0, "FC Violated: %d", pMsg->msg.flowCtrlEvt.opcode);
  }
  else if (pMsg->method == ATT_MTU_UPDATED_EVENT)
  {
    // MTU size updated
    PIN_setOutputValue(led_handle, LED2, 1);
    Display_print1(dispHandle, SBP_ROW_RESULT, 0, "MTU Size: %d", pMsg->msg.mtuEvt.MTU);
  }

  // Free message payload. Needed only for ATT Protocol messages
  GATT_bm_free(&pMsg->msg, pMsg->method);

  // It's safe to free the incoming message
  return (TRUE);
}

/*********************************************************************
 * @fn      SimpleBLEPeripheral_sendAttRsp
 *
 * @brief   Send a pending ATT response message.
 *
 * @param   none
 *
 * @return  none
 */
static void SimpleBLEPeripheral_sendAttRsp(void)
{
  // See if there's a pending ATT Response to be transmitted
  if (pAttRsp != NULL)
  {
    uint8_t status;

    // Increment retransmission count
    rspTxRetry++;

    // Try to retransmit ATT response till either we're successful or
    // the ATT Client times out (after 30s) and drops the connection.
    status = GATT_SendRsp(pAttRsp->connHandle, pAttRsp->method, &(pAttRsp->msg));
    if ((status != blePending) && (status != MSG_BUFFER_NOT_AVAIL))
    {
      // Disable connection event end notice
      HCI_EXT_ConnEventNoticeCmd(pAttRsp->connHandle, selfEntity, 0);

      // We're done with the response message
      SimpleBLEPeripheral_freeAttRsp(status);
    }
    else
    {
      // Continue retrying
      Display_print1(dispHandle, SBP_ROW_STATUS_1, 0, "Rsp send retry: %d", rspTxRetry);
    }
  }
}

/*********************************************************************
 * @fn      SimpleBLEPeripheral_freeAttRsp
 *
 * @brief   Free ATT response message.
 *
 * @param   status - response transmit status
 *
 * @return  none
 */
static void SimpleBLEPeripheral_freeAttRsp(uint8_t status)
{
  // See if there's a pending ATT response message
  if (pAttRsp != NULL)
  {
    // See if the response was sent out successfully
    if (status == SUCCESS)
    {
      Display_print1(dispHandle, SBP_ROW_STATUS_1, 0, "Rsp sent retry: %d", rspTxRetry);
    }
    else
    {
      // Free response payload
      GATT_bm_free(&pAttRsp->msg, pAttRsp->method);

      Display_print1(dispHandle, SBP_ROW_STATUS_1, 0, "Rsp retry failed: %d", rspTxRetry);
    }

    // Free response message
    ICall_freeMsg(pAttRsp);

    // Reset our globals
    pAttRsp = NULL;
    rspTxRetry = 0;
  }
}

/*********************************************************************
 * @fn      SimpleBLEPeripheral_processAppMsg
 *
 * @brief   Process an incoming callback from a profile.
 *
 * @param   pMsg - message to process
 *
 * @return  None.
 */
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;

#if !defined(Display_DISABLE_ALL)
    case SBP_KEY_CHANGE_EVT:
      SimpleBLEPeripheral_handleKeys(pMsg->hdr.state);
      break;
#endif  // !Display_DISABLE_ALL

    default:
      // Do nothing.
      break;
  }
}

/*********************************************************************
 * @fn      SimpleBLEPeripheral_stateChangeCB
 *
 * @brief   Callback from GAP Role indicating a role state change.
 *
 * @param   newState - new state
 *
 * @return  None.
 */
static void SimpleBLEPeripheral_stateChangeCB(gaprole_States_t newState)
{
  SimpleBLEPeripheral_enqueueMsg(SBP_STATE_CHANGE_EVT, newState);
}

/*********************************************************************
 * @fn      SimpleBLEPeripheral_processStateChangeEvt
 *
 * @brief   Process a pending GAP Role state change event.
 *
 * @param   newState - new state
 *
 * @return  None.
 */
static void SimpleBLEPeripheral_processStateChangeEvt(gaprole_States_t newState)
{
#ifdef PLUS_BROADCASTER
  static bool firstConnFlag = false;
#endif // PLUS_BROADCASTER

  switch ( newState )
  {
    case GAPROLE_STARTED:
      {
        uint8_t ownAddress[B_ADDR_LEN];
        uint8_t systemId[DEVINFO_SYSTEM_ID_LEN];

        GAPRole_GetParameter(GAPROLE_BD_ADDR, ownAddress);

        // use 6 bytes of device address for 8 bytes of system ID value
        systemId[0] = ownAddress[0];
        systemId[1] = ownAddress[1];
        systemId[2] = ownAddress[2];

        // set middle bytes to zero
        systemId[4] = 0x00;
        systemId[3] = 0x00;

        // shift three bytes up
        systemId[7] = ownAddress[5];
        systemId[6] = ownAddress[4];
        systemId[5] = ownAddress[3];

        DevInfo_SetParameter(DEVINFO_SYSTEM_ID, DEVINFO_SYSTEM_ID_LEN, systemId);

        // Display device address
        Display_print0(dispHandle, SBP_ROW_BDADDR, 0, Util_convertBdAddr2Str(ownAddress));
        Display_print0(dispHandle, SBP_ROW_ROLESTATE, 0, "Initialized");
      }
      break;

    case GAPROLE_ADVERTISING:
      Display_print0(dispHandle, SBP_ROW_ROLESTATE, 0, "Advertising");
      break;

#ifdef PLUS_BROADCASTER
    // After a connection is dropped, a device in PLUS_BROADCASTER will continue
    // sending non-connectable advertisements and shall send this change of
    // state to the application.  These are then disabled here so that sending
    // connectable advertisements can resume.
    case GAPROLE_ADVERTISING_NONCONN:
      {
        uint8_t advertEnabled = FALSE;

        // Disable non-connectable advertising.
        GAPRole_SetParameter(GAPROLE_ADV_NONCONN_ENABLED, sizeof(uint8_t),
                           &advertEnabled);

        advertEnabled = TRUE;

        // Enabled connectable advertising.
        GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t),
                             &advertEnabled);

        // Reset flag for next connection.
        firstConnFlag = false;

        SimpleBLEPeripheral_freeAttRsp(bleNotConnected);
      }
      break;
#endif //PLUS_BROADCASTER

    case GAPROLE_CONNECTED:
      {
        PIN_setOutputValue(led_handle, LED1, 1);
        linkDBInfo_t linkInfo;
        uint8_t numActive = 0;

        Util_startClock(&periodicClock);
        Util_startClock(&noti_clock);
        numActive = linkDB_NumActive();

        // Use numActive to determine the connection handle of the last
        // connection
        if ( linkDB_GetInfo( numActive - 1, &linkInfo ) == SUCCESS )
        {
          Display_print1(dispHandle, SBP_ROW_ROLESTATE, 0, "Num Conns: %d", (uint16_t)numActive);
          Display_print0(dispHandle, SBP_ROW_STATUS_1, 0, Util_convertBdAddr2Str(linkInfo.addr));
        }
        else
        {
          uint8_t peerAddress[B_ADDR_LEN];

          GAPRole_GetParameter(GAPROLE_CONN_BD_ADDR, peerAddress);

          Display_print0(dispHandle, SBP_ROW_ROLESTATE, 0, "Connected");
          Display_print0(dispHandle, SBP_ROW_STATUS_1, 0, Util_convertBdAddr2Str(peerAddress));
        }

#if !defined(Display_DISABLE_ALL)
        tbm_setItemStatus(&sbpMenuMain, TBM_ITEM_ALL, TBM_ITEM_NONE);
#endif  // !Display_DISABLE_ALL

        #ifdef PLUS_BROADCASTER
          // Only turn advertising on for this state when we first connect
          // otherwise, when we go from connected_advertising back to this state
          // we will be turning advertising back on.
          if (firstConnFlag == false)
          {
            uint8_t advertEnabled = FALSE; // Turn on Advertising

            // Disable connectable advertising.
            GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t),
                                 &advertEnabled);

            // Set to true for non-connectable advertising.
            advertEnabled = TRUE;

            // Enable non-connectable advertising.
            GAPRole_SetParameter(GAPROLE_ADV_NONCONN_ENABLED, sizeof(uint8_t),
                                 &advertEnabled);
            firstConnFlag = true;
          }
        #endif // PLUS_BROADCASTER
      }
//      Uart_SendMsg(UART_HEADER_STR, "Connected", 9);
      break;

    case GAPROLE_CONNECTED_ADV:
      Display_print0(dispHandle, SBP_ROW_ROLESTATE, 0, "Connected Advertising");
      break;

    case GAPROLE_WAITING:
      PIN_setOutputValue(led_handle, LED1, 0);
      Util_stopClock(&periodicClock);
//      Uart_SendMsg(UART_HEADER_STR, "Disconnected", 12);
      SimpleBLEPeripheral_freeAttRsp(bleNotConnected);

      Display_print0(dispHandle, SBP_ROW_ROLESTATE, 0, "Disconnected");

#if !defined(Display_DISABLE_ALL)
      // Disable PHY change
      tbm_setItemStatus(&sbpMenuMain, TBM_ITEM_NONE, TBM_ITEM_ALL);
#endif  // !Display_DISABLE_ALL

      // Clear remaining lines
      Display_clearLines(dispHandle, SBP_ROW_RESULT, SBP_ROW_STATUS_2);
      Util_stopClock(&noti_clock);
      break;

    case GAPROLE_WAITING_AFTER_TIMEOUT:
      SimpleBLEPeripheral_freeAttRsp(bleNotConnected);
      Util_stopClock(&noti_clock);
//      Uart_SendMsg(UART_HEADER_STR, "Time Out.", 9);
      Display_print0(dispHandle, SBP_ROW_RESULT, 0, "Timed Out");

#if !defined(Display_DISABLE_ALL)
      tbm_setItemStatus(&sbpMenuMain, TBM_ITEM_NONE, TBM_ITEM_ALL);
#endif  // !Display_DISABLE_ALL

      // Clear remaining lines
      Display_clearLines(dispHandle, SBP_ROW_STATUS_1, SBP_ROW_STATUS_2);

      #ifdef PLUS_BROADCASTER
        // Reset flag for next connection.
        firstConnFlag = false;
      #endif // PLUS_BROADCASTER
      break;

    case GAPROLE_ERROR:
      Display_print0(dispHandle, SBP_ROW_RESULT, 0, "Error");
      break;

    default:
      Display_clearLines(dispHandle, SBP_ROW_RESULT, SBP_ROW_STATUS_2);
      break;
  }

}

#ifndef FEATURE_OAD_ONCHIP
/*********************************************************************
 * @fn      SimpleBLEPeripheral_charValueChangeCB
 *
 * @brief   Callback from Simple Profile indicating a characteristic
 *          value change.
 *
 * @param   paramID - parameter ID of the value that was changed.
 *
 * @return  None.
 */
static void SimpleBLEPeripheral_charValueChangeCB(uint8_t paramID)
{
  SimpleBLEPeripheral_enqueueMsg(SBP_CHAR_CHANGE_EVT, paramID);
}
#endif //!FEATURE_OAD_ONCHIP

/*********************************************************************
 * @fn      SimpleBLEPeripheral_processCharValueChangeEvt
 *
 * @brief   Process a pending Simple Profile characteristic value change
 *          event.
 *
 * @param   paramID - parameter ID of the value that was changed.
 *
 * @return  None.
 */
static void SimpleBLEPeripheral_processCharValueChangeEvt(uint8_t paramID)
{
#ifndef FEATURE_OAD_ONCHIP
  uint8_t newValue;

  switch(paramID)
  {
    case SIMPLEPROFILE_CHAR1:
      SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR1, &newValue);

      Display_print1(dispHandle, SBP_ROW_STATUS_1, 0, "Char 1: %d", (uint16_t)newValue);
      break;

    case SIMPLEPROFILE_CHAR3:
      SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR3, &newValue);

      Display_print1(dispHandle, SBP_ROW_STATUS_1, 0, "Char 3: %d", (uint16_t)newValue);
      break;

    default:
      // should not reach here!
      break;
  }
#endif //!FEATURE_OAD_ONCHIP
}

/*********************************************************************
 * @fn      SimpleBLEPeripheral_performPeriodicTask
 *
 * @brief   Perform a periodic application task. This function gets called
 *          every five seconds (SBP_PERIODIC_EVT_PERIOD). 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 SimpleBLEPeripheral_performPeriodicTask(void)
{
#ifndef FEATURE_OAD_ONCHIP
  uint8_t valueToCopy;

  // Call to retrieve the value of the third characteristic in the profile
  if (SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR3, &valueToCopy) == SUCCESS)
  {
    // Call to set that value of the fourth characteristic in the profile.
    // Note that if notifications of the fourth characteristic have been
    // enabled by a GATT client device, then a notification will be sent
    // every time this function is called.
    SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR4, sizeof(uint8_t),
                               &valueToCopy);
  }
#endif //!FEATURE_OAD_ONCHIP
}


#ifdef FEATURE_OAD
/*********************************************************************
 * @fn      SimpleBLEPeripheral_processOadWriteCB
 *
 * @brief   Process a write request to the OAD profile.
 *
 * @param   event      - event type:
 *                       OAD_WRITE_IDENTIFY_REQ
 *                       OAD_WRITE_BLOCK_REQ
 * @param   connHandle - the connection Handle this request is from.
 * @param   pData      - pointer to data for processing and/or storing.
 *
 * @return  None.
 */
void SimpleBLEPeripheral_processOadWriteCB(uint8_t event, uint16_t connHandle,
                                           uint8_t *pData)
{
  oadTargetWrite_t *oadWriteEvt = ICall_malloc( sizeof(oadTargetWrite_t) + \
                                             sizeof(uint8_t) * OAD_PACKET_SIZE);

  if ( oadWriteEvt != NULL )
  {
    oadWriteEvt->event = event;
    oadWriteEvt->connHandle = connHandle;

    oadWriteEvt->pData = (uint8_t *)(&oadWriteEvt->pData + 1);
    memcpy(oadWriteEvt->pData, pData, OAD_PACKET_SIZE);

    Queue_put(hOadQ, (Queue_Elem *)oadWriteEvt);

    // Post the application's event.  For OAD, no event flag is used.
    Event_post(syncEvent, SBP_QUEUE_PING_EVT);
  }
  else
  {
    // Fail silently.
  }
}
#endif //FEATURE_OAD

/*********************************************************************
 * @fn      SimpleBLEPeripheral_clockHandler
 *
 * @brief   Handler function for clock timeouts.
 *
 * @param   arg - event type
 *
 * @return  None.
 */
static void SimpleBLEPeripheral_clockHandler(UArg arg)
{
  // Wake up the application.
  Event_post(syncEvent, arg);
}

#if !defined(Display_DISABLE_ALL)
/*********************************************************************
 * @fn      SimpleBLEPeripheral_keyChangeHandler
 *
 * @brief   Key event handler function
 *
 * @param   keys - bitmap of pressed keys
 *
 * @return  none
 */
void SimpleBLEPeripheral_keyChangeHandler(uint8 keys)
{
  SimpleBLEPeripheral_enqueueMsg(SBP_KEY_CHANGE_EVT, keys);
}
#endif  // !Display_DISABLE_ALL

/*********************************************************************
 * @fn      SimpleBLEPeripheral_enqueueMsg
 *
 * @brief   Creates a message and puts the message in RTOS queue.
 *
 * @param   event - message event.
 * @param   state - message state.
 *
 * @return  None.
 */
static void SimpleBLEPeripheral_enqueueMsg(uint8_t event, uint8_t state)
{
  sbpEvt_t *pMsg;

  // Create dynamic pointer to message.
  if ((pMsg = ICall_malloc(sizeof(sbpEvt_t))))
  {
    pMsg->hdr.event = event;
    pMsg->hdr.state = state;

    // Enqueue the message.
    Util_enqueueMsg(appMsgQueue, syncEvent, (uint8*)pMsg);
  }
}

#if !defined(Display_DISABLE_ALL)
/*********************************************************************
 * @fn      SimpleBLEPeripheral_handleKeys
 *
 * @brief   Handles all key events for this device.
 *
 * @param   keys - bit field for key events. Valid entries:
 *                 KEY_LEFT
 *                 KEY_RIGHT
 *
 * @return  none
 */
static void SimpleBLEPeripheral_handleKeys(uint8_t keys)
{
  if (keys & KEY_LEFT)
  {
    // Check if the key is still pressed. WA for possible bouncing.
#if defined(CC2650DK_7ID)
    if (PIN_getInputValue(Board_KEY_LEFT) == 0)
#elif defined(CC2650_LAUNCHXL) || defined(CC2640R2_LAUNCHXL)
    if (PIN_getInputValue(Board_PIN_BUTTON0) == 0)
#endif // CC2650DK_7ID, CC2650_LAUNCHXL, CC2640R2_LAUNCHXL
    {
      tbm_buttonLeft();
    }
  }
  else if (keys & KEY_RIGHT)
  {
    // Check if the key is still pressed. WA for possible bouncing.
#if defined(CC2650DK_7ID)
    if (PIN_getInputValue(Board_KEY_RIGHT) == 0)
#elif defined(CC2650_LAUNCHXL) || defined(CC2640R2_LAUNCHXL)
    if (PIN_getInputValue(Board_PIN_BUTTON1) == 0)
#endif // CC2650DK_7ID, CC2650_LAUNCHXL, CC2640R2_LAUNCHXL
    {
      tbm_buttonRight();
    }
  }
}

/*********************************************************************
 * @fn      SimpleBLEPeripheral_doSetPhy
 *
 * @brief   Set PHY preference.
 *
 * @param   index - 0: 1M PHY
 *                  1: 2M PHY
 *                  2: 1M + 2M PHY
 *                  3: CODED PHY (Long range) (when PHY_LR_CFG is defined)
 *                  4: 1M + 2M + CODED PHY (when PHY_LR_CFG is defined)
 *
 * @return  always true
 */
bool SimpleBLEPeripheral_doSetPhy(uint8 index)
{
  uint8_t gapRoleState;
  uint16_t connectionHandle;
  static uint8_t phy[] = {
    HCI_PHY_1_MBPS, HCI_PHY_2_MBPS, HCI_PHY_1_MBPS | HCI_PHY_2_MBPS,

  // Note: BLE_V50_FEATURES is always defined and long range phy (PHY_LR_CFG) is
  //       defined in build_config.opt
  // To use the long range phy, HCI_PHY_CODED needs to be included
  #if (BLE_V50_FEATURES & PHY_LR_CFG)
    HCI_PHY_CODED, HCI_PHY_1_MBPS | HCI_PHY_2_MBPS | HCI_PHY_CODED,
  #endif  // PHY_LR_CFG
  };

  GAPRole_GetParameter(GAPROLE_STATE, &gapRoleState);
  GAPRole_GetParameter(GAPROLE_CONNHANDLE, &connectionHandle);

  // Set Phy Preference on the current connection. Apply the same value
  // for RX and TX.
  HCI_LE_SetPhyCmd(connectionHandle, 0, phy[index], phy[index], 0);

  Display_print1(dispHandle, SBP_ROW_RESULT, 0, "PHY preference: %s",
                 TBM_GET_ACTION_DESC(&sbpMenuMain, index));

  Display_clearLine(dispHandle, SBP_ROW_STATUS_1);

  return true;
}
#endif  // !Display_DISABLE_ALL

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

  • Hello,

    Can you provide some information that may help us resolve this issue as efficiently as possible? Can you specify the SDK versions you are using the for the CC2652 and the CC2640R2 devices? Have you made any modifications to the simple_central and simple_peripheral projects? If so, then could you specify these? Also, what happens if you try to connect to the CC2640R2 using a smartphone with a BLE scanning application? Could you try connecting to the CC2640R2 with the CC2652 via the UART menu?

    Best Regards,

    Jan

  • SDK of CC2652: 6.20

    SDK of CC2640R2F: 5.30

    Sorry that I forgot to upload the codes I wrote. 

    Files of CC2652

    /*
     * usrs.c
     *
     *  Created on: 2022��10��13��
     *      Author: 604-2
     */
    
    #include "usrs.h"
    
    //uart
    UART_Handle uart = NULL;
    UART_Params uartParams;
    //uart buffer
    char uart_header_str[30] = "STR0";
    char uart_header_hex[5] = "HEX0";
    
    PIN_State led_pins;
    PIN_Handle led_handle = NULL;
    
    //led config
    PIN_Config led_cfg[5] = {
     LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
     LED2 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
     LED3 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
     LED4 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
     PIN_TERMINATE
    };
    
    void Uart_Ini(){
        UART_init();
          // Create a UART with data processing off.
        UART_Params_init(&uartParams);
        uartParams.writeDataMode  = UART_DATA_BINARY;
        uartParams.readMode       = UART_MODE_CALLBACK; //Callbackģʽ
        uartParams.readDataMode   = UART_DATA_BINARY;
        uartParams.readEcho = UART_ECHO_OFF;
        uartParams.baudRate = 256000;
        uartParams.readCallback = UART_Write_Callback;
    
        //uart = UART_open(CC2640R2DK_7ID_UART0, &uartParams);
        uart = UART_open(0, &uartParams);
    
        if (uart == NULL) {
             while (1);
        }
    }
    
    void UART_Write_Callback (UART_Handle handle, void *buf, size_t count){
        ;
    }
    
    void Uart_SendMsg(int type, const void *str, size_t len){
        if(uart){
              switch (type){
              case UART_HEADER_HEX:
                  uart_header_hex[3] = len;
                  for(int i = 0; i < len; ++ i){
                      uart_header_hex[i + 4] = *(const char *)(str + i);
                  }
                  UART_write(uart, uart_header_hex, 4 + len);
                  break;
              case UART_HEADER_STR:
                  uart_header_str[3] = len;
                  for(int i = 0; i < len; ++ i){
                      uart_header_str[i + 4] = *(const char *)(str + i);
                  }
                  UART_write(uart, uart_header_str, 4 + len);
                  break;
              default:
                  return;
              };
        }
    }
    
    
    
    usrs.h3527.simple_central.c

    and the code of sysconfig of CC2652.

    /**
     * These arguments were used when this file was generated. They will be automatically applied on subsequent loads
     * via the GUI or CLI. Run CLI with '--help' for additional information on how to override these arguments.
     * @cliArgs --board "/ti/boards/CC26X2R1_LAUNCHXL" --rtos "tirtos7" --product "simplelink_cc13xx_cc26xx_sdk@6.20.00.29"
     * @versions {"tool":"1.13.0+2553"}
     */
    
    /**
     * Import the modules used in this configuration.
     */
    const ble          = scripting.addModule("/ti/ble5stack/ble");
    const CCFG         = scripting.addModule("/ti/devices/CCFG");
    const rfdesign     = scripting.addModule("/ti/devices/radioconfig/rfdesign");
    const Display      = scripting.addModule("/ti/display/Display");
    const Display1     = Display.addInstance();
    const AESCCM       = scripting.addModule("/ti/drivers/AESCCM");
    const AESCCM1      = AESCCM.addInstance();
    const AESCTRDRBG   = scripting.addModule("/ti/drivers/AESCTRDRBG");
    const AESCTRDRBG1  = AESCTRDRBG.addInstance();
    const AESECB       = scripting.addModule("/ti/drivers/AESECB");
    const AESECB1      = AESECB.addInstance();
    const ECDH         = scripting.addModule("/ti/drivers/ECDH");
    const ECDH1        = ECDH.addInstance();
    const GPIO         = scripting.addModule("/ti/drivers/GPIO");
    const GPIO1        = GPIO.addInstance();
    const GPIO2        = GPIO.addInstance();
    const NVS          = scripting.addModule("/ti/drivers/NVS");
    const NVS1         = NVS.addInstance();
    const Power        = scripting.addModule("/ti/drivers/Power");
    const RF           = scripting.addModule("/ti/drivers/RF");
    const TRNG         = scripting.addModule("/ti/drivers/TRNG");
    const TRNG1        = TRNG.addInstance();
    const UART2        = scripting.addModule("/ti/drivers/UART2", {}, false);
    const UART21       = UART2.addInstance();
    const LED          = scripting.addModule("/ti/drivers/apps/LED", {}, false);
    const LED1         = LED.addInstance();
    const LED2         = LED.addInstance();
    const Settings     = scripting.addModule("/ti/posix/tirtos/Settings");
    const BIOS         = scripting.addModule("/ti/sysbios/BIOS");
    const GateMutexPri = scripting.addModule("/ti/sysbios/gates/GateMutexPri");
    const HeapCallback = scripting.addModule("/ti/sysbios/heaps/HeapCallback");
    const Event        = scripting.addModule("/ti/sysbios/knl/Event");
    const Idle         = scripting.addModule("/ti/sysbios/knl/Idle", {}, false);
    const Idle2        = Idle.addInstance();
    const Mailbox      = scripting.addModule("/ti/sysbios/knl/Mailbox");
    const Error        = scripting.addModule("/ti/sysbios/runtime/Error");
    const SysCallback  = scripting.addModule("/ti/sysbios/runtime/SysCallback");
    const Timestamp    = scripting.addModule("/ti/sysbios/runtime/Timestamp");
    
    /**
     * Write custom configuration values to the imported modules.
     */
    ble.deviceRole                            = "CENTRAL_CFG";
    ble.lockProject                           = true;
    ble.bondPairing                           = "GAPBOND_PAIRING_MODE_INITIATE";
    ble.scanWin                               = 100;
    ble.maxConnNum                            = 1;
    ble.bondFailAction                        = "GAPBOND_FAIL_NO_ACTION";
    ble.rssiPollingPeriod                     = 1000;
    ble.maxPDUNum                             = 7;
    ble.disDevBySerUuid                       = true;
    ble.connIntMin                            = 7.5;
    ble.connIntMax                            = 4000;
    ble.maxPDUSize                            = 250;
    ble.radioConfig.codeExportConfig.$name    = "ti_devices_radioconfig_code_export_param0";
    ble.connUpdateParamsCentral.$name         = "ti_ble5stack_general_ble_conn_update_params0";
    ble.connUpdateParamsCentral.reqMinConnInt = 7.5;
    ble.connUpdateParamsCentral.reqMaxConnInt = 4000;
    ble.connUpdateParamsCentral.reqConnTo     = 32000;
    
    CCFG.enableBootloader         = true;
    CCFG.enableBootloaderBackdoor = true;
    CCFG.dioBootloaderBackdoor    = 13;
    CCFG.levelBootloaderBackdoor  = "Active low";
    CCFG.ccfgTemplate.$name       = "ti_devices_CCFG_CCFGCC26XXTemplate0";
    
    Display1.$name                    = "CONFIG_Display_0";
    Display1.$hardware                = system.deviceData.board.components.XDS110UART;
    Display1.enableANSI               = true;
    Display1.uartBufferSize           = 128;
    Display1.uart.$name               = "CONFIG_DISPLAY_UART";
    Display1.uart.txPinInstance.$name = "CONFIG_GPIO_UART_TX";
    Display1.uart.rxPinInstance.$name = "CONFIG_GPIO_UART_RX";
    
    AESCCM1.$name = "Board_AESCCM0";
    
    AESCTRDRBG1.$name              = "CONFIG_AESCTRDRBG_0";
    AESCTRDRBG1.aesctrObject.$name = "CONFIG_AESCTR_0";
    
    AESECB1.$name = "CONFIG_AESECB0";
    
    ECDH1.$name = "CONFIG_ECDH0";
    
    GPIO1.$hardware = system.deviceData.board.components["BTN-1"];
    GPIO1.$name     = "CONFIG_GPIO_BTN1";
    
    GPIO2.$hardware = system.deviceData.board.components["BTN-2"];
    GPIO2.$name     = "CONFIG_GPIO_BTN2";
    
    NVS1.$name                    = "CONFIG_NVSINTERNAL";
    NVS1.internalFlash.$name      = "ti_drivers_nvs_NVSCC26XX0";
    NVS1.internalFlash.regionBase = 0x48000;
    NVS1.internalFlash.regionSize = 0x4000;
    
    TRNG1.$name = "CONFIG_TRNG_0";
    
    UART21.$name              = "CONFIG_UART2_0";
    UART21.dataDirection      = "Send Only";
    UART21.uart.$assign       = "UART0";
    UART21.uart.txPin.$assign = "boosterpack.11";
    
    LED1.$name     = "CONFIG_LED_0";
    LED1.$hardware = system.deviceData.board.components.LED_RED;
    
    LED2.$name     = "CONFIG_LED_1";
    LED2.$hardware = system.deviceData.board.components.LED_GREEN;
    
    BIOS.assertsEnabled = false;
    BIOS.rtsGateType    = "BIOS_GateMutexPri";
    BIOS.heapSize       = 0x00000000;
    BIOS.heapType       = "HeapCallback";
    
    const Hwi           = scripting.addModule("/ti/sysbios/family/arm/m3/Hwi", {}, false);
    Hwi.enableException = false;
    
    HeapCallback.initFxn           = "osalHeapInitFxn";
    HeapCallback.allocInstFxn      = "osalHeapAllocFxn";
    HeapCallback.freeInstFxn       = "osalHeapFreeFxn";
    HeapCallback.getStatsInstFxn   = "osalHeapGetStatsFxn";
    HeapCallback.isBlockingInstFxn = "osalHeapIsBlockingFxn";
    
    const Clock       = scripting.addModule("/ti/sysbios/knl/Clock", {}, false);
    Clock.tickPeriod  = 10;
    Clock.swiPriority = 5;
    
    const Timer = scripting.addModule("/ti/sysbios/family/arm/cc26xx/Timer", {}, false);
    
    Idle2.$name   = "powerIdle";
    Idle2.idleFxn = "Power_idleFunc";
    
    const Semaphore            = scripting.addModule("/ti/sysbios/knl/Semaphore", {}, false);
    Semaphore.supportsPriority = false;
    
    const Swi         = scripting.addModule("/ti/sysbios/knl/Swi", {}, false);
    Swi.numPriorities = 6;
    
    const Task             = scripting.addModule("/ti/sysbios/knl/Task", {}, false);
    Task.defaultStackSize  = 512;
    Task.idleTaskStackSize = 768;
    Task.numPriorities     = 6;
    
    Error.policy       = "Error_SPIN";
    Error.printDetails = false;
    
    const System           = scripting.addModule("/ti/sysbios/runtime/System", {}, false);
    System.abortFxn        = "System_abortSpin";
    System.exitFxn         = "System_exitSpin";
    System.extendedFormats = "%f";
    System.supportModule   = "SysCallback";
    
    /**
     * Pinmux solution for unlocked pins/peripherals. This ensures that minor changes to the automatic solver in a future
     * version of the tool will not impact the pinmux you originally saw.  These lines can be completely deleted in order to
     * re-solve from scratch.
     */
    Display1.uart.uart.$suggestSolution       = "UART1";
    Display1.uart.uart.txPin.$suggestSolution = "boosterpack.4";
    Display1.uart.uart.rxPin.$suggestSolution = "boosterpack.3";
    GPIO1.gpioPin.$suggestSolution            = "boosterpack.13";
    GPIO2.gpioPin.$suggestSolution            = "boosterpack.12";
    LED1.ledPin.$suggestSolution              = "boosterpack.39";
    LED2.ledPin.$suggestSolution              = "boosterpack.40";
    Timer.rtc.$suggestSolution                = "RTC0";

    I don't know how to upload this file. 

    And files of CC2640R2F 

    /******************************************************************************
    
     @file       simple_peripheral.c
    
     @brief This file contains the Simple Peripheral sample application for use
            with the CC2650 Bluetooth Low Energy Protocol Stack.
    
     Group: CMCU, SCS
     Target Device: CC2640R2
    
     ******************************************************************************
     
     Copyright (c) 2013-2017, Texas Instruments Incorporated
     All rights reserved.
    
     Redistribution and use in source and binary forms, with or without
     modification, are permitted provided that the following conditions
     are met:
    
     *  Redistributions of source code must retain the above copyright
        notice, this list of conditions and the following disclaimer.
    
     *  Redistributions in binary form must reproduce the above copyright
        notice, this list of conditions and the following disclaimer in the
        documentation and/or other materials provided with the distribution.
    
     *  Neither the name of Texas Instruments Incorporated nor the names of
        its contributors may be used to endorse or promote products derived
        from this software without specific prior written permission.
    
     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    
     ******************************************************************************
     Release Name: simplelink_cc2640r2_sdk_1_40_00_45
     Release Date: 2017-07-20 17:16:59
     *****************************************************************************/
    
    /*********************************************************************
     * INCLUDES
     */
    #include <string.h>
    
    #include <ti/sysbios/knl/Task.h>
    #include <ti/sysbios/knl/Clock.h>
    #include <ti/sysbios/knl/Event.h>
    #include <ti/sysbios/knl/Queue.h>
    #include <ti/display/Display.h>
    
    #if defined( USE_FPGA ) || defined( DEBUG_SW_TRACE )
    #include <driverlib/ioc.h>
    #endif // USE_FPGA | DEBUG_SW_TRACE
    
    #include <icall.h>
    #include "util.h"
    /* This Header file contains all BLE API and icall structure definition */
    #include "icall_ble_api.h"
    
    #include "devinfoservice.h"
    #include "simple_gatt_profile.h"
    
    #if defined(FEATURE_OAD) || defined(IMAGE_INVALIDATE)
    #include "oad_target.h"
    #include "oad.h"
    #endif //FEATURE_OAD || IMAGE_INVALIDATE
    
    #include "peripheral.h"
    
    #ifdef USE_RCOSC
    #include "rcosc_calibration.h"
    #endif //USE_RCOSC
    
    
    #include "board.h"
    
    #if !defined(Display_DISABLE_ALL)
    #include "board_key.h"
    #include <menu/two_btn_menu.h>
    
    #include "simple_peripheral_menu.h"
    #endif  // !Display_DISABLE_ALL
    
    #include "simple_peripheral.h"
    
    #include "usrs.h"
    Clock_Struct noti_clock;
    /*********************************************************************
     * CONSTANTS
     */
    
    // Advertising interval when device is discoverable (units of 625us, 160=100ms)
    #define DEFAULT_ADVERTISING_INTERVAL          160
    
    // General discoverable mode: advertise indefinitely
    #define DEFAULT_DISCOVERABLE_MODE             GAP_ADTYPE_FLAGS_GENERAL
    
    #ifndef FEATURE_OAD
    // Minimum connection interval (units of 1.25ms, 80=100ms) for automatic
    // parameter update request
    #define DEFAULT_DESIRED_MIN_CONN_INTERVAL     800
    
    // Maximum connection interval (units of 1.25ms, 800=1000ms) for automatic
    // parameter update request
    #define DEFAULT_DESIRED_MAX_CONN_INTERVAL     900//800
    
    #else // FEATURE_OAD
    // Increase the the connection interval to allow for higher throughput for OAD
    
    // Minimum connection interval (units of 1.25ms, 8=10ms) for automatic
    // parameter update request
    #define DEFAULT_DESIRED_MIN_CONN_INTERVAL     8
    
    // Maximum connection interval (units of 1.25ms, 8=10ms) for automatic
    // parameter update request
    #define DEFAULT_DESIRED_MAX_CONN_INTERVAL     8
    #endif // FEATURE_OAD
    
    // Slave latency to use for automatic parameter update request
    #define DEFAULT_DESIRED_SLAVE_LATENCY         0
    
    // Supervision timeout value (units of 10ms, 1000=10s) for automatic parameter
    // update request
    #define DEFAULT_DESIRED_CONN_TIMEOUT          1000
    
    // After the connection is formed, the peripheral waits until the central
    // device asks for its preferred connection parameters
    #define DEFAULT_ENABLE_UPDATE_REQUEST         GAPROLE_LINK_PARAM_UPDATE_INITIATE_BOTH_PARAMS//GAPROLE_LINK_PARAM_UPDATE_WAIT_REMOTE_PARAMS
    
    // Connection Pause Peripheral time value (in seconds)
    #define DEFAULT_CONN_PAUSE_PERIPHERAL         1//6
    
    // How often to perform periodic event (in msec)
    #define SBP_PERIODIC_EVT_PERIOD               5000
    
    // Application specific event ID for HCI Connection Event End Events
    #define SBP_HCI_CONN_EVT_END_EVT              0x0001
    
    // Type of Display to open
    #if !defined(Display_DISABLE_ALL)
      #if defined(BOARD_DISPLAY_USE_LCD) && (BOARD_DISPLAY_USE_LCD!=0)
        #define SBP_DISPLAY_TYPE Display_Type_LCD
      #elif defined (BOARD_DISPLAY_USE_UART) && (BOARD_DISPLAY_USE_UART!=0)
        #define SBP_DISPLAY_TYPE Display_Type_UART
      #else // !BOARD_DISPLAY_USE_LCD && !BOARD_DISPLAY_USE_UART
        #define SBP_DISPLAY_TYPE 0 // Option not supported
      #endif // BOARD_DISPLAY_USE_LCD && BOARD_DISPLAY_USE_UART
    #else // BOARD_DISPLAY_USE_LCD && BOARD_DISPLAY_USE_UART
      #define SBP_DISPLAY_TYPE 0 // No Display
    #endif // !Display_DISABLE_ALL
    
    #ifdef FEATURE_OAD
    // The size of an OAD packet.
    #define OAD_PACKET_SIZE                       ((OAD_BLOCK_SIZE) + 2)
    #endif // FEATURE_OAD
    
    // Task configuration
    #define SBP_TASK_PRIORITY                     1
    
    #ifndef SBP_TASK_STACK_SIZE
    #define SBP_TASK_STACK_SIZE                   644
    #endif
    
    // Application events
    #define SBP_STATE_CHANGE_EVT                  0x0001
    #define SBP_CHAR_CHANGE_EVT                   0x0002
    #define SBP_KEY_CHANGE_EVT                    0x0004
    
    // Internal Events for RTOS application
    #define SBP_ICALL_EVT                         ICALL_MSG_EVENT_ID // Event_Id_31
    #define SBP_QUEUE_EVT                         UTIL_QUEUE_EVENT_ID // Event_Id_30
    #define SBP_PERIODIC_EVT                      Event_Id_00
    
    #ifdef FEATURE_OAD
    // Additional Application Events for OAD
    #define SBP_QUEUE_PING_EVT                    Event_Id_01
    
    // Bitwise OR of all events to pend on with OAD
    #define SBP_ALL_EVENTS                        (SBP_ICALL_EVT        | \
                                                   SBP_QUEUE_EVT        | \
                                                   SBP_PERIODIC_EVT     | \
                                                   SBP_QUEUE_PING_EVT)
    #else
    // Bitwise OR of all events to pend on
    #define SBP_ALL_EVENTS                        (SBP_ICALL_EVT        | \
                                                   SBP_QUEUE_EVT        | \
                                                   SBP_PERIODIC_EVT)
    #endif /* FEATURE_OAD */
    
    // Row numbers for two-button menu
    #define SBP_ROW_RESULT        TBM_ROW_APP
    #define SBP_ROW_STATUS_1      (TBM_ROW_APP + 1)
    #define SBP_ROW_STATUS_2      (TBM_ROW_APP + 2)
    #define SBP_ROW_ROLESTATE     (TBM_ROW_APP + 3)
    #define SBP_ROW_BDADDR        (TBM_ROW_APP + 4)
    
    /*********************************************************************
     * TYPEDEFS
     */
    
    // App event passed from profiles.
    typedef struct
    {
      appEvtHdr_t hdr;  // event header.
    } sbpEvt_t;
    
    /*********************************************************************
     * GLOBAL VARIABLES
     */
    
    // Display Interface
    Display_Handle dispHandle = NULL;
    
    /*********************************************************************
     * LOCAL VARIABLES
     */
    
    // Entity ID globally used to check for source and/or destination of messages
    static ICall_EntityID selfEntity;
    
    // Event globally used to post local events and pend on system and
    // local events.
    static ICall_SyncHandle syncEvent;
    
    // Clock instances for internal periodic events.
    static Clock_Struct periodicClock;
    
    // Queue object used for app messages
    static Queue_Struct appMsg;
    static Queue_Handle appMsgQueue;
    
    #if defined(FEATURE_OAD)
    // Event data from OAD profile.
    static Queue_Struct oadQ;
    static Queue_Handle hOadQ;
    #endif //FEATURE_OAD
    
    // Task configuration
    Task_Struct sbpTask;
    Char sbpTaskStack[SBP_TASK_STACK_SIZE];
    
    // Scan response data (max size = 31 bytes)
    static uint8_t scanRspData[] =
    {
      // complete name
      0x14,   // length of this data
      GAP_ADTYPE_LOCAL_NAME_COMPLETE,
      'S',
      'i',
      'm',
      'p',
      'l',
      'e',
      'B',
      'L',
      'E',
      'P',
      'e',
      'r',
      'i',
      'p',
      'h',
      'e',
      'r',
      'a',
      'l',
    
      // 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
    };
    
    // Advertisement data (max size = 31 bytes, though this is
    // best kept short to conserve power while advertising)
    static uint8_t advertData[] =
    {
      // Flags: this field sets the device to use general discoverable
      // mode (advertises indefinitely) instead of general
      // discoverable mode (advertise for 30 seconds at a time)
      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
    #if !defined(FEATURE_OAD) || defined(FEATURE_OAD_ONCHIP)
      0x03,   // length of this data
    #else //OAD for external flash
      0x05,  // length of this data
    #endif //FEATURE_OAD
      GAP_ADTYPE_16BIT_MORE,      // some of the UUID's, but not all
    #ifdef FEATURE_OAD
      LO_UINT16(OAD_SERVICE_UUID),
      HI_UINT16(OAD_SERVICE_UUID),
    #endif //FEATURE_OAD
    #ifndef FEATURE_OAD_ONCHIP
      LO_UINT16(SIMPLEPROFILE_SERV_UUID),
      HI_UINT16(SIMPLEPROFILE_SERV_UUID)
    #endif //FEATURE_OAD_ONCHIP
    };
    
    // GAP GATT Attributes
    static uint8_t attDeviceName[GAP_DEVICE_NAME_LEN] = "Simple Peripheral";
    
    // Globals used for ATT Response retransmission
    static gattMsgEvent_t *pAttRsp = NULL;
    static uint8_t rspTxRetry = 0;
    
    /*********************************************************************
     * LOCAL FUNCTIONS
     */
    
    static void SimpleBLEPeripheral_init( void );
    static void SimpleBLEPeripheral_taskFxn(UArg a0, UArg a1);
    
    static uint8_t SimpleBLEPeripheral_processStackMsg(ICall_Hdr *pMsg);
    static uint8_t SimpleBLEPeripheral_processGATTMsg(gattMsgEvent_t *pMsg);
    static void SimpleBLEPeripheral_processAppMsg(sbpEvt_t *pMsg);
    static void SimpleBLEPeripheral_processStateChangeEvt(gaprole_States_t newState);
    static void SimpleBLEPeripheral_processCharValueChangeEvt(uint8_t paramID);
    static void SimpleBLEPeripheral_performPeriodicTask(void);
    static void SimpleBLEPeripheral_clockHandler(UArg arg);
    
    static void SimpleBLEPeripheral_sendAttRsp(void);
    static void SimpleBLEPeripheral_freeAttRsp(uint8_t status);
    
    static void SimpleBLEPeripheral_stateChangeCB(gaprole_States_t newState);
    #ifndef FEATURE_OAD_ONCHIP
    static void SimpleBLEPeripheral_charValueChangeCB(uint8_t paramID);
    #endif //!FEATURE_OAD_ONCHIP
    static void SimpleBLEPeripheral_enqueueMsg(uint8_t event, uint8_t state);
    
    #ifdef FEATURE_OAD
    void SimpleBLEPeripheral_processOadWriteCB(uint8_t event, uint16_t connHandle,
                                               uint8_t *pData);
    #endif //FEATURE_OAD
    
    #if !defined(Display_DISABLE_ALL)
    void SimpleBLEPeripheral_keyChangeHandler(uint8 keys);
    static void SimpleBLEPeripheral_handleKeys(uint8_t keys);
    #endif  // !Display_DISABLE_ALL
    
    /*********************************************************************
     * EXTERN FUNCTIONS
     */
    extern void AssertHandler(uint8 assertCause, uint8 assertSubcause);
    
    /*********************************************************************
     * PROFILE CALLBACKS
     */
    
    // Peripheral GAPRole Callbacks
    static gapRolesCBs_t SimpleBLEPeripheral_gapRoleCBs =
    {
      SimpleBLEPeripheral_stateChangeCB     // GAPRole State Change Callbacks
    };
    
    // GAP Bond Manager Callbacks
    // These are set to NULL since they are not needed. The application
    // is set up to only perform justworks pairing.
    static gapBondCBs_t simpleBLEPeripheral_BondMgrCBs =
    {
      NULL, // Passcode callback
      NULL  // Pairing / Bonding state Callback
    };
    
    // Simple GATT Profile Callbacks
    #ifndef FEATURE_OAD_ONCHIP
    static simpleProfileCBs_t SimpleBLEPeripheral_simpleProfileCBs =
    {
      SimpleBLEPeripheral_charValueChangeCB // Simple GATT Characteristic value change callback
    };
    #endif //!FEATURE_OAD_ONCHIP
    
    #ifdef FEATURE_OAD
    static oadTargetCBs_t simpleBLEPeripheral_oadCBs =
    {
      SimpleBLEPeripheral_processOadWriteCB // OAD Profile Characteristic value change callback.
    };
    #endif //FEATURE_OAD
    
    /*********************************************************************
     * PUBLIC FUNCTIONS
     */
    
    /*********************************************************************
     * @fn      SimpleBLEPeripheral_createTask
     *
     * @brief   Task creation function for the Simple Peripheral.
     *
     * @param   None.
     *
     * @return  None.
     */
    void SimpleBLEPeripheral_createTask(void)
    {
      Task_Params taskParams;
    
      // Configure task
      Task_Params_init(&taskParams);
      taskParams.stack = sbpTaskStack;
      taskParams.stackSize = SBP_TASK_STACK_SIZE;
      taskParams.priority = SBP_TASK_PRIORITY;
    
      Task_construct(&sbpTask, SimpleBLEPeripheral_taskFxn, &taskParams, NULL);
    }
    
    /*********************************************************************
     * @fn      SimpleBLEPeripheral_init
     *
     * @brief   Called during initialization and contains application
     *          specific initialization (ie. hardware initialization/setup,
     *          table initialization, power up notification, etc), and
     *          profile initialization/setup.
     *
     * @param   None.
     *
     * @return  None.
     */
    static void SimpleBLEPeripheral_init(void)
    {
      // ******************************************************************
      // N0 STACK API CALLS CAN OCCUR BEFORE THIS CALL TO ICall_registerApp
      // ******************************************************************
      // Register the current thread as an ICall dispatcher application
      // so that the application can send and receive messages.
      ICall_registerApp(&selfEntity, &syncEvent);
    
    #ifdef USE_RCOSC
      RCOSC_enableCalibration();
    #endif // USE_RCOSC
    
    #if defined( USE_FPGA )
      // configure RF Core SMI Data Link
      IOCPortConfigureSet(IOID_12, IOC_PORT_RFC_GPO0, IOC_STD_OUTPUT);
      IOCPortConfigureSet(IOID_11, IOC_PORT_RFC_GPI0, IOC_STD_INPUT);
    
      // configure RF Core SMI Command Link
      IOCPortConfigureSet(IOID_10, IOC_IOCFG0_PORT_ID_RFC_SMI_CL_OUT, IOC_STD_OUTPUT);
      IOCPortConfigureSet(IOID_9, IOC_IOCFG0_PORT_ID_RFC_SMI_CL_IN, IOC_STD_INPUT);
    
      // configure RF Core tracer IO
      IOCPortConfigureSet(IOID_8, IOC_PORT_RFC_TRC, IOC_STD_OUTPUT);
    #else // !USE_FPGA
      #if defined( DEBUG_SW_TRACE )
        // configure RF Core tracer IO
        IOCPortConfigureSet(IOID_8, IOC_PORT_RFC_TRC, IOC_STD_OUTPUT | IOC_CURRENT_4MA | IOC_SLEW_ENABLE);
      #endif // DEBUG_SW_TRACE
    #endif // USE_FPGA
    
      // Create an RTOS queue for message from profile to be sent to app.
      appMsgQueue = Util_constructQueue(&appMsg);
    
      // Create one-shot clocks for internal periodic events.
      Util_constructClock(&periodicClock, SimpleBLEPeripheral_clockHandler,
                          SBP_PERIODIC_EVT_PERIOD, 0, false, SBP_PERIODIC_EVT);
    
      dispHandle = Display_open(SBP_DISPLAY_TYPE, NULL);
    
      // Set GAP Parameters: After a connection was established, delay in seconds
      // before sending when GAPRole_SetParameter(GAPROLE_PARAM_UPDATE_ENABLE,...)
      // uses GAPROLE_LINK_PARAM_UPDATE_INITIATE_BOTH_PARAMS or
      // GAPROLE_LINK_PARAM_UPDATE_INITIATE_APP_PARAMS
      // For current defaults, this has no effect.
      GAP_SetParamValue(TGAP_CONN_PAUSE_PERIPHERAL, DEFAULT_CONN_PAUSE_PERIPHERAL);
    
      // Setup the Peripheral GAPRole Profile. For more information see the User's Guide:
      // http://software-dl.ti.com/lprf/ble5stack-docs-latest/html/ble-stack/gaprole.html
      {
        // Device starts advertising upon initialization of GAP
        uint8_t initialAdvertEnable = TRUE;
    
        // By setting this to zero, the device will go into the waiting state after
        // being discoverable for 30.72 second, and will not being advertising again
        // until re-enabled by the application
        uint16_t advertOffTime = 0;
    
        uint8_t enableUpdateRequest = DEFAULT_ENABLE_UPDATE_REQUEST;
        uint16_t desiredMinInterval = DEFAULT_DESIRED_MIN_CONN_INTERVAL;
        uint16_t desiredMaxInterval = DEFAULT_DESIRED_MAX_CONN_INTERVAL;
        uint16_t desiredSlaveLatency = DEFAULT_DESIRED_SLAVE_LATENCY;
        uint16_t desiredConnTimeout = DEFAULT_DESIRED_CONN_TIMEOUT;
    
        // Set the Peripheral GAPRole Parameters
        GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t),
                             &initialAdvertEnable);
        GAPRole_SetParameter(GAPROLE_ADVERT_OFF_TIME, sizeof(uint16_t),
                             &advertOffTime);
    
        GAPRole_SetParameter(GAPROLE_SCAN_RSP_DATA, sizeof(scanRspData),
                             scanRspData);
        GAPRole_SetParameter(GAPROLE_ADVERT_DATA, sizeof(advertData), advertData);
    
        GAPRole_SetParameter(GAPROLE_PARAM_UPDATE_ENABLE, sizeof(uint8_t),
                             &enableUpdateRequest);
        GAPRole_SetParameter(GAPROLE_MIN_CONN_INTERVAL, sizeof(uint16_t),
                             &desiredMinInterval);
        GAPRole_SetParameter(GAPROLE_MAX_CONN_INTERVAL, sizeof(uint16_t),
                             &desiredMaxInterval);
        GAPRole_SetParameter(GAPROLE_SLAVE_LATENCY, sizeof(uint16_t),
                             &desiredSlaveLatency);
        GAPRole_SetParameter(GAPROLE_TIMEOUT_MULTIPLIER, sizeof(uint16_t),
                             &desiredConnTimeout);
      }
    
      // Set the Device Name characteristic in the GAP GATT Service
      // For more information, see the section in the User's Guide:
      // http://software-dl.ti.com/lprf/ble5stack-docs-latest/html/ble-stack/gaprole.html
      GGS_SetParameter(GGS_DEVICE_NAME_ATT, GAP_DEVICE_NAME_LEN, attDeviceName);
    
      // Set GAP Parameters to set the advertising interval
      // For more information, see the GAP section of the User's Guide:
      // http://software-dl.ti.com/lprf/ble5stack-docs-latest/html/ble-stack/gatt.html#gap-gatt-service-ggs
      {
        // Use the same interval for general and limited advertising.
        // Note that only general advertising will occur based on the above configuration
        uint16_t advInt = DEFAULT_ADVERTISING_INTERVAL;
    
        GAP_SetParamValue(TGAP_LIM_DISC_ADV_INT_MIN, advInt);
        GAP_SetParamValue(TGAP_LIM_DISC_ADV_INT_MAX, advInt);
        GAP_SetParamValue(TGAP_GEN_DISC_ADV_INT_MIN, advInt);
        GAP_SetParamValue(TGAP_GEN_DISC_ADV_INT_MAX, advInt);
      }
    
      // Setup the GAP Bond Manager. For more information see the section in the
      // User's Guide:
      // http://software-dl.ti.com/lprf/ble5stack-docs-latest/html/ble-stack/gapbondmngr.html#
      {
        // Hard code the passkey that will be used for pairing. The GAPBondMgr will
        // use this key instead of issuing a callback to the application. This only
        // works if both sides of the connection know to use this same key at
        // compile-time.
        uint32_t passkey = 0; // passkey "000000"
        // Don't send a pairing request after connecting; the peer device must
        // initiate pairing
        uint8_t pairMode = GAPBOND_PAIRING_MODE_WAIT_FOR_REQ;
        // Use authenticated pairing: require passcode.
        uint8_t mitm = TRUE;
        // This device only has display capabilities. Therefore, it will display the
        // passcode during pairing. However, since the default passcode is being
        // used, there is no need to display anything.
        uint8_t ioCap = GAPBOND_IO_CAP_DISPLAY_ONLY;
        // Request bonding (storing long-term keys for re-encryption upon subsequent
        // connections without repairing)
        uint8_t bonding = TRUE;
    
        GAPBondMgr_SetParameter(GAPBOND_DEFAULT_PASSCODE, sizeof(uint32_t),
                                &passkey);
        GAPBondMgr_SetParameter(GAPBOND_PAIRING_MODE, sizeof(uint8_t), &pairMode);
        GAPBondMgr_SetParameter(GAPBOND_MITM_PROTECTION, sizeof(uint8_t), &mitm);
        GAPBondMgr_SetParameter(GAPBOND_IO_CAPABILITIES, sizeof(uint8_t), &ioCap);
        GAPBondMgr_SetParameter(GAPBOND_BONDING_ENABLED, sizeof(uint8_t), &bonding);
      }
    
      // Initialize GATT attributes
      GGS_AddService(GATT_ALL_SERVICES);           // GAP GATT Service
      GATTServApp_AddService(GATT_ALL_SERVICES);   // GATT Service
      DevInfo_AddService();                        // Device Information Service
    
    #ifndef FEATURE_OAD_ONCHIP
      SimpleProfile_AddService(GATT_ALL_SERVICES); // Simple GATT Profile
    #endif //!FEATURE_OAD_ONCHIP
    
    #ifdef FEATURE_OAD
      VOID OAD_addService();                       // OAD Profile
      OAD_register((oadTargetCBs_t *)&simpleBLEPeripheral_oadCBs);
      hOadQ = Util_constructQueue(&oadQ);
    #endif //FEATURE_OAD
    
    #ifdef IMAGE_INVALIDATE
      Reset_addService();
    #endif //IMAGE_INVALIDATE
    
    
    #ifndef FEATURE_OAD_ONCHIP
      // Setup the SimpleProfile Characteristic Values
      // For more information, see the sections in the User's Guide:
      // http://software-dl.ti.com/lprf/ble5stack-docs-latest/html/ble-stack/gatt.html#
      // http://software-dl.ti.com/lprf/ble5stack-docs-latest/html/ble-stack/gatt.html#gattservapp-module
      {
        uint8_t charValue1 = 1;
        uint8_t charValue2 = 2;
        uint8_t charValue3 = 3;
        uint8_t charValue4 = 4;
        uint8_t charValue5[SIMPLEPROFILE_CHAR5_LEN] = { 1, 2, 3, 4, 5 };
    
        SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR1, sizeof(uint8_t),
                                   &charValue1);
        SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR2, sizeof(uint8_t),
                                   &charValue2);
        SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR3, sizeof(uint8_t),
                                   &charValue3);
        SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR4, sizeof(uint8_t),
                                   &charValue4);
        SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR5, SIMPLEPROFILE_CHAR5_LEN,
                                   charValue5);
      }
    
      // Register callback with SimpleGATTprofile
      SimpleProfile_RegisterAppCBs(&SimpleBLEPeripheral_simpleProfileCBs);
    #endif //!FEATURE_OAD_ONCHIP
    
      // Start Bond Manager and register callback
      VOID GAPBondMgr_Register(&simpleBLEPeripheral_BondMgrCBs);
    
      // Register with GAP for HCI/Host messages. This is needed to receive HCI
      // events. For more information, see the section in the User's Guide:
      // http://software-dl.ti.com/lprf/ble5stack-docs-latest/html/ble-stack/hci.html
      GAP_RegisterForMsgs(selfEntity);
    
      // Register for GATT local events and ATT Responses pending for transmission
      GATT_RegisterForMsgs(selfEntity);
    
      // Set default values for Data Length Extension
      // This should be included only if Extended Data Length Feature is enabled
      // in build_config.opt in stack project.
      {
        //Set initial values to maximum, RX is set to max. by default(251 octets, 2120us)
        #define APP_SUGGESTED_PDU_SIZE 251 //default is 27 octets(TX)
        #define APP_SUGGESTED_TX_TIME 2120 //default is 328us(TX)
    
        // This API is documented in hci.h
        // See BLE5-Stack User's Guide for information on using this command:
        // http://software-dl.ti.com/lprf/ble5stack-docs-latest/html/ble-stack/data-length-extensions.html
        // HCI_LE_WriteSuggestedDefaultDataLenCmd(APP_SUGGESTED_PDU_SIZE, APP_SUGGESTED_TX_TIME);
      }
    
    #if defined (BLE_V42_FEATURES) && (BLE_V42_FEATURES & PRIVACY_1_2_CFG)
      // Initialize GATT Client
      GATT_InitClient();
    
      // This line masks the Resolvable Private Address Only (RPAO) Characteristic
      // in the GAP GATT Server from being detected by remote devices. This value
      // cannot be toggled without power cycling but should remain consistent across
      // power-cycles. Removing this command when Privacy is used will cause this
      // device to be treated in Network Privacy Mode by bonded devices - this means
      // that after disconnecting they will not respond to this device's PDUs which
      // contain its Identity Address.
      // Devices wanting to use Network Privacy Mode with other BT5 devices, this
      // line should be commented out.
      GGS_SetParamValue(GGS_DISABLE_RPAO_CHARACTERISTIC);
    #endif // BLE_V42_FEATURES & PRIVACY_1_2_CFG
    
    #if !defined(Display_DISABLE_ALL)
      // Set the title of the main menu
      #if defined FEATURE_OAD
        #if defined (HAL_IMAGE_A)
          TBM_SET_TITLE(&sbpMenuMain, "BLE Peripheral A");
        #else
          TBM_SET_TITLE(&sbpMenuMain, "BLE Peripheral B");
        #endif // HAL_IMAGE_A
      #else
        TBM_SET_TITLE(&sbpMenuMain, "BLE Peripheral");
      #endif // FEATURE_OAD
    
      // Initialize Two-Button Menu module
      tbm_setItemStatus(&sbpMenuMain, TBM_ITEM_NONE, TBM_ITEM_ALL);
      tbm_initTwoBtnMenu(dispHandle, &sbpMenuMain, 3, NULL);
    
      // Init key debouncer
      Board_initKeys(SimpleBLEPeripheral_keyChangeHandler);
    #endif  // !Display_DISABLE_ALL
    
    #if !defined (USE_LL_CONN_PARAM_UPDATE)
      // Get the currently set local supported LE features
      // The will result in a HCI_LE_READ_LOCAL_SUPPORTED_FEATURES event that
      // will get received in the main task processing loop. At this point,
      // feature bits can be set / cleared and the features can be updated.
      HCI_LE_ReadLocalSupportedFeaturesCmd();
    #endif // !defined (USE_LL_CONN_PARAM_UPDATE)
    
      // Start the GAPRole
      VOID GAPRole_StartDevice(&SimpleBLEPeripheral_gapRoleCBs);
      HCI_EXT_SetTxPowerCmd(HCI_EXT_TX_POWER_5_DBM);
    
      Uart_Ini();
      led_handle = PIN_open(&led_pins, led_cfg);
      Util_constructClock(&noti_clock, SimpleBLEPeripheral_clockHandler,  SBP_NOTI_EVT_PERIOD, 0, false, SBP_NOTI_EVT);
    //  PIN_setOutputValue(led_handle, LED1, 1);
    }
    
    void SimplePeripheral_SendNotify(){
        uint16_t connectionHandle;
        GAPRole_GetParameter(GAPROLE_CONNHANDLE, &connectionHandle);
        if(connectionHandle == INVALID_CONNHANDLE){
            return;
        }
    
        attHandleValueNoti_t noti;
        noti.handle = 0x29; //simpleProfileAttrTbl[11].handle;
        uint16_t len_msg = 9;
        noti.len = len_msg;
    
        bStatus_t status;
        noti.pValue = (uint8 *)GATT_bm_alloc(connectionHandle, ATT_HANDLE_VALUE_NOTI, len_msg, &len_msg );
        if(noti.pValue!=NULL){
            for(int i = 0;i < 9; i++){
                noti.pValue[i] = i;
            }
            status = GATT_Notification( connectionHandle, &noti, 0);
            if ( status != SUCCESS ){ //if noti not sent
                GATT_bm_free( (gattMsg_t *)&noti, ATT_HANDLE_VALUE_NOTI );
            }
        }
        else{
            GATT_bm_free( (gattMsg_t *)&noti, ATT_HANDLE_VALUE_NOTI );
            status = bleNoResources;
            // bleNoResources was returned
            asm(" NOP ");
        }
    }
    
    /*********************************************************************
     * @fn      SimpleBLEPeripheral_taskFxn
     *
     * @brief   Application task entry point for the Simple Peripheral.
     *
     * @param   a0, a1 - not used.
     *
     * @return  None.
     */
    static void SimpleBLEPeripheral_taskFxn(UArg a0, UArg a1)
    {
      // Initialize application
      SimpleBLEPeripheral_init();
    
      // Application main loop
      for (;;)
      {
        uint32_t events;
    
        // Waits for an event to be posted associated with the calling thread.
        // Note that an event associated with a thread is posted when a
        // message is queued to the message receive queue of the thread
        events = Event_pend(syncEvent, Event_Id_NONE, SBP_ALL_EVENTS | SBP_NOTI_EVT,
                            ICALL_TIMEOUT_FOREVER);
    
        if (events)
        {
          ICall_EntityID dest;
          ICall_ServiceEnum src;
          ICall_HciExtEvt *pMsg = NULL;
    
          // Fetch any available messages that might have been sent from the stack
          if (ICall_fetchServiceMsg(&src, &dest,
                                    (void **)&pMsg) == ICALL_ERRNO_SUCCESS)
          {
            uint8 safeToDealloc = TRUE;
    
            if ((src == ICALL_SERVICE_CLASS_BLE) && (dest == selfEntity))
            {
              ICall_Stack_Event *pEvt = (ICall_Stack_Event *)pMsg;
    
              // Check for BLE stack events first
              if (pEvt->signature == 0xffff)
              {
                // The GATT server might have returned a blePending as it was trying
                // to process an ATT Response. Now that we finished with this
                // connection event, let's try sending any remaining ATT Responses
                // on the next connection event.
                if (pEvt->event_flag & SBP_HCI_CONN_EVT_END_EVT)
                {
                  // Try to retransmit pending ATT Response (if any)
                  SimpleBLEPeripheral_sendAttRsp();
                }
              }
              else
              {
                // Process inter-task message
                safeToDealloc = SimpleBLEPeripheral_processStackMsg((ICall_Hdr *)pMsg);
              }
            }
    
            if (pMsg && safeToDealloc)
            {
              ICall_freeMsg(pMsg);
            }
          }
    
          // If RTOS queue is not empty, process app message.
          if (events & SBP_QUEUE_EVT)
          {
            while (!Queue_empty(appMsgQueue))
            {
              sbpEvt_t *pMsg = (sbpEvt_t *)Util_dequeueMsg(appMsgQueue);
              if (pMsg)
              {
                // Process message.
                SimpleBLEPeripheral_processAppMsg(pMsg);
    
                // Free the space from the message.
                ICall_free(pMsg);
              }
            }
          }
    
          if (events & SBP_PERIODIC_EVT)
          {
            Util_startClock(&periodicClock);
    
            // Perform periodic application task
            SimpleBLEPeripheral_performPeriodicTask();
          }
    
          if(events & SBP_NOTI_EVT){
              Util_startClock(&noti_clock);
              SimplePeripheral_SendNotify();
          }
    #ifdef FEATURE_OAD
          if (events & SBP_QUEUE_PING_EVT)
          {
            while (!Queue_empty(hOadQ))
            {
              oadTargetWrite_t *oadWriteEvt = Queue_get(hOadQ);
    
              // Identify new image.
              if (oadWriteEvt->event == OAD_WRITE_IDENTIFY_REQ)
              {
                OAD_imgIdentifyWrite(oadWriteEvt->connHandle, oadWriteEvt->pData);
              }
              // Write a next block request.
              else if (oadWriteEvt->event == OAD_WRITE_BLOCK_REQ)
              {
                OAD_imgBlockWrite(oadWriteEvt->connHandle, oadWriteEvt->pData);
              }
    
              // Free buffer.
              ICall_free(oadWriteEvt);
            }
          }
    #endif //FEATURE_OAD
        }
      }
    }
    
    /*********************************************************************
     * @fn      SimpleBLEPeripheral_processStackMsg
     *
     * @brief   Process an incoming stack message.
     *
     * @param   pMsg - message to process
     *
     * @return  TRUE if safe to deallocate incoming message, FALSE otherwise.
     */
    static uint8_t SimpleBLEPeripheral_processStackMsg(ICall_Hdr *pMsg)
    {
      uint8_t safeToDealloc = TRUE;
    
      switch (pMsg->event)
      {
        case GATT_MSG_EVENT:
          // Process GATT message
          safeToDealloc = SimpleBLEPeripheral_processGATTMsg((gattMsgEvent_t *)pMsg);
          break;
    
        case HCI_GAP_EVENT_EVENT:
          {
    
            // Process HCI message
            switch(pMsg->status)
            {
              case HCI_COMMAND_COMPLETE_EVENT_CODE:
                // Process HCI Command Complete Event
                {
    
    #if !defined (USE_LL_CONN_PARAM_UPDATE)
                  // This code will disable the use of the LL_CONNECTION_PARAM_REQ
                  // control procedure (for connection parameter updates, the
                  // L2CAP Connection Parameter Update procedure will be used
                  // instead). To re-enable the LL_CONNECTION_PARAM_REQ control
                  // procedures, define the symbol USE_LL_CONN_PARAM_UPDATE
                  // The L2CAP Connection Parameter Update procedure is used to
                  // support a delta between the minimum and maximum connection
                  // intervals required by some iOS devices.
    
                  // Parse Command Complete Event for opcode and status
                  hciEvt_CmdComplete_t* command_complete = (hciEvt_CmdComplete_t*) pMsg;
                  uint8_t   pktStatus = command_complete->pReturnParam[0];
    
                  //find which command this command complete is for
                  switch (command_complete->cmdOpcode)
                  {
                    case HCI_LE_READ_LOCAL_SUPPORTED_FEATURES:
                      {
                        if (pktStatus == SUCCESS)
                        {
                          uint8_t featSet[8];
    
                          // Get current feature set from received event (bits 1-9
                          // of the returned data
                          memcpy( featSet, &command_complete->pReturnParam[1], 8 );
    
                          // Clear bit 1 of byte 0 of feature set to disable LL
                          // Connection Parameter Updates
                          CLR_FEATURE_FLAG( featSet[0], LL_FEATURE_CONN_PARAMS_REQ );
    
                          // Update controller with modified features
                          HCI_EXT_SetLocalSupportedFeaturesCmd( featSet );
                        }
                      }
                      break;
    
                    default:
                      //do nothing
                      break;
                  }
    #endif // !defined (USE_LL_CONN_PARAM_UPDATE)
    
                }
                break;
    
              case HCI_BLE_HARDWARE_ERROR_EVENT_CODE:
                AssertHandler(HAL_ASSERT_CAUSE_HARDWARE_ERROR,0);
                break;
    
              // LE Events
              case HCI_LE_EVENT_CODE:
                {
                  hciEvt_BLEPhyUpdateComplete_t *pPUC
                    = (hciEvt_BLEPhyUpdateComplete_t*) pMsg;
    
                  // A Phy Update Has Completed or Failed
                  if (pPUC->BLEEventCode == HCI_BLE_PHY_UPDATE_COMPLETE_EVENT)
                  {
                    if (pPUC->status != SUCCESS)
                    {
                      Display_print0(dispHandle, SBP_ROW_STATUS_1, 0,
                                     "PHY Change failure");
                    }
                    else
                    {
                      Display_print0(dispHandle, SBP_ROW_STATUS_1, 0,
                                     "PHY Update Complete");
                      // Only symmetrical PHY is supported.
                      // rxPhy should be equal to txPhy.
                      Display_print1(dispHandle, SBP_ROW_STATUS_2, 0,
                                     "Current PHY: %s",
                                     (pPUC->rxPhy == HCI_PHY_1_MBPS) ? "1 Mbps" :
    
    // Note: BLE_V50_FEATURES is always defined and long range phy (PHY_LR_CFG) is
    //       defined in build_config.opt
    #if (BLE_V50_FEATURES & PHY_LR_CFG)
                                       ((pPUC->rxPhy == HCI_PHY_2_MBPS) ? "2 Mbps" :
                                           "Coded:S2"));
    #else  // !PHY_LR_CFG
                                       "2 Mbps");
    #endif // PHY_LR_CFG
                    }
                  }
                }
                break;
    
              default:
                break;
            }
          }
          break;
    
          default:
            // do nothing
            break;
    
        }
    
      return (safeToDealloc);
    }
    
    /*********************************************************************
     * @fn      SimpleBLEPeripheral_processGATTMsg
     *
     * @brief   Process GATT messages and events.
     *
     * @return  TRUE if safe to deallocate incoming message, FALSE otherwise.
     */
    static uint8_t SimpleBLEPeripheral_processGATTMsg(gattMsgEvent_t *pMsg)
    {
      // See if GATT server was unable to transmit an ATT response
      if (pMsg->hdr.status == blePending)
      {
          PIN_setOutputValue(led_handle, LED4, 1);
        // No HCI buffer was available. Let's try to retransmit the response
        // on the next connection event.
        if (HCI_EXT_ConnEventNoticeCmd(pMsg->connHandle, selfEntity,
                                       SBP_HCI_CONN_EVT_END_EVT) == SUCCESS)
        {
          // First free any pending response
          SimpleBLEPeripheral_freeAttRsp(FAILURE);
    
          // Hold on to the response message for retransmission
          pAttRsp = pMsg;
    
          // Don't free the response message yet
          return (FALSE);
        }
      }
      else if (pMsg->method == ATT_FLOW_CTRL_VIOLATED_EVENT)
      {
          PIN_setOutputValue(led_handle, LED3, 1);
        // ATT request-response or indication-confirmation flow control is
        // violated. All subsequent ATT requests or indications will be dropped.
        // The app is informed in case it wants to drop the connection.
    
        // Display the opcode of the message that caused the violation.
        Display_print1(dispHandle, SBP_ROW_RESULT, 0, "FC Violated: %d", pMsg->msg.flowCtrlEvt.opcode);
      }
      else if (pMsg->method == ATT_MTU_UPDATED_EVENT)
      {
        // MTU size updated
        PIN_setOutputValue(led_handle, LED2, 1);
        Display_print1(dispHandle, SBP_ROW_RESULT, 0, "MTU Size: %d", pMsg->msg.mtuEvt.MTU);
      }
    
      // Free message payload. Needed only for ATT Protocol messages
      GATT_bm_free(&pMsg->msg, pMsg->method);
    
      // It's safe to free the incoming message
      return (TRUE);
    }
    
    /*********************************************************************
     * @fn      SimpleBLEPeripheral_sendAttRsp
     *
     * @brief   Send a pending ATT response message.
     *
     * @param   none
     *
     * @return  none
     */
    static void SimpleBLEPeripheral_sendAttRsp(void)
    {
      // See if there's a pending ATT Response to be transmitted
      if (pAttRsp != NULL)
      {
        uint8_t status;
    
        // Increment retransmission count
        rspTxRetry++;
    
        // Try to retransmit ATT response till either we're successful or
        // the ATT Client times out (after 30s) and drops the connection.
        status = GATT_SendRsp(pAttRsp->connHandle, pAttRsp->method, &(pAttRsp->msg));
        if ((status != blePending) && (status != MSG_BUFFER_NOT_AVAIL))
        {
          // Disable connection event end notice
          HCI_EXT_ConnEventNoticeCmd(pAttRsp->connHandle, selfEntity, 0);
    
          // We're done with the response message
          SimpleBLEPeripheral_freeAttRsp(status);
        }
        else
        {
          // Continue retrying
          Display_print1(dispHandle, SBP_ROW_STATUS_1, 0, "Rsp send retry: %d", rspTxRetry);
        }
      }
    }
    
    /*********************************************************************
     * @fn      SimpleBLEPeripheral_freeAttRsp
     *
     * @brief   Free ATT response message.
     *
     * @param   status - response transmit status
     *
     * @return  none
     */
    static void SimpleBLEPeripheral_freeAttRsp(uint8_t status)
    {
      // See if there's a pending ATT response message
      if (pAttRsp != NULL)
      {
        // See if the response was sent out successfully
        if (status == SUCCESS)
        {
          Display_print1(dispHandle, SBP_ROW_STATUS_1, 0, "Rsp sent retry: %d", rspTxRetry);
        }
        else
        {
          // Free response payload
          GATT_bm_free(&pAttRsp->msg, pAttRsp->method);
    
          Display_print1(dispHandle, SBP_ROW_STATUS_1, 0, "Rsp retry failed: %d", rspTxRetry);
        }
    
        // Free response message
        ICall_freeMsg(pAttRsp);
    
        // Reset our globals
        pAttRsp = NULL;
        rspTxRetry = 0;
      }
    }
    
    /*********************************************************************
     * @fn      SimpleBLEPeripheral_processAppMsg
     *
     * @brief   Process an incoming callback from a profile.
     *
     * @param   pMsg - message to process
     *
     * @return  None.
     */
    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;
    
    #if !defined(Display_DISABLE_ALL)
        case SBP_KEY_CHANGE_EVT:
          SimpleBLEPeripheral_handleKeys(pMsg->hdr.state);
          break;
    #endif  // !Display_DISABLE_ALL
    
        default:
          // Do nothing.
          break;
      }
    }
    
    /*********************************************************************
     * @fn      SimpleBLEPeripheral_stateChangeCB
     *
     * @brief   Callback from GAP Role indicating a role state change.
     *
     * @param   newState - new state
     *
     * @return  None.
     */
    static void SimpleBLEPeripheral_stateChangeCB(gaprole_States_t newState)
    {
      SimpleBLEPeripheral_enqueueMsg(SBP_STATE_CHANGE_EVT, newState);
    }
    
    /*********************************************************************
     * @fn      SimpleBLEPeripheral_processStateChangeEvt
     *
     * @brief   Process a pending GAP Role state change event.
     *
     * @param   newState - new state
     *
     * @return  None.
     */
    static void SimpleBLEPeripheral_processStateChangeEvt(gaprole_States_t newState)
    {
    #ifdef PLUS_BROADCASTER
      static bool firstConnFlag = false;
    #endif // PLUS_BROADCASTER
    
      switch ( newState )
      {
        case GAPROLE_STARTED:
          {
            uint8_t ownAddress[B_ADDR_LEN];
            uint8_t systemId[DEVINFO_SYSTEM_ID_LEN];
    
            GAPRole_GetParameter(GAPROLE_BD_ADDR, ownAddress);
    
            // use 6 bytes of device address for 8 bytes of system ID value
            systemId[0] = ownAddress[0];
            systemId[1] = ownAddress[1];
            systemId[2] = ownAddress[2];
    
            // set middle bytes to zero
            systemId[4] = 0x00;
            systemId[3] = 0x00;
    
            // shift three bytes up
            systemId[7] = ownAddress[5];
            systemId[6] = ownAddress[4];
            systemId[5] = ownAddress[3];
    
            DevInfo_SetParameter(DEVINFO_SYSTEM_ID, DEVINFO_SYSTEM_ID_LEN, systemId);
    
            // Display device address
            Display_print0(dispHandle, SBP_ROW_BDADDR, 0, Util_convertBdAddr2Str(ownAddress));
            Display_print0(dispHandle, SBP_ROW_ROLESTATE, 0, "Initialized");
          }
          break;
    
        case GAPROLE_ADVERTISING:
          Display_print0(dispHandle, SBP_ROW_ROLESTATE, 0, "Advertising");
          break;
    
    #ifdef PLUS_BROADCASTER
        // After a connection is dropped, a device in PLUS_BROADCASTER will continue
        // sending non-connectable advertisements and shall send this change of
        // state to the application.  These are then disabled here so that sending
        // connectable advertisements can resume.
        case GAPROLE_ADVERTISING_NONCONN:
          {
            uint8_t advertEnabled = FALSE;
    
            // Disable non-connectable advertising.
            GAPRole_SetParameter(GAPROLE_ADV_NONCONN_ENABLED, sizeof(uint8_t),
                               &advertEnabled);
    
            advertEnabled = TRUE;
    
            // Enabled connectable advertising.
            GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t),
                                 &advertEnabled);
    
            // Reset flag for next connection.
            firstConnFlag = false;
    
            SimpleBLEPeripheral_freeAttRsp(bleNotConnected);
          }
          break;
    #endif //PLUS_BROADCASTER
    
        case GAPROLE_CONNECTED:
          {
            PIN_setOutputValue(led_handle, LED1, 1);
            linkDBInfo_t linkInfo;
            uint8_t numActive = 0;
    
            Util_startClock(&periodicClock);
            Util_startClock(&noti_clock);
            numActive = linkDB_NumActive();
    
            // Use numActive to determine the connection handle of the last
            // connection
            if ( linkDB_GetInfo( numActive - 1, &linkInfo ) == SUCCESS )
            {
              Display_print1(dispHandle, SBP_ROW_ROLESTATE, 0, "Num Conns: %d", (uint16_t)numActive);
              Display_print0(dispHandle, SBP_ROW_STATUS_1, 0, Util_convertBdAddr2Str(linkInfo.addr));
            }
            else
            {
              uint8_t peerAddress[B_ADDR_LEN];
    
              GAPRole_GetParameter(GAPROLE_CONN_BD_ADDR, peerAddress);
    
              Display_print0(dispHandle, SBP_ROW_ROLESTATE, 0, "Connected");
              Display_print0(dispHandle, SBP_ROW_STATUS_1, 0, Util_convertBdAddr2Str(peerAddress));
            }
    
    #if !defined(Display_DISABLE_ALL)
            tbm_setItemStatus(&sbpMenuMain, TBM_ITEM_ALL, TBM_ITEM_NONE);
    #endif  // !Display_DISABLE_ALL
    
            #ifdef PLUS_BROADCASTER
              // Only turn advertising on for this state when we first connect
              // otherwise, when we go from connected_advertising back to this state
              // we will be turning advertising back on.
              if (firstConnFlag == false)
              {
                uint8_t advertEnabled = FALSE; // Turn on Advertising
    
                // Disable connectable advertising.
                GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t),
                                     &advertEnabled);
    
                // Set to true for non-connectable advertising.
                advertEnabled = TRUE;
    
                // Enable non-connectable advertising.
                GAPRole_SetParameter(GAPROLE_ADV_NONCONN_ENABLED, sizeof(uint8_t),
                                     &advertEnabled);
                firstConnFlag = true;
              }
            #endif // PLUS_BROADCASTER
          }
    //      Uart_SendMsg(UART_HEADER_STR, "Connected", 9);
          break;
    
        case GAPROLE_CONNECTED_ADV:
          Display_print0(dispHandle, SBP_ROW_ROLESTATE, 0, "Connected Advertising");
          break;
    
        case GAPROLE_WAITING:
          PIN_setOutputValue(led_handle, LED1, 0);
          Util_stopClock(&periodicClock);
    //      Uart_SendMsg(UART_HEADER_STR, "Disconnected", 12);
          SimpleBLEPeripheral_freeAttRsp(bleNotConnected);
    
          Display_print0(dispHandle, SBP_ROW_ROLESTATE, 0, "Disconnected");
    
    #if !defined(Display_DISABLE_ALL)
          // Disable PHY change
          tbm_setItemStatus(&sbpMenuMain, TBM_ITEM_NONE, TBM_ITEM_ALL);
    #endif  // !Display_DISABLE_ALL
    
          // Clear remaining lines
          Display_clearLines(dispHandle, SBP_ROW_RESULT, SBP_ROW_STATUS_2);
          Util_stopClock(&noti_clock);
          break;
    
        case GAPROLE_WAITING_AFTER_TIMEOUT:
          SimpleBLEPeripheral_freeAttRsp(bleNotConnected);
          Util_stopClock(&noti_clock);
    //      Uart_SendMsg(UART_HEADER_STR, "Time Out.", 9);
          Display_print0(dispHandle, SBP_ROW_RESULT, 0, "Timed Out");
    
    #if !defined(Display_DISABLE_ALL)
          tbm_setItemStatus(&sbpMenuMain, TBM_ITEM_NONE, TBM_ITEM_ALL);
    #endif  // !Display_DISABLE_ALL
    
          // Clear remaining lines
          Display_clearLines(dispHandle, SBP_ROW_STATUS_1, SBP_ROW_STATUS_2);
    
          #ifdef PLUS_BROADCASTER
            // Reset flag for next connection.
            firstConnFlag = false;
          #endif // PLUS_BROADCASTER
          break;
    
        case GAPROLE_ERROR:
          Display_print0(dispHandle, SBP_ROW_RESULT, 0, "Error");
          break;
    
        default:
          Display_clearLines(dispHandle, SBP_ROW_RESULT, SBP_ROW_STATUS_2);
          break;
      }
    
    }
    
    #ifndef FEATURE_OAD_ONCHIP
    /*********************************************************************
     * @fn      SimpleBLEPeripheral_charValueChangeCB
     *
     * @brief   Callback from Simple Profile indicating a characteristic
     *          value change.
     *
     * @param   paramID - parameter ID of the value that was changed.
     *
     * @return  None.
     */
    static void SimpleBLEPeripheral_charValueChangeCB(uint8_t paramID)
    {
      SimpleBLEPeripheral_enqueueMsg(SBP_CHAR_CHANGE_EVT, paramID);
    }
    #endif //!FEATURE_OAD_ONCHIP
    
    /*********************************************************************
     * @fn      SimpleBLEPeripheral_processCharValueChangeEvt
     *
     * @brief   Process a pending Simple Profile characteristic value change
     *          event.
     *
     * @param   paramID - parameter ID of the value that was changed.
     *
     * @return  None.
     */
    static void SimpleBLEPeripheral_processCharValueChangeEvt(uint8_t paramID)
    {
    #ifndef FEATURE_OAD_ONCHIP
      uint8_t newValue;
    
      switch(paramID)
      {
        case SIMPLEPROFILE_CHAR1:
          SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR1, &newValue);
    
          Display_print1(dispHandle, SBP_ROW_STATUS_1, 0, "Char 1: %d", (uint16_t)newValue);
          break;
    
        case SIMPLEPROFILE_CHAR3:
          SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR3, &newValue);
    
          Display_print1(dispHandle, SBP_ROW_STATUS_1, 0, "Char 3: %d", (uint16_t)newValue);
          break;
    
        default:
          // should not reach here!
          break;
      }
    #endif //!FEATURE_OAD_ONCHIP
    }
    
    /*********************************************************************
     * @fn      SimpleBLEPeripheral_performPeriodicTask
     *
     * @brief   Perform a periodic application task. This function gets called
     *          every five seconds (SBP_PERIODIC_EVT_PERIOD). 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 SimpleBLEPeripheral_performPeriodicTask(void)
    {
    #ifndef FEATURE_OAD_ONCHIP
      uint8_t valueToCopy;
    
      // Call to retrieve the value of the third characteristic in the profile
      if (SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR3, &valueToCopy) == SUCCESS)
      {
        // Call to set that value of the fourth characteristic in the profile.
        // Note that if notifications of the fourth characteristic have been
        // enabled by a GATT client device, then a notification will be sent
        // every time this function is called.
        SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR4, sizeof(uint8_t),
                                   &valueToCopy);
      }
    #endif //!FEATURE_OAD_ONCHIP
    }
    
    
    #ifdef FEATURE_OAD
    /*********************************************************************
     * @fn      SimpleBLEPeripheral_processOadWriteCB
     *
     * @brief   Process a write request to the OAD profile.
     *
     * @param   event      - event type:
     *                       OAD_WRITE_IDENTIFY_REQ
     *                       OAD_WRITE_BLOCK_REQ
     * @param   connHandle - the connection Handle this request is from.
     * @param   pData      - pointer to data for processing and/or storing.
     *
     * @return  None.
     */
    void SimpleBLEPeripheral_processOadWriteCB(uint8_t event, uint16_t connHandle,
                                               uint8_t *pData)
    {
      oadTargetWrite_t *oadWriteEvt = ICall_malloc( sizeof(oadTargetWrite_t) + \
                                                 sizeof(uint8_t) * OAD_PACKET_SIZE);
    
      if ( oadWriteEvt != NULL )
      {
        oadWriteEvt->event = event;
        oadWriteEvt->connHandle = connHandle;
    
        oadWriteEvt->pData = (uint8_t *)(&oadWriteEvt->pData + 1);
        memcpy(oadWriteEvt->pData, pData, OAD_PACKET_SIZE);
    
        Queue_put(hOadQ, (Queue_Elem *)oadWriteEvt);
    
        // Post the application's event.  For OAD, no event flag is used.
        Event_post(syncEvent, SBP_QUEUE_PING_EVT);
      }
      else
      {
        // Fail silently.
      }
    }
    #endif //FEATURE_OAD
    
    /*********************************************************************
     * @fn      SimpleBLEPeripheral_clockHandler
     *
     * @brief   Handler function for clock timeouts.
     *
     * @param   arg - event type
     *
     * @return  None.
     */
    static void SimpleBLEPeripheral_clockHandler(UArg arg)
    {
      // Wake up the application.
      Event_post(syncEvent, arg);
    }
    
    #if !defined(Display_DISABLE_ALL)
    /*********************************************************************
     * @fn      SimpleBLEPeripheral_keyChangeHandler
     *
     * @brief   Key event handler function
     *
     * @param   keys - bitmap of pressed keys
     *
     * @return  none
     */
    void SimpleBLEPeripheral_keyChangeHandler(uint8 keys)
    {
      SimpleBLEPeripheral_enqueueMsg(SBP_KEY_CHANGE_EVT, keys);
    }
    #endif  // !Display_DISABLE_ALL
    
    /*********************************************************************
     * @fn      SimpleBLEPeripheral_enqueueMsg
     *
     * @brief   Creates a message and puts the message in RTOS queue.
     *
     * @param   event - message event.
     * @param   state - message state.
     *
     * @return  None.
     */
    static void SimpleBLEPeripheral_enqueueMsg(uint8_t event, uint8_t state)
    {
      sbpEvt_t *pMsg;
    
      // Create dynamic pointer to message.
      if ((pMsg = ICall_malloc(sizeof(sbpEvt_t))))
      {
        pMsg->hdr.event = event;
        pMsg->hdr.state = state;
    
        // Enqueue the message.
        Util_enqueueMsg(appMsgQueue, syncEvent, (uint8*)pMsg);
      }
    }
    
    #if !defined(Display_DISABLE_ALL)
    /*********************************************************************
     * @fn      SimpleBLEPeripheral_handleKeys
     *
     * @brief   Handles all key events for this device.
     *
     * @param   keys - bit field for key events. Valid entries:
     *                 KEY_LEFT
     *                 KEY_RIGHT
     *
     * @return  none
     */
    static void SimpleBLEPeripheral_handleKeys(uint8_t keys)
    {
      if (keys & KEY_LEFT)
      {
        // Check if the key is still pressed. WA for possible bouncing.
    #if defined(CC2650DK_7ID)
        if (PIN_getInputValue(Board_KEY_LEFT) == 0)
    #elif defined(CC2650_LAUNCHXL) || defined(CC2640R2_LAUNCHXL)
        if (PIN_getInputValue(Board_PIN_BUTTON0) == 0)
    #endif // CC2650DK_7ID, CC2650_LAUNCHXL, CC2640R2_LAUNCHXL
        {
          tbm_buttonLeft();
        }
      }
      else if (keys & KEY_RIGHT)
      {
        // Check if the key is still pressed. WA for possible bouncing.
    #if defined(CC2650DK_7ID)
        if (PIN_getInputValue(Board_KEY_RIGHT) == 0)
    #elif defined(CC2650_LAUNCHXL) || defined(CC2640R2_LAUNCHXL)
        if (PIN_getInputValue(Board_PIN_BUTTON1) == 0)
    #endif // CC2650DK_7ID, CC2650_LAUNCHXL, CC2640R2_LAUNCHXL
        {
          tbm_buttonRight();
        }
      }
    }
    
    /*********************************************************************
     * @fn      SimpleBLEPeripheral_doSetPhy
     *
     * @brief   Set PHY preference.
     *
     * @param   index - 0: 1M PHY
     *                  1: 2M PHY
     *                  2: 1M + 2M PHY
     *                  3: CODED PHY (Long range) (when PHY_LR_CFG is defined)
     *                  4: 1M + 2M + CODED PHY (when PHY_LR_CFG is defined)
     *
     * @return  always true
     */
    bool SimpleBLEPeripheral_doSetPhy(uint8 index)
    {
      uint8_t gapRoleState;
      uint16_t connectionHandle;
      static uint8_t phy[] = {
        HCI_PHY_1_MBPS, HCI_PHY_2_MBPS, HCI_PHY_1_MBPS | HCI_PHY_2_MBPS,
    
      // Note: BLE_V50_FEATURES is always defined and long range phy (PHY_LR_CFG) is
      //       defined in build_config.opt
      // To use the long range phy, HCI_PHY_CODED needs to be included
      #if (BLE_V50_FEATURES & PHY_LR_CFG)
        HCI_PHY_CODED, HCI_PHY_1_MBPS | HCI_PHY_2_MBPS | HCI_PHY_CODED,
      #endif  // PHY_LR_CFG
      };
    
      GAPRole_GetParameter(GAPROLE_STATE, &gapRoleState);
      GAPRole_GetParameter(GAPROLE_CONNHANDLE, &connectionHandle);
    
      // Set Phy Preference on the current connection. Apply the same value
      // for RX and TX.
      HCI_LE_SetPhyCmd(connectionHandle, 0, phy[index], phy[index], 0);
    
      Display_print1(dispHandle, SBP_ROW_RESULT, 0, "PHY preference: %s",
                     TBM_GET_ACTION_DESC(&sbpMenuMain, index));
    
      Display_clearLine(dispHandle, SBP_ROW_STATUS_1);
    
      return true;
    }
    #endif  // !Display_DISABLE_ALL
    
    /*********************************************************************
    *********************************************************************/
    
    /*
     * usrs.c
     *
     *  Created on: 2022��10��13��
     *      Author: 604-2
     */
    
    #include "usrs.h"
    
    //uart
    UART_Handle uart = NULL;
    UART_Params uartParams;
    //uart buffer
    char uart_header_str[30] = "STR0";
    char uart_header_hex[5] = "HEX0";
    
    PIN_State led_pins;
    PIN_Handle led_handle = NULL;
    
    //led config
    PIN_Config led_cfg[5] = {
     LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
     LED2 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
     LED3 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
     LED4 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
     PIN_TERMINATE
    };
    
    void Uart_Ini(){
        UART_init();
          // Create a UART with data processing off.
        UART_Params_init(&uartParams);
        uartParams.writeDataMode  = UART_DATA_BINARY;
        uartParams.readMode       = UART_MODE_CALLBACK; //Callbackģʽ
        uartParams.readDataMode   = UART_DATA_BINARY;
        uartParams.readEcho = UART_ECHO_OFF;
        uartParams.baudRate = 256000;
        uartParams.readCallback = UART_Write_Callback;
    
        //uart = UART_open(CC2640R2DK_7ID_UART0, &uartParams);
        uart = UART_open(0, &uartParams);
    
        if (uart == NULL) {
             while (1);
        }
    }
    
    void UART_Write_Callback (UART_Handle handle, void *buf, size_t count){
        ;
    }
    
    void Uart_SendMsg(int type, const void *str, size_t len){
        if(uart){
              switch (type){
              case UART_HEADER_HEX:
                  uart_header_hex[3] = len;
                  for(int i = 0; i < len; ++ i){
                      uart_header_hex[i + 4] = *(const char *)(str + i);
                  }
                  UART_write(uart, uart_header_hex, 4 + len);
                  break;
              case UART_HEADER_STR:
                  uart_header_str[3] = len;
                  for(int i = 0; i < len; ++ i){
                      uart_header_str[i + 4] = *(const char *)(str + i);
                  }
                  UART_write(uart, uart_header_str, 4 + len);
                  break;
              default:
                  return;
              };
        }
    }
    
    
    
    util.h

    When I connect CC2640R2F with my phone, everything is fine. But when I try to connect CC2640R2F with LAUCHXL-CC2652, it seems that the slave cannot receive the MTU exchange request from the master. If the slave retrieves the ATT_MTU_UPDATE_EVENT, the slave will light a LED(line 1026 in simple_peripheral.c). When I connect CC2640R2F with my smartphone, the LED soon shines. But nothing happens when CC2652 try to connect it. I also found that CC2652 can receive some notifications from the slave before the connection broke. I'm wondering if I should call exchangeMTU() in master after the connection has been established. Can the master receive notifications from the slave if they just don't exchange MTU size? If the master call the exchangeMTU(), is it sure for the slave to retrieve the ATT_MTU_UPDATE_EVENT? If the slave fails to retrieve the ATT_MTU_UPDATE_EVENT, does it mean they didn't exchange MTU or that they exchanged MTU size but MTU size didn't update? 

    I tried to control LAUNXL-CC2652 with UART menu, but it didn't function as I expected. Are there any tutorials for me?

    Thanks a lot and best wishes!

  • Sorry again that I forgot uart_events_macros.h included in usrs.h of CC2652.

    Anyway it's an empty file.

    uart_events_macros.h

  • Hello,

    The README for the Simple Peripheral project contains information about how to interface with the UART menu. The Bluetooth Low Energy Fundamentals SLA lab also provides some information on how to operate the UART menu.

    Best Regards,

    Jan

  • Thank you soooooooooooooooo much

    I flashed host_test into LAUCHXL-CC2652 and tried to control it with BTool. The connection was established successfully.

    But how can I debug my own codes? 

  • And it seems I cannot connect CC2640R2F with UART menu. What does group A and group B mean? It seems related to advData only.

  • I found I cannot connect CC2640 by calling SimpleCentral_autoConnect(). If I call SimpleCentral_doConnect(), the connection will not break. So I disabled autoConnect. But why? Is there any difference between the two functions? 

  • Hi,

    The auto-connect feature must be enabled on both the central and the peripheral side and requires the advertising data to contain specific data. I would recommend referencing the code that references the autoConnect global variable in both the central and the peripheral projects. If you would like to implement a simple auto-connection scheme, then I would suggest referencing the simple serial socket example (server | client), as this example implements autoconnect based on UUID

    Best Regards,

    Jan

  • If I established a link, should I call SimpleCentral_doConnUpdate() myself since the peripheral won't request to update the params? 

    And if I just need to receive the notification from the peripheral should I exchange MTU? It seems ok if they don't.

  • Thanks a lot :)

  • Hello,

    The peripheral side can be configured to send the connection parameter request update itself or the central can also do it as well. The Connection Parameter Update chapter of the User's Guide provides some useful information on this. Changing the MTU size is not necessary if the default value of 27 bytes suffices for your application. For information on how to change the size or when changing the size might be useful, please reference the Maximum Transmission Unit (MTU) section of the User's Guide.

    Given that it seems the original query in this post has been resolved, I would suggest that a new thread be created if you have further questions regarding the connection parameter update or any additional questions that do not relate to the original query. This is to allow for better support and benefit the E2E community at large. I will gladly assist you in the new thread. :) 

    Best Regards,

    Jan