⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pioag_receive.c

📁 bluetooth audio gateway
💻 C
字号:
#include "pioag_private.h"
#include "ag_types.h"
#include "ag.h"

#include <audio.h>
#include <panic.h>
#include <ps.h>
#include <stdlib.h>
#include <string.h>



static const audio_note error_beep[] =
{
    AUDIO_TEMPO(180), AUDIO_VOLUME(64), AUDIO_TIMBRE(sine),
    AUDIO_NOTE(E7, QUAVER),    
    AUDIO_NOTE(B7, QUAVER),
    
    AUDIO_NOTE(E7, QUAVER),
    AUDIO_NOTE(C7, QUAVER),

    AUDIO_END
};


/* 
    pioAgConnectionAttemptTimeout
 
    Timer function that times reconnection attempts.
*/
static Delay pioAgConnectionAttemptTimeout(TimerHandle h)
{
    /* Keep compiler happy */
    h = h;   

    /* Become connectable */
    pioAgConnectReq(PioAgSlave, PIO_AG_SLAVE_CONNECT_TIMEOUT);

    /* reset the timer handle */
    PioAgState.connectionTimerHandle = NULL_TIMER;

    return D_NEVER;
}


/*
    handleStartCfm

    Start cfm receivced from the AG
  
    This function checks to see if the FEAG is already paired to a 
    headset, if it is it attempts to connect to it. If not it prompts
    the user to enter a pin code.
*/
void handleStartCfm(void)
{
    uint16  isPaired = 0;    
        
    /* Check to see if we are currently paired to another device */    
    if (PsRetrieve(PIO_AG_PS_IS_PAIRED, &(isPaired), sizeof(isPaired)) && isPaired)
    {
        /* We are currently paired to something, register it with the security manager */        
        pioAgSmAddDevReq();                
        
        /* Now try to connect to the device we're paired with */        
        pioAgConnectReq(PioAgSlave, PIO_AG_SLAVE_CONNECT_TIMEOUT);        
    }
    else
    {
        /* 
            We are not paired to anything, clear the stored address and link key
            and get the pin code.
        */                                        
        uint16 pinlen = 0;
        uint16 *zeroBuf = (uint16*) PanicNull(calloc(32, sizeof(uint16)));
        (void) PsStore(PIO_AG_PS_PEER_ADDR, zeroBuf, sizeof(BD_ADDR_T));
        (void) PsStore(PIO_AG_PS_LINK_KEY, zeroBuf, AG_SIZE_LINK_KEY);

        if(PsRetrieve(PIO_AG_PS_PIN_LENGTH, &pinlen, 1) && pinlen)
        {
            /* 
                We have a PIN so go into pairin mode, if the user wants to enter 
                a new pin they wil perferom a reset 
            */
            pioAgInquiryReq();
        }
        else
        {
            /* No Pin stored. Get Pin Code from user */
            (void) PsStore(PIO_AG_PS_PIN_CODE, zeroBuf, MAX_PIN_LENGTH);
            (void) PsStore(PIO_AG_PS_PIN_LENGTH, zeroBuf, 1);
            
            if (pioAgResetReq())
            {
                pioAgGetPinCode();
            }
        } 
        free(zeroBuf);
    }
}


/*
    handleInquiryResultInd

    Processes the Inquiry results accordingly, since we are only looking for
    one device we can store it in the PS to indicate that a device has been found.
*/
void handleInquiryResultInd(const CM_INQUIRY_RESULT_IND_T *ind)
{       
    /* Store the address in our PS store */
    (void) PsStore(PIO_AG_PS_PEER_ADDR, &ind->inq_result.bd_addr, sizeof(BD_ADDR_T));
}


/*
    handleInquiryCompleteCfm

    Inquiry has completed. Checks the status of the inquiry confirm event 
    and processes accordingly.
*/
void handleInquiryCompleteCfm(ag_inquiry_status_t status)
{
    bd_addr_t bd_addr;

    status = status;    
    
    if (PsRetrieve(PIO_AG_PS_PEER_ADDR, &bd_addr, sizeof(bd_addr_t)) && 
        bd_addr.nap && bd_addr.uap && bd_addr.lap)
    {
        /* We found a device to pair to */
        pairReqAction(bd_addr, 1, PIO_AG_PAIRING_TIMEOUT);        
    }
    else
    {
        /* We didn't find anything so play an error beep and go idle */                
        (void) AudioPlay(error_beep);
    }
    
    PioAgState.inquiryComplete = 1;
}


