QCC300x learning notes: Custom HFP AT command

In order to facilitate your study, we are now jointly launching with our love Bluetooth network [QCC300x/CSR867x/QCC30xx/QCC51xx development board].

QQ group no. of technical exchange: 7434463
QQ group number of development board member: 725398389
——————————Text line

1. introduction

Recently, we are working on a Bluetooth transmitter + receiver project, and the customer has put forward several customization requirements:

  • The receiver can connect a Bluetooth transmitter and a normal mobile phone at the same time
  • There are two buttons, one for Bluetooth transmitter and two for mobile phone
  • The connection order between Bluetooth transmitter and mobile phone and receiver is not fixed

Generally, on the premise of determining the connection order, press the key one corresponding to the event [Initiate voice dial 1] to call the first connected device, and press the key two corresponding to the event [Initiate voice dial 2] to call the second connected device. If the connection order is not determined, the first device connected may be the mobile phone, which causes the button one to fail to call the Bluetooth transmitter.

In order to make the key one always call the Bluetooth transmitter, it is necessary to establish a matching verification mechanism between the transmitter and the receiver. When the transmitter is connected to any device, it sends a matching verification request. If the other party returns a correct matching response, that is, both parties know that the other party is a matching device type. The receiver can specify a key to associate this device, so that the transmitter can always be called without considering the connection order.

Transmitter receiver Bluetooth connection establishment match verification request? Device connection is associated with key one matching verification response matching verification through transmitter receiver

The transmission channel of matching verification message can be HFP, GATT, SPP and other protocols. There is no use scenario of GATT and SPP protocol in this project. It is a labor-saving and reliable solution to transmit custom AT command with existing HFP protocol.

2. What is HFP AT command

AT command is a part of HFP protocol, which is used to transmit control signaling through RFCOMM channel between AG(Audio Gateway) and HF (hands free unit).


Give a simple example to illustrate the use of AT command. In some scenarios, the echo cancellation and noise suppression functions of AG need to be turned off. At this time, HF will send a specific AT command to AG. The flow chart is as follows:

It can be seen that HF sends AT+NREC=0 to AG, and AG returns OK or ERROR to HF according to its own situation. Here, HFP gives several conventions about AT command:

  • The command sent by HF to AG should have "AT +", 0 for closing, 1 for enabling
  • NREC is the order of HFP protocol native support
  • AG can send command s to HFP without "AT +"

Referring to the full text of HFP V1.7, no AT command can be found for matching verification, so we need to customize an AT command to complete matching verification.

Similar practice can refer to AT+BVRA command of Apple device, and SCO connection with headset (HF) can be initiated at mobile terminal (AG):

The accessory should expect the following command sequence:
· The iOS device sends a +BVRA:1 event to the accessory.
· The iOS device launches a Siri session and creates a SCO connection for the
audio.
· When the Siri session is finished, the iOS device sends a +BVRA:0 result code
to the accessory.
· The iOS device disconnects the SCO connection.

3. Customize AT command

3.1. User defined AT command interaction sequence diagram

Ckdevicerole emitter VM emitter AGHFP lib receiver HFP lib receiver VM

3.2. AG end program example

VM sends a message to AGHFP lib:

void aghfp_device_role_ind(bool role)
{
    uint16 index = 0;
    aghfpInstance *inst = theSource->aghfp_data.inst;
        
    if (inst != NULL)
    {
        for_all_aghfp_instance(index)
        {
            if (aghfp_is_connected(inst->aghfp_state))
            {
                /* send voice recognition to remote side */
                AghfpDeviceRoleSet(theSource->aghfp_data.aghfp, role);
            }
            inst++;
        }
    }
}

void AghfpDeviceRoleSet(AGHFP *aghfp, bool role)
{
	MAKE_AGHFP_MESSAGE(AGHFP_INTERNAL_DEVICE_ROLE_SET);
	message->role = role;
	MessageSend(&aghfp->task, AGHFP_INTERNAL_DEVICE_ROLE_SET, message);
}

AGHFP lib calls aghfpSendAtCmd to send custom AT command:

void aghfpHandleDeviceRoleSet(AGHFP *aghfp, bool role)
{
	/* Send AT cmd to HF */
	const char AgMessage[] = "+DERL: 1";
	const char HfMessage[] = "+DERL: 0";
	if (role)
	{
		aghfpSendAtCmd(aghfp, AgMessage);
	}
	else
	{
		aghfpSendAtCmd(aghfp, HfMessage);
	}

	/* Send confirm to app */
	aghfpSendCommonCfmMessageToApp(AGHFP_DEVICE_ROLE_SET_CFM, aghfp, aghfp_success);
}

3.3. HF end program example

When HF receives AT command, it will try to match it with the default supported AT command. If it fails to match, it will send the string of AT command to VM with aghfp ﹐ unrecognized ﹐ at ﹐ CMD ﹐ ind message for parsing.

    case HFP_UNRECOGNISED_AT_CMD_IND:
    {
        sinkHandleUnrecognisedATCmd( (HFP_UNRECOGNISED_AT_CMD_IND_T*)message ) ;
    }
    break ;

We insert the match check handler in the sinkHandleUnrecognisedATCmd.

    AT_DEBUG(("AT command = %s\n", pData));

    sinkAtCommandsCheckDeviceRole(ind, pData); // Match check processing function

    sinkAtCommandsCheckAndProcessProductionTestCommands(ind, pData);

When the match is successful, the HfpAtCmdRequest function is called to return the scheduled AT command "+DERL: 0".

static const char * const device_role_ag_string	            = "+DERL: 1";
static const char * const device_role_ag_string_res_success = "+DERL: 0";

static void sinkAtCommandsCheckDeviceRole(HFP_UNRECOGNISED_AT_CMD_IND_T *ind,
                                                            const char * const command_string)
{
    if(strncmp(command_string, device_role_ag_string, strlen(device_role_ag_string)) == 0)
    {
        AT_DEBUG(("Handle Device Role Ag\n"));
        
        /* Send the success response AT command */
        AT_DEBUG(("Response %s\n", device_role_ag_string_res_success));
        HfpAtCmdRequest(ind->priority, device_role_ag_string_res_success);
    }
}

The corresponding HFP link priority can be obtained from the obtained HFP unrecognised at CMD ind t handle:

typedef struct
{
    /*! The priority of the link. */
    hfp_link_priority   priority;
    /*! The number of bytes pointed to by data.*/
    uint16    size_data;
    /*! The data that could not be parsed. The client should not attempt to
      free this pointer, the memory will be freed when the message is
      destroyed. If the client needs access to this data after the message has
      been destroyed it is the client's responsibility to copy it. */
    uint8    data[1];
} HFP_UNRECOGNISED_AT_CMD_IND_T;

/*!
    @brief Link priority is used to identify different links to
    AG devices using the order in which the devices were connected.
*/
typedef enum
{
    /*! Invalid Link. */
    hfp_invalid_link,
    /*! The link that was connected first. */
    hfp_primary_link,
    /*! The link that was connected second. */
    hfp_secondary_link
} hfp_link_priority;

With priority, you can directly call sinkInitiateVoiceDial(priority) to make a call to the specified device.

4. summary

The method of customizing AT command is suitable for scenarios that require only a small amount of data interaction. Be careful not to affect the AT command of HFP protocol.

5. References

  • SIG: HFP V1.7.0
  • QUALCOMM: CS-330103-UG (Audio Sink Application Custom AT Commands User Guide)
  • APPLE: BluetoothDesignGuideLines
65 original articles published, 107 praised, 280000 visitors+
Private letter follow

Tags: Mobile iOS Session network

Posted on Wed, 12 Feb 2020 09:02:21 -0500 by DeadEvil