File syn_ble_hci.c¶
File List > ble > syn_ble_hci.c
Go to the documentation of this file
#include "syn_ble_hci.h"
#include <string.h>
#define SYN_BLE_HCI_RX_STATE_TYPE 0U
#define SYN_BLE_HCI_RX_STATE_HDR 1U
#define SYN_BLE_HCI_RX_STATE_PAYLOAD 2U
SYN_Status syn_ble_hci_init(SYN_BLE_HCI *hci, const SYN_BLE_HCI_Config *cfg)
{
if (hci == NULL) {
return SYN_INVALID_PARAM;
}
memset(hci, 0, sizeof(*hci));
if (cfg != NULL) {
hci->cfg = *cfg;
}
hci->rx_state = SYN_BLE_HCI_RX_STATE_TYPE;
return SYN_OK;
}
SYN_Status syn_ble_hci_encode_command(uint16_t opcode, const uint8_t *params, uint8_t param_len,
uint8_t *tx_buf, uint16_t *tx_len)
{
if (tx_buf == NULL || tx_len == NULL) {
return SYN_INVALID_PARAM;
}
if (params == NULL && param_len > 0U) {
return SYN_INVALID_PARAM;
}
tx_buf[0] = SYN_BLE_HCI_PKT_CMD;
tx_buf[1] = (uint8_t)(opcode & 0xFFU);
tx_buf[2] = (uint8_t)((opcode >> 8U) & 0xFFU);
tx_buf[3] = param_len;
if (param_len > 0U) {
memcpy(&tx_buf[4], params, param_len);
}
*tx_len = (uint16_t)(4U + param_len);
return SYN_OK;
}
SYN_Status syn_ble_hci_encode_acl(uint16_t conn_handle, uint8_t pb_flags, uint8_t bc_flags,
const uint8_t *data, uint16_t len, uint8_t *tx_buf,
uint16_t *tx_len)
{
if (tx_buf == NULL || tx_len == NULL || data == NULL) {
return SYN_INVALID_PARAM;
}
uint16_t handle_flags = (uint16_t)((conn_handle & 0x0FFFU) | ((pb_flags & 0x03U) << 12U) |
((bc_flags & 0x03U) << 14U));
tx_buf[0] = SYN_BLE_HCI_PKT_ACL;
tx_buf[1] = (uint8_t)(handle_flags & 0xFFU);
tx_buf[2] = (uint8_t)((handle_flags >> 8U) & 0xFFU);
tx_buf[3] = (uint8_t)(len & 0xFFU);
tx_buf[4] = (uint8_t)((len >> 8U) & 0xFFU);
memcpy(&tx_buf[5], data, len);
*tx_len = (uint16_t)(5U + len);
return SYN_OK;
}
static void parse_and_dispatch(SYN_BLE_HCI *hci)
{
if (hci->rx_pkt_type == SYN_BLE_HCI_PKT_EVT) {
uint8_t evt_code = hci->rx_buf[0];
uint8_t param_len = hci->rx_buf[1];
const uint8_t *payload = &hci->rx_buf[2];
if (evt_code == SYN_BLE_HCI_EVT_CMD_COMPLETE && param_len >= 3U) {
hci->last_cmd_opcode = (uint16_t)(payload[1] | (payload[2] << 8U));
hci->last_cmd_status = (param_len >= 4U) ? payload[3] : 0U;
hci->cmd_pending = false;
} else if (evt_code == SYN_BLE_HCI_EVT_CMD_STATUS && param_len >= 4U) {
hci->last_cmd_status = payload[0];
hci->last_cmd_opcode = (uint16_t)(payload[2] | (payload[3] << 8U));
hci->cmd_pending = false;
}
if (hci->cfg.evt_cb != NULL) {
hci->cfg.evt_cb(hci, evt_code, payload, param_len, hci->cfg.user_data);
}
} else if (hci->rx_pkt_type == SYN_BLE_HCI_PKT_ACL) {
uint16_t handle_flags = (uint16_t)(hci->rx_buf[0] | (hci->rx_buf[1] << 8U));
uint16_t conn_handle = handle_flags & 0x0FFFU;
uint8_t pb_bc_flags = (uint8_t)((handle_flags >> 12U) & 0x0FU);
uint16_t data_len = (uint16_t)(hci->rx_buf[2] | (hci->rx_buf[3] << 8U));
const uint8_t *data = &hci->rx_buf[4];
if (hci->cfg.acl_cb != NULL) {
hci->cfg.acl_cb(hci, conn_handle, pb_bc_flags, data, data_len, hci->cfg.user_data);
}
}
}
SYN_Status syn_ble_hci_rx_byte(SYN_BLE_HCI *hci, uint8_t byte)
{
if (hci == NULL) {
return SYN_INVALID_PARAM;
}
switch (hci->rx_state) {
case SYN_BLE_HCI_RX_STATE_TYPE:
if (byte == SYN_BLE_HCI_PKT_EVT || byte == SYN_BLE_HCI_PKT_ACL) {
hci->rx_pkt_type = byte;
hci->rx_idx = 0;
hci->rx_target_len = (byte == SYN_BLE_HCI_PKT_EVT) ? 2U : 4U;
hci->rx_state = SYN_BLE_HCI_RX_STATE_HDR;
}
break;
case SYN_BLE_HCI_RX_STATE_HDR:
if (hci->rx_idx < sizeof(hci->rx_buf)) {
hci->rx_buf[hci->rx_idx++] = byte;
if (hci->rx_idx >= hci->rx_target_len) {
if (hci->rx_pkt_type == SYN_BLE_HCI_PKT_EVT) {
uint8_t param_len = hci->rx_buf[1];
hci->rx_target_len += param_len;
} else if (hci->rx_pkt_type == SYN_BLE_HCI_PKT_ACL) {
uint16_t data_len = (uint16_t)(hci->rx_buf[2] | (hci->rx_buf[3] << 8U));
hci->rx_target_len += data_len;
}
if (hci->rx_target_len > sizeof(hci->rx_buf)) {
hci->rx_state = SYN_BLE_HCI_RX_STATE_TYPE;
return SYN_ERROR;
}
if (hci->rx_idx >= hci->rx_target_len) {
parse_and_dispatch(hci);
hci->rx_state = SYN_BLE_HCI_RX_STATE_TYPE;
} else {
hci->rx_state = SYN_BLE_HCI_RX_STATE_PAYLOAD;
}
}
} else {
hci->rx_state = SYN_BLE_HCI_RX_STATE_TYPE;
return SYN_ERROR;
}
break;
case SYN_BLE_HCI_RX_STATE_PAYLOAD:
if (hci->rx_idx < sizeof(hci->rx_buf)) {
hci->rx_buf[hci->rx_idx++] = byte;
if (hci->rx_idx >= hci->rx_target_len) {
parse_and_dispatch(hci);
hci->rx_state = SYN_BLE_HCI_RX_STATE_TYPE;
}
} else {
hci->rx_state = SYN_BLE_HCI_RX_STATE_TYPE;
return SYN_ERROR;
}
break;
default:
hci->rx_state = SYN_BLE_HCI_RX_STATE_TYPE;
break;
}
return SYN_OK;
}
SYN_Status syn_ble_hci_rx_buf(SYN_BLE_HCI *hci, const uint8_t *buf, uint16_t len)
{
if (hci == NULL || (buf == NULL && len > 0U)) {
return SYN_INVALID_PARAM;
}
for (uint16_t i = 0U; i < len; i++) {
SYN_Status st = syn_ble_hci_rx_byte(hci, buf[i]);
if (st != SYN_OK) {
return st;
}
}
return SYN_OK;
}