예제 #1
0
/*********************************************************************
 * @fn      pairStateCB
 *
 * @brief   Pairing state callback.
 *
 * @return  none
 */
static void timeAppPairStateCB( uint16 connHandle, uint8 state, uint8 status )
{
    if ( state == GAPBOND_PAIRING_STATE_STARTED )
    {
        timeAppPairingStarted = TRUE;
    }
    else if ( state == GAPBOND_PAIRING_STATE_COMPLETE )
    {
        timeAppPairingStarted = FALSE;

        if ( status == SUCCESS )
        {
            linkDBItem_t  *pItem;

            if ( (pItem = linkDB_Find( gapConnHandle )) != NULL )
            {
                // Store bonding state of pairing
                timeAppBonded = ( (pItem->stateFlags & LINK_BOUND) == LINK_BOUND );

                if ( timeAppBonded )
                {
                    osal_memcpy( timeAppBondedAddr, pItem->addr, B_ADDR_LEN );
                }
            }

            // If discovery was postponed start discovery
            if ( timeAppDiscPostponed && timeAppDiscoveryCmpl == FALSE )
            {
                timeAppDiscPostponed = FALSE;
                osal_set_event( thermometerTaskId, TH_START_DISCOVERY_EVT );
            }

        }
    }
}
예제 #2
0
/*---------------------------------------------------------------------------
* Callback indicating the current state of pairing.
*-------------------------------------------------------------------------*/
static void pairStateCB( uint16 connHandle, uint8 state, uint8 status )
{
  if ( state == GAPBOND_PAIRING_STATE_STARTED )
  {    
    //      
  }
  else if ( state == GAPBOND_PAIRING_STATE_COMPLETE )
  {
    if ( status == SUCCESS )
    {
      linkDBItem_t  *pItem;

      if ( (pItem = linkDB_Find(connHandle )) != NULL )
      {
        if (( (pItem->stateFlags & LINK_BOUND) == LINK_BOUND ))
        {
          //cbLED_flash(cbLED_GREEN, 3, 250, 500);             
        }
      }      
    }
    else
    {
      //     
    }
  }
  else if ( state == GAPBOND_PAIRING_STATE_BONDED )
  {
    //cbLED_flash(cbLED_GREEN, 5, 250, 500);               
  }
}
/*********************************************************************
 * @brief   Set/clear the service change indication in a bond record.
 *
 * Public function defined in gapperiphbondmgr.h.
 */
bStatus_t GAPBondMgr_ServiceChangeInd( uint16 connectionHandle, uint8 setParam )
{
  bStatus_t ret = bleNoResources; // return value
  
  if ( connectionHandle == 0xFFFF )
  {
    uint8 idx;  // loop counter
    
    // Run through the bond database and update the Service Change indication
    for ( idx = 0; idx < GAP_BONDINGS_MAX; idx++ )
    {
      if ( gapBondMgrChangeState( idx, GAP_BONDED_STATE_SERVICE_CHANGED, setParam ) )
      {
        ret = SUCCESS;
      }
    }

    // If the service change indication is TRUE, tell the connected devices
    if ( setParam )
    {
      // Run connected database
      linkDB_PerformFunc( gapBondMgrSendServiceChange );
    }
  }
  else
  {
    // Find connection information
    linkDBItem_t *pLinkItem = linkDB_Find( connectionHandle );
    if ( pLinkItem )
    {
      uint8 idx; // loop counter
      idx = GAPBondMgr_ResolveAddr( pLinkItem->addrType, pLinkItem->addr, NULL );
      if ( idx < GAP_BONDINGS_MAX )
      {
        // Bond found, update it.
        VOID gapBondMgrChangeState( idx, GAP_BONDED_STATE_SERVICE_CHANGED, setParam );
        ret = SUCCESS;
      }
      
      // If the service change indication is TRUE, tell the connected device
      if ( setParam )
      {
        gapBondMgrSendServiceChange( pLinkItem );
      }
    }
    else
    {
      ret = bleNotConnected;
    }
  }
  
  return ( ret );
}
예제 #4
0
/*********************************************************************
 * @fn      pairStateCB
 *
 * @brief   Pairing state callback.
 *
 * @return  none
 */
