esp-idf/examples/bluetooth/nimble/bleprph_host_only/main/uart_driver.c

239 lines
6.5 KiB
C

/*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/uart.h"
#include "esp_log.h"
#include "esp_attr.h"
#include "uart_driver.h"
#include "nimble/hci_common.h"
#include "host/ble_hs_mbuf.h"
#define TAG "UART_HCI"
#define UART_NO (1)
#define UART_BUF_SZ (1024)
#define UART_TX_PIN (CONFIG_EXAMPLE_HCI_UART_TX_PIN)
#define UART_RX_PIN (CONFIG_EXAMPLE_HCI_UART_RX_PIN)
#define UART_RTS_PIN (CONFIG_EXAMPLE_HCI_UART_RTS_PIN)
#define UART_CTS_PIN (CONFIG_EXAMPLE_HCI_UART_CTS_PIN)
#define HCI_H4_ACL (0x02)
#define HCI_H4_CMD (0x01)
#define HCI_H4_EVT (0x04)
#define BLE_HCI_EVENT_HDR_LEN (2)
#define BLE_HCI_CMD_HDR_LEN (3)
enum {
UART_RX_TYPE = 0,
UART_RX_LEN,
UART_RX_DATA,
};
enum {
DATA_TYPE_COMMAND = 1,
DATA_TYPE_ACL = 2,
DATA_TYPE_EVENT = 4
};
TaskHandle_t s_rx_task_hdl;
static void IRAM_ATTR hci_uart_rx_task(void *arg)
{
uint8_t buf[1026];
int len_now_read = -1;
uint32_t len_to_read = 1;
uint32_t len_total_read = 0;
uint8_t rx_st = UART_RX_TYPE;
while (1) {
len_now_read = uart_read_bytes(UART_NO, &buf[len_total_read], len_to_read, portMAX_DELAY);
assert(len_now_read == len_to_read);
len_total_read += len_now_read;
switch (rx_st) {
case UART_RX_TYPE: {
assert(buf[0] >= DATA_TYPE_ACL && buf[0] <= DATA_TYPE_EVENT);
if (buf[0] == DATA_TYPE_ACL) {
len_to_read = 4;
} else if (buf[0] == DATA_TYPE_EVENT) {
len_to_read = 2;
} else {
assert(0);
}
rx_st = UART_RX_LEN;
}
break;
case UART_RX_LEN: {
if (buf[0] == DATA_TYPE_ACL) {
len_to_read = buf[3] | (buf[4] << 8);
} else if (buf[0] == DATA_TYPE_EVENT) {
len_to_read = buf[2];
} else {
assert(0);
}
rx_st = UART_RX_DATA;
}
break;
case UART_RX_DATA: {
uint8_t *data = buf;
int rc;
if (data[0] == HCI_H4_EVT) {
uint8_t *evbuf;
int totlen;
totlen = BLE_HCI_EVENT_HDR_LEN + data[2];
assert(totlen <= UINT8_MAX + BLE_HCI_EVENT_HDR_LEN);
if (totlen > MYNEWT_VAL(BLE_TRANSPORT_EVT_SIZE)) {
ESP_LOGE(TAG, "Received HCI data length at host (%d)"
"exceeds maximum configured HCI event buffer size (%d).",
totlen, MYNEWT_VAL(BLE_TRANSPORT_EVT_SIZE));
break;
}
if (data[1] == BLE_HCI_EVCODE_HW_ERROR) {
assert(0);
}
/* Allocate LE Advertising Report Event from lo pool only */
if ((data[1] == BLE_HCI_EVCODE_LE_META) &&
(data[3] == BLE_HCI_LE_SUBEV_ADV_RPT || data[3] == BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) {
evbuf = ble_transport_alloc_evt(1);
/* Skip advertising report if we're out of memory */
if (!evbuf) {
ESP_LOGE(TAG, "No buffers");
break;
}
} else {
evbuf = ble_transport_alloc_evt(0);
assert(evbuf != NULL);
}
memset(evbuf, 0, sizeof * evbuf);
memcpy(evbuf, &data[1], totlen);
rc = ble_transport_to_hs_evt(evbuf);
assert(rc == 0);
} else if (data[0] == HCI_H4_ACL) {
struct os_mbuf *m = NULL;
m = ble_transport_alloc_acl_from_ll();
if (!m) {
ESP_LOGE(TAG, "No buffers");
}
if ((rc = os_mbuf_append(m, &data[1], len_total_read - 1)) != 0) {
ESP_LOGE(TAG, "%s failed to os_mbuf_append; rc = %d", __func__, rc);
os_mbuf_free_chain(m);
return;
}
ble_transport_to_hs_acl(m);
}
rx_st = UART_RX_TYPE;
len_to_read = 1;
len_total_read = 0;
}
break;
default: {
assert(0);
break;
}
}
}
vTaskDelete(NULL);
}
void hci_uart_send(uint8_t *buf, uint16_t len)
{
uint8_t *p = buf;
int len_write = 0;
while (len) {
len_write = uart_write_bytes(UART_NO, p, len);
assert(len_write > 0);
len -= len_write;
p += len_write;
}
}
void
ble_transport_ll_init(void)
{
}
int
ble_transport_to_ll_acl_impl(struct os_mbuf *om)
{
uint8_t buf[OS_MBUF_PKTLEN(om) + 1];
int rc;
buf[0] = HCI_H4_ACL;
rc = ble_hs_mbuf_to_flat(om, buf + 1, OS_MBUF_PKTLEN(om), NULL);
if(rc) {
ESP_LOGE(TAG, "Error copying data %d", rc);
os_mbuf_free_chain(om);
return rc;
}
hci_uart_send(buf, OS_MBUF_PKTLEN(om) + 1);
os_mbuf_free_chain(om);
return 0;
}
int
ble_transport_to_ll_cmd_impl(void *buf)
{
int len = 3 + ((uint8_t *)buf)[2] + 1;
uint8_t data[258];
data[0] = HCI_H4_CMD;
memcpy(data + 1, buf, len - 1);
hci_uart_send(data, len);
ble_transport_free(buf);
return 0;
}
void hci_uart_open(void)
{
uart_config_t uart_config = {
.baud_rate = CONFIG_EXAMPLE_HCI_UART_BAUDRATE,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = CONFIG_EXAMPLE_HCI_UART_FLOW_CTRL,
.source_clk = UART_SCLK_DEFAULT,
};
int intr_alloc_flags = 0;
#if CONFIG_UART_ISR_IN_IRAM
intr_alloc_flags = ESP_INTR_FLAG_IRAM;
#endif
ESP_ERROR_CHECK(uart_driver_install(UART_NO, UART_BUF_SZ * 2, UART_BUF_SZ * 2, 0, NULL, intr_alloc_flags));
ESP_ERROR_CHECK(uart_param_config(UART_NO, &uart_config));
ESP_ERROR_CHECK(uart_set_pin(UART_NO, UART_TX_PIN, UART_RX_PIN, -1, -1));
xTaskCreate(hci_uart_rx_task, "hci_uart_rx_task", 2048, NULL, 12, &s_rx_task_hdl);
}
void hci_uart_close(void)
{
if (s_rx_task_hdl) {
vTaskDelete(s_rx_task_hdl);
}
uart_driver_delete(UART_NO);
}