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.

CC2642R: HomeKit and classic BLE implementation at the same time possible?

Part Number: CC2642R
Other Parts Discussed in Thread: SYSCONFIG, CCSTUDIO

Trying to understand the capabilities of the chipset when it comes to running HomeKit but, also need to support Android devices and using the TI BLE SDK for that. Is there an architecture in which to support both use cases? I've successfully have HAP running on the CC26X2R launch pad. Separately I have Simple Peripheral running as well. Not sure where to start with the integration of both SDK's utilizing the same TI BLE SDK. 

  • Hi Jonathan,

    Thank you for reaching out.

    From what have experienced, the easiest approach is to start from an HomeKit project.
    You will have to add a non-HomeKit advertising set.
    For the GATT table, I recommend you add one service for interfacing with non-HomeKit devices (I recommend non-HomeKit devices access only this newly added service).

    I hope this will help,

    Best regards,

  • Hi Clément, Thanks for the feedback. To probe a bit deeper, adding a "non-HomeKit advertising set" Is this supported by the TI HAP SDK? is it as simple as (for example) importing simple_gatt_profile from the simple peripheral example, setting up a task to kick it off? 

  • Hi Jonathan,

    Without pretending this is the only solution, I actually added the required code directly in simple_np_gap.c without creating any new task. As mentioned before, the GATT table (in simple_np_gatt.c may also have to be modified).

    For your reference, and without committing to further support, I can attach the diff files of the simple_np_gap.c and simple_np_gatt.c I obtained with my project.

    @@ -55,6 +55,10 @@
     #include "simple_np_gatt.h"
     // #include "devinfoservice.h"
     
    +// This is to drive the green led only
    +#include <ti/drivers/GPIO.h>
    +#include "ti_drivers_config.h"
    +
     /*********************************************************************
      * CONSTANTS
      */
    @@ -119,6 +123,9 @@
     // Spin if the expression is not true
     #define NP_GAP_ASSERT(expr) if (!(expr)) np_gap_spin();
     
    +// Spin if the expression is not true
    +#define NP_GAP_ASSERT_NHK(expr) if (!(expr)) np_gap_spin_nhk();
    +
     // Address mode of the local device
     // Note: When using the DEFAULT_ADDRESS_MODE as ADDRMODE_RANDOM or
     // ADDRMODE_RP_WITH_RANDOM_ID, GAP_DeviceInit() should be called with
    @@ -253,6 +260,85 @@ static gapBondCBs_t SNP_BondMgrCBs =
       SNP_securityStateCB              // Pairing and Bonding state callback
     };
     
    +/*********************************************************************
    + * LOCAL VARIABLES for Non-HomeKit (NHK) connections
    + */
    +bool npIsAdvertisingNHK = false;
    +static uint8 advHandleNHK; // Advertisement handle for NHK devices
    +bool activeConnectionIsNHK = false;
    +
    +static GapAdv_params_t advertParamNHK =
    +{
    +  .eventProps = GAP_ADV_PROP_CONNECTABLE | GAP_ADV_PROP_SCANNABLE |
    +                GAP_ADV_PROP_LEGACY,
    +  .primIntMin = 600,
    +  .primIntMax = 600,
    +  .primChanMap = GAP_ADV_CHAN_ALL,
    +  .peerAddrType = PEER_ADDRTYPE_PUBLIC_OR_PUBLIC_ID,
    +  .peerAddr = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa },
    +  .filterPolicy = GAP_ADV_WL_POLICY_ANY_REQ,
    +  .txPower = GAP_ADV_TX_POWER_NO_PREFERENCE,
    +  .primPhy = GAP_ADV_PRIM_PHY_1_MBPS,
    +  .secPhy = GAP_ADV_SEC_PHY_1_MBPS,
    +  .sid = 0
    +};
    +
    +// Advertisement data
    +static uint8_t advertDataNHK[] =
    +{
    +  0x04,                         // Length of this data
    +  GAP_ADTYPE_LOCAL_NAME_SHORT,  // Type of this data
    +  'N',
    +  'H',
    +  'K',
    +
    +  0x02,   // length of this data
    +  GAP_ADTYPE_FLAGS,
    +  DEFAULT_DISCOVERABLE_MODE | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED,
    +
    +  0x03,
    +  GAP_ADTYPE_16BIT_COMPLETE,
    +  LO_UINT16(0xfff0),
    +  HI_UINT16(0xfff0),
    +};
    +
    +// Scan Response Data
    +static uint8_t scanRspDataNHK[] =
    +{
    +  0x0B,                           // length of this data
    +  GAP_ADTYPE_LOCAL_NAME_COMPLETE, // Type of this data
    +  'N',
    +  'o',
    +  'n',
    +  'H',
    +  'o',
    +  'm',
    +  'e',
    +  'K',
    +  'i',
    +  't',
    +};
    +
    +snp_advData_t advPtrTableNHK[2] =
    +{
    +  {sizeof(scanRspDataNHK), scanRspDataNHK},   // reserve for scan rsp
    +  {sizeof(advertDataNHK),  advertDataNHK},   // reserve for adv data  (we only have one set of adv data)
    +};
    +
    +// This variable is used to request the SNP to re-enable
    +// the HK advertisements once the NHK connection is exited
    +static snpStartAdvReq_t postNhkConnStartAdvReq;
    +
    +/*********************************************************************
    + * LOCAL FUNCTIONS for Non-HomeKit (NHK) connections
    + */
    +static void np_gap_advCBNHK(uint32_t event, void *pBuf, uintptr_t arg);
    +
    +static uint16_t np_gap_getNhkConnIndex(uint16_t connHandle);
    +static uint8_t np_gap_clearNhkConnListEntry(uint16_t connHandle);
    +static uint8_t np_gap_addNhkConnInfo(uint16_t connHandle, uint8_t *pAddr, uint8_t role);
    +static uint8_t np_gap_removeNhkConnInfo(uint16_t connHandle);
    +
     /*********************************************************************
      * PUBLIC FUNCTIONS
      */
    @@ -265,6 +351,24 @@ typedef struct
       uint8_t data[];
     } spClockEventData_t;
     
    +/*********************************************************************
    + * @fn      np_gap_spin_nhk
    + *
    + * @brief   Spin forever - To help debug, this spin-lock is called by
    + *                         the non-Home Kit code only.
    + *
    + * @param   none
    + */
    +static void np_gap_spin_nhk(void)
    +{
    +  volatile uint8_t x = 0;
    +
    +  while(1)
    +  {
    +    x++;
    +  }
    +}
    +
     /*********************************************************************
      * @fn      np_gap_clockHandler
      *
    @@ -379,6 +483,34 @@ void NpGap_StartDevice()
         GapAdv_create(&np_gap_advCB, &advertParam,
                       &advHandle);
       }
    +
    +  {
    +    /**
    +     * Create the NHK advertisement
    +     */
    +    bStatus_t status = FAILURE;
    +
    +    // Create Advertisement set #2 (NHK) and assign handle
    +    status = GapAdv_create(&np_gap_advCBNHK, &advertParamNHK,
    +                &advHandleNHK);
    +    NP_GAP_ASSERT_NHK(status == SUCCESS);
    +
    +    // Load advertising data for set #2 (NHK) that is statically allocated by the app
    +    GapAdv_loadByHandle(advHandleNHK, GAP_ADV_DATA_TYPE_ADV,
    +                      sizeof(advertDataNHK), advertDataNHK);
    +    NP_GAP_ASSERT_NHK(status == SUCCESS);
    +
    +    // Set event mask for set #2 (NHK)
    +    status = GapAdv_setEventMask(advHandleNHK,
    +                               GAP_ADV_EVT_MASK_START_AFTER_ENABLE |
    +                               GAP_ADV_EVT_MASK_END_AFTER_DISABLE |
    +                               GAP_ADV_EVT_MASK_SET_TERMINATED);
    +    NP_GAP_ASSERT_NHK(status == SUCCESS);
    +
    +    status = GapAdv_loadByHandle(advHandleNHK, GAP_ADV_DATA_TYPE_SCAN_RSP,
    +                                       sizeof(scanRspDataNHK), scanRspDataNHK);
    +    NP_GAP_ASSERT_NHK(status == SUCCESS);
    +  }
     }
     
     /// @brief GAP Peripheral Role States.
    @@ -497,6 +629,13 @@ static uint8_t numConn = 0;
     // Per-handle connection info
     static npConnRec_t connList[MAX_NUM_BLE_CONNS];
     
    +
    +// Number of connected NHK devices
    +static uint8_t nhkNumConn = 0;
    +
    +// Per-handle NHK connection info
    +static npConnRec_t nhkConnList[MAX_NUM_BLE_CONNS];
    +
     /*********************************************************************
      * @fn      SNP_GAP_processClockEvent
      *
    @@ -553,6 +692,8 @@ void SNP_processGapMsg(gapEventHdr_t *pMsg)
             npGap_state = NP_GAP_STATE_STARTED;
           }
     
    +      GapAdv_enable(advHandleNHK, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0);
    +
           break;
         }
     
    @@ -567,113 +708,179 @@ void SNP_processGapMsg(gapEventHdr_t *pMsg)
           uint16_t connHandle = ((gapTerminateLinkEvent_t*) pMsg)->connectionHandle;
           uint8_t term_reason = ((gapTerminateLinkEvent_t*) pMsg)->reason;
     
    -      // Cancel all connection parameter update timers (if any active)
    -      Util_stopClock(&startUpdateClock);
    +      if(activeConnectionIsNHK == true){
     
    -      // Mark this connection deleted in the connected device list.
    -      np_gap_removeConnInfo(connHandle);
    +          activeConnectionIsNHK = false;
     
    +          // Mark this connection deleted in the connected device list.
    +          np_gap_removeNhkConnInfo(connHandle);
     
    -      // Start advertising
    -      GapAdv_enable(advHandle, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0);
    +          GapAdv_enable(advHandleNHK, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0);
     
    -      //-- From SNP_processStateChangeEvt(newGapRoleState) - state = NP_GAP_STATE_ADVERTISING_NONCONN (GAP_LINK_TERMINATED_EVENT)
    -    /* After a connection is dropped a device will continue
    -     * sending non-connectable advertisements and shall sending this change of
    -     * state to the application.  These are then disabled here so that sending
    -     * connectable advertisements can resume.
    -     */
    -      {
    -        if(firstConnFlag)
    -        {
    -          // We were in a connection.
    -          uint8_t *param = snpHostMsg;
     
    -          UINT16_TO_BUF(param, currentConnectHandle);
    -          UINT16_TO_BUF(param, term_reason);
    +          postNhkConnStartAdvReq.type = SNP_ADV_TYPE_CONN; // connectable advertising
    +          postNhkConnStartAdvReq.timeout = 0;              // never stops
    +          postNhkConnStartAdvReq.interval = 160;           // 160 * 625us = 100 ms interval between advertisement events
    +          postNhkConnStartAdvReq.behavior = SNP_ADV_RESTART_ON_CONN_TERM; // advertising stops upon connection and resumes after the connection terminates
    +
    +          npGap_state = NP_GAP_STATE_ERROR; // this only to force the SNP_startAdv() function to work properly!
    +
    +          SNP_startAdv(&postNhkConnStartAdvReq);
    +
    +          firstConnFlag = false;
     
    -          //reset the GATT state for this connection handle
    -          SNP_resetGATT(*((uint16_t*) &snpHostMsg[0]));
    -          //Connection Ended
    -          SNP_eventToHost_send(SNP_CONN_TERM_EVT, NULL, param-snpHostMsg, snpHostMsg);
    -          npGap_state = NP_GAP_STATE_ADVERTISING;
    -        }
    -        // Reset flag for next connection.
    -        firstConnFlag = false;
           }
    +      else{
    +
    +          // Cancel all connection parameter update timers (if any active)
    +          Util_stopClock(&startUpdateClock);
    +
    +          // Mark this connection deleted in the connected device list.
    +          np_gap_removeConnInfo(connHandle);
    +
    +
    +          // Start advertising
    +          GapAdv_enable(advHandle, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0);
    +          GapAdv_enable(advHandleNHK, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0);
    +
    +          //-- From SNP_processStateChangeEvt(newGapRoleState) - state = NP_GAP_STATE_ADVERTISING_NONCONN (GAP_LINK_TERMINATED_EVENT)
    +        /* After a connection is dropped a device will continue
    +         * sending non-connectable advertisements and shall sending this change of
    +         * state to the application.  These are then disabled here so that sending
    +         * connectable advertisements can resume.
    +         */
    +          {
    +            if(firstConnFlag)
    +            {
    +              // We were in a connection.
    +              uint8_t *param = snpHostMsg;
     
    +              UINT16_TO_BUF(param, currentConnectHandle);
    +              UINT16_TO_BUF(param, term_reason);
    +
    +              //reset the GATT state for this connection handle
    +              SNP_resetGATT(*((uint16_t*) &snpHostMsg[0]));
    +              //Connection Ended
    +              SNP_eventToHost_send(SNP_CONN_TERM_EVT, NULL, param-snpHostMsg, snpHostMsg);
    +              npGap_state = NP_GAP_STATE_ADVERTISING;
    +            }
    +            // Reset flag for next connection.
    +            firstConnFlag = false;
    +          }
    +        }
           break;
         }
     
         case GAP_LINK_ESTABLISHED_EVENT:
         {
    +      GapAdv_disable(advHandleNHK);
    +
           gapEstLinkReqEvent_t *pPkt = (gapEstLinkReqEvent_t *)pMsg;
           uint16_t connHandle = ((gapEstLinkReqEvent_t*) pMsg)->connectionHandle;
           uint8_t role = ((gapEstLinkReqEvent_t*) pMsg)->connRole;
           uint8_t* pAddr      = ((gapEstLinkReqEvent_t*) pMsg)->devAddr;
           uint8_t  connIndex;
     
    -      // Check whether update parameter request is enabled
    -      if ((np_gap_updateConnParams.paramUpdateEnable ==
    -           NP_GAP_LINK_PARAM_UPDATE_INITIATE_BOTH_PARAMS) ||
    -          (np_gap_updateConnParams.paramUpdateEnable ==
    -           NP_GAP_LINK_PARAM_UPDATE_INITIATE_APP_PARAMS))
    -      {
    -        // Get the minimum time upon connection establishment before the
    -        // peripheral can start a connection update procedure.
    -        uint16_t timeout = DEFAULT_CONN_PAUSE_PERIPHERAL;
    -
    -        Util_restartClock(&startUpdateClock, timeout);
    -      }
    +      /**
    +       * Here we have different solution to determine if the central device wants to
    +       * enter an HomeKit or a non-HomeKit connection.
    +       * For the moment this is done per address. The address of the non-HK device is
    +       * known, all the other devices are expected to enter the HK connection.
    +       *
    +       * In the future a few solutions might be used:
    +       *    - filter the connections by device manufacturer (e.g. https://macaddresschanger.com/bluetooth-mac-lookup/Apple)
    +       *    - determine if the device expects a HK connection based on the connection parameter chosen
    +       */
    +
    +      // Using chrome://bluetooth-internals/#adapter, my address is 68:EC:C5:86:A8:F2
    +      if( pAddr[5] == 0x68 &&
    +          pAddr[4] == 0xEC &&
    +          pAddr[3] == 0xC5 &&
    +          pAddr[2] == 0x86 &&
    +          pAddr[1] == 0xA8 &&
    +          pAddr[0] == 0xF2 ){
    +
    +          //Disable HK Advertising
    +          GapAdv_disable(advHandle);
    +
    +          uint8_t status = SNP_SUCCESS;
    +          SNP_eventToHost_send(SNP_ADV_ENDED_EVT, &status, 0, NULL);
    +          firstConnFlag = true;
     
    -      // Add this connection info to the list
    -      connIndex = np_gap_addConnInfo(connHandle, pAddr, role);
    +          // Add this connection to the non-HomeKit connection list
    +          connIndex = np_gap_addNhkConnInfo(connHandle, pAddr, role);
     
    -      if(connIndex != MAX_NUM_BLE_CONNS) {
    -        connList[connIndex].charHandle = 0;
    +          if(connIndex != MAX_NUM_BLE_CONNS) {
    +            nhkConnList[connIndex].charHandle = 0;
    +          }
     
    -        //--!! add check for pPkt->hdr.status, see old peripheral.c
    +          activeConnectionIsNHK = true;
    +      }
    +      else{
     
    -        if(firstConnFlag == false)
    -        {
    -          currentConnectHandle = connList[connIndex].connHandle;
    +          // Check whether update parameter request is enabled
    +          if ((np_gap_updateConnParams.paramUpdateEnable ==
    +               NP_GAP_LINK_PARAM_UPDATE_INITIATE_BOTH_PARAMS) ||
    +              (np_gap_updateConnParams.paramUpdateEnable ==
    +               NP_GAP_LINK_PARAM_UPDATE_INITIATE_APP_PARAMS))
               {
    -            uint8_t *param = snpHostMsg;
    -
    -            UINT16_TO_BUF(param, connList[connIndex].connHandle);
    -            UINT16_TO_BUF(param, pPkt->connInterval);
    -            UINT16_TO_BUF(param, pPkt->connLatency);
    -            UINT16_TO_BUF(param, pPkt->connTimeout);
    -            UINT8_TO_BUF(param, pPkt->devAddrType);
    -            PUINT8_TO_BUF(param, connList[connIndex].addr, B_ADDR_LEN);
    -            //Advertisement Ended due to the connection
    -            SNP_eventToHost_send(SNP_CONN_EST_EVT,
    -                                  NULL, param-snpHostMsg, snpHostMsg);
    -            npGap_state = NP_GAP_STATE_CONNECTED;
    +            // Get the minimum time upon connection establishment before the
    +            // peripheral can start a connection update procedure.
    +            uint16_t timeout = DEFAULT_CONN_PAUSE_PERIPHERAL;
    +
    +            Util_restartClock(&startUpdateClock, timeout);
               }
     
    -          //--!! advBehavior is not supported, after connection disable ADV without check
    -          //if((advBehavior &  SNP_ADV_DATA_IN_CONNECTION) == 0)
    -          {
    -            //Disable Advertising.
    -            GapAdv_disable(advHandle);
    +          // Add this connection info to the list
    +          connIndex = np_gap_addConnInfo(connHandle, pAddr, role);
    +
    +          if(connIndex != MAX_NUM_BLE_CONNS) {
    +            connList[connIndex].charHandle = 0;
     
    -            //-- Don't wait for gap event GAP_EVT_ADV_SET_TERMINATED, send event to host now
    +            //--!! add check for pPkt->hdr.status, see old peripheral.c
    +
    +            if(firstConnFlag == false)
                 {
    -              uint8_t status = SNP_SUCCESS;
    -              SNP_eventToHost_send(SNP_ADV_ENDED_EVT, &status, 0, NULL);
    +              currentConnectHandle = connList[connIndex].connHandle;
    +              {
    +                uint8_t *param = snpHostMsg;
    +
    +                UINT16_TO_BUF(param, connList[connIndex].connHandle);
    +                UINT16_TO_BUF(param, pPkt->connInterval);
    +                UINT16_TO_BUF(param, pPkt->connLatency);
    +                UINT16_TO_BUF(param, pPkt->connTimeout);
    +                UINT8_TO_BUF(param, pPkt->devAddrType);
    +                PUINT8_TO_BUF(param, connList[connIndex].addr, B_ADDR_LEN);
    +                //Advertisement Ended due to the connection
    +                SNP_eventToHost_send(SNP_CONN_EST_EVT,
    +                                      NULL, param-snpHostMsg, snpHostMsg);
    +                npGap_state = NP_GAP_STATE_CONNECTED;
    +              }
    +
    +              //--!! advBehavior is not supported, after connection disable ADV without check
    +              //if((advBehavior &  SNP_ADV_DATA_IN_CONNECTION) == 0)
    +              {
    +                //Disable Advertising.
    +                GapAdv_disable(advHandle);
    +
    +                //-- Don't wait for gap event GAP_EVT_ADV_SET_TERMINATED, send event to host now
    +                {
    +                  uint8_t status = SNP_SUCCESS;
    +                  SNP_eventToHost_send(SNP_ADV_ENDED_EVT, &status, 0, NULL);
    +                }
    +              }
    +
    +              // if 4.1 feature are enable on the controller,
    +              // then the adv needs to be forced to
    +              // be non-connectable, since peripheral.c does not support multiple
    +              // connection.
    +              // 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.
    +              firstConnFlag = true;
                 }
    -          }
    +      }
     
    -          // if 4.1 feature are enable on the controller,
    -          // then the adv needs to be forced to
    -          // be non-connectable, since peripheral.c does not support multiple
    -          // connection.
    -          // 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.
    -          firstConnFlag = true;
    -        }
           }
           break;
         }
    @@ -755,6 +962,33 @@ static void np_gap_advCB(uint32_t event, void *pBuf, uintptr_t arg)
       }
     }
     
    +/*********************************************************************
    + * @fn      np_gap_advCBNHK
    + *
    + * @brief   GapAdv module callback
    + */
    +static void np_gap_advCBNHK(uint32_t event, void *pBuf, uintptr_t arg)
    +{
    +    /**
    +     *  In a previous version, this Callback was used to light the green
    +     *  led while the NHK advertisement was active. This function has been
    +     *  kept since but does nothing.
    +     */
    +    switch (event)
    +    {
    +        case GAP_EVT_ADV_START_AFTER_ENABLE:
    +        case GAP_EVT_ADV_START:
    +            //GPIO_write(CONFIG_GPIO_LED_1, CONFIG_GPIO_LED_ON);
    +          break;
    +
    +        case GAP_EVT_ADV_SET_TERMINATED:
    +        case GAP_EVT_ADV_END_AFTER_DISABLE:
    +        case GAP_EVT_ADV_END:
    +            //GPIO_write(CONFIG_GPIO_LED_1, CONFIG_GPIO_LED_OFF);
    +          break;
    +    }
    +}
    +
     /*********************************************************************
      * @fn      SNP_GAP_processAdvEvent
      *
    @@ -1541,6 +1775,148 @@ static uint8_t np_gap_removeConnInfo(uint16_t connHandle)
       return connIndex;
     }
     
    +/*********************************************************************
    +* @fn      np_gap_getNhkConnIndex
    +*
    +* @brief   Translates connection handle to index (for NHK handles only)
    +*
    +* @param   connHandle - the connection handle (must be NHK)
    +*
    + * @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 uint16_t np_gap_getNhkConnIndex(uint16_t connHandle)
    +{
    +  uint8_t i;
    +  // Loop through connection
    +  for (i = 0; i < MAX_NUM_BLE_CONNS; i++)
    +  {
    +    // If matching connection handle found
    +    if (nhkConnList[i].connHandle == connHandle)
    +    {
    +      return i;
    +    }
    +  }
    +
    +  // Not found if we got here
    +  return(MAX_NUM_BLE_CONNS);
    +}
    +
    +/*********************************************************************
    + * @fn      np_gap_clearNhkConnListEntry
    + *
    + * @brief   clear device list by connHandle
    + *
    + * @param   connHandle - the connection handle (must be NHK).
    + *                       Use LINKDB_CONNHANDLE_ALL to clear all the
    + *                       NHK connHandle list
    + *
    + * @return  SUCCESS if connHandle found valid index or bleInvalidRange
    + *          if index wasn't found. LINKDB_CONNHANDLE_ALL will always succeed.
    + */
    +static uint8_t np_gap_clearNhkConnListEntry(uint16_t connHandle)
    +{
    +  uint8_t i;
    +  // Set to invalid connection index initially
    +  uint8_t connIndex = MAX_NUM_BLE_CONNS;
    +
    +  if(connHandle != LINKDB_CONNHANDLE_ALL)
    +  {
    +    connIndex = np_gap_getNhkConnIndex(connHandle);
    +    // Get connection index from handle
    +    if(connIndex >= MAX_NUM_BLE_CONNS)
    +    {
    +      return bleInvalidRange;
    +    }
    +  }
    +
    +  // Clear specific handle or all handles
    +  for(i = 0; i < MAX_NUM_BLE_CONNS; i++)
    +  {
    +    if((connIndex == i) || (connHandle == LINKDB_CONNHANDLE_ALL))
    +    {
    +      nhkConnList[i].connHandle = LINKDB_CONNHANDLE_INVALID;
    +      nhkConnList[i].charHandle = 0;
    +      nhkConnList[i].discState  =  0;
    +    }
    +  }
    +
    +  return SUCCESS;
    +}
    +
    +/*********************************************************************
    +* @fn      np_gap_addNhkConnInfo
    +*
    +* @brief   add a new connection to the index-to-connHandle NHK map
    +*
    +* @param   connHandle - the connection handle (must be NHK)
    +*
    +* @param   addr - pointer to device address
    +*
    +* @return  index of connection handle
    +*/
    +static uint8_t np_gap_addNhkConnInfo(uint16_t connHandle, uint8_t *pAddr,
    +                                      uint8_t role)
    +{
    +  uint8_t i;
    +  //--!!npClockEventData_t *paramUpdateEventData;
    +
    +  for (i = 0; i < MAX_NUM_BLE_CONNS; i++)
    +  {
    +    if (nhkConnList[i].connHandle == LINKDB_CONNHANDLE_INVALID)
    +    {
    +      // Found available entry to put a new connection info in
    +        nhkConnList[i].connHandle = connHandle;
    +      memcpy(nhkConnList[i].addr, pAddr, B_ADDR_LEN);
    +      nhkNumConn++;
    +
    +      break;
    +    }
    +  }
    +
    +  return i;
    +}
    +
    +/*********************************************************************
    + * @fn      np_gap_removeNhkConnInfo
    + *
    + * @brief   Remove a device from the NHK connected device list
    + *
    + * @param   connHandle - connection handle to remove (must be an NHK connection)
    + *
    + * @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 np_gap_removeNhkConnInfo(uint16_t connHandle)
    +{
    +  uint8_t connIndex = np_gap_getNhkConnIndex(connHandle);
    +
    +  if(connIndex < MAX_NUM_BLE_CONNS)
    +  {
    +    Clock_Struct* pUpdateClock = connList[connIndex].pUpdateClock;
    +
    +    if (pUpdateClock != NULL)
    +    {
    +      // Stop and destruct the RTOS clock if it's still alive
    +      if (Util_isActive(pUpdateClock))
    +      {
    +        Util_stopClock(pUpdateClock);
    +      }
    +
    +      // Destruct the clock object
    +      Clock_destruct(pUpdateClock);
    +      // Free clock struct
    +      ICall_free(pUpdateClock);
    +    }
    +    // Clear Connection List Entry
    +    np_gap_clearNhkConnListEntry(connHandle);
    +    nhkNumConn--;
    +  }
    +
    +  return connIndex;
    +}
    +
     
     /*********************************************************************
     *********************************************************************/
    

    @@ -54,6 +54,10 @@
     #include "simple_np_uuid.h"
     // #include "devinfoservice.h"
     
    +// This is to drive the green led only
    +#include <ti/drivers/GPIO.h>
    +#include "ti_drivers_config.h"
    +
     /*******************************************************************************
      * CONSTANTS
      */
    @@ -195,6 +199,105 @@ CONST gattServiceCBs_t SNP_CBs =
       NULL              // Authorization callback function pointer
     };
     
    +
    +/*********************************************************************
    + * PROFILES and SERVICES for Non-HomeKit (NHK) connections
    + */
    +// Simple Profile Service UUID
    +#define SIMPLEPROFILE_SERV_UUID             0xFFF0
    +#define SIMPLEPROFILE_SERVICE               0x00000001
    +#define SIMPLEPROFILE_CHAR1_UUID            0xFFF1
    +
    +/*********************************************************************
    + * EXTERN VARIABLES for Non-HomeKit (NHK) connections
    + */
    +extern bool activeConnectionIsNHK;
    +
    +/*********************************************************************
    + * LOCAL VARIABLES for Non-HomeKit (NHK) connections
    + */
    +// Simple GATT Profile Service UUID: 0xFFF0
    +CONST uint8 simpleProfileServUUID[ATT_BT_UUID_SIZE] =
    +{
    +  LO_UINT16(SIMPLEPROFILE_SERV_UUID), HI_UINT16(SIMPLEPROFILE_SERV_UUID)
    +};
    +
    +// Characteristic 1 UUID: 0xFFF1
    +CONST uint8 simpleProfilechar1UUID[ATT_BT_UUID_SIZE] =
    +{
    +  LO_UINT16(SIMPLEPROFILE_CHAR1_UUID), HI_UINT16(SIMPLEPROFILE_CHAR1_UUID)
    +};
    +
    +// Simple Profile Service attribute
    +static CONST gattAttrType_t simpleProfileService = { ATT_BT_UUID_SIZE, simpleProfileServUUID };
    +
    +// Simple Profile Characteristic 1 Properties
    +static uint8 simpleProfileChar1Props = GATT_PROP_READ | GATT_PROP_WRITE;
    +
    +// Characteristic 1 Value
    +static uint8 simpleProfileChar1 = 1; // simpleProfileChar1 value will determine the state of the green led
    +                                     // simpleProfileChar1 = 1, 3, 5,... > led is off
    +                                     // simpleProfileChar1 = 2, 4, 6,... > led is on
    +                                     // LED will initially be switched off
    +
    +// Simple Profile Characteristic 1 User Description
    +static uint8 simpleProfileChar1UserDesp[17] = "Characteristic 1";
    +
    +// Simple Profile Attributes Table
    +static gattAttribute_t simpleProfileAttrTbl[4] =
    +{
    +  // Simple Profile Service
    +  {
    +    { ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */
    +    GATT_PERMIT_READ,                         /* permissions */
    +    0,                                        /* handle */
    +    (uint8 *)&simpleProfileService            /* pValue */
    +  },
    +
    +    // Characteristic 1 Declaration
    +    {
    +      { ATT_BT_UUID_SIZE, characterUUID },
    +      GATT_PERMIT_READ,
    +      0,
    +      &simpleProfileChar1Props
    +    },
    +
    +      // Characteristic Value 1
    +      {
    +        { ATT_BT_UUID_SIZE, simpleProfilechar1UUID },
    +        GATT_PERMIT_READ | GATT_PERMIT_WRITE,
    +        0,
    +        &simpleProfileChar1
    +      },
    +
    +      // Characteristic 1 User Description
    +      {
    +        { ATT_BT_UUID_SIZE, charUserDescUUID },
    +        GATT_PERMIT_READ,
    +        0,
    +        simpleProfileChar1UserDesp
    +      }
    +};
    +
    +/*********************************************************************
    + * LOCAL FUNCTIONS for Non-HomeKit (NHK) connections
    + */
    +static bStatus_t NHK_AddServices(uint32 services);
    +static bStatus_t NHK_WriteAttrCB(uint16_t connHandle, gattAttribute_t *pAttr, uint8_t *pValue,
    +                                           uint16_t len, uint16_t offset, uint8_t method);
    +static bStatus_t NHK_ReadAttrCB(uint16_t connHandle, gattAttribute_t *pAttr, uint8_t *pValue,
    +                                          uint16_t *pLen, uint16_t offset, uint16_t maxLen, uint8_t method);
    +
    +/*********************************************************************
    + * PROFILE CALLBACKS for Non-HomeKit (NHK) connections
    + */
    +CONST gattServiceCBs_t simpleProfileCBs =
    +{
    +  NHK_ReadAttrCB,  // Read callback function pointer
    +  NHK_WriteAttrCB, // Write callback function pointer
    +  NULL             // Authorization callback function pointer
    +};
    +
     /*********************************************************************
      * PUBLIC FUNCTIONS
      */
    @@ -260,6 +363,9 @@ void SNP_initGATT(void)
       GATTServApp_AddService(GATT_ALL_SERVICES);   // GATT attributes
       // DevInfo_AddService();                        // Device Information Service
     
    +  // Non-HK services
    +  NHK_AddServices(GATT_ALL_SERVICES);
    +
       // Reset GATT session, hard-coded to 0 for first init.
       SNP_resetGATT(0);
     }
    @@ -2466,6 +2572,181 @@ uint8_t SNP_sendNotifInd(snpNotifIndReq_t *pReq, int16_t length)
     }
     
     
    +/*********************************************************************
    + * STATIC FUNCTIONS for Non-HomeKit (NHK) connections
    + */
    +
    +/*********************************************************************
    + * @fn          NHK_ReadAttrCB
    + *
    + * @brief       Read an attribute.
    + *
    + * @param       connHandle - connection message was received on
    + * @param       pAttr - pointer to attribute
    + * @param       pValue - pointer to data to be read
    + * @param       pLen - length of data to be read
    + * @param       offset - offset of the first octet to be read
    + * @param       maxLen - maximum length of data to be read
    + * @param       method - type of read message
    + *
    + * @return      SUCCESS, blePending or Failure
    + */
    +static bStatus_t NHK_ReadAttrCB(uint16_t connHandle,
    +                                gattAttribute_t *pAttr,
    +                                uint8_t *pValue, uint16_t *pLen,
    +                                uint16_t offset, uint16_t maxLen,
    +                                uint8_t method)
    +{
    +  bStatus_t status = SUCCESS;
    +
    +  // Make sure it's not a blob operation (no attributes in the profile are long)
    +  if ( offset > 0 )
    +  {
    +    return ( ATT_ERR_ATTR_NOT_LONG );
    +  }
    +
    +  if ( pAttr->type.len == ATT_BT_UUID_SIZE )
    +  {
    +    // 16-bit UUID
    +    uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
    +    switch ( uuid )
    +    {
    +
    +      // characteristic 1 has read permission
    +      case SIMPLEPROFILE_CHAR1_UUID:
    +        *pLen = 1;
    +        pValue[0] = *pAttr->pValue;
    +        break;
    +
    +      default:
    +        // Should never get here! (characteristics 3 and 4 do not have read permissions)
    +        *pLen = 0;
    +        status = ATT_ERR_ATTR_NOT_FOUND;
    +        break;
    +    }
    +  }
    +  else
    +  {
    +    // 128-bit UUID
    +    *pLen = 0;
    +    status = ATT_ERR_INVALID_HANDLE;
    +  }
    +
    +  return ( status );
    +}
    +
    +/*********************************************************************
    + * @fn      NHK_WriteAttrCB
    + *
    + * @brief   Validate attribute data prior to a write operation
    + *
    + * @param   connHandle - connection message was received on
    + * @param   pAttr - pointer to attribute
    + * @param   pValue - pointer to data to be written
    + * @param   len - length of data
    + * @param   offset - offset of the first octet to be written
    + * @param   method - type of write message
    + *
    + * @return  SUCCESS, blePending or Failure
    + */
    +static bStatus_t NHK_WriteAttrCB(uint16_t connHandle,
    +                                 gattAttribute_t *pAttr,
    +                                 uint8_t *pValue, uint16_t len,
    +                                 uint16_t offset, uint8_t method)
    +{
    +  bStatus_t status = SUCCESS;
    +
    +  if ( pAttr->type.len == ATT_BT_UUID_SIZE )
    +  {
    +    // 16-bit UUID
    +    uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
    +    switch ( uuid )
    +    {
    +      case SIMPLEPROFILE_CHAR1_UUID:
    +
    +        //Validate the value
    +        // Make sure it's not a blob oper
    +        if ( offset == 0 )
    +        {
    +          if ( len != 1 )
    +          {
    +            status = ATT_ERR_INVALID_VALUE_SIZE;
    +          }
    +        }
    +        else
    +        {
    +          status = ATT_ERR_ATTR_NOT_LONG;
    +        }
    +
    +        //Write the value
    +        if ( status == SUCCESS )
    +        {
    +            if(activeConnectionIsNHK == true){
    +
    +                // The connection has the right to be used to update this char
    +                uint8 *pCurValue = (uint8 *)pAttr->pValue;
    +                *pCurValue = pValue[0];
    +
    +                // Here we only use the value transmitted to turn on or off the green LED
    +                if(pValue[0] % 2 != 1){
    +                    GPIO_write(CONFIG_GPIO_LED_1, CONFIG_GPIO_LED_ON);
    +                }
    +                else{
    +                    GPIO_write(CONFIG_GPIO_LED_1, CONFIG_GPIO_LED_OFF);
    +                }
    +
    +
    +            }
    +        }
    +
    +        break;
    +
    +
    +      default:
    +        // Should never get here! (characteristics 2 and 4 do not have write permissions)
    +        status = ATT_ERR_ATTR_NOT_FOUND;
    +        break;
    +    }
    +  }
    +  else
    +  {
    +    // 128-bit UUID
    +    status = ATT_ERR_INVALID_HANDLE;
    +  }
    +
    +  return ( status );
    +}
    +
    +/*********************************************************************
    + * @fn      NHK_AddServices
    + *
    + * @brief   Initializes the Simple Profile service by registering
    + *          GATT attributes with the GATT server.
    + *
    + * @param   services - services to add. This is a bit map and can
    + *                     contain more than one service.
    + *
    + * @return  Success or Failure
    + */
    +static bStatus_t NHK_AddServices( uint32 services )
    +{
    +  uint8 status;
    +
    +  if ( services & SIMPLEPROFILE_SERVICE )
    +  {
    +    // Register GATT attribute list and CBs with GATT Server App
    +    status = GATTServApp_RegisterService( simpleProfileAttrTbl,
    +                                          GATT_NUM_ATTRS( simpleProfileAttrTbl ),
    +                                          GATT_MAX_ENCRYPT_KEY_SIZE,
    +                                          &simpleProfileCBs );
    +  }
    +  else
    +  {
    +    status = SUCCESS;
    +  }
    +
    +  return ( status );
    +}
     
     /*********************************************************************
     *********************************************************************/
    

    I hope this will help,

    Best regards,

  • Clément, thank you for this. I found the files to modify. Just a quick question to further understand. Do I need to disable sysConfig for the manual changes to work? Much appreciated. 

  • Hi,

    Do I need to disable sysConfig for the manual changes to work?

    I don't think so.

    Best regards,

  • Hi Clément, I went through the code below. It make sense what you did here. I hate to ask this question, but, how do you compile this source code? I noticed its not being compile through the standard build process of the projects in CCS. Much appreciated. 

  • Hi,

    The homekit enabled projects should be used as baseline. They are already configured to properly build.

    In case you do not manage to compile unmodified examples, please fix this first.

    Best regards,

  • Hi Clément, I'm using an existing ti homekit example (that's modified tested and working). I've changed modified the simple_np_gap and gatt in the following included directory with above suggestions -> 

    hap_cc26x2_4_10_00_04/source/ti/sap/simple_np_gap.c 

    hap_cc26x2_4_10_00_04/source/ti/sap/simple_np_gatt.c

    Ive checked that these paths are in the build environment however, when I build the project simple_np_gap.c and gatt.c  are not be compiled. I tested this by putting garbage code in files and no errors after building the project. I assume there is something simple I'm missing with ccs. 

    I've attached some pictures of my ccStudio setup. Thanks again for your continued help on this! 

  • Hi,

    I cannot help you further on this one. Please contact your local support team in case more assistance is required.

    Best regards,

  • What project are you building to compile these source files? The included homekit examples (blink, RGB and custom) do not build the hap_cc26x2_r_10_00_04/source directory. 

  • Hi,

    I cannot help you further on this one. Please contact your local support team in case more assistance is required.

    Best regards,