예제 #1
0
/*! Initiate a light sensor cycle.  Then send the instantaneous and average
 * light sense values to the host.
 *
 * \param tHostMsg* pMsg is unused
 *
 */
static void ReadLightSensorHandler(void)
{
  /* start cycle and wait for it to finish */
  LightSenseCycle();

  /* send message to the host */
  tMessage OutgoingMsg;
  SetupMessageAndAllocateBuffer(&OutgoingMsg,
                                ReadLightSensorResponse,
                                NO_MSG_OPTIONS);

  /* instantaneous value */
  unsigned int lv = ReadLightSense();
  OutgoingMsg.pBuffer[0] = lv & 0xFF;
  OutgoingMsg.pBuffer[1] = (lv >> 8 ) & 0xFF;

  /* average value */
  lv = ReadLightSenseAverage();
  OutgoingMsg.pBuffer[2] = lv & 0xFF;
  OutgoingMsg.pBuffer[3] = (lv >> 8 ) & 0xFF;

  OutgoingMsg.Length = 4;

  RouteMsg(&OutgoingMsg);

}
예제 #2
0
static void ChangeModeHandler(unsigned char Option)
{  
  unsigned char Mode = Option & MODE_MASK;

  tMessage Msg;
  SetupMessageAndAllocateBuffer(&Msg, ModeChangeIndMsg,  (CurrentIdleScreen() << 4) | Mode);
  Msg.pBuffer[0] = eScUpdateComplete;
  Msg.Length = 1;
  RouteMsg(&Msg);

  PrintStringAndHexByte("- ChgModInd:", Msg.Options);
  
  if (Option & MSG_OPT_CHGMOD_IND) return; // ask for current idle page only
    
  if (Mode == MUSIC_MODE) SendMessage(&Msg, UpdConnParamMsg, ShortInterval);
  
  if (Mode != IDLE_MODE)
  {
    PageType = PAGE_TYPE_IDLE;
    if (ModeTimerId == UNASSIGNED) ModeTimerId = AllocateOneSecondTimer();
    SetupOneSecondTimer(ModeTimerId, ModeTimeout[Mode], NO_REPEAT, DISPLAY_QINDEX, ModeTimeoutMsg, Mode);
    StartOneSecondTimer(ModeTimerId);
    
    if (Option & MSG_OPT_UPD_INTERNAL) SendMessage(&Msg, UpdateDisplayMsg, Option);
  }
  else
  {
    StopOneSecondTimer(ModeTimerId);
    IdleUpdateHandler();
  }
  
  CurrentMode = Mode;
}
예제 #3
0
static void ModeTimeoutHandler()
{
  /* send a message to the host indicating that a timeout occurred */
  PrintString2("- ModChgTout", CR);
  
  tMessage Msg;
  SetupMessageAndAllocateBuffer(&Msg, ModeChangeIndMsg, CurrentMode);
  Msg.pBuffer[0] = eScModeTimeout;
  Msg.Length = 1;
  RouteMsg(&Msg);
  
  ChangeModeHandler(IDLE_MODE);
}
예제 #4
0
/*! Read the voltage of the battery. This provides power good, battery charging,
 * battery voltage, and battery voltage average.
 *
 * \param tHostMsg* pMsg is unused
 *
 */
