Multi-NUS: Sending several messages in a row

Hi,

In my setup I have one central where several peripherals are connected. I'm using the Multi-NUS service to communicate from the central to the peripherals. Here you see a snippet of sending a broadcast to all peripherals. I'm using a single semaphore which will be freed in the on_ble_data_sent(...) callback

K_SEM_DEFINE(ble_send_semaphore, 1, 1);

void ble_connector_t::on_ble_data_sent(bt_nus_client *nus, uint8_t err, const uint8_t *const data, uint16_t len) {
	k_sem_give(&ble_send_semaphore);
}

int ble_connector_t::send_broadcast(uint8_t *data, uint16_t len) {
    int err = 0;
	LOG_INF("BLE broadcast: Length:%d", len);

	const size_t num_nus_conns = bt_conn_ctx_count(&conns_ctx_lib);
	for (size_t i = 0; i < num_nus_conns; i++) {
		const struct bt_conn_ctx *ctx = bt_conn_ctx_get_by_id(&conns_ctx_lib, i);
		if (ctx) {
			struct bt_nus_client *nus_client = (struct bt_nus_client*) ctx->data;
			if (nus_client) {
				err = k_sem_take(&ble_send_semaphore, K_MSEC(5000));
				if(err) {
					LOG_WRN("BLE semaphore timeout, dropping packet (err %d)", err);
				} else {
					err = bt_nus_client_send(nus_client, data, len);
					if (err) {
						LOG_WRN("Failed to send data over BLE connection (err %d)", err);
						k_sem_give(&ble_send_semaphore);
					}
				}
			}
			bt_conn_ctx_release(&conns_ctx_lib, (void *)ctx->data);
		}
	}
	return err;
}

The problem with this is you kinda destroy the performance. You can't send a broadcast to all peripherals in "parallel" because the system waits for each message to be finished (semaphore). If I get rid of the semaphore I can send one broadcast to all peripherals without any problems but if I try to send two broadcast fast in a row, the second one will fail.

I'm wondering how I could improve the performance of this.

  • If I get rid of the semaphore, several messages to the same peripheral will fail, cause there is still a write process ongoing (NUS_C_RX_WRITE_PENDING flag)
  • If I use the semaphore I wait for each message to be finished, although I could send all in "parallel" (if they are for different peripherals).
  • Should I use a semaphore array, one for each peripheral?
  • Is there any other elegant way, maybe a queue for each peripheral, am I missing anything?

My Setup is: NRF52840, Zephyr, NCS 2.5.1 

Thanks for your help,
Phobios

Related