static void timeAppPairStateCB( uint16 connHandle, uint8 state, uint8 status )
{
  if ( state == GAPBOND_PAIRING_STATE_STARTED )
  {
    timeAppPairingStarted = TRUE;
    
    LCD_WRITE_STRING( "Pairing started", HAL_LCD_LINE_1 );
  }
  else if ( state == GAPBOND_PAIRING_STATE_COMPLETE )
  {
    timeAppPairingStarted = FALSE;

    if ( status == SUCCESS )
    {
      linkDBItem_t  *pItem;
      
      if ( (pItem = linkDB_Find( timeAppConnHandle )) != NULL )
      {
        // Store bonding state of pairing
        timeAppBonded = ( (pItem->stateFlags & LINK_BOUND) == LINK_BOUND );
        
        if ( timeAppBonded )
        {
          osal_memcpy( timeAppBondedAddr, pItem->addr, B_ADDR_LEN );
        }
      }
      
      // If discovery was postponed start discovery
      if ( timeAppDiscPostponed && timeAppDiscoveryCmpl == FALSE )
      {
        timeAppDiscPostponed = FALSE;
        osal_set_event( timeAppTaskId, START_DISCOVERY_EVT );
      }
      
      LCD_WRITE_STRING( "Pairing success", HAL_LCD_LINE_1 );
    }
    else
    {
      LCD_WRITE_STRING_VALUE( "Pairing fail", status, 10, HAL_LCD_LINE_1 );
    }
  }
  else if ( state == GAPBOND_PAIRING_STATE_BONDED )
  {
    if ( status == SUCCESS )
    {
      LCD_WRITE_STRING( "Bonding success", HAL_LCD_LINE_1 );
    }
  }
}
예제 #5
0
/*********************************************************************
 * @fn      softCmdGapStateCB
 *
 * @brief   Notification from the profile of a state change.
 *
 * @param   newState - new state
 *
 * @return  none
 */
static void softCmdGapStateCB( gaprole_States_t newState )
{
  // if connected
  if (newState == GAPROLE_CONNECTED)
  {
    linkDBItem_t  *pItem;

    // Get connection handle
    GAPRole_GetParameter( GAPROLE_CONNHANDLE, &softCmdConnHandle );

    // Get peer bd address
    if ( (pItem = linkDB_Find( softCmdConnHandle )) != NULL)
    {
      // If connected to device without bond do service discovery
      if ( !osal_memcmp( pItem->addr, softCmdBondedAddr, B_ADDR_LEN ) )
      {
        softCmdDiscoveryCmpl = FALSE;
      }
      
      // Initiate service discovery if necessary
      if ( softCmdDiscoveryCmpl == FALSE )
      {
        osal_start_timerEx( softCmdTaskId, START_DISCOVERY_EVT, DEFAULT_DISCOVERY_DELAY );
      }
    }      
  }
  
  // if disconnected
  else if (softCmdGapState == GAPROLE_CONNECTED && 
           newState != GAPROLE_CONNECTED)
  {
    softCmdDisconnected();
    
    // reset client characteristic configuration descriptors
    uint16 param = GATT_CFG_NO_OPERATION;
    Batt_SetParameter(BATT_PARAM_LVL_ST_CHAR_CFG, sizeof(uint16), (uint8 *) &param);
  }    
  
  softCmdGapState = newState;
}
/*********************************************************************
 * @fn      gapRole_ProcessGAPMsg
 *
 * @brief   Process an incoming task message.
 *
 * @param   pMsg - message to process
 *
 * @return  none
 */
