/********************************** (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; }