static void ReadBatteryVoltageHandler(void)
{
  tMessage Msg;
  SetupMessageAndAllocateBuffer(&Msg, VBatRespMsg, MSG_OPT_NONE);
  Msg.Length = 6;

  Msg.pBuffer[0] = ClipOn();
  Msg.pBuffer[1] = Charging();
  Msg.pBuffer[2] = BatteryPercentage();

  unsigned int bv = Read(BATTERY);
  Msg.pBuffer[4] = bv & 0xFF;
  Msg.pBuffer[5] = (bv >> 8) & 0xFF;

  RouteMsg(&Msg);
}
예제 #5
0
static void HandleMusicPlayStateChange(unsigned char State)
{
  // music icon fits into one message
  PrintStringAndDecimal("- HdlMusicPlyChg:", State);
  tMessage Msg;
  SetupMessageAndAllocateBuffer(&Msg, WriteBufferMsg,
    MUSIC_MODE | MSG_OPT_WRTBUF_MULTILINE | ICON_MUSIC_WIDTH << 3);
  
  Msg.pBuffer[0] = MUSIC_STATE_START_ROW;
  Msg.Length = ICON_MUSIC_WIDTH * ICON_MUSIC_HEIGHT + 1;
  PrintStringAndTwoDecimals("- start:", Msg.pBuffer[0], "L:", Msg.Length);
  
  unsigned char i = 1;
  for (; i < Msg.Length; ++i) Msg.pBuffer[i] = pIconMusicState[1 - State][i - 1];
  RouteMsg(&Msg);
  
  SendMessage(&Msg, UpdateDisplayMsg, MUSIC_MODE);
}
/* send a vibration to the wearer */
void GenerateLinkAlarm(void)
{
  tMessage Msg;
  
  SetupMessageAndAllocateBuffer(&Msg,SetVibrateMode,NO_MSG_OPTIONS);
  
  tSetVibrateModePayload* pMsgData;
  pMsgData = (tSetVibrateModePayload*) Msg.pBuffer;
  
  pMsgData->Enable = 1;
  pMsgData->OnDurationLsb = 0x00;
  pMsgData->OnDurationMsb = 0x01;
  pMsgData->OffDurationLsb = 0x00;
  pMsgData->OffDurationMsb = 0x01;
  pMsgData->NumberOfCycles = 5;
  
  RouteMsg(&Msg);
}
예제 #7
0
/*! Read configuration of a specified button.  This is used to read the
 * configuration of a button that needs to be restored at a later time
 * by the application.
 *
 * \param tHostMsg* pMsg - A message with a tButtonActionPayload payload
 */
static void ReadButtonConfigHandler(tMessage* pMsg)
{
  /* map incoming message payload to button information */
  tButtonActionPayload* pButtonActionPayload =
    (tButtonActionPayload*)pMsg->pBuffer;

  tMessage OutgoingMsg;
  SetupMessageAndAllocateBuffer(&OutgoingMsg,
                                ReadButtonConfigResponse,
                                NO_MSG_OPTIONS);

  ReadButtonConfiguration(pButtonActionPayload->DisplayMode,
                          pButtonActionPayload->ButtonIndex,
                          pButtonActionPayload->ButtonPressType,
                          OutgoingMsg.pBuffer);

  OutgoingMsg.Length = 5;

  RouteMsg(&OutgoingMsg);

}
예제 #8
0
static void ShowCall(tString *pString, unsigned char Type)
{
  static tString CallerId[15] = "";
  static tTimerId NotifyTimerId = UNASSIGNED;
  tMessage Msg;

  if (Type == SHOW_NOTIF_CALLER_ID) strcpy(CallerId, pString);
  
  if (Type == SHOW_NOTIF_CALLER_NAME && *CallerId)
  {
    PrintString3("- Caller:", pString, CR);
  
    SetupMessageAndAllocateBuffer(&Msg, SetVibrateMode, MSG_OPT_NONE);
    *(tSetVibrateModePayload *)Msg.pBuffer = RingTone;
    RouteMsg(&Msg);
    
    PageType = PAGE_TYPE_INFO;
    CurrentPage[PageType] = CallPage;
    DrawCallScreen(CallerId, pString);

    // set a 5s timer for switching back to idle screen
    if (NotifyTimerId == UNASSIGNED) NotifyTimerId = AllocateOneSecondTimer();
    SetupOneSecondTimer(NotifyTimerId, 10, NO_REPEAT, DISPLAY_QINDEX, CallerNameMsg, SHOW_NOTIF_END);
    StartOneSecondTimer(NotifyTimerId);
  }
  else if (Type == SHOW_NOTIF_END || Type == SHOW_NOTIF_REJECT_CALL)
  {
    PrintString2("- Call Notif End", CR);
    
    *CallerId = NULL;
    StopOneSecondTimer(NotifyTimerId);

    PageType = PAGE_TYPE_IDLE;
    SendMessage(&Msg, UpdateDisplayMsg, CurrentMode | MSG_OPT_UPD_INTERNAL |
                (CurrentMode == IDLE_MODE ? MSG_OPT_NEWUI : 0));

    if (Type == SHOW_NOTIF_REJECT_CALL) SendMessage(&Msg, HfpMsg, MSG_OPT_HFP_HANGUP);
  }
}
예제 #9
0
static void NvalOperationHandler(tMessage* pMsg)
{
  if (pMsg->pBuffer == NULL) // Property
  {
    HandleProperty(pMsg->Options);
  }
  else
  {
    tNvalOperationPayload* pNvPayload = (tNvalOperationPayload*)pMsg->pBuffer;

    /* create the outgoing message */
    tMessage Msg;
    SetupMessageAndAllocateBuffer(&Msg, PropRespMsg, MSG_OPT_NONE);

    /* add identifier to outgoing message */
    tWordByteUnion Identifier;
    Identifier.word = pNvPayload->NvalIdentifier;
    Msg.pBuffer[0] = Identifier.Bytes.byte0;
    Msg.pBuffer[1] = Identifier.Bytes.byte1;
    Msg.Length = 2;

    PrintStringAndTwoHexBytes("- Nval Id:Val 0x", Identifier.word, pNvPayload->DataStartByte);
    
    unsigned char Property = PropertyBit(pNvPayload->NvalIdentifier);

    if (pMsg->Options == NVAL_READ_OPERATION)
    {
      if (Property) Msg.pBuffer[2] = GetProperty(Property);
      Msg.Length += pNvPayload->Size;
    }
    else if (Property) // write operation
    {
      SetProperty(Property, pNvPayload->DataStartByte ? Property : 0);
      UpdateClock();
    }
    RouteMsg(&Msg);
  }
}
예제 #10
0
/*! Read the voltage of the battery. This provides power good, battery charging,
 * battery voltage, and battery voltage average.
 *
 * \param tHostMsg* pMsg is unused
 *
 */
static void ReadBatteryVoltageHandler(void)
{
  tMessage OutgoingMsg;
  SetupMessageAndAllocateBuffer(&OutgoingMsg,
                                ReadBatteryVoltageResponse,
                                NO_MSG_OPTIONS);

  /* if the battery is not present then these values are meaningless */
  OutgoingMsg.pBuffer[0] = QueryPowerGood();
  OutgoingMsg.pBuffer[1] = QueryBatteryCharging();

  unsigned int bv = ReadBatterySense();
  OutgoingMsg.pBuffer[2] = bv & 0xFF;
  OutgoingMsg.pBuffer[3] = (bv >> 8 ) & 0xFF;

  bv = ReadBatterySenseAverage();
  OutgoingMsg.pBuffer[4] = bv & 0xFF;
  OutgoingMsg.pBuffer[5] = (bv >> 8 ) & 0xFF;

  OutgoingMsg.Length = 6;

  RouteMsg(&OutgoingMsg);

}
예제 #11
0
/*! Handle the messages routed to the display queue */
static void DisplayQueueMessageHandler(tMessage* pMsg)
{
  tMessage Msg;
  unsigned char i = 0;

  switch (pMsg->Type)
  {
  case WriteBufferMsg:
    WriteBufferHandler(pMsg);
    break;

  case SetWidgetListMsg:
    SetWidgetList(pMsg);
    break;
  
  case UpdateDisplayMsg:
    UpdateDisplayHandler(pMsg);
    break;
    
  case UpdateClockMsg:
    UpdateClock();
    break;
    
  case DrawClockWidgetMsg:
    DrawClockWidget(pMsg->Options);
    break;

  case MonitorBatteryMsg:
    MonitorBattery();
    break;

  case BluetoothStateChangeMsg:
    BluetoothStateChangeHandler(pMsg);
    break;

  case IdleUpdateMsg:
    IdleUpdateHandler();
    break;

  case ButtonStateMsg:
    ButtonStateHandler();
    break;

  case CallerIdMsg:
//    PrintStringAndDecimal("LcdDisp:CallerId Len:", pMsg->Length);
    pMsg->pBuffer[pMsg->Length] = NULL;
    ShowCall((char *)pMsg->pBuffer, pMsg->Options);
    break;
    
  case CallerNameMsg:
    if (pMsg->Length)
    {
      pMsg->pBuffer[pMsg->Length] = NULL;
      ShowCall((char *)pMsg->pBuffer, SHOW_NOTIF_CALLER_NAME);
    }
    else ShowCall("", pMsg->Options);
    break;

  case MusicPlayStateMsg:
    HandleMusicPlayStateChange(pMsg->Options);
    break;
    
  case ChangeModeMsg:
    ChangeModeHandler(pMsg->Options);
    break;
  
  case ConfigureIdleBufferSize:
    SetProperty(PROP_PHONE_DRAW_TOP, *pMsg->pBuffer ? PROP_PHONE_DRAW_TOP : 0);
    break;

  case ModifyTimeMsg:
    ModifyTimeHandler(pMsg);
    break;

  case MenuModeMsg:
    MenuModeHandler(pMsg->Options);
    break;

  case MenuButtonMsg:
    MenuButtonHandler(pMsg->Options);
    break;

  case EnableButtonMsg:
    EnableButtonMsgHandler(pMsg);
    break;

  case DevTypeMsg:
    SetupMessageAndAllocateBuffer(&Msg, DevTypeRespMsg, MSG_OPT_NONE);
    Msg.Options = BOARD_TYPE; //default G2
    Msg.pBuffer[0] = BOARD_TYPE; // backward compatible

#ifdef WATCH
    if (GetMsp430HardwareRevision() < 'F')
    {
      Msg.Options = DIGITAL_WATCH_TYPE_G1;
      Msg.pBuffer[0] = DIGITAL_WATCH_TYPE_G1; // backward compatible
    }
#endif

    Msg.Length = 1;
    RouteMsg(&Msg);
    PrintStringAndDecimal("- DevTypeResp:", Msg.pBuffer[0]);
    break;

  case VerInfoMsg:
    SetupMessageAndAllocateBuffer(&Msg, VerInfoRespMsg, MSG_OPT_NONE);

    /* exclude middle '.' */
    strncpy((char *)Msg.pBuffer, BUILD, 3);
    strncpy((char *)Msg.pBuffer + 3, BUILD + 4, 3);
    Msg.Length += strlen(BUILD) - 1;
      
    *(Msg.pBuffer + Msg.Length++) = (unsigned char)atoi(VERSION);
    
    while (VERSION[i++] != '.');
    *(Msg.pBuffer + Msg.Length++) = atoi(VERSION + i);
    *(Msg.pBuffer + Msg.Length++) = NULL;
    
    RouteMsg(&Msg);
    
    PrintString("-Ver:"); for (i = 6; i < Msg.Length; ++i) PrintHex(Msg.pBuffer[i]);
    break;
    
  case SetVibrateMode:
    SetVibrateModeHandler(pMsg);
    break;

  case SetRtcMsg:
    halRtcSet((tRtcHostMsgPayload*)pMsg->pBuffer);

#ifdef DIGITAL
    UpdateClock();
#endif
    break;

  case GetRtcMsg:
    SetupMessageAndAllocateBuffer(&Msg, RtcRespMsg, MSG_OPT_NONE);
    halRtcGet((tRtcHostMsgPayload*)Msg.pBuffer);
    Msg.Length = sizeof(tRtcHostMsgPayload);
    RouteMsg(&Msg);
    break;

  case ServiceMenuMsg:
    ServiceMenuHandler();
    break;
    
  case DisableButtonMsg:
    DisableButtonMsgHandler(pMsg);
    break;

  case ReadButtonConfigMsg:
    ReadButtonConfigHandler(pMsg);
    break;

  case LedChange:
    LedChangeHandler(pMsg);
    break;

  case BatteryConfigMsg:
    SetBatteryLevels(pMsg->pBuffer);
    break;

  case ReadBatteryVoltageMsg:
    ReadBatteryVoltageHandler();
    break;

  case ResetMsg:
    SoftwareResetHandler(pMsg);
    break;

  case NvalOperationMsg:
    NvalOperationHandler(pMsg);
    break;

  case SecInvertMsg:
    HandleSecInvert(pMsg->Options);
    break;

  case LoadTemplateMsg:
    LoadTemplateHandler(pMsg);
    break;

  case LinkAlarmMsg:
    if (!GetProperty(PROP_DISABLE_LINK_ALARM))
    {
      SetupMessageAndAllocateBuffer(&Msg, SetVibrateMode, MSG_OPT_NONE);
      tSetVibrateModePayload* pMsgData;
      pMsgData = (tSetVibrateModePayload *)Msg.pBuffer;
      
      pMsgData->Enable = 1;
      pMsgData->OnDurationLsb = 0xC8;
      pMsgData->OnDurationMsb = 0x00;
      pMsgData->OffDurationLsb = 0xF4;
      pMsgData->OffDurationMsb = 0x01;
      pMsgData->NumberOfCycles = 1; //3
      
      RouteMsg(&Msg);
    }
    break;

  case ModeTimeoutMsg:
    ModeTimeoutHandler();
    break;

  case WatchStatusMsg:
    PageType = PAGE_TYPE_INFO;
    CurrentPage[PageType] = StatusPage;
    DrawWatchStatusScreen();
    break;

//  case ListPairedDevicesMsg:
//    ListPairedDevicesHandler();
//    break;

  case WatchDrawnScreenTimeout:
    IdleUpdateHandler();
    break;

  case TermModeMsg:
    TermModeHandler();
    break;
    
  case LowBatteryWarningMsg:
    break;
    
  case LowBatteryBtOffMsg:
    UpdateClock();
    break;

#if __IAR_SYSTEMS_ICC__
  case EraseTemplateMsg:
    EraseTemplateHandler(pMsg);
    break;
    
  case WriteToTemplateMsg:
    WriteToTemplateHandler(pMsg);
    break;
#endif

  case EnableAccelerometerMsg:
  case DisableAccelerometerMsg:
  case AccelerometerSendDataMsg:
  case AccelerometerAccessMsg:
  case AccelerometerSetupMsg:

    HandleAccelerometer(pMsg);
    break;

  case ReadLightSensorMsg:
    ReadLightSensorHandler();
    break;

  case RateTestMsg:
    SetupMessageAndAllocateBuffer(&Msg, DiagnosticLoopback, MSG_OPT_NONE);
    /* don't care what data is */
    Msg.Length = 10;
    RouteMsg(&Msg);
    break;
    
  case RamTestMsg:
    RamTestHandler(pMsg);
    break;
    
  default:
    PrintStringAndHexByte("# Disp Msg: 0x", pMsg->Type);
    break;
  }
}
예제 #12
0
static void NvalOperationHandler(tMessage* pMsg)
{
  /* overlay */
  tNvalOperationPayload* pNvPayload = (tNvalOperationPayload*)pMsg->pBuffer;

  /* create the outgoing message */
  tMessage OutgoingMsg;
  SetupMessageAndAllocateBuffer(&OutgoingMsg,
                                NvalOperationResponseMsg,
                                NV_FAILURE);

  /* add identifier to outgoing message */
  tWordByteUnion Identifier;
  Identifier.word = pNvPayload->NvalIdentifier;
  OutgoingMsg.pBuffer[0] = Identifier.Bytes.byte0;
  OutgoingMsg.pBuffer[1] = Identifier.Bytes.byte1;
  OutgoingMsg.Length = 2;

  /* option byte in return message is status */
  switch (pMsg->Options)
  {

  case NVAL_INIT_OPERATION:
    /* may allow access to a specific range of nval ids that
     * the phone can initialize and use
     */
    break;

  case NVAL_READ_OPERATION:

    /* read the value and update the length */
    OutgoingMsg.Options = OsalNvRead(pNvPayload->NvalIdentifier,
                                     NV_ZERO_OFFSET,
                                     pNvPayload->Size,
                                     &OutgoingMsg.pBuffer[2]);

    OutgoingMsg.Length += pNvPayload->Size;

    break;

  case NVAL_WRITE_OPERATION:

    /* check that the size matches (otherwise NV_FAILURE is sent) */
    if ( OsalNvItemLength(pNvPayload->NvalIdentifier) == pNvPayload->Size )
    {
      OutgoingMsg.Options = OsalNvWrite(pNvPayload->NvalIdentifier,
                                        NV_ZERO_OFFSET,
                                        pNvPayload->Size,
                                        (void*)(&pNvPayload->DataStartByte));
    }

    /* update the copy in ram */
    NvUpdater(pNvPayload->NvalIdentifier);
    break;

  default:
    break;
  }

  RouteMsg(&OutgoingMsg);

}
예제 #13
0
/*! Handle the messages routed to the background task */
static void BackgroundMessageHandler(tMessage* pMsg)
{
  tMessage OutgoingMsg;

  switch(pMsg->Type)
  {
  case SetCallbackTimerMsg:
    SetCallbackTimerHandler(pMsg);
    break;

  case GetDeviceType:
    SetupMessageAndAllocateBuffer(&OutgoingMsg,
                                  GetDeviceTypeResponse,
                                  NO_MSG_OPTIONS);

    OutgoingMsg.pBuffer[0] = BOARD_TYPE;
    OutgoingMsg.Length = 1;
    RouteMsg(&OutgoingMsg);
    break;

  case AdvanceWatchHandsMsg:
    AdvanceWatchHandsHandler(pMsg);
    break;

  case SetVibrateMode:
    SetVibrateModeHandler(pMsg);
    break;

  case SetRealTimeClock:
    halRtcSet((tRtcHostMsgPayload*)pMsg->pBuffer);

#ifdef DIGITAL
    SetupMessage(&OutgoingMsg,IdleUpdate,NO_MSG_OPTIONS);
    RouteMsg(&OutgoingMsg);
#endif
    break;

  case GetRealTimeClock:
    SetupMessageAndAllocateBuffer(&OutgoingMsg,
                                  GetRealTimeClockResponse,
                                  NO_MSG_OPTIONS);

    halRtcGet((tRtcHostMsgPayload*)OutgoingMsg.pBuffer);
    OutgoingMsg.Length = sizeof(tRtcHostMsgPayload);
    RouteMsg(&OutgoingMsg);
    break;

  case EnableButtonMsg:
    EnableButtonMsgHandler(pMsg);
    break;

  case DisableButtonMsg:
    DisableButtonMsgHandler(pMsg);
    break;

  case ReadButtonConfigMsg:
    ReadButtonConfigHandler(pMsg);
    break;

  case BatteryChargeControl:

#ifdef DIGITAL
    /* update the screen if there has been a change in charging status */
    if ( BatteryChargingControl() )
    {
      SetupMessage(&OutgoingMsg, IdleUpdate, NO_MSG_OPTIONS);
      RouteMsg(&OutgoingMsg);
    }
#endif

    BatterySenseCycle();
    LowBatteryMonitor();

#ifdef TASK_DEBUG
    UTL_FreeRtosTaskStackCheck();
#endif

#if 0
    LightSenseCycle();
#endif

    break;

  case LedChange:
    LedChangeHandler(pMsg);
    break;

  case BatteryConfigMsg:
    SetBatteryLevels(pMsg->pBuffer);
    break;

  case ReadBatteryVoltageMsg:
    ReadBatteryVoltageHandler();
    break;

  case ReadLightSensorMsg:
    ReadLightSensorHandler();
    break;

  case SoftwareResetMsg:
    SoftwareResetHandler(pMsg);
    break;

  case NvalOperationMsg:
    NvalOperationHandler(pMsg);
    break;

  case GeneralPurposeWatchMsg:
    /* insert handler here */
    break;

  case ButtonStateMsg:
    ButtonStateHandler();
    break;

  /*
   * Accelerometer Messages
   */
  case AccelerometerEnableMsg:
    AccelerometerEnable();
    break;

  case AccelerometerDisableMsg:
    AccelerometerDisable();
    break;

  case AccelerometerSendDataMsg:
    AccelerometerSendDataHandler();
    break;

  case AccelerometerAccessMsg:
    AccelerometerAccessHandler(pMsg);
    break;

  case AccelerometerSetupMsg:
    AccelerometerSetupHandler(pMsg);
    break;

  /*
   *
   */
  case RateTestMsg:
    SetupMessageAndAllocateBuffer(&OutgoingMsg,DiagnosticLoopback,NO_MSG_OPTIONS);
    /* don't care what data is */
    OutgoingMsg.Length = 10;
    RouteMsg(&OutgoingMsg);
    break;

  /*
   *
   */
  default:
    PrintStringAndHex("<<Unhandled Message>> in Background Task: Type 0x", pMsg->Type);
    break;
  }

}
예제 #14
0
/*! Function to implement the BackgroundTask loop
 *
 * \param pvParameters not used
 *
 */
static void BackgroundTask(void *pvParameters)
{
  if ( QueueHandles[BACKGROUND_QINDEX] == 0 )
  {
    PrintString("Background Queue not created!\r\n");
  }

  PrintString(SPP_DEVICE_NAME);
  PrintString2("\r\nSoftware Version ",VERSION_STRING);
  PrintString("\r\n\r\n");

  InitializeRstNmiConfiguration();

  /*
   * check on the battery
   */
  ConfigureBatteryPins();
  BatteryChargingControl();
  BatterySenseCycle();

  /*
   * now set up a timer that will cause the battery to be checked at
   * a regular frequency.
   */
  BatteryMonitorTimerId = AllocateOneSecondTimer();

  InitializeBatteryMonitorInterval();

  SetupOneSecondTimer(BatteryMonitorTimerId,
                      nvBatteryMonitorIntervalInSeconds,
                      REPEAT_FOREVER,
                      BACKGROUND_QINDEX,
                      BatteryChargeControl,
                      NO_MSG_OPTIONS);

  StartOneSecondTimer(BatteryMonitorTimerId);

  /*
   * Setup a timer to use with the LED for the LCD.
   */
  LedTimerId = AllocateOneSecondTimer();

  SetupOneSecondTimer(LedTimerId,
                      ONE_SECOND*3,
                      NO_REPEAT,
                      BACKGROUND_QINDEX,
                      LedChange,
                      LED_OFF_OPTION);

  // Allocate a timer for wake-up iOS background BLE app
  CallbackTimerId = AllocateOneSecondTimer();

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

#ifdef RAM_TEST

  RamTestTimerId = AllocateOneSecondTimer();

  SetupOneSecondTimer(RamTestTimerId,
                      ONE_SECOND*20,
                      NO_REPEAT,
                      DISPLAY_QINDEX,
                      RamTestMsg,
                      NO_MSG_OPTIONS);

  StartOneSecondTimer(RamTestTimerId);

#endif

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

  InitializeAccelerometer();

#ifdef ACCELEROMETER_DEBUG

  SetupMessageAndAllocateBuffer(&BackgroundMsg,
                                AccelerometerSetupMsg,
                                ACCELEROMETER_SETUP_INTERRUPT_CONTROL_OPTION);

  BackgroundMsg.pBuffer[0] = INTERRUPT_CONTROL_ENABLE_INTERRUPT;
  BackgroundMsg.Length = 1;
  RouteMsg(&BackgroundMsg);

  /* don't call AccelerometerEnable() directly use a message*/
  SetupMessage(&BackgroundMsg,AccelerometerEnableMsg,NO_MSG_OPTIONS);
  RouteMsg(&BackgroundMsg);

#endif

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

#ifdef RATE_TEST

  StartCrystalTimer(CRYSTAL_TIMER_ID3,RateTestCallback,RATE_TEST_INTERVAL_MS);

#endif

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

  for(;;)
  {
    if( pdTRUE == xQueueReceive(QueueHandles[BACKGROUND_QINDEX],
                                &BackgroundMsg, portMAX_DELAY ) )
    {
      PrintMessageType(&BackgroundMsg);

      BackgroundMessageHandler(&BackgroundMsg);

      SendToFreeQueue(&BackgroundMsg);

      CheckStackUsage(xBkgTaskHandle,"Background Task");

      CheckQueueUsage(QueueHandles[BACKGROUND_QINDEX]);

    }

  }

}