Пример #1
0
/****************************************************************************
NAME    
    handleBatteryLow
    
DESCRIPTION
  	Called when the battery voltage is detected to be in Battery Low state
*/
static void handleBatteryLow( void )
{
    bool last_state = theHeadset.battery_low_state; 
    
    PM_DEBUG(("PM: Battery Low\n"));
   
    /*we only want low battery reminders if the headset is ON and not charging */
    if(stateManagerGetState() != headsetLimbo)
    {
        MessageSend(&theHeadset.task, EventLowBattery, 0); 
		#if 0
		theHeadset.battery_low_state = TRUE;    
		#endif
		PM_DEBUG(("battery_low_state = true\n"));
    }
    
    if(ChargerIsChargerConnected() || stateManagerGetState() == headsetLimbo)
    {
      /*  printf("the battery is charging or the headset is in limbo state\n");*/
        theHeadset.battery_low_state = FALSE;
	  	PM_DEBUG(("battery_low_state = false\n"));
    }

    if(!last_state || !theHeadset.battery_low_state)
    {
#ifdef ROM_LEDS          /* update state indication to indicate low batt state change */
	 	PM_DEBUG(("Low battery state\n"));
        LEDManagerIndicateState( stateManagerGetState() );
#endif     
     }

}
Пример #2
0
void VolumeSetHeadsetVolume( uint16 pNewVolume , bool pPlayTone, hfp_link_priority priority, bool set_gain, volume_direction dir ) 
{      
    bool lPlayTone = FALSE ;
    bool lOverideMute = theHeadset.features.OverideMute ;
    bool lMuteLocalVolAction = theHeadset.features.MuteLocalVolAction ;

    VOL_DEBUG(("SetVol [%x] [%d][%d][%d]\n " ,pNewVolume, theHeadset.gMuted , lOverideMute , lMuteLocalVolAction)) ;
    
	/* this should only occur if we are not muted or if we are muted but wish to overide */
    if ( (!theHeadset.gMuted ) || ( lOverideMute ) || (lMuteLocalVolAction))
    {
        /*set the local volume only*/
        if ((theHeadset.gMuted) && (!lMuteLocalVolAction))
			MessageSend( &theHeadset.task , EventMuteOff , 0 ) ;
       
        /* the tone needs to be played so set flag */
        lPlayTone = TRUE ;     
        
        /* set new volume */
        theHeadset.profile_data[PROFILE_INDEX(priority)].audio.gSMVolumeLevel = pNewVolume ; 
        
        if(set_gain)
            AudioSetVolume ( theHeadset.audioData.gVolMaps[ pNewVolume ].VolGain , theHeadset.codec_task ) ;
    }
    
    /* ensure there is a valid tone (non zero) to be played */
    if( pPlayTone && lPlayTone && theHeadset.audioData.gVolMaps[pNewVolume].Tone )
    {   /*only attempt to play the tone if it has not yet been played*/

		/*VOL_DEBUG(("VOL: VolTone[%x]\n" , (int)theHeadset.audioData.gVolMaps[pNewVolume].Tone)) ;*/

#if 1
		if(theHeadset.TTS_ASR_Playing == false)
		{
			VOL_DEBUG(("VOL: VolTone[%x]\n" , (int)theHeadset.audioData.gVolMaps[pNewVolume].Tone)) ;
			#ifdef DifferentToneForVolumeButton
			if((stateManagerGetState() == headsetActiveCallSCO || stateManagerGetState() == headsetActiveCallNoSCO) && (theHeadset.sco_sink != 0))
			{
				if(dir)
				{
					TonesPlayTone(0x42 ,theHeadset.features.QueueVolumeTones, FALSE);
				}
				else
				{
	        		TonesPlayTone(theHeadset.audioData.gVolMaps[pNewVolume].Tone ,theHeadset.features.QueueVolumeTones, FALSE);
				}
			}
			#else
			/*TonesPlayTone(theHeadset.audioData.gVolMaps[pNewVolume].Tone ,theHeadset.features.QueueVolumeTones, FALSE);*/
			#endif
		}
#endif
    }    
}
Пример #3
0
/****************************************************************************
NAME    
    sinkEnableMultipointConnectable
    
DESCRIPTION
    when in multi point mode check to see if device can be made connectable,
    this will be when only one AG is currently connected. this function will
    be called upon certain button presses which will reset the 60 second timer
    and allow a second AG to connect should the device have become non discoverable
    
RETURNS
    none
*/
void sinkEnableMultipointConnectable( void )
{    
    /* only applicable to multipoint devices and don't go connectable when taking or making
       an active call, allow connectable in streaming music state */
    if((theSink.MultipointEnable)&&(stateManagerGetState() != deviceLimbo))
    {
       /* if only one hfp instance is connected then set connectable to active */
       if(deviceManagerNumConnectedDevs() < 2)
       {
            MAIN_DEBUG(("MP Go Conn \n" ));
            
            /* make device connectable */
            sinkEnableConnectable();
         
            /* cancel any currently running timers that would disable connectable mode */
            MessageCancelAll( &theSink.task, EventSysConnectableTimeout );
            
            /* remain connectable for a further 'x' seconds to allow a second 
               AG to be connected if non-zero, otherwise stay connecatable forever */
            if(theSink.conf1->timeouts.ConnectableTimeout_s)
            {
                MessageSendLater(&theSink.task, EventSysConnectableTimeout, 0, D_SEC(theSink.conf1->timeouts.ConnectableTimeout_s));
            }
       }
       /* otherwise do nothing */
    }
}
Пример #4
0
/****************************************************************************
NAME    
    powerManagerHandleVbatLow
    
DESCRIPTION
    Called when the battery voltage is detected to be in Battery Low state
*/
static void powerManagerHandleVbatLow( void )
{
    sinkState lSinkState = stateManagerGetState ();
    bool batt_was_low = powerManagerIsVbatLow();

    PM_DEBUG(("PM: Battery Low\n"));
    if(powerManagerIsChargerConnected() || lSinkState == deviceLimbo)
    {
        theSink.battery_state = POWER_BATT_LEVEL0;
    }
    else
    {
        theSink.battery_state = POWER_BATT_LOW;  
    }

    if(!batt_was_low || !powerManagerIsVbatLow())
    {
        /* update state indication to indicate low batt state change */
#ifndef NO_LED         
        LEDManagerIndicateState( lSinkState );
#endif        
    }
    
    AudioSetPower(powerManagerGetLBIPM());
}
Пример #5
0
/****************************************************************************
NAME    
    powerManagerPowerOff
    
DESCRIPTION
    Power off due to critical battery or temperature outside operational
    limits
    
RETURNS
    void
*/
static void powerManagerPowerOff(void)
{
    if(stateManagerGetState() == deviceLimbo)
        stateManagerUpdateLimboState();
    else
        MessageSend(&theSink.task, EventUsrPowerOff, 0);
}
Пример #6
0
/****************************************************************************
DESCRIPTION
    sets the current A2dp volume
    
*/
void VolumeSetA2dp(uint16 index, uint16 oldVolume)
{               
    if(theHeadset.audioData.gVolMaps[ theHeadset.a2dp_link_data->gAvVolumeLevel[index] ].A2dpGain == VOLUME_A2DP_MUTE_GAIN)
    {                   
        /* if actual mute enabled, activate it now */
        if(theHeadset.audioData.gVolMaps[ oldVolume ].A2dpGain != VOLUME_A2DP_MUTE_GAIN)
        {
            VOL_DEBUG(("VOL: A2dp mute\n"));
            AudioSetMode(AUDIO_MODE_MUTE_SPEAKER, NULL);
        }
    }                
    else
    {
        VOL_DEBUG(("VOL: A2dp set vol [%d][%d]\n", theHeadset.a2dp_link_data->gAvVolumeLevel[index], theHeadset.audioData.gVolMaps[ theHeadset.a2dp_link_data->gAvVolumeLevel[index] ].A2dpGain - 1));
        AudioSetVolume ( theHeadset.audioData.gVolMaps[ theHeadset.a2dp_link_data->gAvVolumeLevel[index] ].A2dpGain - 1 , theHeadset.codec_task ) ;
    }
    /* set volume level in audio plugin */
    if ((theHeadset.audioData.gVolMaps[ theHeadset.a2dp_link_data->gAvVolumeLevel[index] ].A2dpGain != VOLUME_A2DP_MUTE_GAIN) && (theHeadset.audioData.gVolMaps[ oldVolume ].A2dpGain == VOLUME_A2DP_MUTE_GAIN))
    {
        /* the audio was muted but now should be un-muted as above minimum volume */   
        VOL_DEBUG(("VOL: A2dp unmute\n"));
        AudioSetMode(AUDIO_MODE_CONNECTED, NULL);
    }         
    /* play tone if applicable */
#if 1
    if(theHeadset.audioData.gVolMaps[theHeadset.a2dp_link_data->gAvVolumeLevel[index]].Tone)
    {
    	if(stateManagerGetState() == headsetA2DPStreaming)
		{
        	TonesPlayTone(theHeadset.audioData.gVolMaps[theHeadset.a2dp_link_data->gAvVolumeLevel[index]].Tone ,theHeadset.features.QueueVolumeTones, FALSE);
    	}
    }
#endif
}
Пример #7
0
/****************************************************************************
NAME    
    sinkRecallQueuedEvent
    
DESCRIPTION
    Checks to see if an event was Queued and issues it

RETURNS
    void
*/
void sinkRecallQueuedEvent ( void )
{
    /*this is currently only applicable to  LNR and voice Dial but does not care */
    if ((theSink.gEventQueuedOnConnection != (EventInvalid - EVENTS_MESSAGE_BASE)))
    {
        switch (stateManagerGetState() )
        {
            case deviceIncomingCallEstablish:
            case deviceOutgoingCallEstablish:
            case deviceActiveCallSCO:            
            case deviceActiveCallNoSCO:       
            case deviceThreeWayCallWaiting:
            case deviceThreeWayCallOnHold:
            case deviceThreeWayMulticall:
                /* Do Nothing Message Gets ignored*/
            break ;
            default:
               /* delay sending of queued message by 1 second as some phones are ignoring the AT command when
                  using native firmware as the connection time is much quicker using that firmware */             
               MessageSendLater ( &theSink.task , (theSink.gEventQueuedOnConnection + EVENTS_MESSAGE_BASE), 0 , 1500) ; 
            break;
        }
    }    
    
    /*reset the queued event*/
	sinkClearQueueudEvent(); 
}
Пример #8
0
/****************************************************************************
NAME    
    batteryNormal
    
DESCRIPTION
    Called when the battery voltage is detected to be in a Normal state
*/
static void handleBatteryNormal(power_battery_level pLevel)
{
    uint16 level = (uint16)(pLevel - POWER_BATT_LEVEL0);

    PM_DEBUG(("PM: Battery Normal,level %d\n",level));

	#ifndef BHC612	
	MessageSend(&theHeadset.task, EventOkBattery, 0);
	
    /* If charger connected send a charger gas gauge message (these don't have any functional use but can be associated with LEDs/tones) */
	if (ChargerIsChargerConnected())
	    MessageSend(&theHeadset.task, (EventChargerGasGauge0+level), 0);
    #endif
	
    /* Send notification to AG if batt level has changed */
    MessageSend(&theHeadset.task, EventGasGauge0+level, 0);    
    
#ifdef ROM_LEDS
    /* when changing from low battery state to a normal state, refresh the led state pattern
       to replace the low battery pattern should it have been shown */
    if(theHeadset.battery_low_state == TRUE)
    {
        /* kick off a check to see if there is a low battery led state configured */
	 PM_DEBUG(("Battery Normal\n"));
        LEDManagerIndicateState( stateManagerGetState() );
    }
#endif
    
    /* reset any low battery warning that may be in place */
    theHeadset.battery_low_state   = FALSE;  
    theHeadset.low_battery_flag_ag = FALSE;

}
Пример #9
0
/****************************************************************************
NAME    
    audioHandleSyncDisconnectInd
    
DESCRIPTION
    Handle HFP_AUDIO_DISCONNECT_IND.  This indicates that an incoming sychronous 
    connection has been disconnected

RETURNS
    
*/
void audioHandleSyncDisconnectInd ( const HFP_AUDIO_DISCONNECT_IND_T * pInd )
{
    Sink sink;   
    /* Get the priority of the other link */
    hfp_link_priority other = (pInd->priority == hfp_primary_link) ? hfp_secondary_link : hfp_primary_link;
    AUD_DEBUG(("AUD: Synchronous Disconnect Ind [%x]:\n",pInd->priority)) ;

    /* ensure disconnection was succesfull */
    if(pInd->status == hfp_audio_disconnect_success)
    {
        MessageSend ( &theSink.task , EventSCOLinkClose , 0 ) ;
            
        /* update sco priority */
        setScoPriorityFromHfpPriority(pInd->priority, sco_none);                    

        /* SCO has been disconnected, check for the prescence of another sco in hold state, this occurs
           when the AG has performed an audio transfer, promote the held call to active */
        if(getScoPriorityFromHfpPriority(other) == sco_held_call)
            setScoPriorityFromHfpPriority(other, sco_active_call);                    
        
        AUD_DEBUG(("AUD: Synchronous Disconnect Ind [%x]: sco_pri = %d\n",pInd->priority, HfpLinkPriorityFromAudioSink(theSink.routed_audio) )) ;
    
        /* deroute the audio */
        audioHandleRouting(audio_source_none);    

        /*change the active call state if necessary*/
        if ((stateManagerGetState() == deviceActiveCallSCO))
            stateManagerEnterActiveCallState();
    
        /* Send our link policy settings for normal role  now SCO is dropped */
        if(HfpLinkGetSlcSink(pInd->priority, &sink))
            linkPolicyUseHfpSettings(pInd->priority, sink);
    }
    
}
Пример #10
0
/****************************************************************************
NAME 
    LedsEnableFilterOverrides

DESCRIPTION
    Enable or disable filters overriding LEDs. This will not change which 
    filters are active, it will just turn off any LEDs the filters are 
    forcing on.
    
RETURNS
    void    
*/
void LedsEnableFilterOverrides(bool enable)
{
    uint16 lFilterIndex;
    /* Run through all filters */
    for (lFilterIndex = 0 ; lFilterIndex < theSink.theLEDTask->gLMNumFiltersUsed ; lFilterIndex ++ )
    {
        LEDFilter_t *lEventFilter = &(theSink.theLEDTask->gEventFilters [ lFilterIndex ]);
        /* If filter is overriding an LED turn it off */
        if (LedsIsFilterEnabled(lFilterIndex) && (lEventFilter->FilterType == OVERRIDE))
            PioSetLedPin(lEventFilter->OverideLED, (enable ? LED_ON : LED_OFF));
    }
    /* Restore state (ensures we haven't disabled any LEDs we shouldn't) */
#ifndef NO_LED     
    LEDManagerIndicateState ( stateManagerGetState () ) ;  
#endif    
}
Пример #11
0
/****************************************************************************
NAME    
    sinkCheckForAudioTransfer
    
DESCRIPTION
    checks on connection for an audio connction and performs a transfer if not present

RETURNS
    void
*/
void sinkCheckForAudioTransfer ( void )
{
    sinkState lState = stateManagerGetState() ;
    
    AUD_DEBUG(("AUD: Tx[%d] [%x]\n", lState , (int)theSink.routed_audio)) ;
    
    switch (lState)
    {
        case deviceIncomingCallEstablish :
        case deviceThreeWayCallWaiting :
        case deviceThreeWayCallOnHold :
        case deviceThreeWayMulticall :
        case deviceIncomingCallOnHold : 
        case deviceActiveCallNoSCO :
        {              
            Sink sink;            
            hfp_call_state state;  
            hfp_link_priority priority = hfp_invalid_link;
              
            /* check call state and sink of AG1 */
            if((HfpLinkGetCallState(hfp_primary_link, &state))&&(state == hfp_call_state_active)&&
               (HfpLinkGetAudioSink(hfp_primary_link, &sink))&&(!sink))
            {
                priority = hfp_primary_link;
            }
            /* or check call state and sink of AG2 */
            else if((HfpLinkGetCallState(hfp_secondary_link, &state))&&(state == hfp_call_state_active)&&
                    (HfpLinkGetAudioSink(hfp_secondary_link, &sink))&&(!sink))    
            {
                priority = hfp_secondary_link;
            }
            /* if call found with no audio */
            if (priority)
            {
                hfp_audio_params * audio_params = NULL;
                HfpAudioTransferRequest(priority, 
                                        hfp_audio_to_hfp , 
                                        theSink.HFP_supp_features.packet_types,
                                        audio_params );
            }    
        }
        break ;
        default:
        break;
    }
}
Пример #12
0
/****************************************************************************  
DESCRIPTION
    function to handle a button press - informs button manager of a change
    currently makes direct call - may want to use message handling (tasks)
*/ 
static void ButtonsButtonDetected (  ButtonsTaskData * pButtonsTask, uint32 pButtonMask  , ButtonsTime_t pTime )
{
    B_DEBUG(("B:But Det[%lx]\n", pButtonMask)) ;
    
    if( pButtonMask == 0 )
    {
        MessageCancelAll ( &pButtonsTask->task , B_REPEAT_TIMER ) ;
    }
    else
    {
        BMButtonDetected ( pButtonMask, pTime ) ;             
        
        if (stateManagerGetState() == deviceTestMode)
        {
            checkDUTKeyRelease(pButtonMask, pTime);
        }
    }
}
Пример #13
0
/****************************************************************************
NAME    
    powerManagerHandleVbat
    
DESCRIPTION
    Called when the battery voltage is detected to be in a Normal state
*/
static void powerManagerHandleVbat(voltage_reading vbat, battery_level_source source)
{
    /* Get the event associated with this battery level */
    sink_battery_setting setting = theSink.conf1->power.bat_events[vbat.level];
    sinkEvents_t event = setting.event;

    PM_DEBUG(("PM: Battery Voltage 0x%02X (%dmV)\n", vbat.level, vbat.voltage));

    displayUpdateBatteryLevel(powerManagerIsChargerConnected());
    
    /* Send indication if not charging, not in limbo state and indication enabled for this source */
    if(!powerManagerIsChargerConnected() && (stateManagerGetState() != deviceLimbo) && (setting.sources & source))
    {
        PM_DEBUG(("PM: Sending Event 0x%X\n", event));
        MessageSend(&theSink.task, event, NULL);
    }
    
    switch(event)
    {
        case EventSysBatteryCritical:
            /* Always indicate critical battery */
            powerManagerHandleVbatCritical();
            usbSetVbatDead(TRUE);
            break;

        case EventSysBatteryLow:
            powerManagerHandleVbatLow();
            usbSetVbatDead(FALSE);
            break;

        case EventSysGasGauge0 :
        case EventSysGasGauge1 :
        case EventSysGasGauge2 :
        case EventSysGasGauge3 :
            powerManagerHandleVbatNormal(event - EventSysGasGauge0);
            usbSetVbatDead(FALSE);
            break;

        default:
            break;
    }
}
Пример #14
0
/****************************************************************************
NAME    
    sinkFmRxAudioDisconnect
    
DESCRIPTION
    Disconnects the FM audio via the audio library/FM audio plugin

RETURNS
    nothing
*/   
void sinkFmRxAudioDisconnect(void)
{
    FM_DEBUG(("sinkFmRxAudioDisconnect \n"));
    
    /* ensure FM is on and FM audio currently being routed to speaker */
    if ((theSink.conf2->sink_fm_data.fmRxOn) && sinkFmAudioSinkMatch(theSink.routed_audio))
    {
        FM_DEBUG(("FM audio disconnected \n"));

        /* reset routed audio */
        theSink.routed_audio = 0;
        
        /* disconnect FM audio via audio library */
        AudioDisconnect(); 

        /* Update limbo state */
        if (stateManagerGetState() == deviceLimbo )
            stateManagerUpdateLimboState();
    }
}
Пример #15
0
/****************************************************************************
NAME 
 LedsEnableFilter

DESCRIPTION
    enable / disable a given filter ID
RETURNS
 	void
*/
static void LedsEnableFilter ( uint16 pFilter , bool pEnable)
{
    uint32 lOldMask = LED_GETACTIVEFILTERS() ;
    
    if (pEnable)
    {
        /*to set*/
        LED_SETACTIVEFILTERS((lOldMask | ( (uint32)0x1 << pFilter )));
        LED_DEBUG(("LED: EnF [%lx] [%lx] [%x]\n", lOldMask , LED_GETACTIVEFILTERS() , pFilter));
    }
    else
    {
        /*to unset*/
        LED_SETACTIVEFILTERS(lOldMask & ~(  (uint32)0x1 << pFilter ));
        LED_DEBUG(("LED: DisF [%lx] [%lx] [%x]\n", lOldMask , LED_GETACTIVEFILTERS() , pFilter));
    }
#ifndef NO_LED     
    /* Check if we should indicate state */
    if ((theSink.theLEDTask->gEventFilters[pFilter].OverideDisable) && (lOldMask != LED_GETACTIVEFILTERS()))
        LEDManagerIndicateState ( stateManagerGetState () ) ;                          
#endif    
}
Пример #16
0
/****************************************************************************
NAME    
    batteryNormal
    
DESCRIPTION
    Called when the battery voltage is detected to be in a Normal state
*/
static void powerManagerHandleVbatNormal(uint8 level)
{
#ifndef NO_LED     
    bool low_batt = powerManagerIsVbatLow();
#endif    
    PM_DEBUG(("PM: Battery Normal %d\n", level));
    MessageSend(&theSink.task, EventSysBatteryOk, 0);
    
    /* If charger connected send a charger gas gauge message (these don't have any functional use but can be associated with LEDs/tones) */
    if (powerManagerIsChargerConnected())
        MessageSend(&theSink.task, (EventSysChargerGasGauge0+level), 0);
    
    /* reset any low battery warning that may be in place */
    theSink.battery_state = POWER_BATT_LEVEL0 + level;
    csr2csrHandleAgBatteryRequestRes(level);
#ifndef NO_LED 
    /* when changing from low battery state to a normal state, refresh the led state pattern
       to replace the low battery pattern should it have been shown */
    if(low_batt) LEDManagerIndicateState(stateManagerGetState());
#endif    
    AudioSetPower(powerManagerGetLBIPM());
}
Пример #17
0
void slcContinueEstablishSLCRequest( void )
{
    SLC_DEBUG(("SLC: ContSLCReq, listId = %d\n",gSlcData.gListID)) ;

    /* is multipoint enabled ?, if so see if necessary to connect further devices, also check for 
       non multipoint and no devices, otherwise exit */
    if((!gSlcData.gSlcConnectRemote) && (deviceManagerCanConnect()) && 
#ifdef ENABLE_PARTYMODE
       (!((theSink.PartyModeEnabled)&&(theSink.features.PartyMode)))&&
#endif
       (stateManagerGetState() != deviceLimbo))
    {
        if(slcDetermineConnectAction() & AR_Rssi)
        {
            /* Connect next result*/
            inquiryConnectNext();
        }
        else
        {
            /* if there are more devices to connect to then continue */
            if(slcGetNextListID())
            {
                SLC_DEBUG(("SLC: PDL entry available for connection , listId = %d\n",gSlcData.gListID)) ;
                /* attempt to connect to next item in list */ 
                slcAttemptConnection();
            }
            /* otherwise check whether any connection attempt was successful, if not check feature
               to automatically enter pairing mode */
            else if(theSink.features.EnterPairingModeOnFailureToConnect && !stateManagerIsConnected())
            {
                SLC_DEBUG(("SLC: Failed to Connect to anything, enter pairing mode\n")) ;
                /* enter pairing mode */
                MessageSend(&theSink.task, EventUsrEnterPairing, 0);
                /* now allow role switches */
                theSink.rundata->connection_in_progress = FALSE;
            }
            /* all connection attempts now complete, allow role switching */
            else
            {
                /* now allow role switches */
                theSink.rundata->connection_in_progress = FALSE;
            }
        }
    }
    /* Need to handle this case to stop RSSI when all devs connected */
    else if(slcDetermineConnectAction() & AR_Rssi)
    {
        /* All done, stop inquiring */
        if(theSink.inquiry.action != rssi_subwoofer)
            inquiryStop();
        /* set flag to block role switch requests until all connections are complete to avoid unneccesary switching */
        theSink.rundata->connection_in_progress = FALSE;
    }
    /* connections complete, allow role switches to commence if necessary */
    else
    {
        /* set flag to block role switch requests until all connections are complete to avoid unneccesary switching */
        theSink.rundata->connection_in_progress = FALSE;
    }

    /* reset connection via remote ag instead of device flag */
    gSlcData.gSlcConnectRemote = FALSE;

    SLC_DEBUG(("SLC: StopReq\n")) ;
}       
Пример #18
0
/****************************************************************************
NAME 
 LedsCheckForFilter

DESCRIPTION
 This function checksif a filter has been configured for the given event, 
    if it has then activates / deactivates the filter 
    
    Regardless of whether a filter has been activated or not, the event is signalled as 
    completed as we have now deaklt with it (only checked for a filter if a pattern was not
    associated.

RETURNS
 void
    
*/       
void LedsCheckForFilter ( sinkEvents_t pEvent ) 
{
    uint16 lFilterIndex = 0 ;
    
    for (lFilterIndex = 0 ; lFilterIndex < theSink.theLEDTask->gLMNumFiltersUsed ; lFilterIndex ++ )
    { 
        LEDFilter_t *lEventFilter = &(theSink.theLEDTask->gEventFilters [ lFilterIndex ]);
        
        if((uint16)(lEventFilter->Event) == pEvent && lEventFilter->FilterType != DISABLED)
        {
            if (lEventFilter->FilterType != CANCEL)
            {
                /* Check filter isn't already enabled */
                if (!LedsIsFilterEnabled(lFilterIndex))
                {
                    /* Enable filter */
                    LedsEnableFilter (lFilterIndex , TRUE) ;
            
                    /* If it is an overide fLED filter and the currently playing pattern is OFF then turn on the overide led immediately*/
                    if ( lEventFilter->FilterType == OVERRIDE)
                    {                        
                        uint16 lOverideLEDIndex = lEventFilter->OverideLED ;                    
                        
                        /* this should only happen if the led in question is currently off*/
                        if ( theSink.theLEDTask->gActiveLEDS[lOverideLEDIndex].OnOrOff == LED_OFF)
                        {
                             LED_DEBUG(("LED: FilEnable Turn on[%d][%d] \n",lFilterIndex + 1 , lOverideLEDIndex  )) ;
                             PioSetLedPin ( lOverideLEDIndex , LED_ON) ;
                        }
                    }
                }
            }
            else
            {
                 uint16 lFilterToCancel = lEventFilter->FilterToCancel ;
                /*disable the according filter*/
                 if ( lFilterToCancel != 0 )
                 {
                     uint16 lFilterToCancelIndex = lFilterToCancel - 1 ;
                     LEDFilter_t *lEventFilter1  = &(theSink.theLEDTask->gEventFilters [ lFilterToCancelIndex ]);
                     uint16 lOverideLEDIndex     = lEventFilter1->OverideLED ;
                    
                     LED_DEBUG(("LED: FilCancel[%d][%d] [%d]\n",lFilterIndex + 1 , lFilterToCancel , lFilterToCancelIndex )) ;
                     
                        /*lFilter To cancel = 1-n, LedsEbnable filter requires 0-n */
                     LedsEnableFilter (lFilterToCancelIndex , FALSE ) ;
                     
                     if ( theSink.theLEDTask->gActiveLEDS[lOverideLEDIndex].OnOrOff == LED_OFF)
                     {   /*  LedsHandleOverideLED ( theSink.theLEDTask , LED_OFF) ;*/
                         if ( lEventFilter1->FilterType == OVERRIDE)
                         {
                             LED_DEBUG(("LED: FilCancel Turn off[%d][%d] [%d]\n",lFilterIndex + 1 , lFilterToCancel , lFilterToCancelIndex )) ;
	          	             PioSetLedPin ( lOverideLEDIndex, LED_OFF) ;                
                             
                             /* it is possible for the cancel filter to turn off leds used in a solid led
                                state indication such as a solid blue pairing indication, should the charger be
                                removed and then reinserted the solid blue state is turned off, this call will reset
                                the state indication and turn it back on again */
#ifndef NO_LED                              
                             LEDManagerIndicateState ( stateManagerGetState () ) ;                       
#endif
                         }    
                     }                           
                 }
                 else
                 {
                    LED_DEBUG(("LED: Fil !\n")) ;
                 }
            }
            LED_DEBUG(("LM : Filter Found[%d]A[%x] [%d]\n", lFilterIndex + 1,  pEvent , theSink.theLEDTask->gEventFilters[ lFilterIndex ].IsFilterActive )) ;
       }      
    }
}
Пример #19
0
/****************************************************************************
NAME    
    linkPolicyHandleRoleCfm
    
DESCRIPTION
    this is a function checks the returned role of the device and makes the decision of
    whether to change it or not, if it  needs changing it sends a role change reuest

RETURNS
    void
*/
void linkPolicyHandleRoleCfm(CL_DM_ROLE_CFM_T *cfm)
{
    hci_role requiredRole = hci_role_dont_care;
    
    LP_DEBUG(("RoleConfirm, sink = %x role=%s\n", (unsigned int)cfm->sink, (cfm->role == hci_role_master) ? "master" : "slave"));
   
    /* ensure role read successfully */
    if ((cfm->status == hci_success)&&(!theSink.features.DisableRoleSwitching))
    {
        
        /* when multipoint enabled connect as master, this can be switched to slave
        later on if required when only 1 ag is connected */
        if((theSink.MultipointEnable) && (linkPolicyNumberPhysicalConnections() > 1))
        {
#if defined ENABLE_PEER
            uint16 priority;
            
            if (getA2dpIndexFromSink(cfm->sink, &priority) && (theSink.a2dp_link_data->peer_device[priority] == remote_device_peer))
            {
                if (A2dpMediaGetRole(theSink.a2dp_link_data->device_id[priority], theSink.a2dp_link_data->stream_id[priority]) == a2dp_source)
                {
                    LP_DEBUG(("LP: Multipoint: Peer, require Master role\n")) ;
                    requiredRole = hci_role_master;
                }
                else
                {
                    LP_DEBUG(("LP: Multipoint: Peer, require Slave role\n")) ;
                    requiredRole = hci_role_slave;
                }
            }
            else
#endif
            {
#if defined ENABLE_PEER && defined PEER_SCATTERNET_DEBUG   /* Scatternet debugging only */
                if (getA2dpIndexFromSink(cfm->sink, &priority) && theSink.a2dp_link_data->invert_ag_role[priority])
                {
                    LP_DEBUG(("LP: Multipoint: Non-peer, require Slave role (inverted)\n")) ;
                    requiredRole = hci_role_slave;
                }
                else
#endif
                {
                    LP_DEBUG(("LP: Multipoint: Non-peer, require Master role\n")) ;
                    requiredRole = hci_role_master;
                }
            }
        }
#ifdef ENABLE_SUBWOOFER
        /* when a sub woofer is in use the sink app needs to be master of all links
           to maintain stable connections */
        else if((cfm->status == hci_success)&&(SwatGetSignallingSink(theSink.rundata->subwoofer.dev_id)))
        {
            LP_DEBUG(("LP: Subwoofer, require Master role\n")) ;
            requiredRole = hci_role_master;
        }        
#endif        
        /* non multipoint case, device needs to be slave */
        else
        {
            /* Set required role to slave as only one AG connected */
            if((theSink.user_power_table)&&(theSink.user_power_table->normalEntries))
            {   /* if user supplied role request then use that */
                LP_DEBUG(("LP: Singlepoint, require Master role\n")) ;
                requiredRole = theSink.user_power_table->normalRole;
            }
            else
            {   /* otherwise default to slave */
                LP_DEBUG(("LP: Singlepoint, require Slave role\n")) ;
                requiredRole = hci_role_slave;
            }
        }
    }
    /* check for failure of role switch due to AG having a sco open, if this is the case then
    reschedule the role switch until it is successfull or fails completely */
    else if((cfm->status == hci_error_role_change_not_allowed)&&(!theSink.features.DisableRoleSwitching))
    {
        LP_DEBUG(("LP: hci_error_role_change_not_allowed on sink = %x\n",(uint16)cfm->sink));    
    }
    /* automatic role switching is disabled, use the hfp_power_table pskey role requirements
       instead */
    else if(cfm->status == hci_success)
    {
        LP_DEBUG(("LP: Bypass Automatic role sw, use hfp_power_table role requirements\n")) ;

        /* check for the prescence of a user configured role requirement */
        if(theSink.user_power_table)
        {
            /* determine device state, if stream a2dp check for power table entry and use that role
               if available */
            if((stateManagerGetState() == deviceA2DPStreaming)&&(theSink.user_power_table->A2DPStreamEntries))
            {
                LP_DEBUG(("LP: Bypass: use A2dp role\n")) ;
                requiredRole = theSink.user_power_table->A2DPStreamRole;
            }
            /* or if in call and sco is present check for sco power table entry and use role from that */
            else if((stateManagerGetState() > deviceConnected)&&(theSink.routed_audio)&&(theSink.user_power_table->SCOEntries))
            {
                LP_DEBUG(("LP: Bypass: use SCO role\n")) ;
                requiredRole = theSink.user_power_table->SCORole;
            }
            /* or default to normal role power table entry and use role from that */
            else if(theSink.user_power_table->normalEntries)
            {                    
                LP_DEBUG(("LP: Bypass: use Normal role\n")) ;
                requiredRole = theSink.user_power_table->normalRole;
            }
            /* if no suitable power table entries available then default to slave role */
            else
            {
                LP_DEBUG(("LP: Bypass: use default slave role\n")) ;
                requiredRole = hci_role_slave;
            }
        }
    }        
    
    /* Request a role change if required */
    if (requiredRole != hci_role_dont_care) 
    {
        if (cfm->role != requiredRole)
        {
            LP_DEBUG(("LP: Set dev as %s %x\n",(requiredRole == hci_role_master) ? "master" : "slave", (unsigned int)cfm->sink)) ;

            /* Set role for this connection */
            ConnectionSetRole(&theSink.task, cfm->sink, requiredRole);             
        }
        else
        {
            LP_DEBUG(("LP: role not set, already %s\n",(requiredRole == hci_role_master) ? "master" : "slave")) ;
        }
    }
    else
    {
        LP_DEBUG(("LP: role change not required\n")) ;
    }
}
Пример #20
0
/****************************************************************************
NAME    
    audioHandleSyncConnectCfm
    
DESCRIPTION
    Handle HFP_AUDIO_CONNECT_CFM.  This indicates that an incoming sychronous 
    connection has been established

RETURNS
    
*/
void audioHandleSyncConnectCfm ( const HFP_AUDIO_CONNECT_CFM_T * pCfm )
{       
    uint8 index = PROFILE_INDEX(pCfm->priority);
    hfp_call_state CallState;
    
    /* Get the priority of the other link */
    hfp_link_priority other = (pCfm->priority == hfp_primary_link) ? hfp_secondary_link : hfp_primary_link;
    
    
    AUD_DEBUG(("Synchronous Connect Cfm from [%x]:\n", (uint16)pCfm->priority)) ;
 
    /* if successful */
    if ( pCfm->status == hfp_success)
    {      
        Sink sink;
        
        /* obtain sink for this audio connection */
        if(HfpLinkGetSlcSink(pCfm->priority, &sink))
        {
            /* Send our link policy settings for active SCO role */
            linkPolicyUseHfpSettings(pCfm->priority, sink);
        }

        /* store in individual hfp struct as it may be necessary to disconnect and reconnect
           audio on a per hfp basis for multipoint multiparty calling */
        theSink.profile_data[index].audio.tx_bandwidth= pCfm->tx_bandwidth;
        theSink.profile_data[index].audio.link_type= pCfm->link_type;           
        theSink.profile_data[index].audio.codec_selected = pCfm->codec;           
                
        /* Send an event to indicate that a SCO has been opened */           
        /* this indicates that an audio connection has been successfully created to the AG*/
        MessageSend ( &theSink.task , EventSCOLinkOpen , 0 ) ;

        /* update the audio priority state 
           is this sco a streaming audio sco?, check call state for this ag */
        if(HfpLinkGetCallState(pCfm->priority, &CallState))
        {          
            /* determine sco priority based on call status */
            switch(CallState)
            {
                /* no call so this is a steaming audio connection */
                case hfp_call_state_idle:
                    setScoPriorityFromHfpPriority(pCfm->priority, sco_streaming_audio);
                break;
                
                /* incoming call so this is an inband ring sco */
                case hfp_call_state_incoming:
                case hfp_call_state_incoming_held:
                case hfp_call_state_twc_incoming:
                    setScoPriorityFromHfpPriority(pCfm->priority, sco_inband_ring);                    
                break;
   
                /* active call states so this sco has highest priority */
                case hfp_call_state_active:
                case hfp_call_state_twc_outgoing:
                    /* this audio connection may have been the result of the an audio transfer
                       from the AG and there is already an active call on the other AG, check for this
                       and make this new audio connection held leaving the other routed audio connection 
                       intact */
                    if(getScoPriorityFromHfpPriority(other)==sco_active_call)                    
                        setScoPriorityFromHfpPriority(pCfm->priority, sco_held_call);                    
                    else
                        setScoPriorityFromHfpPriority(pCfm->priority, sco_active_call);                    
                break;
                
                /* an outgoing call sco has highest priority, if there is a call on other AG
                   it needs to be put on hold whilst this outgoing call is made */
                case hfp_call_state_outgoing:
                    /* does other AG have active call on it?, if so hold the audio */
                    if(getScoPriorityFromHfpPriority(other)==sco_active_call)
                        setScoPriorityFromHfpPriority(other, sco_held_call);
                    /* make the outgoing call audio the one that gets routed */
                    setScoPriorityFromHfpPriority(pCfm->priority, sco_active_call);
                break;

                /* this call is held so the sco is put to on hold priority which is lower than
                   active call but higher than streaming */
                case hfp_call_state_held_active:
                case hfp_call_state_held_remaining:
                    if(theSink.routed_audio)                    
                        setScoPriorityFromHfpPriority(pCfm->priority, sco_held_call);                    
                break;
   
                /* non covered states treat as highest priority sco connection */
                default:
                    setScoPriorityFromHfpPriority(pCfm->priority, sco_active_call);                    
                break;
            }
        }
        
        /* route the appropriate audio connection */
        audioHandleRouting(audio_source_none);

        /*change the active call state if necessary*/
        if ((stateManagerGetState() == deviceActiveCallNoSCO) )
        {
            stateManagerEnterActiveCallState();
        }
                       
#ifdef DEBUG_AUDIO
        switch (pCfm->link_type)
        {
            case (sync_link_unknown):
                AUD_DEBUG(("AUD: Link = ?\n")) ;
            break ;
            case (sync_link_sco) :
                AUD_DEBUG(("AUD: Link = SCO\n")) ;
            break;
            case sync_link_esco:
                AUD_DEBUG(("AUD: Link = eSCO\n")) ;
            break ;    
        }
#endif        

    }
    else
    {
        AUD_DEBUG(("Synchronous Connect Cfm: FAILED\n")) ;       
    }
    AUD_DEBUG(("AUD : Sco->\n")) ;
}
Пример #21
0
/****************************************************************************
DESCRIPTION
    function to detect level changes of buttons / multiple buttons, both 
    PIO and capsense 
*/ 
static void ButtonsLevelDetect ( const uint32 pInput , ButtonsTaskData * pButtonsTask ) 
{
    uint32 lNewInput = (uint32) (pInput & (pButtonsTask->gPerformInputLevelCheck)) ;
    uint32 lOldInput = (uint32) (pButtonsTask->gBOldInputState & pButtonsTask->gPerformInputLevelCheck);

    B_DEBUG(("But Lev Det|:NewInput[%lx] OldInput[%lx]\n", lNewInput, pButtonsTask->gBOldInputState )) ;
    
    if ( ButtonsWasButtonPressed(lOldInput, lNewInput )  )
    {
        /* check whether device needs to be made connectable as a result of a button press
           on a multipoint device */
        if(theSink.features.GoConnectableButtonPress)
            sinkEnableMultipointConnectable();

        /*cancel all previously timed messages*/   
        MessageCancelAll ( &pButtonsTask->task , B_INTERNAL_TIMER ) ;
        MessageCancelAll ( &pButtonsTask->task , B_REPEAT_TIMER ) ;
        
        /* send new timed messages*/
        MessageSendLater ( &pButtonsTask->task , B_INTERNAL_TIMER , 0 ,  pButtonsTask->button_config->long_press_time ) ; 
        MessageSendLater ( &pButtonsTask->task , B_REPEAT_TIMER   , 0 ,  pButtonsTask->button_config->repeat_time ) ;   
        
        /*having restrted the timers, reset the time*/
        pButtonsTask->gBTime = B_SHORT ;      
        
        if (stateManagerGetState() == deviceTestMode)
        {
            checkDUTKeyPress(lNewInput);
        }
    }
    /*button was released or was masked out, check to make sure there is an input bit change as vreg enable
      can generate an addition MSG without any input's changing state */
    else if(lOldInput!= lNewInput )              
    {   
        /*it was only a released if there was a button actually pressed last time around - 
          buttons we have masked out still end up here but no state changes are made  */       
        if ( lOldInput != 0 )
        {
             /*if we have had a double press in the required time 
                 and the button pressed was the same as this one*/
             if (  (pButtonsTask->gBTapCount ) && (lOldInput == pButtonsTask->gBMultipleState ) )
             {
                /* button has been released, increment multiple press counter */
                 pButtonsTask->gBTapCount++;
                 
                 B_DEBUG(("TapCount: [%lx][%lx][%x]\n", lOldInput , pButtonsTask->gBMultipleState , pButtonsTask->gBTapCount  )) ;

                 /* if the multiple press count is 2, set the time as a double, this will be used
                    if no further presses are detected before the multiple press timeout occurs */
                 if(pButtonsTask->gBTapCount == DOUBLE_PRESS)
                    pButtonsTask->gBTime = B_DOUBLE ;
                 /* if the multiple press count is 3, process immediately as a triple press and cancel the 
                    multiple press timer */
                 else if(pButtonsTask->gBTapCount == TRIPLE_PRESS)
                 {
                    pButtonsTask->gBTime = B_TRIPLE ;
                    /* indicate a triple press has been detected */
                    ButtonsButtonDetected ( pButtonsTask , lOldInput , B_TRIPLE  ); 
                    /* reset current state and multiple press counter */                    
                    pButtonsTask->gBMultipleState = 0x0000 ;
                    pButtonsTask->gBTapCount = 0;
                    MessageCancelAll ( &pButtonsTask->task , B_MULTIPLE_TIMER ) ;           
                 }
             }

             /*only send a message if it was a short one - long / v long /double handled elsewhere*/
             if ( (pButtonsTask->gBTime == B_SHORT ) )
             {
                 ButtonsButtonDetected ( pButtonsTask , lOldInput , B_SHORT  ); 
                 
                 /*store the double state*/
                 pButtonsTask->gBMultipleState = lOldInput ;
                 pButtonsTask->gBTapCount++;

                    /*start the double timer - only applicable to a short press*/
                 MessageSendLater ( &pButtonsTask->task , B_MULTIPLE_TIMER , 0 ,pButtonsTask->button_config->double_press_time ) ;
             }  
             else if ( (pButtonsTask->gBTime == B_LONG) )
             {
                 ButtonsButtonDetected ( pButtonsTask , lOldInput , B_LONG_RELEASE  );                  
             }
             else if ( (pButtonsTask->gBTime == B_VERY_LONG) )
             {
                 ButtonsButtonDetected ( pButtonsTask , lOldInput , B_VERY_LONG_RELEASE  ); 
             }
             else if ( (pButtonsTask->gBTime == B_VERY_VERY_LONG) )
             {
                 ButtonsButtonDetected ( pButtonsTask , lOldInput , B_VERY_VERY_LONG_RELEASE  ); 
             }
             
             if (pButtonsTask->gBTime != B_INVALID)
             {
                MessageCancelAll ( &pButtonsTask->task , B_INTERNAL_TIMER) ;
                MessageCancelAll ( &pButtonsTask->task , B_REPEAT_TIMER ) ; 
             }    
             
             /*removing this allows all releases to generate combination presses is this right?*/
             if ( !lNewInput )
             {
                 pButtonsTask->gBTime = B_INVALID ;      
             } 
         }     
    }
}
Пример #22
0
/****************************************************************************
NAME    
    sinkInitComplete
    
DESCRIPTION
    Sink device initialisation has completed. 

RETURNS
    void
*/
void sinkInitComplete( const HFP_INIT_CFM_T *cfm )
{
    uint8 i;
    /* Make sure the profile instance initialisation succeeded. */
    if (cfm->status == hfp_init_success)
    {
        /* initialise connection status for this instance */            
        for(i=0;i<2;i++)
        {
            theSink.profile_data[i].status.list_id = INVALID_LIST_ID;
            theSink.a2dp_link_data->list_id[i] = INVALID_LIST_ID;
        }                
        
        /* Disable SDP security */
        ConnectionSmSetSecurityLevel(protocol_l2cap,1,ssp_secl4_l0,TRUE,FALSE,FALSE);
        
        /* WAE - no ACL, Debug keys - off, Legacy pair key missing - on */
        ConnectionSmSecModeConfig(&theSink.task, cl_sm_wae_acl_none, FALSE, TRUE);
        
        /* Require MITM on the MUX (incomming and outgoing)*/
        if(theSink.features.ManInTheMiddle)
        {
            ConnectionSmSetSecurityLevel(0,3,ssp_secl4_l3,TRUE,TRUE,FALSE);
        }          
            
        RegisterDeviceIdServiceRecord();

#ifdef ENABLE_PEER
        RegisterPeerDeviceServiceRecord();
        peerInitPeerStatus();
#endif
        
        /* Initialise Inquiry Data to NULL */
        theSink.inquiry.results = NULL;     
        
#ifdef ENABLE_AVRCP     
        /* initialise the AVRCP library */    
        sinkAvrcpInit();       
#endif

#ifdef ENABLE_SUBWOOFER
        /* Initialise the swat the library - Use library default service record - Library does not auto handles messages */
        if ( (theSink.rundata->subwoofer.esco_params.tx_bandwidth == 0) &&
             (theSink.rundata->subwoofer.esco_params.rx_bandwidth == 0) &&
             (theSink.rundata->subwoofer.esco_params.max_latency == 0) )
        {
            /* Use library default eSCO parameters */
            SwatInit(&theSink.task, SW_MAX_REMOTE_DEVICES, swat_role_source, FALSE, 0, 0, NULL);
        }
        else
        {
            /* Use custom eSCO parameters from configuration data */
            SwatInit(&theSink.task, SW_MAX_REMOTE_DEVICES, swat_role_source, FALSE, 0, 0, &theSink.rundata->subwoofer.esco_params);
        }
#endif

        /* No audio sources are gated at startup */
        theSink.gated_audio = 0;
        
        /*if we receive the init message in the correct state*/    
        if ( stateManagerGetState() == deviceLimbo )
        {                                           
#ifdef ENABLE_PBAP                      
            /* If hfp has been initialised successfully, start initialising PBAP */                 
            INIT_DEBUG(("INIT: PBAP Init start\n"));                     
            initPbap();
#else
            /*init the configurable parameters*/
            InitUserFeatures();                   
#endif        
        }

        /* try to get a power table entry from ps if one exists after having read the user features as
           A2DP enable state is used to determine size of power table entry */
        SetupPowerTable();
        
        
#ifdef ENABLE_MAPC
        /* if the map feature is enabled, start the map notification service at initialisation time */
        initMap();       
#endif        

        /* disable automatic mic bias control as this is handled by the audio plugins */
        AudioPluginSetMicPio(theSink.conf1->PIOIO.digital.mic_a, FALSE);
        AudioPluginSetMicPio(theSink.conf1->PIOIO.digital.mic_b, FALSE);

    }
    else
        /* If the profile initialisation has failed then things are bad so panic. */
        Panic();
    

    /* initialisation is complete */    
    theSink.SinkInitialising = FALSE;

}
Пример #23
0
/****************************************************************************
NAME 
 TonesPlayEvent

DESCRIPTION
 function to indaicate an event by playing its associated tone uses underlying
    tones playback

RETURNS
 void
    
*/
void TonesPlayEvent ( sinkEvents_t pEvent )
{    
    uint16 lEvent = pEvent;
	int i = 0 ;
	
    /* Don't play tone for Mute Toggle, this event is auto-converted to either EventUsrMuteOn or EventUsrMuteOff */
    if (pEvent == EventUsrMuteToggle)
        return;
    
#ifdef ENABLE_SOUNDBAR
	/* In Limbo for sound bar build, playing tones may cause panic if I2S amplifier is powered down by PIO */
    if(stateManagerGetState() == deviceLimbo)
    {
        /* If sound bar I2S amplifier shut down is managed by PIO, first check the logic state of amplifier power pin */
        if((theSink.conf2->audio_routing_data.PluginFeatures.audio_output_type == OUTPUT_INTERFACE_TYPE_I2S)
            &&(theSink.features.AmplifierShutDownByPIO))
        {
            /* Check configuration for AMP pio drive */
            if(theSink.conf1->PIOIO.pio_outputs.PowerOnPIO != NO_PIO)
            {
				/* Do not attempt to play tones through I2S if amplifier is shut down already,
				otherwise, I2C comms will fail and cause panic */
                if(theSink.audioAmpPowerPin != TRUE)
                
                    return;
            }
        }
    }
#endif
    
    /* ensure sink is not in muted state or trying to play the mute reminder */
    if((theSink.sink_enable_present != TRUE)||(pEvent == EventSysMuteReminder)||(pEvent == EventUsrMuteOn))
    {
        /* If Audio Prompts are disabled go straight to tones. Otherwise if Audio Prompt is assigned to this 
           event tone playback would be skipped.*/
        if(theSink.audio_prompts_enabled)
        { 
            /* If there's a valid Audio Prompt event to play don't play any tones */
            if(AudioPromptPlayEvent( pEvent ))
                return;
        }
    
        /* scan available tones list, list end is signified by NOT_DEFINED */
     while ( theSink.conf2->gEventTones [i].tone != TONE_NOT_DEFINED )
     {
            /* if an event matche is found then play tone */
      if (theSink.conf2->gEventTones [i].event == lEvent )
      {
                /* turn on audio amp */
                PioSetPio ( theSink.conf1->PIOIO.pio_outputs.DeviceAudioActivePIO , pio_drive, TRUE) ;
                /* start check to turn amp off again if required */ 
                MessageSendLater(&theSink.task , EventSysCheckAudioAmpDrive, 0, 1000);    
    
       /* check event as tone queueing not allowed on mute and ring tones */					   
       switch(pEvent)
                {
                    case EventSysMuteReminder:
                    case EventSysRingtone1:
                    case EventSysRingtone2:
                    
             /* check whether to play mute reminder tone at default volume level, never queue mute reminders to 
                   protect against the case that the tone is longer than the mute reminder timer */
                        TonesPlayTone (theSink.conf2->gEventTones [ i ].tone ,FALSE, (theSink.features.MuteToneFixedVolume)) ;			
                        break;
                       
                    /* for all other events use the QueueEventTones feature bit setting */
                    default:
                        
            /* play tone */
                     TonesPlayTone (theSink.conf2->gEventTones [ i ].tone ,theSink.features.QueueEventTones, FALSE ) ;			
                        break;    
                }
            }
      i++ ;
     }
   }
} 
Пример #24
0
/****************************************************************************
NAME    
    sinkHandleSlcConnectCfm
    
DESCRIPTION
    Confirmation that the SLC has been established (or not).

RETURNS
    void
*/
bool sinkHandleSlcConnectCfm( const HFP_SLC_CONNECT_CFM_T *cfm )
{
    sink_attributes attributes;
    bool lResult = FALSE;
    
#ifdef ENABLE_PEER    
    inquiry_result_t* connecting_device = inquiryGetConnectingDevice();
#endif
    
    deviceManagerGetDefaultAttributes(&attributes, FALSE);
    (void)deviceManagerGetAttributes(&attributes, &cfm->bd_addr);
    
    /* cancel any link loss reminders */        
    MessageCancelAll(&theSink.task , EventSysLinkLoss );

    /* Check the status of the SLC attempt */
    if (cfm->status == hfp_connect_success)
    {
        SLC_DEBUG(("SLC: ConnCfm - Success\n")) ;
        lResult = TRUE ;

        /* update the profile volume level */
        theSink.profile_data[PROFILE_INDEX(cfm->priority)].audio.gSMVolumeLevel = attributes.hfp.volume;     
        /* Handle new connection setup */
        slcConnectionComplete(cfm->priority, cfm->sink, (bdaddr *)&cfm->bd_addr);
        /* Handle common setup for new SLC/link loss */
        slcConnectionSetup(cfm->priority, cfm->sink, (bdaddr *)&cfm->bd_addr);
        /* Record the position of the device in the PDL - prevents reconnection later */
        theSink.profile_data[PROFILE_INDEX(cfm->priority)].status.list_id = deviceManagerSetPriority((bdaddr *)&cfm->bd_addr);
        
#ifdef ENABLE_PEER
        /* If RSSI pairing, check inquiry results for A2DP support */
        if (theSink.inquiry.action == rssi_pairing)
        {
            if ((connecting_device != NULL) && BdaddrIsSame(&connecting_device->bd_addr, &cfm->bd_addr) && (connecting_device->remote_profiles & profile_a2dp))
            {
                attributes.profiles |= sink_a2dp;
            }
        }
#endif
        
        /* Make sure we store this device */
        attributes.profiles |= sink_hfp;
        deviceManagerStoreAttributes(&attributes, &cfm->bd_addr);
                
        /* if rssi pairing check to see if need to cancel rssi pairing or not */           
        if(theSink.inquiry.action == rssi_pairing)
        {   
            /* if rssi pairing has completed and the device being connected currently doesn't support A2DP, then stop it progressing further */            
            if(!((theSink.features.PairIfPDLLessThan) && ( ConnectionTrustedDeviceListSize() < theSink.features.PairIfPDLLessThan )))
            {
#ifdef ENABLE_PEER                
                if(!((connecting_device != NULL) && BdaddrIsSame(&connecting_device->bd_addr, &cfm->bd_addr) && (connecting_device->remote_profiles & profile_a2dp)))
#endif
                {
                    inquiryStop();
                }
            }
        }

        /* Disable A2dp link loss management if connected on remote device */
        if( theSink.a2dp_link_data && (theSink.a2dp_link_data->connected[a2dp_primary]) && BdaddrIsSame(&cfm->bd_addr, &theSink.a2dp_link_data->bd_addr[a2dp_primary]) )
        {
            A2dpDeviceManageLinkloss(theSink.a2dp_link_data->device_id[a2dp_primary], FALSE);
        }
        else if( theSink.a2dp_link_data && (theSink.a2dp_link_data->connected[a2dp_secondary]) && BdaddrIsSame(&cfm->bd_addr, &theSink.a2dp_link_data->bd_addr[a2dp_secondary]) )
        {
            A2dpDeviceManageLinkloss(theSink.a2dp_link_data->device_id[a2dp_secondary], FALSE);
        }

        /* Auto answer call if ringing - only answer the incoming call if its 
           on the connecting AG */
        if ( (theSink.features.AutoAnswerOnConnect) && (HfpLinkPriorityFromCallState(hfp_call_state_incoming) == cfm->priority) && (stateManagerGetState() < deviceActiveCallSCO) )
        {
            MessageSend (&theSink.task , EventUsrAnswer , 0 ) ;
            SLC_DEBUG(("SLC: AutoAnswer triggered\n")) ;
        }
    }
    else
    {
        SLC_DEBUG(("SLC: ConnCfm - Fail\n")) ;
        
        /* a connection timeout will arrive here, need to report fail for multipoint
           connections also such that a link loss retry will be performed */
        if(!stateManagerIsConnected() || theSink.MultipointEnable)
        {
            /* Update local state to reflect this */
            slcConnectFail();
        }
    }
 
    /* if using multipoint and both devices are connected disable connectable */
    if((theSink.MultipointEnable) && (deviceManagerNumConnectedDevs() == MAX_MULTIPOINT_CONNECTIONS))
    {
        SLC_DEBUG(("SLC: disable Conn \n" ));
        MessageCancelAll(&theSink.task, EventSysConnectableTimeout);

#ifdef ENABLE_SUBWOOFER     
        if(SwatGetSignallingSink(theSink.rundata->subwoofer.dev_id))
        {
           sinkDisableConnectable();            
        }        
#else
        sinkDisableConnectable();            
#endif        
    }
    
    SLC_DEBUG(("SLC: Connect A2DP? En=%d att=%d\n",theSink.features.EnableA2dpStreaming,attributes.profiles)) ;
    
    /* if the AG supports A2DP profile attempt to connect to it if auto reconnect is enabled */
    if ((theSink.features.EnableA2dpStreaming) && 
         ((!cfm->priority)||(cfm->status == hfp_connect_success) || (cfm->status == hfp_connect_sdp_fail) || (cfm->status == hfp_connect_rejected)) &&
         ((slcDetermineConnectAction() & AR_Rssi)||(attributes.profiles & sink_a2dp)) &&                         
         ((slcDetermineConnectAction() & AR_Rssi)||(stateManagerGetState()!=deviceConnDiscoverable)))                          
    {
        SLC_DEBUG(("SLC: Connecting A2DP Remote %x\n",gSlcData.gSlcConnectRemote)) ;
        /* attempt connection to device supporting A2DP */
        theSink.a2dp_link_data->remote_connection = gSlcData.gSlcConnectRemote;
        A2dpSignallingConnectRequest((bdaddr *)&cfm->bd_addr);
        MessageCancelFirst(&theSink.task, EventSysContinueSlcConnectRequest);
        /* if rssi pairing check to see if need to cancel rssi pairing or not */           
        if(theSink.inquiry.action == rssi_pairing)
        {
            /* if rssi pairing has completed then stop it progressing further */            
            if(!((theSink.features.PairIfPDLLessThan)&&( ConnectionTrustedDeviceListSize() < theSink.features.PairIfPDLLessThan )))
            {
#ifdef ENABLE_PEER                
                if(!((connecting_device != NULL) && BdaddrIsSame(&connecting_device->bd_addr, &cfm->bd_addr) && (connecting_device->remote_profiles & profile_a2dp)))
#endif                   
                {
                    inquiryStop();
                }
            }
        }
    }
    else
    {
        /* reset connection via remote ag instead of device flag */
        gSlcData.gSlcConnectRemote = FALSE;
    }

#ifdef ENABLE_MAPC
    mapcMasConnectRequest((bdaddr *)&cfm->bd_addr);    
#endif
    
    return lResult ;
}
Пример #25
0
/****************************************************************************
NAME    
    handleBatteryLevelInd
    
DESCRIPTION
    Called when the battery voltage is detected to be in a Normal state
*/
static void handleBatteryLevelInd(power_battery_level pLevel)
{
    /* based on the pLevel and send different messages */
    switch(pLevel)
    {
        case POWER_BATT_CRITICAL:
            PM_DEBUG(("PM: POWER_BATTERY_SHUTDOWN\n"));
            if ( (!ChargerIsChargerConnected()) && stateManagerGetState() != headsetLimbo )
	        {
    	        MessageSend(&theHeadset.task, EventLowBattery, 0); 
		        MessageSend(&theHeadset.task, EventPowerOff, 0);
	        }
            /* reset any low battery warning that may be in place */
            theHeadset.battery_low_state   = FALSE;  
            theHeadset.low_battery_flag_ag = FALSE;
        break;
        case POWER_BATT_LOW:
#ifdef BHC612
		if(theHeadset.batt_level != POWER_BATT_LOW)
		{
			theHeadset.batt_level = POWER_BATT_LOW;
			/*MessageSendLater(&theHeadset.task, EventBatteryLevelRequest, 0,100);*/ 
			PM_DEBUG(("batt_level = low\n"));
		}
#endif			
            handleBatteryLow();
        break;
        case POWER_BATT_LEVEL0:
#ifdef BHC612
		if(theHeadset.batt_level != POWER_BATT_LEVEL0)
		{
			theHeadset.batt_level = POWER_BATT_LEVEL0;
			/*MessageSendLater(&theHeadset.task, EventBatteryLevelRequest, 0,100);*/ 
			PM_DEBUG(("batt_level = 0\n"));
		}
#endif
		handleBatteryNormal(pLevel);
		break;
	    case POWER_BATT_LEVEL1:
#ifdef BHC612
		if(theHeadset.batt_level != POWER_BATT_LEVEL1)
		{
			theHeadset.batt_level = POWER_BATT_LEVEL1;
			/*MessageSendLater(&theHeadset.task, EventBatteryLevelRequest, 0,100); */
			PM_DEBUG(("batt_level = 1\n"));
		}
#endif
		handleBatteryNormal(pLevel);
		break;			
	    case POWER_BATT_LEVEL2:
#ifdef BHC612
		if(theHeadset.batt_level != POWER_BATT_LEVEL2)
		{
			theHeadset.batt_level = POWER_BATT_LEVEL2;
			/*MessageSendLater(&theHeadset.task, EventBatteryLevelRequest, 0,100); */
			PM_DEBUG(("batt_level = 2\n"));
		}
#endif
		handleBatteryNormal(pLevel);
		break;						
	    case POWER_BATT_LEVEL3:
#ifdef BHC612
		if(theHeadset.batt_level != POWER_BATT_LEVEL3)
		{
			theHeadset.batt_level = POWER_BATT_LEVEL3;
			/*MessageSendLater(&theHeadset.task, EventBatteryLevelRequest, 0,100); */
			PM_DEBUG(("batt_level = 3\n"));
		}
#endif
		handleBatteryNormal(pLevel);			
        	break;
        default :
            PM_DEBUG(("PM: Unhandled Battery Level[%x]\n", pLevel));
        break ;           
    }
    
    /* notify the audio plugin of the new power state, 
       if the charger is connected this is fixed at max level */
    AudioSetPower(LBIPMPowerLevel());
}
Пример #26
0
/****************************************************************************
NAME    
    sinkHandleSlcDisconnectInd
    
DESCRIPTION
    Indication that the SLC has been released.

RETURNS
    void
*/
void sinkHandleSlcDisconnectInd( const HFP_SLC_DISCONNECT_IND_T *ind )
{	    
    conn_mask mask = deviceManagerProfilesConnected(&ind->bd_addr);

    SLC_DEBUG(("SLC: slc DiscInd for index %d, status = %d\n",ind->priority, ind->status)) ;     
        
    if(ind->status == hfp_disconnect_success || ind->status == hfp_disconnect_link_loss || ind->status == hfp_disconnect_abnormally)
    {
        /* store volume info */
        deviceManagerUpdateAttributes(&ind->bd_addr, sink_hfp, ind->priority, 0); 

        /* Sends the indication to the device manager to send an event out if a device has disconnected*/
        deviceManagerDeviceDisconnectedInd(&ind->bd_addr);
	
        /*if the device is off then this is disconnect as part of the power off cycle - dont re-enable connectable*/	
    	if ( stateManagerGetState() != deviceLimbo)
        {
            /* Enable A2dp link loss management if connected on remote device */
            if( theSink.a2dp_link_data && (theSink.a2dp_link_data->connected[a2dp_primary]) && BdaddrIsSame(&ind->bd_addr, &theSink.a2dp_link_data->bd_addr[a2dp_primary]) )
            {
                A2dpDeviceManageLinkloss(theSink.a2dp_link_data->device_id[a2dp_primary], TRUE);
            }
            else if( theSink.a2dp_link_data && (theSink.a2dp_link_data->connected[a2dp_secondary]) && BdaddrIsSame(&ind->bd_addr, &theSink.a2dp_link_data->bd_addr[a2dp_secondary]) )
            {
                A2dpDeviceManageLinkloss(theSink.a2dp_link_data->device_id[a2dp_secondary], TRUE);
            }

            /* Kick role checking now a device has disconnected */
            linkPolicyCheckRoles();

            /* at least one device disconnected, re-enable connectable for another 60 seconds */
            sinkEnableMultipointConnectable();
        }
    
        /*a disconnect in active call state is a call transfer*/
        if ( (stateManagerGetState() == deviceActiveCallSCO) || 
             (stateManagerGetState() == deviceActiveCallNoSCO) )
        {
		    gSlcData.gCallTransferInProgress = TRUE ;           
        }
        else
        {
		    gSlcData.gCallTransferInProgress = FALSE ;	
        }
    
        /* if not a link loss reset the last outgoing AG as AG1 will no longer exist now */        
        theSink.last_outgoing_ag = hfp_primary_link;

        /* reset the list id of the device just dropped */              
        theSink.profile_data[PROFILE_INDEX(ind->priority)].status.list_id = INVALID_LIST_ID;

        /* if device has now disconnected all profiles, mark as disconnected */
        if((ind->status != hfp_disconnect_link_loss)&&(!(mask & conn_hfp)))
            theSink.profile_data[PROFILE_INDEX(ind->priority)].status.connected = FALSE;
        
        /* If primary disconnected */
        if(ind->priority == hfp_primary_link)
        {
            /* ...and we have a secondary link it will be promoted to primary */
            if(theSink.profile_data[PROFILE_INDEX(hfp_secondary_link)].status.list_id != INVALID_LIST_ID)
            {
                /* Block copy secondary data to primary location */
                theSink.profile_data[PROFILE_INDEX(hfp_primary_link)] = theSink.profile_data[PROFILE_INDEX(hfp_secondary_link)];
                /* Secondary link no longer exists, set it to invalid */
                theSink.profile_data[PROFILE_INDEX(hfp_secondary_link)].status.list_id = INVALID_LIST_ID;
            }
        }
        /* send event slc disconnected only if the status of the indication is success or link loss indication */
        MessageSend(&theSink.task , ((ind->status == hfp_disconnect_link_loss) ? EventSysReconnectFailed : EventSysSLCDisconnected) , 0) ;
    }
    

    /*if the device is off then this is disconnect as part of the power off cycle, otherwise check
      whether device needs to be made connectable */	
	if ( stateManagerGetState() != deviceLimbo)
    {
	    /* if the device state still shows connected and there are no profiles currently
           connected then update the device state to reflect the change of connections */
	    if ((stateManagerIsConnected()) && (!deviceManagerNumConnectedDevs()))
	    {
	        stateManagerEnterConnectableState( FALSE ) ;
	    }
    }
    
}