BT SPP -> where am I losing bytes?
Posted: Mon Oct 08, 2018 8:21 pm
Hello there
I've recently bought a couple of PicoKits and would like to establish a robust SPP connection which is able to handle at least 1MBaud throughput. Sadly I'm currently nowhere near that and seem to be struggling with losing some bytes in the process... I've tested my application by sending rather large files (~2-3MB) with 115kBaud around and there are always a couple of hundred bytes missing.
The application is rather simple. There is a UART RX task which reads data, puts it into a ringbuffer and sends the ringbuffer handle to a queue. Then there is a BT TX task which receives from that queue, takes the ringbuffer handle, reads the data and writes it with the "esp_spp_write" function.
// UART RX task
// BT TX task
On the "SPP" receiving side I use the ESP_SPP_DATA_IND_EVT event inside my SPP callback and do basically the same thing I did with UART. Putting the data into a ringbuffer and shipping the handle of by queue... This is actually the part I believe is wrong. I'm not sure if I'm supposed to stall the SPP callback in case the buffer or queue blocks? Any suggestions how this could be handled any better?
I guess by now you could probably have guessed how the UART TX task looks, but here it is for completeness. Again it uses the same ringbuffer/queue pattern seen before.
Am I doing something horribly wrong? Is this "ringbuffer/queue" pattern the right one for this task?
I've recently bought a couple of PicoKits and would like to establish a robust SPP connection which is able to handle at least 1MBaud throughput. Sadly I'm currently nowhere near that and seem to be struggling with losing some bytes in the process... I've tested my application by sending rather large files (~2-3MB) with 115kBaud around and there are always a couple of hundred bytes missing.
The application is rather simple. There is a UART RX task which reads data, puts it into a ringbuffer and sends the ringbuffer handle to a queue. Then there is a BT TX task which receives from that queue, takes the ringbuffer handle, reads the data and writes it with the "esp_spp_write" function.
// UART RX task
Code: Select all
static void uart_rx_task(void* pvParameter) {
std::unique_ptr<uint8_t[]> rx{new (std::nothrow) uint8_t[uart_chunk_size]};
for (;;) {
esp_task_wdt_reset();
// Read data from UART
size_t buffered_len{0};
uart_get_buffered_data_len(uart_num, &buffered_len);
if (!buffered_len)
continue;
auto len{uart_read_bytes(
uart_num,
&rx[0],
buffered_len > uart_chunk_size ? uart_chunk_size : buffered_len,
pdMS_TO_TICKS(10))};
if (len <= 0)
continue;
// Send data to ring buffer
while (!xRingbufferSend(uart2bt_buf, &rx[0], len, pdMS_TO_TICKS(10)))
vTaskDelay(pdMS_TO_TICKS(10));
// Send ring buffer handle to queue
while (!xQueueSend(uart2bt_queue, &uart2bt_buf, pdMS_TO_TICKS(10)))
vTaskDelay(pdMS_TO_TICKS(10));
}
}
Code: Select all
static void bt_tx_task(void* pvParameter) {
uint32_t const handle{(uint32_t const)pvParameter};
for (;;) {
esp_task_wdt_reset();
// Receive handle from queue
RingbufHandle_t uart2bt_buf{nullptr};
if (!xQueueReceive(uart2bt_queue, &uart2bt_buf, portMAX_DELAY))
continue;
// Receive data from ring buffer
size_t len{};
vRingbufferGetInfo(uart2bt_buf, nullptr, nullptr, nullptr, &len);
if (!len)
continue;
uint8_t* data{(uint8_t*)xRingbufferReceiveUpTo(
uart2bt_buf, &len, pdMS_TO_TICKS(10), len)};
if (!data)
continue;
// Write data to SPP
esp_spp_write(handle, len, data);
// Return item from ring buffer
vRingbufferReturnItem(uart2bt_buf, (void*)data);
}
}
Code: Select all
...
case ESP_SPP_DATA_IND_EVT:
// Send data to ring buffer
while (!xRingbufferSend(bt2uart_buf,
param->data_ind.data,
param->data_ind.len,
pdMS_TO_TICKS(10)))
vTaskDelay(pdMS_TO_TICKS(10));
// Send ring buffer handle to queue
while (!xQueueSend(bt2uart_queue, &bt2uart_buf, pdMS_TO_TICKS(10)))
vTaskDelay(pdMS_TO_TICKS(10));
...
I guess by now you could probably have guessed how the UART TX task looks, but here it is for completeness. Again it uses the same ringbuffer/queue pattern seen before.
Code: Select all
static void uart_tx_task(void* pvParameter) {
for (;;) {
esp_task_wdt_reset();
// Receive handle from queue
RingbufHandle_t bt2uart_buf{nullptr};
if (!xQueueReceive(bt2uart_queue, &bt2uart_buf, portMAX_DELAY))
continue;
// Receive data from ring buffer
size_t len{};
vRingbufferGetInfo(bt2uart_buf, nullptr, nullptr, nullptr, &len);
if (!len)
continue;
uint8_t* data{(uint8_t*)xRingbufferReceiveUpTo(
bt2uart_buf, &len, pdMS_TO_TICKS(10), len)};
if (!data)
continue;
// Write data to UART
uart_write_bytes(uart_num, (const char*)data, len);
// Return item from ring buffer
vRingbufferReturnItem(bt2uart_buf, (void*)data);
}
}
Am I doing something horribly wrong? Is this "ringbuffer/queue" pattern the right one for this task?