Files
microchip-application-bmd38…/app/le_uart_c.c
T
2025-08-15 17:35:51 +08:00

468 lines
14 KiB
C

#ifdef __cplusplus
extern "C"
{
#endif
#include "ble_db_discovery.h"
#include "ble_gattc.h"
#include "ble_srv_common.h"
#include "sdk_config.h"
#include "nrf_ble_gq.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "FreeRTOS.h"
#include "message_buffer.h"
#include "semphr.h"
#include "task.h"
#include "timers.h"
#ifdef __cplusplus
}
#endif
#define MAX_CHAR_CNT 4
extern nrf_ble_gq_t *le_gap_queue(void);
struct le_uart_c_s
{
void (*evt_handler)(ble_evt_t const *p_ble_evt, void *p_context);
uint16_t conn_handle;
uint16_t char_handles[MAX_CHAR_CNT];
TimerHandle_t le_uart_c_cccd_timer;
MessageBufferHandle_t rx_msg;
SemaphoreHandle_t baud_sem;
uint32_t baud_rate;
};
#define UART_TX_HAND_IDX 0
#define UART_RX_HAND_IDX 1
#define UART_BAUD_HAND_IDX 2
typedef struct le_uart_c_s le_uart_c_t;
static le_uart_c_t m_le_uart_c;
static void on_disconnected(le_uart_c_t *p_le_uart_c, ble_evt_t const *p_ble_evt)
{
p_le_uart_c->conn_handle = BLE_CONN_HANDLE_INVALID;
for (int i = 0; i < COUNTOF(p_le_uart_c->char_handles); i++)
{
p_le_uart_c->char_handles[i] = BLE_GATT_HANDLE_INVALID;
}
}
static void on_connected(le_uart_c_t *p_le_uart_c, ble_evt_t const *p_ble_evt)
{
xTimerStart(p_le_uart_c->le_uart_c_cccd_timer, 0);
}
static void on_hvx(le_uart_c_t *p_le_uart_c, ble_evt_t const *p_ble_evt)
{
ble_gattc_evt_hvx_t *hvx = (void *)&p_ble_evt->evt.gattc_evt.params.hvx;
if (p_le_uart_c->rx_msg)
{
taskENTER_CRITICAL();
xMessageBufferSend(p_le_uart_c->rx_msg, (void *)hvx->data, hvx->len, 0);
taskEXIT_CRITICAL();
}
}
static void on_read_rsp(le_uart_c_t *p_le_uart_c, ble_evt_t const *p_ble_evt)
{
uint16_t handle = p_ble_evt->evt.gattc_evt.params.read_rsp.handle;
ble_gattc_evt_read_rsp_t const *p_rsp = &p_ble_evt->evt.gattc_evt.params.read_rsp;
if (handle == p_le_uart_c->char_handles[UART_RX_HAND_IDX])
{
}
else if (handle == p_le_uart_c->char_handles[UART_BAUD_HAND_IDX])
{
xSemaphoreGive(m_le_uart_c.baud_sem);
m_le_uart_c.baud_rate = *(uint32_t *)p_rsp->data;
}
}
ret_code_t le_uart_ccdc_configure(uint16_t conn_handle, uint16_t char_handle, bool notification_enable)
{
if (conn_handle == BLE_CONN_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_PARAM;
}
if (char_handle == BLE_GATT_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_PARAM;
}
NRF_LOG_INFO("Configuring CCCD Handle = 0x%04X, Connection Handle = 0x%04X",
char_handle + 1,
notification_enable);
nrf_ble_gq_req_t cccd_req;
uint16_t cccd_val = notification_enable ? BLE_GATT_HVX_NOTIFICATION : BLE_GATT_HVX_INVALID;
uint8_t cccd[BLE_CCCD_VALUE_LEN];
cccd[0] = LSB_16(cccd_val);
cccd[1] = MSB_16(cccd_val);
memset(&cccd_req, 0, sizeof(nrf_ble_gq_req_t));
cccd_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE;
cccd_req.params.gattc_write.handle = char_handle + 1;
cccd_req.params.gattc_write.len = BLE_CCCD_VALUE_LEN;
cccd_req.params.gattc_write.offset = 0;
cccd_req.params.gattc_write.p_value = cccd;
cccd_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ;
return nrf_ble_gq_item_add(le_gap_queue(), &cccd_req, conn_handle);
}
static void le_uart_c_cccd_timer_cb(TimerHandle_t xTimer)
{
xTimerStop(xTimer, pdMS_TO_TICKS(0));
extern ret_code_t le_uart_rx_notify(bool enable);
le_uart_rx_notify(true);
xMessageBufferReset(m_le_uart_c.rx_msg);
}
static void le_uart_c_evt_handler(ble_evt_t const *p_ble_evt, void *p_context)
{
le_uart_c_t *p_le_uart_c = (le_uart_c_t *)p_context;
if ((p_le_uart_c == NULL) || (p_ble_evt == NULL))
{
return;
}
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_DISCONNECTED:
on_disconnected(p_le_uart_c, p_ble_evt);
break;
case BLE_GAP_EVT_CONNECTED:
on_connected(p_le_uart_c, p_ble_evt);
break;
case BLE_GATTC_EVT_HVX:
/*
Handle Value Notification or Indication event.
Confirm indication with @ref sd_ble_gattc_hv_confirm.
See @ref ble_gattc_evt_hvx_t. */
on_hvx(p_le_uart_c, p_ble_evt);
break;
case BLE_GATTC_EVT_READ_RSP:
/*
Read Response event.
See @ref ble_gattc_evt_read_rsp_t. */
on_read_rsp(p_le_uart_c, p_ble_evt);
break;
case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP:
/*
Primary Service Discovery Response event.
See @ref ble_gattc_evt_prim_srvc_disc_rsp_t. */
break;
case BLE_GATTC_EVT_REL_DISC_RSP:
/*
Relationship Discovery Response event.
See @ref ble_gattc_evt_rel_disc_rsp_t. */
__BKPT(255);
break;
case BLE_GATTC_EVT_CHAR_DISC_RSP:
/*
Characteristic Discovery Response event.
See @ref ble_gattc_evt_char_disc_rsp_t. */
break;
case BLE_GATTC_EVT_DESC_DISC_RSP:
/*
Descriptor Discovery Response event.
See @ref ble_gattc_evt_desc_disc_rsp_t. */
break;
case BLE_GATTC_EVT_ATTR_INFO_DISC_RSP:
/*
Attribute Information Response event.
See @ref ble_gattc_evt_attr_info_disc_rsp_t. */
__BKPT(255);
break;
case BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP:
/*
Read By UUID Response event.
See @ref ble_gattc_evt_char_val_by_uuid_read_rsp_t. */
__BKPT(255);
break;
case BLE_GATTC_EVT_CHAR_VALS_READ_RSP:
/*
Read multiple Response event.
See @ref ble_gattc_evt_char_vals_read_rsp_t. */
__BKPT(255);
break;
case BLE_GATTC_EVT_WRITE_RSP:
/*
Write Response event.
See @ref ble_gattc_evt_write_rsp_t. */
break;
case BLE_GATTC_EVT_EXCHANGE_MTU_RSP:
/*
Exchange MTU Response event.
See @ref ble_gattc_evt_exchange_mtu_rsp_t. */
break;
case BLE_GATTC_EVT_TIMEOUT:
/*
Timeout event.
See @ref ble_gattc_evt_timeout_t. */
__BKPT(255);
break;
case BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE:
/*
Write without Response transmission complete. */
__BKPT(255);
break;
default:
// No implementation needed.
break;
}
}
void le_uart_c_on_db_disc_evt(ble_db_discovery_evt_t *p_evt)
{
ble_gatt_db_char_t *p_chars = p_evt->params.discovered_db.charateristics;
// Check if the service discovery is necessary for the link and if the event handler is present.
if (m_le_uart_c.evt_handler == NULL || m_le_uart_c.conn_handle == p_evt->conn_handle)
{
return;
}
// Check if the uart service was discovered.
if ((p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE) &&
(p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_UART_SERVICE) &&
(p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE))
{
m_le_uart_c.conn_handle = p_evt->conn_handle;
for (int i = 0; i < p_evt->params.discovered_db.char_count; i++)
{
for (int j = 0; j < COUNTOF(m_le_uart_c.char_handles); j++)
{
if (p_chars[i].characteristic.uuid.uuid == BLE_UUID_UART_CHAR(j + 1))
{
m_le_uart_c.char_handles[j] = p_chars[i].characteristic.handle_value;
break;
}
}
}
}
}
static void le_uart_c_error_handler(uint32_t nrf_error, void *p_contex, uint16_t conn_handle)
{
UNUSED_PARAMETER(conn_handle);
__BKPT(255);
}
ret_code_t le_uart_tx(uint8_t const *p_data, uint16_t len)
{
if (m_le_uart_c.conn_handle == BLE_CONN_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_STATE;
}
nrf_ble_gq_req_t gq_req;
memset(&gq_req, 0, sizeof(gq_req));
gq_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE;
gq_req.error_handler.cb = le_uart_c_error_handler;
gq_req.error_handler.p_ctx = &m_le_uart_c;
gq_req.params.gattc_write.handle = m_le_uart_c.char_handles[UART_TX_HAND_IDX];
gq_req.params.gattc_write.p_value = p_data;
gq_req.params.gattc_write.len = len;
gq_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ;
return nrf_ble_gq_item_add(le_gap_queue(), &gq_req, m_le_uart_c.conn_handle);
}
ret_code_t le_uart_rx_notify(bool enable)
{
if (m_le_uart_c.conn_handle == BLE_CONN_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_PARAM;
}
if (m_le_uart_c.char_handles[UART_RX_HAND_IDX] == BLE_GATT_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_PARAM;
}
ret_code_t ret = le_uart_ccdc_configure(m_le_uart_c.conn_handle, m_le_uart_c.char_handles[UART_RX_HAND_IDX], enable);
if (ret == NRF_SUCCESS)
{
NRF_LOG_INFO(enable == true ? "Enable Rx notifications." : "Disable Rx notifications.");
}
return ret;
}
ret_code_t le_uart_rx(uint8_t *p_data, uint16_t len, uint32_t timeout)
{
size_t recv_size = 0;
if (timeout)
{
recv_size = xMessageBufferReceive(m_le_uart_c.rx_msg, p_data, len, timeout);
}
else
{
taskENTER_CRITICAL();
recv_size = xMessageBufferReceive(m_le_uart_c.rx_msg, p_data, len, 0);
taskEXIT_CRITICAL();
}
if (recv_size)
{
return recv_size;
}
return NRF_ERROR_TIMEOUT;
}
ret_code_t le_uart_baudrate_get(uint32_t *baudrate)
{
ret_code_t ret;
if (m_le_uart_c.conn_handle == BLE_CONN_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_STATE;
}
nrf_ble_gq_req_t gq_req;
memset(&gq_req, 0, sizeof(gq_req));
gq_req.type = NRF_BLE_GQ_REQ_GATTC_READ;
gq_req.error_handler.cb = le_uart_c_error_handler;
gq_req.error_handler.p_ctx = &m_le_uart_c;
gq_req.params.gattc_read.handle = m_le_uart_c.char_handles[UART_BAUD_HAND_IDX];
ret = nrf_ble_gq_item_add(le_gap_queue(), &gq_req, m_le_uart_c.conn_handle);
if (ret == NRF_SUCCESS)
{
if (xSemaphoreTake(m_le_uart_c.baud_sem, pdMS_TO_TICKS(100)) == pdFALSE)
{
return NRF_ERROR_TIMEOUT;
}
*baudrate = m_le_uart_c.baud_rate;
}
return ret;
}
ret_code_t le_uart_baudrate_set(uint32_t baudrate)
{
if (m_le_uart_c.conn_handle == BLE_CONN_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_STATE;
}
nrf_ble_gq_req_t gq_req;
memset(&gq_req, 0, sizeof(gq_req));
gq_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE;
gq_req.error_handler.cb = le_uart_c_error_handler;
gq_req.error_handler.p_ctx = &m_le_uart_c;
gq_req.params.gattc_write.handle = m_le_uart_c.char_handles[UART_BAUD_HAND_IDX];
gq_req.params.gattc_write.p_value = (void *)&baudrate;
gq_req.params.gattc_write.len = sizeof(baudrate);
gq_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ;
return nrf_ble_gq_item_add(le_gap_queue(), &gq_req, m_le_uart_c.conn_handle);
}
static void ble_uart_echo(void *p_arg)
{
void le_scan_start(void);
le_scan_start();
vTaskDelay(pdMS_TO_TICKS(3000));
void le_scan_stop(void);
le_scan_stop();
vTaskDelay(pdMS_TO_TICKS(10));
ble_gap_addr_t peer_addr;
peer_addr.addr_id_peer = 0;
peer_addr.addr_type = BLE_GAP_ADDR_TYPE_ANONYMOUS;
peer_addr.addr[0] = 0xDA;
peer_addr.addr[1] = 0x71;
peer_addr.addr[2] = 0x1F;
peer_addr.addr[3] = 0x1F;
peer_addr.addr[4] = 0x05;
peer_addr.addr[5] = 0xDC;
extern void le_scan_get_peer_addr(ble_gap_addr_t * p_peer_addr);
le_scan_get_peer_addr(&peer_addr);
vTaskDelay(pdMS_TO_TICKS(10));
extern void le_gap_connet(ble_gap_addr_t * p_peer_addr);
le_gap_connet(&peer_addr);
vTaskDelay(pdMS_TO_TICKS(1000));
uint32_t get_baud = 1000000;
uint32_t set_baud = 115200;
extern ret_code_t le_uart_baudrate_get(uint32_t * baudrate);
le_uart_baudrate_get(&get_baud);
NRF_LOG_INFO("Get Baud rate: %d", get_baud);
extern ret_code_t le_uart_baudrate_set(uint32_t baudrate);
le_uart_baudrate_set(set_baud);
NRF_LOG_INFO("Set Baud rate: %d", set_baud);
le_uart_baudrate_get(&get_baud);
NRF_LOG_INFO("Get Baud rate: %d", get_baud);
extern ret_code_t le_uart_tx(uint8_t const *p_data, uint16_t len);
uint8_t str[] = "ABCDEF";
le_uart_tx(str, strlen(str));
for (;;)
{
uint8_t recv[256];
uint32_t size;
size = le_uart_rx(recv, sizeof(recv), portMAX_DELAY);
le_uart_tx(recv, size);
}
}
void le_uart_c_init(void)
{
m_le_uart_c.rx_msg = xMessageBufferCreate(4096);
m_le_uart_c.baud_sem = xSemaphoreCreateBinary();
m_le_uart_c.evt_handler = le_uart_c_evt_handler;
m_le_uart_c.conn_handle = BLE_CONN_HANDLE_INVALID;
for (int i = 0; i < COUNTOF(m_le_uart_c.char_handles); i++)
{
m_le_uart_c.char_handles[i] = BLE_GATT_HANDLE_INVALID;
}
ret_code_t err_code;
uint8_t uuid_type;
ble_uuid_t uuid = {
.type = BLE_UUID_TYPE_BLE,
.uuid = BLE_UUID_UART_SERVICE,
};
err_code = ble_db_discovery_evt_register(&uuid);
APP_ERROR_CHECK(err_code);
NRF_SDH_BLE_OBSERVER(m_uart_c_observer, 1, le_uart_c_evt_handler, &m_le_uart_c);
m_le_uart_c.le_uart_c_cccd_timer = xTimerCreate("Timer", pdMS_TO_TICKS(1000), pdTRUE, (void *)1, le_uart_c_cccd_timer_cb);
#if 0
xTaskCreate(ble_uart_echo, "ble uart echo", 2048, NULL, 3, NULL);
#endif
}