mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
224 lines
6.0 KiB
C
224 lines
6.0 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 (4)
|
|
#define UART_RX_PIN (5)
|
|
#define UART_RTS_PIN (19)
|
|
#define UART_CTS_PIN (23)
|
|
#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;
|
|
|
|
if (data[0] == HCI_H4_EVT) {
|
|
uint8_t *evbuf;
|
|
int totlen;
|
|
int rc;
|
|
|
|
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");
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
|
|
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);
|
|
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 = 0, // UART_HW_FLOWCTRL_CTS_RTS,
|
|
.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);
|
|
}
|