void gapBondMgr_ProcessGAPMsg( gapEventHdr_t *pMsg )
{
  switch ( pMsg->opcode )
  {
    case GAP_PASSKEY_NEEDED_EVENT:
      {
        gapPasskeyNeededEvent_t *pPkt = (gapPasskeyNeededEvent_t *)pMsg;
        
        if ( pGapBondCB && pGapBondCB->passcodeCB )
        {
          // Ask app for a passcode
          pGapBondCB->passcodeCB( pPkt->deviceAddr, pPkt->connectionHandle, pPkt->uiInputs, pPkt->uiOutputs );
        }
        else
        {
          // No app support, use the default passcode
          if ( GAP_PasscodeUpdate( gapBond_Passcode, pPkt->connectionHandle ) != SUCCESS )
          {
            VOID GAP_TerminateAuth( pPkt->connectionHandle, SMP_PAIRING_FAILED_PASSKEY_ENTRY_FAILED );
          }
        }        
      }
      break;
      
    case GAP_AUTHENTICATION_COMPLETE_EVENT:
      {
        gapAuthCompleteEvent_t *pPkt = (gapAuthCompleteEvent_t *)pMsg;
        
        // Should we save bonding information
        if ( (pPkt->hdr.status == SUCCESS) && (pPkt->authState & SM_AUTH_STATE_BONDING) )
        {
          gapBondRec_t bondRec;
          
          VOID osal_memset( &bondRec, 0, sizeof ( gapBondRec_t ) ) ;
          
          // Do we have a public address in the data?
          if ( pPkt->pIdentityInfo )
          {
            VOID osal_memcpy( bondRec.publicAddr, pPkt->pIdentityInfo->bd_addr, B_ADDR_LEN );
          }
          else
          {
            linkDBItem_t *pLinkItem = linkDB_Find( pPkt->connectionHandle );
            if ( pLinkItem )
            {
              VOID osal_memcpy( bondRec.publicAddr, pLinkItem->addr, B_ADDR_LEN );
            }
            else
            {
              // We don't have an address, so ignore the message.
              break;
            }
          }
          
          // Save off of the authentication state
          bondRec.stateFlags |= (pPkt->authState & SM_AUTH_STATE_AUTHENTICATED) ? GAP_BONDED_STATE_AUTHENTICATED : 0;
          
          VOID gapBondMgrAddBond( &bondRec, 
                             (gapBondLTK_t *)pPkt->pSecurityInfo, 
                             (gapBondLTK_t *)pPkt->pDevSecInfo,
                             ((uint8 *)((pPkt->pIdentityInfo) ? pPkt->pIdentityInfo->irk : NULL )),
                             ((uint8 *)((pPkt->pSigningInfo) ? pPkt->pSigningInfo->srk : NULL )),
                             ((uint32)((pPkt->pSigningInfo) ? pPkt->pSigningInfo->signCounter : GAP_INIT_SIGN_COUNTER )) );
                             
        }
        
        // Call app state callback
        if ( pGapBondCB && pGapBondCB->pairStateCB )
        {
          pGapBondCB->pairStateCB( GAPBOND_PAIRING_STATE_COMPLETE, pPkt->hdr.status );
        }
      }
      break;
        
    case GAP_BOND_COMPLETE_EVENT:
      // This message is received when the bonding is complete.  If hdr.status is SUCCESS
      // then call app state callback.  If hdr.status is NOT SUCCESS, the connection will be 
      // dropped at the LL because of a MIC failure, so again nothing to do.
      if ( pGapBondCB && pGapBondCB->pairStateCB && pMsg->hdr.status == SUCCESS )
      {
        pGapBondCB->pairStateCB( GAPBOND_PAIRING_STATE_BONDED, pMsg->hdr.status );
      }  
      break;
      
    case GAP_SIGNATURE_UPDATED_EVENT:
      {
        uint8 idx;
        gapSignUpdateEvent_t *pPkt = (gapSignUpdateEvent_t *)pMsg;
        
        idx = GAPBondMgr_ResolveAddr( pPkt->addrType, pPkt->devAddr, NULL );
        if ( idx < GAP_BONDINGS_MAX )
        {
          // Save the sign counter
          VOID osal_snv_write( devSignCounterNvID(idx), sizeof ( uint32 ), &(pPkt->signCounter) );
        }
      }
      break;
      
    case GAP_PAIRING_REQ_EVENT:
      {
        gapPairingReqEvent_t *pPkt = (gapPairingReqEvent_t *)pMsg;
        
        if ( gapBond_AutoFail != FALSE )
        {
          // Auto Fail TEST MODE (DON'T USE THIS) - Sends pre-setup reason
          VOID GAP_TerminateAuth( pPkt->connectionHandle, gapBond_AutoFailReason );
        }
        else if ( gapBond_PairingMode == GAPBOND_PAIRING_MODE_NO_PAIRING )
        {
          // No Pairing - Send error
          VOID GAP_TerminateAuth( pPkt->connectionHandle, SMP_PAIRING_FAILED_NOT_SUPPORTED );
        }
        else
        {
          gapAuthParams_t params;
          linkDBItem_t *pLinkItem = linkDB_Find( pPkt->connectionHandle );
          
          // Requesting bonding?
          if ( pPkt->pairReq.authReq & SM_AUTH_STATE_BONDING )
          {
            if ( pLinkItem ) 
            {
              if ( (pLinkItem->addrType != ADDRTYPE_PUBLIC) && (pPkt->pairReq.keyDist.mIdKey == FALSE) )
              {
                uint8 publicAddr[B_ADDR_LEN];
                
                // Check if we already have the public address in NV
                if ( GAPBondMgr_ResolveAddr(pLinkItem->addrType, pLinkItem->addr, publicAddr ) == FALSE )
                {
                  // Can't bond to a non-public address if we don't know the public address
                  VOID GAP_TerminateAuth( pPkt->connectionHandle, SMP_PAIRING_FAILED_AUTH_REQ );
                  break;
                }
              }
            }
            else
            {
              // Can't find the connection, ignore the message
              break;
            }
          }

          VOID osal_memset( &params, 0, sizeof ( gapAuthParams_t ) );
          
          // Setup the pairing parameters
          params.connectionHandle = pPkt->connectionHandle;
          params.secReqs.ioCaps = gapBond_IOCap;
          params.secReqs.oobAvailable = gapBond_OOBDataFlag;
          params.secReqs.maxEncKeySize = gapBond_KeySize;
          
          // TBD - Should we distribute keys if bonding is turned off???
          params.secReqs.keyDist.sEncKey = (gapBond_KeyDistList | GAPBOND_KEYDIST_SENCKEY) ? TRUE : FALSE;
          params.secReqs.keyDist.sIdKey = (gapBond_KeyDistList | GAPBOND_KEYDIST_SIDKEY) ? TRUE : FALSE;
          params.secReqs.keyDist.mEncKey = (gapBond_KeyDistList | GAPBOND_KEYDIST_MENCKEY) ? TRUE : FALSE;
          params.secReqs.keyDist.mIdKey = (gapBond_KeyDistList | GAPBOND_KEYDIST_MIDKEY) ? TRUE : FALSE;
          params.secReqs.keyDist.mSign = (gapBond_KeyDistList | GAPBOND_KEYDIST_MSIGN) ? TRUE : FALSE;
          params.secReqs.keyDist.sSign = (gapBond_KeyDistList | GAPBOND_KEYDIST_SSIGN) ? TRUE : FALSE;
          
          // Is bond manager setup for OOB data?
          if ( gapBond_OOBDataFlag )
          {
            VOID osal_memcpy( params.secReqs.oob, gapBond_OOBData, KEYLEN );
          }
          
          if ( (pPkt->pairReq.authReq & SM_AUTH_STATE_BONDING) && (gapBond_Bonding) )
          {
            params.secReqs.authReq |= SM_AUTH_STATE_BONDING;
            if ( pLinkItem->addrType != ADDRTYPE_PUBLIC )
            {
              // Force a master ID key 
              params.secReqs.keyDist.mIdKey = TRUE;
            }
          }
          
          // Is Bond Manager setup for passkey protection?
          if ( gapBond_MITM )
          {
            params.secReqs.authReq |= SM_AUTH_STATE_AUTHENTICATED;
          }
          
          VOID GAP_Authenticate( &params, &(pPkt->pairReq) );
        }
        
        // Call app state callback
        if ( pGapBondCB && pGapBondCB->pairStateCB )
        {
          pGapBondCB->pairStateCB( GAPBOND_PAIRING_STATE_STARTED, pPkt->hdr.status );
        }        
      }
      break;
      
    default:
      break;
  }
}
예제 #7
0
//static void peripheralStateNotificationCB( gaprole_States_t newState )
static void peripheralStateNotificationCB( gaprole_States_t* newState )
{

    // if connected
    if ( *newState == GAPROLE_CONNECTED )
    {
        linkDBItem_t  *pItem;

        // Get connection handle
        GAPRole_GetParameter( GAPROLE_CONNHANDLE, &gapConnHandle );

        // Get peer bd address
        if ( (pItem = linkDB_Find( gapConnHandle )) != NULL)
        {
            // If connected to device without bond do service discovery
            if ( !osal_memcmp( pItem->addr, timeAppBondedAddr, B_ADDR_LEN ) )
            {
                timeAppDiscoveryCmpl = FALSE;
            }
            else
            {
                timeAppDiscoveryCmpl = TRUE;
            }

            // if this was last connection address don't do discovery
            if(osal_memcmp( pItem->addr, lastConnAddr, B_ADDR_LEN ))
            {
                timeAppDiscoveryCmpl = TRUE;
                connectedToLastAddress = true;
            }
            else
            {
                //save the last connected address
                osal_memcpy(lastConnAddr, pItem->addr, B_ADDR_LEN );
            }

            // Initiate service discovery if necessary
            if ( timeAppDiscoveryCmpl == FALSE )
            {
                osal_start_timerEx( thermometerTaskId, TH_START_DISCOVERY_EVT, DEFAULT_DISCOVERY_DELAY );
            }

            //on connection initiate disconnect timer in 20 seconds
            osal_start_timerEx( thermometerTaskId, TH_DISCONNECT_EVT, 20000 );

        }
    }
    // if disconnected
    else if ( gapProfileState == GAPROLE_CONNECTED &&
              *newState != GAPROLE_CONNECTED )
    {
        timeAppDisconnected();

        //always stop intermediate timer
        osal_stop_timerEx( thermometerTaskId, TH_PERIODIC_IMEAS_EVT );

    }
    // if started
    else if ( *newState == GAPROLE_STARTED )
    {
        // Initialize time clock
        timeAppClockInit();
    }

    gapProfileState = *newState;

    updateUI();

}
예제 #8
0
/*********************************************************************
 * @fn      gapProfileStateCB
 *
 * @brief   Notification from the profile of a state change.
 *
 * @param   newState - new state
 *
 * @return  none
 */
