This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Sending a CSV File over ble Gatt connection

Hi,

I need to send data from a CSV file on the nordic board(Via fatfs library). I have presently gotten a Gatt service up and running.

I have a mobile application which, can see the gatt service and write to the characteristics. From a specific write command from the mobile device I want the nordic board to send the CSV file over.

I can presently read a single line of the CSV file formatted like this: (Time stamp, data1, data 2, data3, data 4, data 5).

What I need to implement is:

  • Reading the whole file but, one or multiple lines at a time due to the size of the CSV
  • Changing the read pointer of the SD card (So I know where to continue to read from)
  • Send this data to the characteristic
  • Read this characteristic data.

My code is based upon :  https://github.com/bjornspockeli/custom_ble_service_example

My CSV file size depends on the length of time I have been storing data from. It could be upto around 1-2mbytes. I beleive I need to set up some kind of notification service. Where I read a line(or several) of the SD card, set the GATT characteristic value to this. Then change the SD card pointer. Wait till the data is received by the mobile application. Then repeat until the file is read full.y

Note I am using SDK 16 NRF52840-dk PCA 10056 S140.

This post is similar and mentions using two characteristics one from commication from the mobile app and, one for receiving the data.

https://devzone.nordicsemi.com/f/nordic-q-a/53987/nrf52840-file-transfer-via-ble

Parents
  • Hello,

    So you want to send a CSV file rom the SD card to the connected mobile phone, right?

    If I were you, I would start with the ble_app_uart example, and use ble_nus_data_send() to send your notifications. You can probably do it in the application you have started developing now. Just send the data using notifications.

    I didn't really see any questions in your post. Have you attempted this? Did you get stuck somewhere?

    Best regards,

    Edvin

  • Yes I want to send a CSV file from the SD card on the nordic board to a mobile phone. 

    Is there an example of this?

    I have not used the ble_app_uart example for this. However I do have my own custom service and Gatt connection working. My question is

    • How do I change the pointer location for the SD card?
    • How do I setup the notifications? As in how do I get them to work and change the value to be sent via this notification to the value of the CSV data?

    Also does with ble_app_uart example have a custom service? As I will need to move alot of my functionality too it.

    Also how does ble_nus_data_send work?

    Is there some guidance for how to setup notifications?

    Thanks

  • Yes. It looks like the attr_char_value.max_len is the parameter you want to change. If you look in ble_app_uart, then this is probably the same pointer passed into sd_ble_gatts_characteristic add().

    Try to set NRF_SDH_BLE_GATT_MAX_MTU_SIZE to 247, and also check that you have the gatt_init() and gatt_evt_handler() in your function. Does gatt_evt_handler() get called? If so, check the log output from this function. What does it say?

    Hint: Try to not call sd_ble_gatts_hvx() before the gatt_evt_handler() is called. Basically, you can't send a notification larger than your MTU size, and the MTU isn't updated before you get this callback. Before that, the maximum payload length you can use is 20 (23 - OPCODE_LENGTH - HANDLE_LENGTH = 23 - 1 -2 = 20).

  • When you say have gatt_init() and gatt_evt_handler in my function what do you mean by this?

    I call gatt_init in my main before the main loop runs. I  did add the gatt event handler too.

    I changed the mtu size to 247 and NRF_SDH_BLE_GAP_DATA_LENGTH from 27 to 251. As this is what is done inside the app_uart example.

    Then I programmed it and it crashed. It needed a change in ram start location and ram size.

    Then I run it and it goes but, when I call my function to send 51 bytes of data i get :sd_ble_gatts_hvx result: 3401.

    Ok sorry this is a dug with my android application. So I have a bug where I need to press notify twice for it to send the notification request to the nordic board. Then I can submit my gatt request to send the data. I pressed it twice and I cansee a line of my CSV on my phone!

    The output however is far too long why is this?

    The below image is my application. And the top line is the first of my CSV. The rest is junk and I dont know why nor do i want it. How do I get rid of it?

  • I can't say what your mobile application outputs. Do you send more than one packet from the nRF? Because the app is printing far more than 51 bytes. Did you check what the return message 0x3401 means?

    Hint: Check all the return values found in the description of sd_ble_gatts_hvx(). If you use sdk_16.0.0 this is found in ble_gatts.h line 573-636. Then a short google search reveals threads like this one:

    https://devzone.nordicsemi.com/f/nordic-q-a/17688/ble_error_gatts_sys_attr_missing-from-sd_ble_gatts_hvx

    Although I give you the answer here, please do the exercise, so that you see how you find the cause of these return values.

    Since you print out a lot more than the 51 bytes that you send, I suspect that you just print out random bytes in the RAM in your phone app, and not the actual length of the packet. 

  • I manged to look up and get rid of my error. However, I believe my nordic application is output too much data.

    Below is the nordic nrf connect output and, my code:

    As the NRF connect has too much data as well. I think the nordic board is outputting far too much data. 

    void SEND_CSV()//Send the CSV file
    {
        static uint8_t data_array[BLE_NUS_MAX_DATA_LEN];
        static uint8_t index = 0;
        ret_code_t err_code;
        SD_CARD_Read_Line();//Gets a line of 51bytes of data
        NRF_LOG_INFO("D1: %s\r\n",ble_csv_data);
        
        uint16_t data_length = 0;
        data_length =sizeof(ble_csv_data);
        err_code = ble_cus_send_csv(&m_cus, ble_csv_data,&data_length, m_conn_handle);//Too much data
               
        APP_ERROR_CHECK(err_code);
         
    }

    Update characteristic value

    uint32_t ble_cus_send_csv(ble_cus_t * p_cus, uint8_t   * p_data, uint16_t  * p_length, uint16_t    conn_handle)
    {
        ble_gatts_hvx_params_t hvx_params;
        NRF_LOG_INFO("Sending CSV.\r\n"); 
        if (p_cus == NULL)
        {
            return NRF_ERROR_NULL;
        }
    
        uint32_t err_code = NRF_SUCCESS;
        uint8_t length = 51;
        // Send value if connected and notifying.
        if ((p_cus->conn_handle != BLE_CONN_HANDLE_INVALID)) 
        {
            
            memset(&hvx_params, 0, sizeof(hvx_params));
    
            hvx_params.handle = p_cus->custom_value_handles.value_handle;
            hvx_params.p_data = p_data;
            hvx_params.p_len  = p_length;
            hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
    
            err_code = sd_ble_gatts_hvx(p_cus->conn_handle, &hvx_params);
            NRF_LOG_INFO("sd_ble_gatts_hvx result: %x. \r\n", err_code); 
        }
        else
        {
            err_code = NRF_ERROR_INVALID_STATE;
            NRF_LOG_INFO("sd_ble_gatts_hvx result: NRF_ERROR_INVALID_STATE. \r\n"); 
        }
        return err_code;
    }

    NRF connect output

  • Where do you declare ble_csv_data? Can you show me?

Reply Children
  • Its in another file thats custom called SD_Card.c

    char ble_csv_data[51]={0}; /* Line buffer */

    It prints out to a terminal correctly though.

  • Try to set:

    data_lengt = 51;

    (hardcode it) to see if the length is the issue.

    And where do you call SEND_CSV() from? Do you do it once, or many times?

    If that doesn't give any improvement, compare the data in the nRF Connect for Mobile (your last screenshot) with the data that you are sending. You probably need an ascii table to translate it. Compare the bytes after the ble_csv_data array with the data being sent. Does it look similar?

    I don't know what IDE you are using, so I'll show you for SES. If you are using something else, you can probably find out how you can see it using google.

    As you can see, you can see what's located in the RAM after the array of "helloworld". If that area is used before, it is likely populated, and if the length is incorrectly set, then the data you send will look like jibberish.

    Best regards,

    Edvin

  • Cheers, I do use SES.

    I did set the data length to 51 made no difference. Below is my output

    So the first bits of data are fine but the rest is 0. This is the same for the NRF connect application.

    SEND_CSV is sent once. If i press a specific command on my phone. Which writes gatt data to another characteristic. Then runs in the main loop.

  • So it seems like you do not want to send 51 bytes, then? In this case, it looks like you would only want to send 41 bytes? Perhaps you should try to cut after you see "0D 0A", since each line would end with this?

    I suspect that you read it into the same area each time, so the next time you would call this, and the new line is shorter than the previous one, you probably don't reset this string, and you send the full 51 bytes again, is that correct?

    1st line:

    31 35 38 34 39 36 39 30 36 35 2C 31 38 37 35 26 31 38 34 33 2C 31 38 36 32 2C 31 38 36 32 2C 2D 30 2E 30 32 30 30 30 30 0D 0A 00 00 00 00 00 00 00 00 00

    Then for the argument's sake, let us say that your second line is only: "1,2,3", which would be "31 32 33 0D 0A", then that would not be the case if you send the entire 51 bytes. It would be:

    31 32 33 0D 0A 36 39 30 36 35 2C 31 38 37 35 26 31 38 34 33 2C 31 38 36 32 2C 31 38 36 32 2C 2D 30 2E 30 32 30 30 30 30 0D 0A 00 00 00 00 00 00 00 00 00

    Remember that the softdevice will do exactly what you tell it to do. If you tell it to send 51 bytes from a pointer, it will do that. If you tell it to send 247 bytes from a pointer, it will do that too. You must find out based on your readouts where the line ends, and then send that many bytes.

    BR,

    Edvin

    • Thank you for your response. I do want to send 51 bytes. 
    • You are correct it reads the same data each time as I am just reading the first line of my CSV at the moment for testing purposes.
    • But, where in my code does it say send more than 51 bytes?
    • The data length I send into my ble_cus_send_csv is 51. But this function clearly sends more.
    • Also what do you mean by cut off? I read 51 bytes via my reading CSV function yes this will include commas, and return characters.
    • Or do I need to change this in the sdk_config.h? As NRF_SDH_BLE_GAP_DATA_LENGTH i have set to 251 from 27.

    Also to have only the specified bytes sent aka 51. Do I need:

    blcm_link_ctx_storage_t * const p_link_ctx_storage; /**< Pointer to link context storage with handles of all current connections and its context. */

        ble_nus_client_context_t * p_client;
    
        VERIFY_PARAM_NOT_NULL(p_nus);
    
        err_code = blcm_link_ctx_get(p_nus->p_link_ctx_storage, conn_handle, (void *) &p_client);
        VERIFY_SUCCESS(err_code);

Related