This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC2564: Firmware example of how to permanently pair (bond) an A2DP Source device with another A2DP Sync

Part Number: CC2564
Other Parts Discussed in Thread: BT-MSPAUDSOURCE,

We are using the A3DP reference design to implement an audio source application that pairs with the infotainment system of a car. We need to implement a one-time pairing process such that if power is lost the BT connection will be automatically re-established once power is restored.  We have tried to save and restore the link key but this alone doesn't enable the connection to be automatically restored.  Is there an existing example of how to do this?

I see that a similar question was left unanswered in the past: https://e2e.ti.com/support/wireless_connectivity/bluetooth_cc256x/f/660/t/267220

  • Hi Ruben,

    There are 2 parts of this implementation from the BT stack side to store the link key of a paired device in NVM.

    - When a new device is paired, the atLinkKeyCreation event will occur in the GAP_Event_Callback. When this event occurs, you can see that the application is storing the link key in the following struct.

    static LinkKeyInfo_t       LinkKeyInfo[MAX_SUPPORTED_LINK_KEYS];

    This struct is stored in the RAM, so it will not be retained over a power cycle. At this time, you can take a backup of the LinkKeyInfo in the NVM of the MCU.

    - When the device powers up, read the backup that is stored in the NVM. Then you can pass this data to the LinkKeyInfo struct in the InitializeApplication() function after the OpenStack call is successful. This way, the previously stored LinkKeyInfo is restored after the power cycle and when the remote device tries to reconnect, the A3DP application will be able to use the previously stored link key. This occurs in the atLinkKeyRequest event of the GAP_Event_Callback.

    For MSP430, you can write the link key to the Info page memory :

    Best regards,

    Vihang

  • Vihang,

    Thank you for the quick reply.  I have implemented the save and restore of the link key as you describe, but there seems to be something more missing.  When I cycle power on the CC256x target the other device (BT sync) initiates authentication and the A3DP code correctly responds with the stored link key.  However the A3DP streaming connection does not get re-established as desired.  I was hoping there would be an existing example of this with the Bluetopia stack since it is such a common use-case.  I haven't found any relative information in the included stack and profiles documentation.

    Below is the debug terminal output when I restore power to the CC256x based unit. I have highlighted the following with different font colors: During inquiry the stack finds and skips BT device 0xA48D3B99BC4C because it is not an audio sync.  After this, the previously paired BT device 0xE0750A5F0317 issues a link key request and the CC256x device responds with the previously stored link key. At this point the previously paired device 0xE0750A5F0317 ndicates that the connection is re-established, however the CC256x device does not re-connect and does not stream audio.  The BT device 0xE0750A5F0317 issues a series of remote control commands which show up in the debug terminal output as transactionID 1 through 8.

    BOOT

    OpenStack().

    Bluetooth Stack ID: 1

    A3DP Source Feature enabled.

    Device Chipset: 4.1

    BD_ADDR: 0x84DD20F0CD15

    EIR Data Configured Successfully (Device Name SXM-DEMO-F0CD15).

    A3DP Endpoint opened successfully.

    Class of Device: 0x100428.

    Supported formats:

      Frequency: 44100, Channels: 2, Flags: 0

      Frequency: 48000, Channels: 2, Flags: 0

      Frequency: 48000, Channels: 1, Flags: 0

      Frequency: 44100, Channels: 1, Flags: 0

    ******************************************************************

    * Command Options: Inquiry, DisplayInquiryList, GetLocalAddress, *

    *                  OpenSink, CloseSink, Play, Pause, Help        *

    ******************************************************************

    A3DP+SRC>

    Skipping 0xA48D3B99BC4C.

    A3DP+SRC>

    Failed to perform auto-connect.

    A3DP+SRC>

    atLinkKeyRequest: 0xE0750A5F0317

    GAP_Authentication_Response success.

    A3DP+SRC>

    etAUD_Signalling_Channel_Open_Indication

    BD_ADDR:  0xE0750A5F0317

    A3DP+SRC>

    etAUD_Remote_Control_Command_Indication

    BD_ADDR:          0xE0750A5F0317

    TransactionID:    1

    Remote control response: 0

     

    A3DP+SRC>

    etAUD_Remote_Control_Command_Indication

    BD_ADDR:          0xE0750A5F0317

    TransactionID:    2

     

    AUD_Change_Stream_State success.

    Remote control response: 0

    A3DP+SRC>

    etAUD_Remote_Control_Command_Indication

    BD_ADDR:          0xE0750A5F0317

    TransactionID:    3

    Remote control response: 0

     

    A3DP+SRC>

    etAUD_Remote_Control_Command_Indication

    BD_ADDR:          0xE0750A5F0317

    TransactionID:    4

     

    AUD_Change_Stream_State success.

    Remote control response: 0

     

    A3DP+SRC>

    etAUD_Remote_Control_Command_Indication

    BD_ADDR:          0xE0750A5F0317

    TransactionID:    5

    Remote control response: 0

     

    A3DP+SRC>

    etAUD_Remote_Control_Command_Indication

    BD_ADDR:          0xE0750A5F0317

    TransactionID:    6

     

    AUD_Change_Stream_State success.

    Remote control response: 0

     

    A3DP+SRC>

    etAUD_Remote_Control_Command_Indication

    BD_ADDR:          0xE0750A5F0317

    TransactionID:    7

    Remote control response: 0

     

    A3DP+SRC>

    etAUD_Remote_Control_Command_Indication

    BD_ADDR:          0xE0750A5F0317

    TransactionID:    8

     

    AUD_Change_Stream_State success.

    Remote control response: 0

  • Hi Ruben,

    Could you please share the source code with these additions? I will try it out on the A3DP reference design and try to debug this.

    BR,
    Vihang
  • Thank you Vihang.  I will send the code separately by email.

    -Ruben

  • Vihang, I noticed that the A3DP Demo code doesn't take any action when it receives the (etAUD_Stream_Open_Indication) in the AUD event callback. The switch statement just has a break for that case. Should the code be issuing some response when it receives this indication, or should it change some state variables when this happens? I confirmed that the program is receiving that indication when the remote device tries to re-establish the stream after previously being paired.
  • Ok I have made some progress now.  I added the code below in the AUD_Event_Callback in response to the etAUD_Stream_Open_Indication.  Now I am able to re-establish the audio stream after initial pairing, however the sampling rate is off and I get a warning about this in the debug UART.  So I think I need to change something in the parameter for OpenA3DPStream(). Maybe the AUD_Stream_Format_t member???  Please let me know your thoughts on this.  I'm almost there.

    ---------------- Start code snippet ----------------

    case etAUD_Stream_Open_Indication:
    /* Occurs whenever the master device connects out to us. */

    Display(("RDP etAUD_Stream_Open_Indication\r\n"));

    /* Track this connection's BD_ADDR. */
    RemoteSinkBD_ADDR = AUD_Event_Data->Event_Data.AUD_Stream_Open_Indication_Data->BD_ADDR;
    OpenA3DPStream((AUD_Stream_Open_Confirmation_Data_t *)AUD_Event_Data->Event_Data.AUD_Stream_Open_Indication_Data);

                break;

    ----------------  End code snippet ----------------

    I get the following additional output on the debug uart:

    A3DP+SRC>
    RDP etAUD_Stream_Open_Indication
    A3DP Open: 0
    Reconfiguring codec...?done.
    Stream Format:
    Frequency: 131072
    Channels: 0
    Flags: 1106771968
    WARNING: Incompatible sample rate given, defaulting to 44.1 kHz

    Audio plays and remote control works as expected but you can tell that the sampling rate is wrong from the audible distortion and occasional pauses in playback.

  • Ok I fixed the last problem. I didn't notice that the AUD_Stream_Open_Confirmation_Data_t structure required by OpenA3DPStream() has one extra member versus the AUD_Stream_Open_Indication_Data_t structure, so its not ok to just cast. After fixing this, the CC256x board is able to re-establish the audio stream with the car audio system even after cycling power.
  • Hi Ruben,

    So if I follow the thread correctly, all the issues are solved is that correct?

    Steps so far:
    1) Save and restore the Link Key as discussed above.
    2) Add OpenA3DPStream() API call under the etAUD_Stream_Open_Indication event of the AUD_Event_Callback to autonomously send the VS_A3DP_Open_Stream to the controller when a paired device connects.

    Please let us know if there is anything missing. Thanks.

    Best regards,
    Vihang
  • Vihang,

    Yes that's basically it, but now I wonder what else is missing from this code example.  The unit successfully connects to some audio syncs but not others.  I haven't had time to debug the connection with the other devices.

    Ruben

  • Vihang,
    See below example of debug output I get when I try to pair the A3DP source demo with another sync device. Can you tell from looking at this why the other device refused the connection? Is it because the A3DP source demo doesn't support man in the middle security? I noticed that the atIOCapabilityResponse for this device lists MITM, but I'm not sure if that means it will only pair with other devices that have MITM support enabled. If this is the case, can you share an example of how to enable MITM support in the A3DP source example?

    Do you have any suggestions on how to debug this? Would I need a BT protocol analyzer?

    A3DP+SRC>BOOT
    OpenStack().
    Bluetooth Stack ID: 1
    A3DP Source Feature enabled.
    Device Chipset: 4.1
    BD_ADDR: 0x84DD20F0CD15
    EIR Data Configured Successfully (Device Name SXM-DEMO-F0CD15).
    A3DP Endpoint opened successfully.
    Class of Device: 0x100428.
    Supported formats:
    Frequency: 44100, Channels: 2, Flags: 0
    Frequency: 48000, Channels: 2, Flags: 0
    Frequency: 48000, Channels: 1, Flags: 0
    Frequency: 44100, Channels: 1, Flags: 0

    ******************************************************************
    * Command Options: Inquiry, DisplayInquiryList, GetLocalAddress, *
    * OpenSink, CloseSink, Play, Pause, Help *
    ******************************************************************

    A3DP+SRC>
    Adding 0x48A9D2AAF086 to auto-connect list.

    A3DP+SRC>
    Auto-connecting to 0x48A9D2AAF086 via AUD...

    A3DP+SRC>
    atLinkKeyRequest: 0x48A9D2AAF086

    GAP_Authentication_Response success.

    A3DP+SRC>
    atIOCapabilityRequest: 0x48A9D2AAF086

    Auth success.

    A3DP+SRC>
    atIOCapabilityResponse: 0x48A9D2AAF086
    Capabilities: Display Yes/No, MITM

    A3DP+SRC>
    atUserConfirmationRequest: 0x48A9D2AAF086

    Auto Accepting: 712567

    GAP_Authentication_Response success.

    A3DP+SRC>Un-handled Auth. Event.
    GAP_Authentication_Event_Type = 757792779

    A3DP+SRC>
    etAUD_Stream_Open_Confirmation
    Status: 2
    BD_ADDR: 0x48A9D2AAF086
    Connection to 0x48A9D2AAF086 failed.
    Ending auto-connect process.

    A3DP+SRC>
    atAuthenticationStatus: 5 for 0x48A9D2AAF086

    A3DP+SRC>
  • Hi Ruben,

    Apologies for the delay.

    The "atAuthenticationStatus: 5" indicates that the authentication was failed due to incorrect PINcode or incorrect Link Key. Considering you are using previously stored link key, this error is most likely due to incorrect Link Key.

    I would recommend capturing the CC256x FW logs for the entire operation (from saving the first link key to when the authentication fails after power cycle). Moreover, please make sure that the MAX_SUPPORTED_LINK_KEYS is defined to be more than 1. By default, this macro is set to 1. This will cause the sample application not to save more than 1 remote device's link key.

    Best regards,
    Vihang
  • Hi Vihang. The code has been modified to either replace the stored link key (pairing mode) or use the stored link key (paired mode). We wired in an external button to select between these two modes. So, we only have need for MAX_SUPPORTED_LINK_KEYS set to 1. As I mentioned, this works 100% of the time with some A2DP sink devices but not with others. Please let me know how to capture the CC256x FW logs. Is this done through the same debug UART pins or some other way?
  • Hi Ruben,

    Thanks for the update. I understand that the MAX_SUPPORTED_LINK_KEYS macro is not the reason for this problem.

    You can capture the CC256x FW logs from the TX_DBG line of the CC2564. This signal is accessible from J18 of the BT-MSPAUDSOURCE board. You will need a 1.8V UART to USB cable for this to capture the CC256x FW logs using TX_DBG and GND.
    processors.wiki.ti.com/.../CC256x_Logger_User_Guide

    I will be looking for HCI commands and CC256x FW traces in the logs that can help us understand why the failing A2DP sink device is not getting paired. Please keep me posted. Thanks.

    Best regards,
    Vihang
  • Vihang,

    I was able to get the BT logger to work with CC256x. Is it possible to save both the main log “BT Logger” and the HCI log at the same time?  It seems like I only see the main logger if I select both. Or do I need to run this once with “BT Logger” selected, then repeat with “HCI/LMP viewer 1” selected (see screenshot of relevant setup)?


     

    Can you please confirm the attached files are in the correct format? These are not the actual failing case I asked about in the previous post, just my initial test of the logger.

     

    Thanks,

    Ruben

    cc256x_test_logs.zip

  • Hi Ruben,

    Looks like the first log (BT_logger_test_april11_RDP.lgr) is captured with only the "BT Logger 1" option selected. While the second one (HCI_log_test_april11_RDP.lgr) is captured only using the "HCI/LMP viewer 1" option.

    It is best to enable (checkbox) both of these options when capturing so that they are in time sync. Then we can filter only certain part from a captured log if needed. Please ensure that you have the COM port setup in both options.

    Best regards,
    Vihang

  • Vihang,

    I have attached BT Logger logs for both the passing example and the failing example.  

    1. The file "Good_Pair_n_Play_Jeep_April11.lgr" captures the CC256x system in pairing mode followed by a successful pairing with, and A2DP playback to the infotainment system of a 2015 Jeep Wrangler. 
    2. After this, the system was powered down and the file "Good_prev_paired_n_Play_Jeep_April11.lgr" captures the CC256x system in non-pairing mode (retains link key from previous pairing) followed by authentication with, and A2DP playback to the infotainment system of the jeep from 1.
    3. Next the file "Failed_Pair_Dodge_April11.lgr" captures the CC256x system in pairing mode followed by an unsuccessful pairing attempt with the infotainment system of a 2015 Dodge Durango.

    As mentioned before it seems that the IO Capabilities request/response sequence is different between the passing and failing systems.

    Please let me know what the logs reveal.

    Thanks,

    Rubencc256x_logs.zip