static void peripheralStateNotificationCB( gaprole_States_t newState )
{
 
  
  
  // if connected
  if ( newState == GAPROLE_CONNECTED )
  {
    linkDBItem_t  *pItem;

    
    HalLedSet ( HAL_LED_1, HAL_LED_MODE_OFF );
    
    // Get connection handle
    GAPRole_GetParameter( GAPROLE_CONNHANDLE, &gapConnHandle );

    // Get peer bd address
    if ( (pItem = linkDB_Find( gapConnHandle )) != NULL)
    {
      // If connected to device without bond do service discovery
      if ( !osal_memcmp( pItem->addr, timeAppBondedAddr, B_ADDR_LEN ) )
      {
        timeAppDiscoveryCmpl = FALSE;
      }
      else
      {
        timeAppDiscoveryCmpl = TRUE;
      }
      
      // if this was last connection address don't do discovery
      if(osal_memcmp( pItem->addr, lastConnAddr, B_ADDR_LEN ))
      {
        timeAppDiscoveryCmpl = TRUE;
        connectedToLastAddress = true;
      }
      else
      {
        //save the last connected address  
        osal_memcpy(lastConnAddr, pItem->addr, B_ADDR_LEN );
      }

      // Initiate service discovery if necessary
      if ( timeAppDiscoveryCmpl == FALSE )
      {
       
       // osal_start_timerEx( bloodPressureTaskId, BP_START_DISCOVERY_EVT, DEFAULT_DISCOVERY_DELAY );
      }
        
    } 
  }
  // if disconnected
  else if ( gapProfileState == GAPROLE_CONNECTED && 
            newState != GAPROLE_CONNECTED )
  {
    timeAppDisconnected();
    
    //always stop intermediate timer
    osal_stop_timerEx( bloodPressureTaskId, BP_TIMER_CUFF_EVT ); 
    
    // stop disconnect timer
    osal_stop_timerEx( bloodPressureTaskId, BP_DISCONNECT_PERIOD ); 
    
  }    
  // if started
  else if ( newState == GAPROLE_STARTED )
  {
    // Initialize time clock display
    //timeAppClockInit();
  }
  
  gapProfileState = newState;
  
  updateUI();
  
}
예제 #9
0
/*********************************************************************
 * @fn      timeAppGapStateCB
 *
 * @brief   Notification from the profile of a state change.
 *
 * @param   newState - new state
 *
 * @return  none
 */
