387 lines
8.9 KiB
C
387 lines
8.9 KiB
C
/********************************** (C) COPYRIGHT *******************************
|
|
* File Name : hci_test.c
|
|
* Author : WCH
|
|
* Version : V1.0
|
|
* Date : 2022/06/30
|
|
* Description :
|
|
*********************************************************************************
|
|
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
|
* Attention: This software (modified or not) and binary are used for
|
|
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
|
*******************************************************************************/
|
|
|
|
#include "hci_test.h"
|
|
#include "config.h"
|
|
#include "uart.h"
|
|
|
|
static uint16_t _opcode;
|
|
static uint8_t hci_pool[100];
|
|
static struct simple_buf hci_buffer;
|
|
|
|
struct simple_buf *bt_hci_cmd_complete_create(uint16_t op, uint8_t plen)
|
|
{
|
|
struct simple_buf *buf;
|
|
struct bt_hci_evt_cmd_complete *cc;
|
|
struct bt_hci_evt_hdr *hdr;
|
|
struct bt_hci_pkt_type *pt;
|
|
|
|
buf = simple_buf_create(&hci_buffer, hci_pool, sizeof(hci_pool));
|
|
|
|
pt = simple_buf_add(buf, sizeof(*pt));
|
|
pt->type = BT_HCI_PKT_TYPE_EVT;
|
|
|
|
hdr = simple_buf_add(buf, sizeof(*hdr));
|
|
hdr->evt = BT_HCI_EVT_CMD_COMPLETE;
|
|
hdr->len = sizeof(*cc) + plen;
|
|
|
|
cc = simple_buf_add(buf, sizeof(*cc));
|
|
cc->ncmd = 1U;
|
|
cc->opcode = op;
|
|
|
|
return buf;
|
|
}
|
|
|
|
void *hci_cmd_complete(struct simple_buf **buf, uint8_t plen)
|
|
{
|
|
*buf = bt_hci_cmd_complete_create(_opcode, plen);
|
|
|
|
return simple_buf_add(*buf, plen);
|
|
}
|
|
|
|
struct simple_buf *cmd_complete_status(uint8_t status)
|
|
{
|
|
struct simple_buf *buf;
|
|
struct bt_hci_evt_cc_status *ccst;
|
|
|
|
buf = bt_hci_cmd_complete_create(_opcode, sizeof(*ccst));
|
|
ccst = simple_buf_add(buf, sizeof(*ccst));
|
|
ccst->status = status;
|
|
|
|
return buf;
|
|
}
|
|
|
|
static void reset(struct simple_buf *buf, struct simple_buf **evt)
|
|
{
|
|
if (buf) {
|
|
PRINT("%s:\n", __FUNCTION__);
|
|
*evt = cmd_complete_status(0x00);
|
|
}
|
|
}
|
|
|
|
static void le_rx_test(struct simple_buf *buf, struct simple_buf **evt)
|
|
{
|
|
struct bt_hci_cp_le_rx_test *cmd = (void *)buf->data;
|
|
uint8_t status;
|
|
|
|
PRINT("%s:\n", __FUNCTION__);
|
|
PRINT(" rx channel: %#x\n", cmd->rx_ch);
|
|
|
|
status = API_LE_ReceiverTestCmd((uint8_t *)cmd, BT_HCI_OP_LE_RX_TEST);
|
|
*evt = cmd_complete_status(status);
|
|
}
|
|
|
|
/* Modulation_Index feature is not currently supported */
|
|
static void le_rx_test_v2(struct simple_buf *buf, struct simple_buf **evt)
|
|
{
|
|
struct bt_hci_cp_le_rx_test_v2 *cmd = (void *)buf->data;
|
|
uint8_t status;
|
|
|
|
PRINT("%s:\n", __FUNCTION__);
|
|
PRINT(" rx channel: %#x\n", cmd->rx_ch);
|
|
PRINT(" phy: ");
|
|
switch(cmd->phy) {
|
|
case BT_HCI_LE_RX_PHY_1M:
|
|
PRINT("1M\n");
|
|
break;
|
|
case BT_HCI_LE_RX_PHY_2M:
|
|
PRINT("2M\n");
|
|
break;;
|
|
case BT_HCI_LE_RX_PHY_CODED:
|
|
PRINT("CODED\n");
|
|
break;
|
|
default:
|
|
PRINT("Invalid\n");
|
|
break;
|
|
}
|
|
PRINT(" mod_index: %#x\n", cmd->mod_index);
|
|
|
|
status = API_LE_ReceiverTestCmd((uint8_t *)cmd, BT_HCI_OP_LE_RX_TEST_V2);
|
|
*evt = cmd_complete_status(status);
|
|
}
|
|
|
|
static void le_tx_test(struct simple_buf *buf, struct simple_buf **evt)
|
|
{
|
|
struct bt_hci_cp_le_tx_test *cmd = (void *)buf->data;
|
|
uint8_t status;
|
|
|
|
PRINT("%s:\n", __FUNCTION__);
|
|
PRINT(" tx channel: %#x\n", cmd->tx_ch);
|
|
PRINT(" test data len: %d\n", cmd->test_data_len);
|
|
PRINT(" pkt payload: ");
|
|
switch (cmd->pkt_payload) {
|
|
case BT_HCI_TEST_PKT_PAYLOAD_PRBS9:
|
|
PRINT("PRBS9\n");
|
|
break;
|
|
case BT_HCI_TEST_PKT_PAYLOAD_11110000:
|
|
PRINT("11110000\n");
|
|
break;
|
|
case BT_HCI_TEST_PKT_PAYLOAD_10101010:
|
|
PRINT("10101010\n");
|
|
break;
|
|
case BT_HCI_TEST_PKT_PAYLOAD_PRBS15:
|
|
PRINT("PRBS15\n");
|
|
break;
|
|
case BT_HCI_TEST_PKT_PAYLOAD_11111111:
|
|
PRINT("11111111\n");
|
|
break;
|
|
case BT_HCI_TEST_PKT_PAYLOAD_00000000:
|
|
PRINT("00000000\n");
|
|
break;
|
|
case BT_HCI_TEST_PKT_PAYLOAD_00001111:
|
|
PRINT("00001111\n");
|
|
break;
|
|
case BT_HCI_TEST_PKT_PAYLOAD_01010101:
|
|
PRINT("01010101\n");
|
|
break;
|
|
default:
|
|
PRINT("Invalid\n");
|
|
break;
|
|
}
|
|
|
|
status =API_LE_TransmitterTestCmd((uint8_t *)cmd, BT_HCI_OP_LE_TX_TEST);
|
|
*evt = cmd_complete_status(status);
|
|
}
|
|
|
|
static void le_tx_test_v2(struct simple_buf *buf, struct simple_buf **evt)
|
|
{
|
|
struct bt_hci_cp_le_tx_test_v2 *cmd = (void *)buf->data;
|
|
uint8_t status;
|
|
|
|
PRINT("%s:", __FUNCTION__);
|
|
PRINT(" tx channel: %#x\n", cmd->tx_ch);
|
|
PRINT(" test data len: %d\n", cmd->test_data_len);
|
|
PRINT(" pkt payload: ");
|
|
switch (cmd->pkt_payload) {
|
|
case BT_HCI_TEST_PKT_PAYLOAD_PRBS9:
|
|
PRINT("PRBS9\n");
|
|
break;
|
|
case BT_HCI_TEST_PKT_PAYLOAD_11110000:
|
|
PRINT("11110000\n");
|
|
break;
|
|
case BT_HCI_TEST_PKT_PAYLOAD_10101010:
|
|
PRINT("10101010\n");
|
|
break;
|
|
case BT_HCI_TEST_PKT_PAYLOAD_PRBS15:
|
|
PRINT("PRBS15\n");
|
|
break;
|
|
case BT_HCI_TEST_PKT_PAYLOAD_11111111:
|
|
PRINT("11111111\n");
|
|
break;
|
|
case BT_HCI_TEST_PKT_PAYLOAD_00000000:
|
|
PRINT("00000000\n");
|
|
break;
|
|
case BT_HCI_TEST_PKT_PAYLOAD_00001111:
|
|
PRINT("00001111\n");
|
|
break;
|
|
case BT_HCI_TEST_PKT_PAYLOAD_01010101:
|
|
PRINT("01010101\n");
|
|
break;
|
|
default:
|
|
PRINT("Invalid\n");
|
|
break;
|
|
}
|
|
|
|
PRINT(" phy: ");
|
|
switch(cmd->phy) {
|
|
case BT_HCI_LE_TX_PHY_1M:
|
|
PRINT("1M\n");
|
|
break;
|
|
case BT_HCI_LE_TX_PHY_2M:
|
|
PRINT("2M\n");
|
|
break;;
|
|
case BT_HCI_LE_TX_PHY_CODED_S8:
|
|
PRINT("CODED_S8\n");
|
|
break;
|
|
case BT_HCI_LE_TX_PHY_CODED_S2:
|
|
PRINT("CODED_S2\n");
|
|
break;
|
|
default:
|
|
PRINT("Invalid\n");
|
|
break;
|
|
}
|
|
|
|
status = API_LE_TransmitterTestCmd((uint8_t *)cmd, BT_HCI_OP_LE_TX_TEST_V2);
|
|
*evt = cmd_complete_status(status);
|
|
}
|
|
|
|
static void le_test_end(struct simple_buf *buf, struct simple_buf **evt)
|
|
{
|
|
struct bt_hci_rp_le_test_end *rp;
|
|
uint16_t rx_pkt_count;
|
|
uint8_t status;
|
|
|
|
PRINT("%s:\n", __FUNCTION__);
|
|
|
|
LL_TestEnd((uint8_t *)&rx_pkt_count);
|
|
status = API_LE_TestEndCmd();
|
|
|
|
PRINT(" status: %#x\n", status);
|
|
PRINT(" pkt count: %ld\n", rx_pkt_count);
|
|
|
|
rp = hci_cmd_complete(evt, sizeof(*rp));
|
|
rp->status = status;
|
|
rp->rx_pkt_count = rx_pkt_count;
|
|
}
|
|
|
|
static void le_set_txpower(struct simple_buf *buf, struct simple_buf **evt)
|
|
{
|
|
struct bt_hci_set_txpower *tp = (void *)buf->data;
|
|
uint8_t status;
|
|
|
|
PRINT("%s:\n", __FUNCTION__);
|
|
PRINT(" tx power: %#x\n", tp->tx_power);
|
|
|
|
status = LL_SetTxPowerLevel(tp->tx_power);
|
|
*evt = cmd_complete_status(status);
|
|
}
|
|
|
|
static void le_set_xt32m_tune(struct simple_buf *buf, struct simple_buf **evt)
|
|
{
|
|
struct bt_hci_xt32m_tune *xt = (void *)buf->data;
|
|
uint8_t status;
|
|
|
|
PRINT("%s:\n", __FUNCTION__);
|
|
PRINT(" xt32m tune: %#x\n", xt->xt32m_tune);
|
|
|
|
if(xt->xt32m_tune > 7) {
|
|
*evt = cmd_complete_status(0x12); //Invalid hci comd param
|
|
}
|
|
|
|
OSC->HSE_CAL_CTRL &= ~(0x07<<28);
|
|
OSC->HSE_CAL_CTRL |= xt->xt32m_tune<<28;
|
|
|
|
*evt = cmd_complete_status(0x00);
|
|
}
|
|
|
|
static void le_set_single_carrier(struct simple_buf *buf, struct simple_buf **evt)
|
|
{
|
|
struct bt_hci_single_carrier *sc = (void *)buf->data;
|
|
uint8_t status;
|
|
|
|
PRINT("%s:\n", __FUNCTION__);
|
|
PRINT(" single carrier: %#x\n", sc->single_carrier);
|
|
|
|
status = LL_SingleChannel(sc->single_carrier);
|
|
*evt = cmd_complete_status(status);
|
|
}
|
|
|
|
static int ctrl_bb_cmd_handle(uint16_t ocf, struct simple_buf *cmd,
|
|
struct simple_buf **evt)
|
|
{
|
|
switch (ocf) {
|
|
case BT_OCF(BT_HCI_OP_RESET):
|
|
reset(cmd, evt);
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int controller_cmd_handle(uint16_t ocf, struct simple_buf *cmd,
|
|
struct simple_buf **evt)
|
|
{
|
|
switch (ocf) {
|
|
case BT_OCF(BT_HCI_OP_LE_RX_TEST):
|
|
le_rx_test(cmd, evt);
|
|
break;
|
|
case BT_OCF(BT_HCI_OP_LE_TX_TEST):
|
|
le_tx_test(cmd, evt);
|
|
break;
|
|
case BT_OCF(BT_HCI_OP_LE_RX_TEST_V2):
|
|
le_rx_test_v2(cmd, evt);
|
|
break;
|
|
case BT_OCF(BT_HCI_OP_LE_TX_TEST_V2):
|
|
le_tx_test_v2(cmd, evt);
|
|
break;
|
|
case BT_OCF(BT_HCI_OP_LE_TEST_END):
|
|
le_test_end(cmd, evt);
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int hci_vendor_cmd_handle(uint16_t ocf, struct simple_buf *cmd,
|
|
struct simple_buf **evt)
|
|
{
|
|
switch (ocf)
|
|
{
|
|
case BT_OCF(BT_HCI_SET_TXPOWER):
|
|
le_set_txpower(cmd, evt);
|
|
break;
|
|
case BT_OCF(BT_HCI_XT32M_TUNE):
|
|
le_set_xt32m_tune(cmd, evt);
|
|
break;
|
|
case BT_OCF(BT_HCI_SINGLE_CARRIER):
|
|
le_set_single_carrier(cmd, evt);
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct simple_buf *hci_cmd_handle(struct simple_buf *cmd)
|
|
{
|
|
struct bt_hci_pkt_type *pt;
|
|
struct bt_hci_cmd_hdr *chdr;
|
|
struct simple_buf *evt = NULL;
|
|
uint16_t ocf;
|
|
int err;
|
|
|
|
pt = simple_buf_pull(cmd, sizeof(*pt));
|
|
if(pt->type != BT_HCI_PKT_TYPE_CMD) {
|
|
PRINT("Invalid HCI CMD packet type\n");
|
|
return NULL;
|
|
}
|
|
|
|
if (cmd->len < sizeof(*chdr)) {
|
|
PRINT("No HCI Command header\n");
|
|
return NULL;
|
|
}
|
|
|
|
chdr = simple_buf_pull(cmd, sizeof(*chdr));
|
|
|
|
if (cmd->len < chdr->param_len) {
|
|
PRINT("Invalid HCI CMD packet length\n");
|
|
return NULL;
|
|
}
|
|
|
|
/* store in a global for later CC/CS event creation */
|
|
_opcode = chdr->opcode;
|
|
|
|
ocf = BT_OCF(_opcode);
|
|
|
|
switch (BT_OGF(_opcode)) {
|
|
case BT_OGF_BASEBAND:
|
|
err = ctrl_bb_cmd_handle(ocf, cmd, &evt);
|
|
break;
|
|
case BT_OGF_LE:
|
|
err = controller_cmd_handle(ocf, cmd, &evt);
|
|
break;
|
|
case BT_OGF_VS:
|
|
err = hci_vendor_cmd_handle(ocf, cmd, &evt);
|
|
break;
|
|
default:
|
|
err = -1;
|
|
break;
|
|
}
|
|
|
|
return evt;
|
|
}
|