Sending data over bluetooth to a peripheral UART

Greetings Nordic Team,

I am trying to pass data from an application on a dk-nrf52840 to a nrf52840-dongle whose uart is connected to the uart on a microcontroller.
Using the example programs for central_uart and peripheral_uart in nrf connect desktop. everything works fine sending data to and from the respective central and peripheral uarts.
However, I need to send internal data from the application on the dk to the dongles uart (and vice versa). I thought it would be simple enough to just use the
bt_nus_client_send() function, and replace the buf->data and buf->len with my own data. Alas, this only results in an error.

//this is my attempt to use bt_nus_client_send()
char internal_data[UART_BUF_SIZE]={"Jim was here."};
uint16_t length = sizeof(internal_data);
err = bt_nus_client_send(&nus_client, internal_data, length);
if (err) {
LOG_WRN("Fudge! Failed to send data over BLE connection"
"(err %d)", err);
}

//this is the error
<wrn> central_uart: Fudge! Failed to send data over BLE connection(err -128)

//this is the working sample code
for (;;) {
/* Wait indefinitely for data to be sent over Bluetooth */
struct uart_data_t *buf = k_fifo_get(&fifo_uart_rx_data,
K_FOREVER);

err = bt_nus_client_send(&nus_client, buf->data, buf->len);
if (err) {
LOG_WRN("Failed to send data over BLE connection"
"(err %d)", err);
}

err = k_sem_take(&nus_write_sem, NUS_WRITE_TIMEOUT);
if (err) {
LOG_WRN("NUS send timeout");
}
}
any sugestions?

  • Hello,

    Error -128 is the NOT CONNECTED error, which is expected to be returned if you attempt to use the bt_nus_client_send function when you are not in a connection. Could you make sure that you are in a connection when you attempt to send the data, or implement a local error handling routine to handle this specific error?

    Best regards,
    Karl

  • Greetings Karl,

    Thank you for your timely response.
    Thank you for showing a link to all error codes.
    If I force the issue by changing my code to:

    char internal_data[UART_BUF_SIZE]={"Jim was here.\r\n"};
    uint16_t length = sizeof(internal_data);
    printf("Sending %s to dongle\n\r",internal_data);
    do{
    err = bt_nus_client_send(&nus_client, internal_data, length);
    if (err) {
    LOG_WRN("Initial Error# %d", err);
    err = bt_nus_client_send(&nus_client, internal_data, length);
    LOG_WRN("2nd Error# %d", err);
    }
    }while(err);

    I get the following in the debug terminal (this repeats).
    ...
    <wrn> central_uart: Initial Error# -128
    <wrn> central_uart: 2nd Error# -128
    <wrn> central_uart: Initial Error# -128
    <wrn> central_uart: 2nd Error# -128
    <wrn> central_uart: Initial Error# -128
    <wrn> central_uart: 2nd Error# -128
    <wrn> central_uart: Initial Error# -128
    <wrn> central_uart: 2nd Error# -128
    <inf> central_uart: Service discovery completed
    <wrn> central_uart: Initial Error# -128
    <wrn> central_uart: 2nd Error# 0
    <err> os: r0/a1: 0x00000004 r1/a2: 0x00000081 r2/a3: 0x00000001
    <err> os: r3/a4: 0x00020259 r12/ip: 0x00000000 r14/lr: 0x00023f27
    <err> os: xpsr: 0x41000000
    <err> os: Faulting instruction address (r15/pc): 0x0002a800
    <err> os: >>> ZEPHYR FATAL ERROR 4: Kernel panic on CPU 0
    <err> os: Current thread: 0x20001a20 (unknown)
    <err> fatal_error: Resetting system

    So it appears my function gets executed before bluetooth initialization is
    finished. I could work with that.
    The data does get sent to and received by the peripheral
    dongle. YAY!!!
    But then I get a self destruct error causing the system to reset/reboot.

    This is the message I get on the central device console.

    Starting Bluetooth Central UART example
    Sending Jim was here. to dongle

    ASSERTION FAIL [z_spin_lock_valid(l)] @ WEST_TOPDIR/zephyr/include/spinlock.h:129
    Recursive spinlock 0x1079d
    Starting Bluetooth Central UART example
    Sending Jim was here. to dongle

    ASSERTION FAIL [z_spin_lock_valid(l)] @ WEST_TOPDIR/zephyr/include/spinlock.h:129
    Recursive spinlock 0x1079d

    And the cycle repeats ad infinitum.

    Any suggestions for avoiding a fatal error?

  • Hello,

    Jim Ellyson said:
    Thank you for your timely response.
    Thank you for showing a link to all error codes.

    No problem at all, I am happy to help! :) 

    Jim Ellyson said:
    If I force the issue by changing my code to:

    The best approach here depends on the requirements and constraint of your application - i.e if it is just 'spewing' sensor data, and it is not important if some data is lost, or if every piece of data needs to get across the link so long as the link is active. In case of the latter you should instead make sure that you are in a connection before you start sending data, and implement a ring-buffer for storage of any data that is not successfully queued for transmission (whenever the call to bt_nus_client_send fails, for whatever reason) to avoid this data being lost.
    In case of the former, you are a lot more free with regards to the approach, and you could basically just ignore the failure and move on to the next sample.

    The issue with your currently implementation is that your device immediately will get stuck in this infinite while-loop, because there is no telling when you will actually enter into a connection. This is why I would not recommend using a while loop for this, since the bt_nus_client_send can start failing at any time, such as if the connection is suddenly terminated by the peer.
    If you are to keep the current setup I would at the very least add specific error handling, i.e make the different handling specific to the different errors that you expect could be returned. In this case, the handling for the -128 error code could for example be to buffer the attempted data (if necessary) and then stop re-trying to send (since you know this will continue to fail so long as you are not in a connection anymore).

    Best regards,
    Karl

  • Greetings Karl,

    There is no arguing that the do while loop is bad form, but for debugging,
    it did reveal that it takes a second for the physical connection to complete.
    I can just put in a delay to wait a few seconds and then start sending data.
    Now the data is sent to and received by peripheral.
    Is there a function to test for connectedness?
    However, as soon as the data is transmitted over to the peripheral, the
    central unit generates an error causing it to restart.
    Can you tell me what might cause this?

    //my code inserted in the central_uart example just before infinite for loop
    char internal_data[UART_BUF_SIZE]={"Jim was here."};
    uint16_t length = sizeof(internal_data);
    nrf_delay_ms(5000);
    printf("\n\rSending %s to nRF52840 dongle",internal_data);

    err = bt_nus_client_send(&nus_client, internal_data, length);
    if (err) {
    LOG_WRN("Initial Error# %d", err);
    }


    //Debug Terminal Output
    <inf>[00:00:00.006,958] [0m<inf> fs_nvs: alloc wra: 0, fb8
    <inf> fs_nvs: data wra: 0, 88
    <inf> sdc_hci_driver: SoftDevice Controller build revision:
    0e e7 c5 66 67 18 3c ac b3 d2 cc 81 a3 dc f1 c0 |...fg.<. ........
    c0 36 02 22 |.6."
    <inf> bt_hci_core: No ID address. App must call settings_load()
    <inf> central_uart: Bluetooth initialized
    <inf> central_uart: Scan module initialized
    <inf> central_uart: NUS Client module initialized
    <inf> central_uart: Filters matched. Address: DF:FE:3E:E2:44:AE (random) connectable: 0
    <inf> central_uart: Connected: DF:FE:3E:E2:44:AE (random)
    <inf> central_uart: Security changed: DF:FE:3E:E2:44:AE (random) level 2
    <inf> central_uart: MTU exchange done
    <inf> central_uart: Service discovery completed

    <err> os: r0/a1: 0x00000004 r1/a2: 0x00000081 r2/a3: 0x00000001
    <err> os: r3/a4: 0x000202ad r12/ip: 0x00000000 r14/lr: 0x00023f7b
    <err> os: xpsr: 0x41000000
    <err> os: Faulting instruction address (r15/pc): 0x0002a854
    <err> os: >>> ZEPHYR FATAL ERROR 4: Kernel panic on CPU 0
    <err> os: Current thread: 0x20001a20 (unknown)
    <err> fatal_error: Resetting system

  • Hello again, jim-ellyson

    Thank you for your extreme patience with this. I have been out of office for some time, but now I am back.

    Do you still require technical support with this issue?

    To round off the remaining questions from the previous comment:

    Jim Ellyson said:
    I can just put in a delay to wait a few seconds and then start sending data.
    Now the data is sent to and received by peripheral.
    Is there a function to test for connectedness?

    Yes, you can use the connection handle, for instance, to see this - I would recommend this approach rather than waiting for an arbitrary number of seconds, since the connection can take longer for many different reasons.

    Jim Ellyson said:
    However, as soon as the data is transmitted over to the peripheral, the
    central unit generates an error causing it to restart.
    Can you tell me what might cause this?

    It seems to me that it never makes it to the code you have included, could you post more of the relevant code?
    Is the shown lines the only modification you've made to the default central_uart code?

    Best regards,
    Karl

Related