468 lines
14 KiB
C
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
|
|
}
|