KW41Z(hid device) connects to 2 cell phones at the same time

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

KW41Z(hid device) connects to 2 cell phones at the same time

761 Views
seanwu
Contributor IV

Dear sir,

I want to use KW41z(using hid device example) to connect to 2 cell phones at the same time.

If KW41z can, how to set?

Thanks.

BR,

Sean

Labels (2)
0 Kudos
2 Replies

481 Views
mario_castaneda
NXP TechSupport
NXP TechSupport

Hi SeanWu,

1.- First, make sure low power is disabled with cPWR_UsePowerDownMode define in app_preinclude.h

2.-Services’ functions must be modified. HID requires a  service and a battery service. Let’s start modifications with the hid service description located in the hid_service.c file.

3. First, modify mHid_SubscribedClientId variable to store 2 devices IDs,and add a variable for a connections.

hid_service.c file

/*! HID Service - Subscribed Client*/
static deviceId_t mHid_SubscribedClientId[2] =
{
  gInvalidDeviceId_c,
  gInvalidDeviceId_c
};

uint8_t HidConnections = 0;‍‍‍‍‍‍‍‍

4. Initialize the created variables in Hid_Start function. Make sure the previous mHid_SubscribedClientId initialization is commented:

bleResult_t Hid_Start(hidConfig_t *pServiceConfig)
{
   //mHid_SubscribedClientId = gInvalidDeviceId_c;
   
   mHid_SubscribedClientId[0] = gInvalidDeviceId_c;
   mHid_SubscribedClientId[1] = gInvalidDeviceId_c;
   
   HidConnections = 0;
   
   Hid_SetProtocolMode(pServiceConfig->serviceHandle, pServiceConfig->protocolMode);
   
   return gBleSuccess_c;
}‍‍‍‍‍‍‍‍‍‍‍‍‍

5. Modify Hid_Subscribe function to allow 2 connections.

bleResult_t Hid_Subscribe(deviceId_t clientdeviceId)
{
   //if (mHid_SubscribedClientId == gInvalidDeviceId_c)
   // mHid_SubscribedClientId = clientdeviceId;
   if(HidConnections < 2)
   {
      mHid_SubscribedClientId[HidConnections] = clientdeviceId;
      HidConnections++;
      return gBleSuccess_c;
   }
   else
   {
      return gBleInvalidState_c;
   }
}
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

6. Modify Hid_Unsubscribe function

