mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-11-04 06:11:06 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			239 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			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);
 | 
						|
}
 |