static void timeAppGapStateCB( gaprole_States_t newState )
{
  // if connected
  if ( newState == GAPROLE_CONNECTED )
  {
    linkDBItem_t  *pItem;

    // Get connection handle
    GAPRole_GetParameter( GAPROLE_CONNHANDLE, &timeAppConnHandle );

    // Get peer bd address
    if ( (pItem = linkDB_Find( timeAppConnHandle )) != NULL)
    {
      // If connected to device without bond do service discovery
      if ( !osal_memcmp( pItem->addr, timeAppBondedAddr, B_ADDR_LEN ) )
      {
        timeAppDiscoveryCmpl = FALSE;
      }
      
      // Initiate service discovery if necessary
      if ( timeAppDiscoveryCmpl == FALSE )
      {
        osal_start_timerEx( timeAppTaskId, START_DISCOVERY_EVT, DEFAULT_DISCOVERY_DELAY );
      }
      // Perform configuration of characteristics on connection setup
      else
      {
        timeAppConfigState = timeAppConfigNext( TIMEAPP_CONFIG_CONN_START );
      }
      
    }
      
    LCD_WRITE_STRING( "Connected", HAL_LCD_LINE_1 );
    LCD_WRITE_STRING( "", HAL_LCD_LINE_2 );
  }
  // if disconnected
  else if ( timeAppGapState == GAPROLE_CONNECTED && 
            newState != GAPROLE_CONNECTED )
  {
    uint8 advState = TRUE;
      
    timeAppDisconnected();
    
    if ( newState == GAPROLE_WAITING_AFTER_TIMEOUT )
    {
      // link loss timeout-- use fast advertising
      GAP_SetParamValue( TGAP_GEN_DISC_ADV_INT_MIN, DEFAULT_FAST_ADV_INTERVAL );
      GAP_SetParamValue( TGAP_GEN_DISC_ADV_INT_MAX, DEFAULT_FAST_ADV_INTERVAL );
      GAP_SetParamValue( TGAP_GEN_DISC_ADV_MIN, DEFAULT_FAST_ADV_DURATION );
    }
    else
    {
      // Else use slow advertising
      GAP_SetParamValue( TGAP_GEN_DISC_ADV_INT_MIN, DEFAULT_SLOW_ADV_INTERVAL );
      GAP_SetParamValue( TGAP_GEN_DISC_ADV_INT_MAX, DEFAULT_SLOW_ADV_INTERVAL );
      GAP_SetParamValue( TGAP_GEN_DISC_ADV_MIN, DEFAULT_SLOW_ADV_DURATION );
    }

    // Enable advertising
    GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &advState );   
    
    LCD_WRITE_STRING( "Disconnected", HAL_LCD_LINE_1 );
    LCD_WRITE_STRING( "", HAL_LCD_LINE_2 );
  }
  // if advertising stopped
  else if ( timeAppGapState == GAPROLE_ADVERTISING && 
            newState == GAPROLE_WAITING )
  {
    // if advertising stopped by user
    if ( timeAppAdvCancelled )
    {
      timeAppAdvCancelled = FALSE;
    }
    // if fast advertising switch to slow
    else if ( GAP_GetParamValue( TGAP_GEN_DISC_ADV_INT_MIN ) == DEFAULT_FAST_ADV_INTERVAL )
    {
      uint8 advState = TRUE;
      
      GAP_SetParamValue( TGAP_GEN_DISC_ADV_INT_MIN, DEFAULT_SLOW_ADV_INTERVAL );
      GAP_SetParamValue( TGAP_GEN_DISC_ADV_INT_MAX, DEFAULT_SLOW_ADV_INTERVAL );
      GAP_SetParamValue( TGAP_GEN_DISC_ADV_MIN, DEFAULT_SLOW_ADV_DURATION );
      GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &advState );   
    }  
  }
  // if started
  else if ( newState == GAPROLE_STARTED )
  {
    
#ifndef CC2540_MINIDK    
    uint8 bdAddr[B_ADDR_LEN];
    
    GAPRole_GetParameter( GAPROLE_BD_ADDR, &bdAddr );
    LCD_WRITE_STRING( "Time App", HAL_LCD_LINE_1 );
    LCD_WRITE_STRING( bdAddr2Str( bdAddr ),  HAL_LCD_LINE_2 );
#endif 
    
    // Initialize time clock after writing first two lines of LCD
    timeAppClockInit();
  }
  
  timeAppGapState = newState;
}