/*
    handlePinReq

    Retrieve PIN code entered by the user and send to the lower layers.
*/
void handlePinReq(BD_ADDR_T addr)
{
    bd_addr_t tmp_addr;
    tmp_addr.nap = addr.nap;
    tmp_addr.uap = addr.uap;
    tmp_addr.lap = addr.lap;

    /* Send the stored Pin code */    
    pioAgPinReplyReq(tmp_addr);    
}


/*
    handleLinkKeyReq

    A request for the link key has arrived, send the stored link key back.
*/
void handleLinkKeyReq(uint16 handle)
{
    uint8 link_key[AG_SIZE_LINK_KEY];
    uint16 isValid = 0;
    memset(link_key, 0, AG_SIZE_LINK_KEY);
    
    if (PsRetrieve(PIO_AG_PS_LINK_KEY_VALID, &isValid, sizeof(uint16)) && isValid)
    {
        /* We have a valid link key, check that the handles match */
        if (handle == PioAgState.handle)
        {
            /* The handles match fetch the link key from PS and send it back */            
            (void) PsRetrieve(PIO_AG_PS_LINK_KEY, link_key, AG_SIZE_LINK_KEY);
            linkKeyResAction(1, handle, link_key);
        }
        else
        {
            /* The handle does not match, reject the request and flag an error */
            linkKeyResAction(0, handle, link_key);
        }
    }
    else
    {
        /* There is no valid link key so we have to send a reject here */
        linkKeyResAction(0, handle, link_key);
    }
}


/*
    handlePairCfm

    Process Pair Confirm accordingly, currently if the pairing fails nothing 
    happens. The state machine returns to idle so could start inquiries again.
*/
void handlePairCfm(BD_ADDR_T addr, ag_pair_status_t status, const uint8 *link_key)
{
    uint16 isPaired, isValid;           
        
    switch (status)
    {
        /* 
            If the pairing succeeded, store link key, bd addr, etc in PS
            and attempt connection
        */
    case AgPairingComplete:           
        {
            bd_addr_t tmp_addr;
            tmp_addr.nap = addr.nap;
            tmp_addr.uap = addr.uap;
            tmp_addr.lap = addr.lap;

            isPaired = 1;
            isValid = 1;
            (void) PsStore(PIO_AG_PS_LINK_KEY, link_key, AG_SIZE_LINK_KEY);
            (void) PsStore(PIO_AG_PS_IS_PAIRED, &(isPaired), 1);
            (void) PsStore(PIO_AG_PS_LINK_KEY_VALID, &(isValid), 1);
            (void) PsStore(PIO_AG_PS_PEER_ADDR, &tmp_addr, sizeof(bd_addr_t));
            
            /* Start trying to connect to the remote device */                                    
            PioAgState.connectionTimerHandle = TimerAdd(D_SEC(PIO_AG_CONNECTION_RETRY_TIMEOUT), pioAgConnectionAttemptTimeout);
        }
        break; 
        
        /* If pairing was cancelled, return to idle we must be resetting */
    case AgPairingError:
    case AgPairingCancelled:                    
    case AgPairingFailed:
    case AgPairingTimedOut: 
        (void) AudioPlay(error_beep);
        break;
        
        /* Flag an error, we got an unknown response */
    default:
        break;
    }
}


/*
    handleConnectionHandleMap

    A connection request indicator has arrived, store the device handle.
*/
void handleConnectionHandleMap(uint16 hdl, bd_addr_t addr)
{
    bd_addr_t bdAddr;
    
    (void) PsRetrieve(PIO_AG_PS_PEER_ADDR, &bdAddr, sizeof(bd_addr_t));
    
    if (bdAddr.nap == addr.nap && 
        bdAddr.uap == addr.uap && 
        bdAddr.lap == addr.lap)
    {
        /* Device address matches stored address */
        PioAgState.handle = hdl;
    }
    else
    {
        /* Device addresses do not match */
        PioAgState.handle = UNDEFINED_HANDLE;
    }
}


