/****************************************************************************
Copyright (C) Cambridge Silicon Radio Ltd. 2004-2007
FILE NAME
headset_leds.c
DESCRIPTION
Module responsible for managing the LED outputs and the pios
configured as led outputs.
*/
#include "headset_LEDmanager.h"
#include "headset_leds.h"
#include "headset_pio.h"
#include "headset_private.h"
#include "headset_statemanager.h"
#include <charger.h>
#include <panic.h>
#include <stddef.h>
#ifdef DEBUG_LEDS
#define LED_DEBUG(x) DEBUG(x)
#else
#define LED_DEBUG(x)
#endif
#define LED_ON TRUE
#define LED_OFF FALSE
#define LEDS_STATE_START_DELAY_MS 300
/****************************************************************************
LOCAL FUNCTION PROTOTYPES
*/
/*internal message handler for the LED callback messages*/
static void LedsMessageHandler( Task task, MessageId id, Message message ) ;
/*helper functions for the message handler*/
static uint16 LedsApplyFilterToTime ( LedTaskData * pLEDTask , uint16 pTime ) ;
static LEDColour_t LedsGetPatternColour ( LedTaskData * pLEDTask , const LEDPattern_t * pPattern ) ;
/*helper functions to change the state of LED pairs depending on the pattern being played*/
static void LedsTurnOffLEDPair ( LedTaskData * pLEDTask , LEDPattern_t * pPattern, bool pUseOveride ) ;
static void LedsTurnOnLEDPair ( LedTaskData * pLEDTask , LEDPattern_t * pPattern , LEDActivity_t * pLED );
/*method to complete an event*/
static void LedsEventComplete ( LedTaskData * pLEDTask, LEDActivity_t * pPrimaryLed , LEDActivity_t * pSecondaryLed ) ;
/*method to indicate that an event has been completed*/
static void LedsSendEventComplete ( headsetEvents_t pEvent , bool pPatternCompleted ) ;
/*filter enable - check methods*/
static bool LedsIsFilterEnabled ( LedTaskData * pLEDTask , uint16 pFilter ) ;
static void LedsEnableFilter ( LedTaskData * pLEDTask , uint16 pFilter , bool pEnable) ;
static void LedsHandleOverideLED ( LedTaskData * pLEDTask , bool pOnOrOff ) ;
/*Follower LED helper functions*/
static bool LedsCheckFiltersForLEDFollower( LedTaskData * pLEDTask ) ;
static uint16 LedsGetLedFollowerRepeatTimeLeft( LedTaskData * pLEDTask , LEDPattern_t* pPattern) ;
static uint16 LedsGetFollowerPin( LedTaskData * pLEDTask ) ;
static uint16 LedsGetLedFollowerStartDelay( LedTaskData * pLEDTask ) ;
static void LedsSetEnablePin ( LedTaskData * pLEDTask , bool pOnOrOff ) ;
/****************************************************************************
FUNCTIONS
*/
/*****************************************************************************/
void LedsInit ( LedTaskData * pTask )
{
/*Set the callback handler for the task*/
pTask->task.handler = LedsMessageHandler ;
pTask->gCurrentlyIndicatingEvent = FALSE ;
/*set the tricolour leds to known values*/
pTask->gTriColLeds.TriCol_a = 0 ;
pTask->gTriColLeds.TriCol_b = 0 ;
pTask->gTriColLeds.TriCol_c = 0 ;
pTask->gFollowing = FALSE ;
/*Disable the built-in charger indications*/
ChargerSupressLed0(TRUE);
}
/*****************************************************************************/
void LedsIndicateEvent ( LedTaskData * pLEDTask , headsetEvents_t pEvent )
{
uint16 lPrimaryLED = 0;
uint16 lSecondaryLED = 0;
uint16 lEventIndex = pEvent - EVENTS_EVENT_BASE ;
/*get the event and start the display*/
lPrimaryLED = pLEDTask->gEventPatterns[lEventIndex]->LED_A;
lSecondaryLED = pLEDTask->gEventPatterns[lEventIndex]->LED_B;
LED_DEBUG(("LM : Ev LED [%x]i[%x] ", pEvent , lEventIndex )) ;
#ifdef DEBUG_LM
LMPrintPattern ( pLEDTask->gEventPatterns [lEventIndex] ) ;
#endif
/*if the PIO we want to use is currently indicating an event then do interrupt the event*/
MessageCancelAll ( &pLEDTask->task, lPrimaryLED ) ;
MessageCancelAll ( &pLEDTask->task, lSecondaryLED ) ;
/*cancel all led state indications*/
LedsIndicateNoState ( pLEDTask ) ;
/* - need to set the LEDS to a known state before starting the pattern*/
LedsTurnOffLEDPair ( pLEDTask , pLEDTask->gEventPatterns[lEventIndex] , TRUE) ;
/*now set up and start the event indication*/
LedsSetLedActivity ( &pLEDTask->gActiveLEDS[lPrimaryLED] , IT_EventIndication , lEventIndex , pLEDTask->gEventPatterns[lEventIndex]->DimTime ) ;
/*Set the Alternative LED up with the same info*/
LedsSetLedActivity ( &pLEDTask->gActiveLEDS[lSecondaryLED] , IT_EventIndication , lEventIndex , pLEDTask->gEventPatterns[lEventIndex]->DimTime ) ;
/*if we just want to set a pin as an output (numFlashes == 0) - then dont send a message*/
LED_DEBUG(("LM : NF[%x]\n" , pLEDTask->gEventPatterns [ lEventIndex ]->NumFlashes )) ;
if ( pLEDTask->gEventPatterns [ lEventIndex ]->NumFlashes == 0 )
{
/*set the pins on or off as required*/
if ( pLEDTask->gEventPatterns [ lEventIndex ]->OnTime > 0 )
{
LED_DEBUG(("LM : PIO_ON\n")) ;
LedsTurnOnLEDPair ( pLEDTask , pLEDTask->gEventPatterns [ lEventIndex ] , &pLEDTask->gActiveLEDS[lPrimaryLED] ) ;
}
else if ( pLEDTask->gEventPatterns [ lEventIndex ]->OffTime > 0 )
{
LED_DEBUG(("LM : PIO_OFF\n")) ;
LedsTurnOffLEDPair ( pLEDTask , pLEDTask->gEventPatterns [ lEventIndex ] ,TRUE) ;
/*If we are turning a pin off the revert to state indication*/
LedsEventComplete ( pLEDTask, &pLEDTask->gActiveLEDS[lPrimaryLED] , &pLEDTask->gActiveLEDS[lSecondaryLED] ) ;
}
}
else
{ /*start the pattern indication*/ /*All messages are handled via the primary LED*/
MessageSend (&pLEDTask->task , lPrimaryLED , 0 ) ;
pLEDTask->gCurrentlyIndicatingEvent = TRUE ;
}
}
/*****************************************************************************/
void LedsIndicateState ( LedTaskData * pLEDTask , headsetHfpState pState , headsetA2dpState pA2dpState )
{
uint16 led_state = pState + (HEADSET_NUM_HFP_STATES * pA2dpState);
LEDPattern_t * lPattern = pLEDTask->gStatePatterns[led_state] ;
#ifdef DEBUG_LM
LMPrintPattern( lPattern ) ;
#endif
LED_DEBUG(("LED: st[%x][%x]", pLEDTask->gActiveLEDS[lPattern->LED_A].Type , pLEDTask->gActiveLEDS[lPattern->LED_B].Type)) ;
/*only indicate state if both leds we want to use are not currently indicating an event*/
if ( ( pLEDTask->gActiveLEDS[lPattern->LED_A].Type != IT_EventIndication )
&& ( pLEDTask->gActiveLEDS[lPattern->LED_B].Type != IT_EventIndication ) )
{
LED_DEBUG(("LED: IS : OK\n")) ;
/*Find the LEDS that are set to indicate states and Cancel the messages,
-do not want to indicate more than one state at a time*/
LedsIndicateNoState ( pLEDTask ) ;
/*Set up the Active LED with the State we want to indicate*/
LedsSetLedActivity ( &pLEDTask->gActiveLEDS[lPattern->LED_A] , IT_StateIndication , led_state , lPattern->DimTime ) ;
/*Set the Alternative LED up with the same info*/
LedsSetLedActivity ( &pLEDTask->gActiveLEDS[lPattern->LED_B] , IT_StateIndication , led_state ,lPattern->DimTime) ;
/* - need to set the LEDS to a known state before starting the pattern*/
LedsTurnOffLEDPair ( pLEDTask , lPattern , TRUE ) ;
LED_DEBUG(("LED: st2[%x][%x]", pLEDTask->gActiveLEDS[lPattern->LED_A].Type , pLEDTask->gActiveLEDS[lPattern->LED_B].Type)) ;
/*Handle permanent output leds*/
if ( lPattern->NumFlashes == 0 )
{
/*set the pins on or off as required*/
if ( lPatter