Files

244 lines
8.5 KiB
C

#ifdef __cplusplus
extern "C"
{
#endif
#include "app_config.h"
#include "app_error.h"
#include "sdk_common.h"
#include "ble.h"
#include "ble_srv_common.h"
#include "le_uart_srv.h"
#include "uart_drv.h"
#include "nrf_log.h"
#include "nrf_sdh_ble.h"
#include "FreeRTOS.h"
#include "message_buffer.h"
#include "task.h"
#include <string.h>
#ifdef __cplusplus
}
#endif
#if NRF_MODULE_ENABLED(BLE_UART_SRV)
#define BLE_UUID_UART_SERVICE 0xFFF8 /**< The UUID of the Service. */
#define BLE_UUID_UART_RX_CHAR 0xFFF9 /**< The UUID of the RX Characteristic. */
#define BLE_UUID_UART_TX_CHAR 0xFFFA /**< The UUID of the TX Characteristic. */
#define BLE_UUID_UART_BAUD_CHAR 0xFFFB /**< The UUID of the Baud Characteristic. */
#define BLE_UART_BASE_UUID \
{ \
{ \
0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x00, 0x00, 0x40, 0x6E \
} \
} /**< Used vendor specific UUID. */
#define DEF_BAUD_RATE 115200
typedef struct
{
uint16_t conn_handle;
uint16_t service_handle;
ble_gatts_char_handles_t rx_handle;
ble_gatts_char_handles_t tx_handle;
ble_gatts_char_handles_t baud_handle;
bool tx_notify_enable;
uint8_t rx_buf[BLE_UART_MAX_DATA_LEN];
uint8_t tx_buf[BLE_UART_MAX_DATA_LEN];
uint32_t baudrate;
} ble_uart_context_t;
static ble_uart_context_t ble_uart_context = {
.conn_handle = BLE_CONN_HANDLE_INVALID,
.tx_notify_enable = false,
.baudrate = DEF_BAUD_RATE
};
static void on_connect(ble_evt_t const *p_ble_evt, ble_uart_context_t *p_context)
{
taskENTER_CRITICAL();
p_context->conn_handle = p_ble_evt->evt.common_evt.conn_handle;
taskEXIT_CRITICAL();
}
static void on_disconnect(ble_evt_t const *p_ble_evt, ble_uart_context_t *p_context)
{
taskENTER_CRITICAL();
p_context->conn_handle = BLE_CONN_HANDLE_INVALID;
p_context->tx_notify_enable = false;
taskEXIT_CRITICAL();
}
static void ble_uart_ccc_update(ble_evt_t const *p_ble_evt, ble_uart_context_t *p_context)
{
ble_gatts_evt_write_t const *p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
if (p_evt_write->handle == p_context->tx_handle.cccd_handle)
{
p_context->tx_notify_enable = ble_srv_is_notification_enabled(p_evt_write->data);
NRF_LOG_INFO("data_notify:%s", p_context->tx_notify_enable ? "enable" : "disable");
}
}
static void on_write(ble_evt_t const *p_ble_evt, ble_uart_context_t *p_context)
{
ble_uuid_t uuid = p_ble_evt->evt.gatts_evt.params.write.uuid;
uint16_t handle = p_ble_evt->evt.gatts_evt.params.write.handle;
ble_gatts_evt_write_t const *p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
switch (uuid.uuid)
{
case BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG:
ble_uart_ccc_update(p_ble_evt, p_context);
break;
case BLE_UUID_UART_RX_CHAR:
NRF_LOG_INFO("RX:");
NRF_LOG_HEXDUMP_INFO(p_evt_write->data, p_evt_write->len);
uart_send((void *)p_evt_write->data, p_evt_write->len);
break;
case BLE_UUID_UART_BAUD_CHAR:
NRF_LOG_INFO("BAUD: %d", *(uint32_t *)p_evt_write->data);
uart_set_baud(*(uint32_t *)p_evt_write->data);
break;
default:
break;
}
}
static void on_hvx_tx_complete(ble_evt_t const *p_ble_evt, ble_uart_context_t *p_context)
{
// TODO...
}
static void on_ble_evt_handler(ble_evt_t const *p_ble_evt, void *p_context)
{
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
on_connect(p_ble_evt, p_context);
break;
case BLE_GAP_EVT_DISCONNECTED:
on_disconnect(p_ble_evt, p_context);
break;
case BLE_GATTS_EVT_WRITE:
on_write(p_ble_evt, p_context);
break;
case BLE_GATTS_EVT_HVN_TX_COMPLETE:
on_hvx_tx_complete(p_ble_evt, p_context);
default:
// No implementation needed.
break;
}
}
static ret_code_t add_rx_characteristic(uint16_t uuid, uint8_t uuid_type, ble_uart_context_t *context)
{
ble_add_char_params_t add_char_params;
memset(&add_char_params, 0, sizeof(add_char_params));
add_char_params.uuid = uuid;
add_char_params.uuid_type = uuid_type;
add_char_params.max_len = sizeof(context->rx_buf);
add_char_params.init_len = 0;
add_char_params.p_init_value = (void *)context->rx_buf;
add_char_params.is_var_len = true;
add_char_params.write_access = SEC_OPEN;
add_char_params.char_props.write = 1;
add_char_params.char_props.write_wo_resp = 1;
add_char_params.read_access = SEC_OPEN;
add_char_params.char_props.read = 1;
ret_code_t err_code = characteristic_add(context->service_handle, &add_char_params, &context->rx_handle);
return err_code;
}
static ret_code_t add_tx_characteristic(uint16_t uuid, uint8_t uuid_type, ble_uart_context_t *context)
{
ble_add_char_params_t add_char_params;
memset(&add_char_params, 0, sizeof(add_char_params));
add_char_params.uuid = uuid;
add_char_params.uuid_type = uuid_type;
add_char_params.max_len = sizeof(context->tx_buf);
add_char_params.init_len = 0;
add_char_params.p_init_value = (void *)context->tx_buf;
add_char_params.is_value_user = true;
add_char_params.is_var_len = true;
add_char_params.read_access = SEC_OPEN;
add_char_params.char_props.read = 1;
add_char_params.cccd_write_access = SEC_OPEN;
add_char_params.char_props.notify = 1;
ret_code_t err_code = characteristic_add(context->service_handle, &add_char_params, &context->tx_handle);
return err_code;
}
static ret_code_t add_baud_characteristic(uint16_t uuid, uint8_t uuid_type, ble_uart_context_t *context)
{
ble_add_char_params_t add_char_params;
memset(&add_char_params, 0, sizeof(add_char_params));
add_char_params.uuid = uuid;
add_char_params.uuid_type = uuid_type;
add_char_params.max_len = sizeof(context->baudrate);
add_char_params.init_len = sizeof(context->baudrate);
add_char_params.p_init_value = (void *)&context->baudrate;
add_char_params.is_value_user = true;
add_char_params.is_var_len = false;
add_char_params.write_access = SEC_OPEN;
add_char_params.char_props.write = 1;
add_char_params.read_access = SEC_OPEN;
add_char_params.char_props.read = 1;
ret_code_t err_code = characteristic_add(context->service_handle, &add_char_params, &context->baud_handle);
return err_code;
}
void le_uart_srv_init(void)
{
ret_code_t err_code;
uint8_t uuid_type = 0;
/**@snippet [Adding proprietary Service to the SoftDevice] */
ble_uuid_t ble_uuid = {
.type = BLE_UUID_TYPE_BLE,
.uuid = BLE_UUID_UART_SERVICE,
};
// Add the service.
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
&ble_uuid,
&ble_uart_context.service_handle);
APP_ERROR_CHECK(err_code);
// Add rx char
err_code = add_rx_characteristic(BLE_UUID_UART_RX_CHAR, ble_uuid.type, &ble_uart_context);
APP_ERROR_CHECK(err_code);
// Add tx char
err_code = add_tx_characteristic(BLE_UUID_UART_TX_CHAR, ble_uuid.type, &ble_uart_context);
APP_ERROR_CHECK(err_code);
// Add baud char
err_code = add_baud_characteristic(BLE_UUID_UART_BAUD_CHAR, ble_uuid.type, &ble_uart_context);
APP_ERROR_CHECK(err_code);
// Register a handler for BLE events.
NRF_SDH_BLE_OBSERVER(m_ble_uart_observer, BLE_UART_OBSERVER_PRIO, on_ble_evt_handler, &ble_uart_context);
}
ret_code_t le_uart_notify(uint8_t *p_value, uint16_t len)
{
ble_gatts_hvx_params_t hvx_params = {
.handle = ble_uart_context.tx_handle.value_handle,
.type = BLE_GATT_HVX_NOTIFICATION,
.offset = 0,
.p_len = &len,
.p_data = p_value,
};
return sd_ble_gatts_hvx(ble_uart_context.conn_handle, &hvx_params);
}
#endif