/*
    handleRfcommStatusInd

    An RFCOMM connection may have been established, find out and deal with it.
*/
void handleRfcommStatusInd(ag_handle_t hdl, ag_connection_status_t status, ag_profile_role_t role)
{
    /* keep the compiler happy */
    hdl = hdl;
	role = role;

    switch(status)
    {
        /* If the attempt was a success, wait for user to establish a SCO */
    case AgConnectComplete:               
        PioAgState.connectAsSlave = 0;
        break;
        
        /* If the attempt failed, flag error */
    case AgConnectDisconnect:
    case AgConnectDisconnectAbnormal:
    case AgConnectFailed:
    case AgConnectTimeout:        
        if (!agRfcommConnectedQuery())
        {
            /* If not connected, schedule another attempt to connect */
            PioAgState.connectAsSlave = 0;
            PioAgState.connectionTimerHandle = TimerAdd(D_SEC(PIO_AG_CONNECTION_RETRY_TIMEOUT), pioAgConnectionAttemptTimeout);
        }
        break;
        
        /* The attempt was cancelled - resetting or flipping connect mode */
    case AgConnectCancelled:  
        if (PioAgState.connectAsSlave)
        {
            /* If the connect as slave flag is set then try connecting as master */
            pioAgConnectReq(PioAgMaster, PIO_AG_MASTER_CONNECT_TIMEOUT);
        }
        break;
        
    default:
        /* Flag an error, we got an unknown response */
        break;
    }
}


/*
    handleButtonPressInd

    A button press has been received from the headset, this could mean
    one of two things, if there is no SCO connection then start one up.
    If there is a SCO connection, tear it down.
*/
void handleButtonPressInd(ag_handle_t hdl)
{
    if (agScoConnectedQuery())
    {
        /* Tear down SCO connection */
        agScoDisconnectReqAction(hdl);
    }
    else
    {
        /* Start a SCO Connection, packet type hard coded */
        agScoConnectReqAction(hdl, PIO_AG_HV3);
    }    
}


/*
    handleScoStatusInd

    Process the SCO connection status indicator and update state variable.
*/
void handleScoStatusInd(ag_handle_t hdl, ag_connection_status_t status, hci_connection_handle_t sco_handle)
{    
    hdl = hdl;    
    sco_handle = sco_handle;

    /* if the connection was not opened or disconnected properly beep for error */
    if (status != AgConnectComplete && status != AgConnectDisconnect)
        (void) AudioPlay(error_beep);
}


/*
    handleErrorInd

    This function handles the error events from the EAG and stores 
    the results in the PS.
*/
void handleErrorInd(ag_handle_t hdl, ag_error_code_t error_reason)
{
    /* TODO currently unused but could store this in the PS error ind keys */
    hdl = hdl;
    error_reason = error_reason;

    /* Beep to indicate an error but not for warnings */
    if (error_reason != AgWarnLocalSniffNotEnabled &&
        error_reason != AgWarnLocalParkNotEnabled &&
        error_reason != AgWarnLocalLowPwrModeNotEnabled &&
        error_reason != AgWarnRemoteDevDoesNotSupportSniffMode &&
        error_reason != AgWarnRemoteDevDoesNotSupportParkMode &&
        error_reason != AgWarnRemoteLowPwrModeNotEnabled)
        (void) AudioPlay(error_beep);    
}


/*
    handleVolumeChangeInd

    Volume indication from headset
*/
void handleVolumeChangeInd(ag_handle_t hdl, uint8 gain)
{
    /* 
        Currently this is ignored as it is not clear what to do with this 
        volume message (its an unsolicited result code informing the AG of 
        the volume settings at the headset)
    */
    hdl = hdl;
    gain = gain;
}


/*
    handleMicrophoneChangeInd

    Microphone gain indication from headset
*/
void handleMicrophoneChangeInd(ag_handle_t hdl, uint8 gain)
{
    /* 
        Currently this is ignored as it is not clear what to do with this 
        mic gain message (its an unsolicited result code informing the AG of 
        the mic gain setting at the headset)
    */
    hdl = hdl;
    gain = gain;
}

void handleCallAnsweredInd(ag_handle_t hdl, uint16 accept_flag)
{
    /* Not used by the headset profile AG so just ignore for now */
    hdl = hdl;
    accept_flag = accept_flag;
}

void handleRemoteDialReq(ag_handle_t hdl, dial_mode_t dial_what, uint16 length, const uint8 *data)
{
    /* Not used by the headset profile AG so just ignore for now */
    hdl = hdl;
    dial_what = dial_what;
    length = length;
    data = data;
}

void handleUnparsedData(ag_handle_t hdl, uint16 length, const uint8 *data)
{
    /* Just ignore data that the parser cannot cope with */
    hdl = hdl;
    length = length;
    data = data;
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -