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.

Storing Link Keys in Flash and retrieving them on start up

Other Parts Discussed in Thread: MSP430F5438A

Hi,

I have been developing a bluetooth application using Bluetopia stack on MSP430F5438A  and PAN1323 using only SPP Demo.
I connect this setup to an android phone. 

I require that the bonding between my device and phone even after reset power cycle.

To do this, I can successfully write the Bluetooth address and Link Key of the phone to the flash.
However, after power up, I retrieve the bd_addr and link_keys from flash and store them in  LinkKeyInfo structure.
But when the phone tries to connect to my device, again a new link key is generated and on some phones connection is not successful.

How can I make the Bluetooth Host controller  to understand that the phone is already paired?
How should I store the link keys? 

  • When you say "flash", is this an external device? For android SPP, it is easier to use the an API on the phone that skips the pairing step:

    http://stackoverflow.com/questions/5885438/bluetooth-pairing-without-user-confirmation

    For ex: you can try an Android app called "Zahid's Blueterm" that includes this API.

     

  • Zahid,

    Sorry I was not clear before.

    By "flash", I mean the MCU flash.

    And I am using SimpleSecurePairing without user confirmation on both android as well as pan1323.
    The problem arises when Phone has a link key remembered and PAN1323 does not.
    The connection is initiated by PAN1323 (client) tp Android phone (server).
    When android already has the link key remembered, the connection fails.

    I have tried this with Blueterm too. 

  • Had the same Task, here's how I solved it: Use one of the Information Memory Segments of you MSP430 to store the link Keys+BT-Addr. (5 of those pairs fit in one segment). Have a look at the datasheet of your MCU to find out the correct memory addresses, have a look at the programing manual to find out how to write/read to/from flash, then have a closer look at the LinkKeyInfo_t struct in the Demo.

    Cheers

  • Hey Florian,

    I did the exact same thing you have said.

    I stored BD_ADDR and link key in flash. On power up, I retrieved from flash and stored it in LinkKeyInfo_t struct in the demo.

    But when I tried to connect to my phone, it was not possible?
    Were u successfully able to connect? Using the same structure in SPPDemo? 

  • Well then something most go wrong either on writing or on reading the Linkkeys - it works fine in my application which is based on the SPPLEDemo. Post your Code here then we can see what goes wrong, you can also set a Breakpoint in CCS at a line after you wrote the Keys and check with the memory browser if the right data goes into the flash. Also pay attention to the time when you read the keys back; somewhere in the init-process the whole LinkKey array gets filled with NULL_BD_ADDR so make sure you read from flash _after_ this is done (or delete it from the code), this caused also in my app some trouble.

  • This is the code which assigns the bd_addr and link_key.
    tmpPhone struct contains linkkey and bd_addr in string format retrieved from flash. 

    /* Copy the data to link_key_info */
    ASSIGN_BD_ADDR(LinkKeyInfo[i].BD_ADDR, tmpPhone.BT_ADDR[5], tmpPhone.BT_ADDR[4], tmpPhone.BT_ADDR[3]
    , tmpPhone.BT_ADDR[2], tmpPhone.BT_ADDR[1], tmpPhone.BT_ADDR[0]);
    ASSIGN_LINK_KEY(LinkKeyInfo[i].LinkKey, tmpPhone.BT_LinkKey[0], tmpPhone.BT_LinkKey[1], tmpPhone.BT_LinkKey[2]
    , tmpPhone.BT_LinkKey[3], tmpPhone.BT_LinkKey[4], tmpPhone.BT_LinkKey[5], tmpPhone.BT_LinkKey[6]
    , tmpPhone.BT_LinkKey[7], tmpPhone.BT_LinkKey[8], tmpPhone.BT_LinkKey[9], tmpPhone.BT_LinkKey[10]
    , tmpPhone.BT_LinkKey[11], tmpPhone.BT_LinkKey[12], tmpPhone.BT_LinkKey[13], tmpPhone.BT_LinkKey[14]
    , tmpPhone.BT_LinkKey[15]);

    When connecting to phone... I call 

    OpenRemoteServer(LinkKeyInfo[0].BD_ADDR, 1);

    But there is no response from the phone. And yeah, I have taken care of the NULL_BD_ADDR

  • Okay so this is how you assign the distinct bytes to the struct, but you're still not sure if everything goes right on writing/reading the data from/to flash? This would be the interesting part of the code.

    Does everything work if you don't go through a power cycle? Meaning pairing phone and MCU and right afterwords opening a port? There are two things that came to my mind about that:

    - For opening a port from the MCU side, the phone must provide a SPP Server, is that so?
    - I only tried the app using the MCU as a server and on opening a connection/port from the Computer/Phone, these devices request the already stored LinkKey from the MCU which is shown on the terminal (see the corresponding code in the "GAP_Callback_Function" - "LinkKey request ...") and I'm not sure if you have to do that manually before/when opening a remote port from the MCU side or if its done automatically, at least when you're connecting to a device that has not the Demo code running on it.

  • Here are some thoughts

    1. The phone is providing a SPP server.

    2. Yes this is somewhat related. I need the connection to be initiated by MCU (client) and its is to be accepted by server (Android Phone)
        The other way round is fine, because the PAN1323 module is set to Just Works - SSP. Hence it will generate LinkKey once again.
        But the connection is to be made from MCU.
       

    Will the MCU search for LinkKey in the struct LinkKeyInfo_t?

    I also found a function in Bluetopia Core API manual - HCI_Write_Stored_Link_Key() 
    Any idea what does it do?? Not very clear in manual, that whether the PAN1323 uses the LinkKeys stored in it?? 

  • Yes, have a look at the GAP Callback, there you can see how the MCU searches the array for the connecting BD_ADDR. It should _Not_ generate the LinkKey once again but rather find it - that's why im guessing that something goes wrong on reading/writing, note that almost every GAP-Event issues a Display() to tell you whats going on.

    Yes until today I also dont know what the HCI_Write/Read_Stored_Link_Key() functions are good for; what really confuses me is that in the core API doc they speak of "stored in the Host controller" - so what, either they are stored in the Host OR in the controller, according to the BT spec?? I'll open a thread a long with another question and see what SS1 knows about that.

  • Hi, i am faced to the same problem.

    could anyone copy a code that works for saving and loading the linkkey?
    i think many people would like to use this snippets!?

    i think it should look like this:

    - WriteKeyToFlash()        // from LinkKeyInfo[0]
    - ReadKeyFromFlash()  // to LinkKeyInfo[0]

    thanks!

  • Hi, i managed to store and read the keys - here is my solution (quick&dirty) - works fine!

    #define NUMBER_OF_BYTES 22
    Byte_t savedata[NUMBER_OF_BYTES]; // 6 byte BD_ADDR + 16 byte linkkey
    #define Data_START (0x1800)
    static void WriteKeyFromSystemToFlash()
    {
    uint16_t status;

    savedata[0] = LinkKeyInfo[0].BD_ADDR.BD_ADDR0;
    savedata[1] = LinkKeyInfo[0].BD_ADDR.BD_ADDR1;
    savedata[2] = LinkKeyInfo[0].BD_ADDR.BD_ADDR2;
    savedata[3] = LinkKeyInfo[0].BD_ADDR.BD_ADDR3;
    savedata[4] = LinkKeyInfo[0].BD_ADDR.BD_ADDR4;
    savedata[5] = LinkKeyInfo[0].BD_ADDR.BD_ADDR5;

    savedata[6] = LinkKeyInfo[0].LinkKey.Link_Key0;
    savedata[7] = LinkKeyInfo[0].LinkKey.Link_Key1;
    savedata[8] = LinkKeyInfo[0].LinkKey.Link_Key2;
    savedata[9] = LinkKeyInfo[0].LinkKey.Link_Key3;
    savedata[10] = LinkKeyInfo[0].LinkKey.Link_Key4;
    savedata[11] = LinkKeyInfo[0].LinkKey.Link_Key5;
    savedata[12] = LinkKeyInfo[0].LinkKey.Link_Key6;
    savedata[13] = LinkKeyInfo[0].LinkKey.Link_Key7;
    savedata[14] = LinkKeyInfo[0].LinkKey.Link_Key8;
    savedata[15] = LinkKeyInfo[0].LinkKey.Link_Key9;
    savedata[16] = LinkKeyInfo[0].LinkKey.Link_Key10;
    savedata[17] = LinkKeyInfo[0].LinkKey.Link_Key11;
    savedata[18] = LinkKeyInfo[0].LinkKey.Link_Key12;
    savedata[19] = LinkKeyInfo[0].LinkKey.Link_Key13;
    savedata[20] = LinkKeyInfo[0].LinkKey.Link_Key14;
    savedata[21] = LinkKeyInfo[0].LinkKey.Link_Key15;


    //Erase Data
    do {
    FLASH_segmentErase(FLASH_BASE,
    (uint8_t*)Data_START
    );
    status = FLASH_eraseCheck(FLASH_BASE,
    (uint8_t*)Data_START,
    NUMBER_OF_BYTES
    );
    } while (status == STATUS_FAIL);

    //Flash Write
    FLASH_write8(FLASH_BASE,
    savedata,
    (uint8_t*)Data_START,
    NUMBER_OF_BYTES
    );

    }

    static void ReadKeyFromFlashToSystem()
    {

    char *FLASH_ptrC;

    uint16_t status;

    //Initialize Flash segment C ptr
    FLASH_ptrC = (char*)Data_START;

    LinkKeyInfo[0].BD_ADDR.BD_ADDR0 = *FLASH_ptrC;
    LinkKeyInfo[0].BD_ADDR.BD_ADDR1 = *(FLASH_ptrC+1);
    LinkKeyInfo[0].BD_ADDR.BD_ADDR2 = *(FLASH_ptrC+2);
    LinkKeyInfo[0].BD_ADDR.BD_ADDR3 = *(FLASH_ptrC+3);
    LinkKeyInfo[0].BD_ADDR.BD_ADDR4 = *(FLASH_ptrC+4);
    LinkKeyInfo[0].BD_ADDR.BD_ADDR5 = *(FLASH_ptrC+5);

    LinkKeyInfo[0].LinkKey.Link_Key0 = *(FLASH_ptrC+6);
    LinkKeyInfo[0].LinkKey.Link_Key1 = *(FLASH_ptrC+7);
    LinkKeyInfo[0].LinkKey.Link_Key2 = *(FLASH_ptrC+8);
    LinkKeyInfo[0].LinkKey.Link_Key3 = *(FLASH_ptrC+9);
    LinkKeyInfo[0].LinkKey.Link_Key4 = *(FLASH_ptrC+10);
    LinkKeyInfo[0].LinkKey.Link_Key5 = *(FLASH_ptrC+11);
    LinkKeyInfo[0].LinkKey.Link_Key6 = *(FLASH_ptrC+12);
    LinkKeyInfo[0].LinkKey.Link_Key7 = *(FLASH_ptrC+13);
    LinkKeyInfo[0].LinkKey.Link_Key8 = *(FLASH_ptrC+14);
    LinkKeyInfo[0].LinkKey.Link_Key9 = *(FLASH_ptrC+15);
    LinkKeyInfo[0].LinkKey.Link_Key10 = *(FLASH_ptrC+16);
    LinkKeyInfo[0].LinkKey.Link_Key11 = *(FLASH_ptrC+17);
    LinkKeyInfo[0].LinkKey.Link_Key12 = *(FLASH_ptrC+18);
    LinkKeyInfo[0].LinkKey.Link_Key13 = *(FLASH_ptrC+19);
    LinkKeyInfo[0].LinkKey.Link_Key14 = *(FLASH_ptrC+20);
    LinkKeyInfo[0].LinkKey.Link_Key15 = *(FLASH_ptrC+21);

    SelectedBD_ADDR = LinkKeyInfo[0].BD_ADDR; 

    }

  • I use the following code:

    #define SEGMENT_INFO_A      0x1980
    #define SEGMENT_INFO_B      0x1900
    #define SEGMENT_INFO_C      0x1880
    #define SEGMENT_INFO_D      0x1800
    
    //************************************************************************
    // Write to the Information flash
    //************************************************************************
    void Flash_Write(int address, Byte_t *value, Byte_t length)
    {
       Byte_t *Flash_ptr; // Flash pointer
    
       __disable_interrupt();
    
       Flash_ptr = (Byte_t *)address; // Initialize Flash pointer to 0x1080
    
       FCTL3 = FWKEY; // Clear Lock bit
       FCTL1 = FWKEY + WRT; // Set WRT bit for write operation
    
       while (length > 0)
       {
          //test busy
          while((FCTL3 & BUSY));
    
          //Write to Flash
          *Flash_ptr++ = *value++;
          length--;
       }
    
       while((FCTL3 & BUSY));
    
       FCTL1 = FWKEY; // Clear WRT bit
       FCTL3 = FWKEY + LOCK; // Set LOCK bit
    
       __enable_interrupt();
    }
    
    //*************************************************************************
    // Erase Information Flash
    //*************************************************************************
    void Flash_Erase(int address)
    {
       int *Flash_ptr; // Flash pointer
    
       __disable_interrupt();
    
       Flash_ptr = (int *)address; // Initialize Flash pointer to 0x1980
    
       FCTL1 = FWKEY + ERASE; // Set Erase bit
       FCTL3 = FWKEY; // Clear Lock bit
    
       *Flash_ptr = 0; // Dummy write to erase Flash segment
    
       FCTL3 = FWKEY + LOCK; // Set LOCK bit
    
       __enable_interrupt();
    }
    
    //*************************************************************************
    // Read stored Information flash
    //*************************************************************************
    Byte_t Flash_Read(int address)
    {
       __disable_interrupt();
       Byte_t *Flash_ptr; // Flash pointer
    
       Flash_ptr = (Byte_t *)address; // Initialize flash pointer
       __enable_interrupt();
    
       return *Flash_ptr;
    }
    
    void EraseLinkKey(void)
    {
       Flash_Erase(SEGMENT_INFO_B);
    }
    
    void ReadBluetoothLinkKey(Byte_t length, Byte_t *data)
    {
       int i;
    
       for (i = 0; i < length; i++, data++)
       {
          *data = Flash_Read(SEGMENT_INFO_B + i);
       }
    }
    
    void WriteBluetoothLinkKey(Byte_t length, Byte_t *data)
    {
       Flash_Erase(SEGMENT_INFO_B);
       Flash_Write(SEGMENT_INFO_B, data, length);
    }
    
    void WriteBluetoothDeviceInfo(Byte_t length, Byte_t *data)
    {
       Flash_Erase(SEGMENT_INFO_C);
       Flash_Write(SEGMENT_INFO_C, data, length);
    }
    
    void ReadBluetoothDeviceInfo(Byte_t length, Byte_t *data)
    {
       int i;
    
       for (i = 0; i < length; i++, data++)
       {
          *data = Flash_Read(SEGMENT_INFO_B + i);
       }
    }
    

    To use it is as follows:

    WriteBluetoothLinkKey(sizeof(LinkKeyInfo[Index]), (Byte_t *)&LinkKeyInfo[Index]);

    and

    ReadBluetoothLinkKey(sizeof(link_key), (Byte_t *)&link_key);

  • Daniel,

    Have you figured out these two functions?

    I'm trying to accomplish the same thing and I'm not sure where to store the writekeytoflash() and readkeytoflash(). Part of me wants to keep these inside SPPDemo.c , but I read in e2e.ti.com/.../1229315 that the write to flash would hang inside the GAP eventcallback. So they said they moved it out to the foreground thread... but where? (I don't understand OS very well).

    From looking at this example(e2e.ti.com/.../183178) on how to write/read to flash, I could simply set:

    static LinkKeyInfo_t LinkKeyInfo[MAX_SUPPORTED_LINK_KEYS];
    LinkKeyInfo[0] = 0x1800; //Start of info D

    Then keys will always be written and read from flash...

    Is that not a valid way of writing to flash?
  • Apparently this thread didn't appear until I posted the message above. Sorry. I'll go through the code and see if it'll work for me. Thank you!
  • Barak,

    where do you place the
    WriteBluetoothLinkKey(sizeof(LinkKeyInfo[Index]), (Byte_t *)&LinkKeyInfo[Index]);
    and
    ReadBluetoothLinkKey(sizeof(link_key), (Byte_t *)&link_key);

    in the project? Thanks!
  • Hi,

    Did you find out where to place these functions? I am working on a project that uses OOB. I wanted to know when i should load the Link Key obtained out of band to the LinkKeyInfo_t struct. Sorry for bringing up a very old thread.

    thanks,
    Sooraj

  • Sorry, didn't see the notification about this.
    Pretty sure I just call the ReadBluetoothLinkKey when the unit boots and can open the SPP port - ie it can talk to the BT chip. The WriteBluetoothLinkKey was performed when atLinkKeyCreation event was triggered, although I had to set a flag and do the flash erase/write in foreground code as you cannot block in the callbacks from the stack.