bleResult_t Hid_Unsubscribe(deviceId_t clientdeviceId)
{
    //mHid_SubscribedClientId = gInvalidDeviceId_c;
  if(HidConnections)
  {
    if(clientdeviceId == mHid_SubscribedClientId[0])
    {
      HidConnections--;
      mHid_SubscribedClientId[0] = gInvalidDeviceId_c;
    }
    else if(mHid_SubscribedClientId[1] == clientdeviceId)
    {
      HidConnections--;
      mHid_SubscribedClientId[1] = gInvalidDeviceId_c;
    }
  }  
  
  return gBleSuccess_c;
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

7. Then Hid_Stop function

bleResult_t Hid_Stop(hidConfig_t *pServiceConfig)
{
   Hid_Unsubscribe(mHid_SubscribedClientId[0]);
   Hid_Unsubscribe(mHid_SubscribedClientId[1]);
   
   return gBleSuccess_c;
   //return Hid_Unsubscribe();
}‍‍‍‍‍‍‍‍

8. Modify Hid_SendNotifications function to send the data to both centrals.

static void Hid_SendReportNotifications
(
 uint16_t handle
)
{
    uint16_t  hCccd;
    bool_t isNotifActive;

    /* Get handle of CCCD */
    if (GattDb_FindCccdHandleForCharValueHandle(handle, &hCccd) != gBleSuccess_c)
        return;
    if (mHid_SubscribedClientId[0] != gInvalidDeviceId_c)
    {
        if (gBleSuccess_c == Gap_CheckNotificationStatus \
            (mHid_SubscribedClientId[0], hCccd, &isNotifActive) && \
            TRUE == isNotifActive)
        {
          GattServer_SendNotification(mHid_SubscribedClientId[0], handle);
        }
    }
    if (mHid_SubscribedClientId[1] != gInvalidDeviceId_c) 
    {
      if (gBleSuccess_c == Gap_CheckNotificationStatus \
      (mHid_SubscribedClientId[1], hCccd, &isNotifActive) && \
      TRUE == isNotifActive)
      {
        GattServer_SendNotification(mHid_SubscribedClientId[1], handle);
      }
    }
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

9. Now open hid_service.h file under Bluetooth folder and add a deviceId_t input parameter to Hid_Unsubscribe

bleResult_t Hrs_Unsubscribe(deviceId_t clientDeviceId);‍‍

Modify battery service’s functions

1. Next step is to do the same modifications to battery service. Open battery_service.c file stored in Bluetooth folder. Modify the ID’s variable to support 2 connections and add the next variable to count connections.

/*! Battery Service - Subscribed Client*/
deviceId_t mBas_SubscribedClientId[2] =
{
   gInvalidDeviceId_c,
   gInvalidDeviceId_c
};‍‍‍‍‍‍‍‍‍‍‍‍

uint8_t BasConnections = 0;

2. Modify Bas_Start function.

bleResult_t Bas_Start (basConfig_t *pServiceConfig)
{
   /* Record initial battery level measurement */
   Bas_RecordBatteryMeasurement(pServiceConfig->serviceHandle, pServiceConfig->batteryLevel);
   mBas_SubscribedClientId[0] = gInvalidDeviceId_c;
   mBas_SubscribedClientId[1] = gInvalidDeviceId_c;
   return gBleSuccess_c;
}

3. Now do the next modifications in Bas_Stop function.

bleResult_t Bas_Stop (basConfig_t *pServiceConfig)
{
  mBas_SubscribedClientId[0] = gInvalidDeviceId_c;
  mBas_SubscribedClientId[1] = gInvalidDeviceId_c;
  BasConnections = 0;
  return gBleSuccess_c;
}


4. Modify Bas_Subscribe function.

bleResult_t Bas_Subscribe(deviceId_t clientDeviceId)
{
   if(BasConnections < 2)
   {
     mBas_SubscribedClientId[BasConnections] = clientDeviceId;
     BasConnections ++;
     return gBleSuccess_c;
   }
   else
   {
     return gBleInvalidState_c;
   }
}


5. Do the same with Bas_Unsubscribe function.

bleResult_t Bas_Unsubscribe(deviceId_t clientDeviceId)
{
   if(BasConnections)
   {
     if(clientDeviceId == mBas_SubscribedClientId[0])
     {
       BasConnections--;
       mBas_SubscribedClientId[0] = gInvalidDeviceId_c;
     }
     else if(mBas_SubscribedClientId[1] == clientDeviceId)
     {
       BasConnections--;
       mBas_SubscribedClientId[1] = gInvalidDeviceId_c;
     }
   }
   return gBleSuccess_c;
}

6. Finally, for this file do the next changes in Bas_SendNotifications functions.

static void Bas_SendNotifications(uint16_t handle)
{
   uint16_t handleCccd;
   bool_t isActive;
   /* Get handle of CCCD */
   if (GattDb_FindCccdHandleForCharValueHandle(handle, &handleCccd) != gBleSuccess_c)
   return;
   if(mBas_SubscribedClientId[0] != gInvalidDeviceId_c)
   {
     if (gBleSuccess_c == Gap_CheckNotificationStatus
      (mBas_SubscribedClientId[0], handleCccd, &isActive) &&
      TRUE == isActive)
     {
        GattServer_SendNotification(mBas_SubscribedClientId[0], handle);
     }
   }
   if(mBas_SubscribedClientId[1] != gInvalidDeviceId_c)
   {
      if (gBleSuccess_c == Gap_CheckNotificationStatus
      (mBas_SubscribedClientId[1], handleCccd, &isActive) &&
      TRUE == isActive)
      {
         GattServer_SendNotification(mBas_SubscribedClientId[1], handle);
      }
   }
}


7. Now open battery_interface.h file stored in Bluetooth folder. Update Bas_Unsubscribe function declaration to receive an input deviceId_t parameter.

bleResult_t Bas_Unsubscribe(deviceId_t clientDeviceId);

Hid device source

1.Open the Hid_device.c file stored in source folder. Modify ID variable to store 2 devices.

static deviceId_t  mPeerDeviceId [2] =
{
  gInvalidDeviceId_c,
  gInvalidDeviceId_c
};


2. Declare a timer to restart advertising.

static tmrTimerID_t RestartAdvTimerId;


3. Declare the timer callback that will be used to re-start advertising after the first device is connected.

static void RestartAdvTimerCallback (void *);


4. Definition of the timer callback. Note the timer is disabled. This definition should be at the end of the file.

static void RestartAdvTimerCallback (void * pParam)
{
    BleApp_Start();
    TMR_StopTimer(RestartAdvTimerId);
}

5. In BleApp_HandleKeys  function do the following changes. These allow the application to start advertising when SW4 is pressed if there are connections available:

a. In gKBD_EventPressPB1_c change the comparison to handle both connections

case gKBD_EventPressPB1_c:
{
   if ((mPeerDeviceId[0] == gInvalidDeviceId_c) || (mPeerDeviceId[1] == gInvalidDeviceId_c))
   {
       BleApp_Start();
   }
   break;
}


b. In gKBD_EventLongPB1_c. When SW4 is pressed for more than 10 seconds, both devices will be disconnected

case gKBD_EventLongPB1_c:
{
   // if (mPeerDeviceId != gInvalidDeviceId_c)
     //   Gap_Disconnect(mPeerDeviceId);
  if (mPeerDeviceId[0] != gInvalidDeviceId_c)
  {
      Gap_Disconnect(mPeerDeviceId[0]);
  }
  if(mPeerDeviceId[1] != gInvalidDeviceId_c)
  {
      Gap_Disconnect(mPeerDeviceId[1]);
  }
  break;
}


6. On BleApp_Config function allocate the Restart advertising.

RestartAdvTimerId = TMR_AllocateTimer();


7. In BleApp_ConnectionCallback do the next changes.

a. At gConnEvtConnected_c
i. Comment mPeerDeviceId = peerDeviceId and assign the connected device ID to an empty slot on the device list.
ii. To start advertising after the first device is connected, add the following code. Also, comment the led flashing code lines.

case gConnEvtConnected_c:
{
    //mPeerDeviceId = peerDeviceId;
    if(mPeerDeviceId[0] == gInvalidDeviceId_c)
    {
        mPeerDeviceId[0] = peerDeviceId;
    }
    else if (mPeerDeviceId[1] == gInvalidDeviceId_c)
    {
        mPeerDeviceId[1] = peerDeviceId;
    }

    /* Advertising stops when connected */
    mAdvState.advOn = FALSE;            

    /* Subscribe client*/
    Bas_Subscribe(peerDeviceId);        
    Hid_Subscribe(peerDeviceId);

    /* UI */
   // LED_StopFlashingAllLeds();
   // Led1On();
    
    if((mPeerDeviceId[0] != gInvalidDeviceId_c) && (mPeerDeviceId[1] !=
    gInvalidDeviceId_c))
    {
        LED_StopFlashingAllLeds(); Led1On();
    {
        TMR_StartLowPowerTimer(RestartAdvTimerId, gTmrLowPowerSingleShotMillisTimer_c, TmrSeconds(5), RestartAdvTimerCallback, NULL);
    }
    }
    else
    {
        TMR_StartLowPowerTimer(RestartAdvTimerId, gTmrLowPowerSingleShotMillisTimer_c, TmrSeconds(5), RestartAdvTimerCallback, NULL);
    }

b. At gConnEvtDisconnected_c
i. Once a disconnection happens, the services must be unsubscribed. Chane the peer device as a parameter to unsubscribe the correct one.
ii. Add the following code to disable the current device. Don’t forget to comment mPeerDeviceId = gInvalidDeviceId_c;

iii. Add the code to stop timers used to report data when there’s no device connected. Comment old TMR_StopTimer function.

case gConnEvtDisconnected_c:
{
    /* Unsubscribe client */
    Bas_Unsubscribe(peerDeviceId);
    Hid_Unsubscribe(peerDeviceId);

    //mPeerDeviceId = gInvalidDeviceId_c;
    if(mPeerDeviceId[0] == peerDeviceId)
    {
        mPeerDeviceId[0] = gInvalidDeviceId_c;
    }
    else if(mPeerDeviceId[1] == peerDeviceId)
    {
        mPeerDeviceId[1] = gInvalidDeviceId_c;
    }
    if((mPeerDeviceId[0] == gInvalidDeviceId_c)||(mPeerDeviceId[1] ==
                    gInvalidDeviceId_c))
    {
            //TMR_StopTimer(mMeasurementTimerId);
            TMR_StopTimer(mBatteryMeasurementTimerId);
    }

    if (pConnectionEvent->eventData.disconnectedEvent.reason == gHciConnectionTimeout_c)
    {
        /* Link loss detected*/
        BleApp_Start();
    }
    else
    {
      /* Connection was terminated by peer or application */
        BleApp_Start();
    }
}
break;

Please let me know if you have problems with the implementation.

Regards,

Mario

0 Kudos

481 Views
mario_castaneda
NXP TechSupport
NXP TechSupport

Hi SeanWu,

I will reply to the HID example with 2 connections. I am working on it

Regards,

Mario

0 Kudos