/** * @file cmd_ble_etf.c * @author XRADIO Bluetooth Team */ /* * Copyright (C) 2019 XRADIO TECHNOLOGY CO., LTD. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * 3. Neither the name of XRADIO TECHNOLOGY CO., LTD. nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * =========================================================================== * * -------------------------- temporary -------------------------------------- * * =========================================================================== */ #ifdef PRJCONF_BLE_ETF #include #include "cmd_util.h" #include "blec.h" #include "driver/chip/hal_wdg.h" #include "kernel/os/os.h" /* 0x01: command, 0x02: acl data, 0x04:event */ #define LE_ETF_HCI_CMD_PCKT 1 #define LE_ETF_HCI_ACL_DATA_PCKT 2 #define LE_ETF_HCI_EVNT_PCKT 4 #define LE_ETF_OP(ogf, ocf) ((ocf) | ((ogf) << 10)) #define LE_ETF_OGF_LE 0x08 #define LE_ETF_OGF_VS 0x3f #define LE_ETF_HCI_OP_LE_TX_TEST LE_ETF_OP(LE_ETF_OGF_LE, 0x001e) #define LE_ETF_HCI_OP_LE_RX_TEST LE_ETF_OP(LE_ETF_OGF_LE, 0x001d) #define LE_ETF_HCI_OP_LE_TEST_END LE_ETF_OP(LE_ETF_OGF_LE, 0x001f) #define LE_ETF_HCI_OP_LE_ENH_RX_TEST LE_ETF_OP(LE_ETF_OGF_LE, 0x0033) #define LE_ETF_HCI_OP_LE_ENH_TX_TEST LE_ETF_OP(LE_ETF_OGF_LE, 0x0034) #define LE_ETF_HCI_SINGLE_TONE_OPEN LE_ETF_OP(LE_ETF_OGF_VS, 0x0043) #define LE_ETF_HCI_SET_TEST_PWR_FEC_OPCODE LE_ETF_OP(LE_ETF_OGF_VS, 0x0044) #define LE_ETF_HCI_READ_RSSI LE_ETF_OP(LE_ETF_OGF_VS, 0x0015) #define LE_ETF_HCI_OP_LE_SET_POWER LE_ETF_OP(LE_ETF_OGF_VS, 0x0303) #define LE_ETF_HCI_OP_LE_SET_POWER_MAX LE_ETF_OP(LE_ETF_OGF_VS, 0x0304) #define LE_ETF_HCI_DBG_RD_MEM_CMD_OPCODE LE_ETF_OP(LE_ETF_OGF_VS, 0x0001) #define LE_ETF_HCI_DBG_WR_MEM_CMD_OPCODE LE_ETF_OP(LE_ETF_OGF_VS, 0x0002) #define CMD_OGF(pckt) (((uint8_t)pckt[1]) >> 2) #define CMD_OCF(pckt) (((((uint16_t)pckt[1])&0x03) << 8)| ((uint16_t)pckt[0])) #define HCI_MAX_EVENT_SIZE 260 #define UINT8_TO_STREAM(p, u8) \ { *(p)++ = (uint8_t)(u8); } #define UINT16_TO_STREAM(p, u16) \ { \ *(p)++ = (uint8_t)(u16); \ *(p)++ = (uint8_t)((u16) >> 8); \ } typedef struct { uint8_t chan; uint8_t payload_len; uint8_t payload_type; uint8_t phy; uint8_t mod_index; uint8_t power_level; uint8_t power; uint8_t hopping_enable; } ble_etf_config; #define BLE_ETF_HCI_CMD_TIMEOUT 2000 #define BLE_ETF_ENABLE_CHECK() \ do { \ if (!ble_etf_enable) { \ CMD_ERR("ble etf not enable\n"); \ return CMD_STATUS_FAIL; \ } \ } while (0) #define HCI_TRACE_PRINTK_MAX_SIZE 128 #define _8_Bit 8 /// 16 bit access types #define _16_Bit 16 /// 32 bit access types #define _32_Bit 32 struct dbg_rd_mem_cmd { ///Start address to read uint32_t start_addr; ///Access size uint8_t type; ///Length to read uint8_t length; }; struct buffer_tag { /// length of buffer uint8_t length; /// data of 128 bytes length uint8_t data[HCI_TRACE_PRINTK_MAX_SIZE]; }; struct dbg_wr_mem_cmd { ///Start address to read uint32_t start_addr; ///Access size uint8_t type; ///buffer structure to return struct buffer_tag buf; }; int etf_blec_hci_c2h(unsigned char hci_type, const unsigned char *buff, unsigned int offset, unsigned int len); int etf_blec_hci_h2c_cb(unsigned char status, const unsigned char *buff, unsigned int offset, unsigned int len); static blec_hci_t ble_hci_hst = { .blec_hci_c2h = etf_blec_hci_c2h, .blec_hci_h2c_cb = etf_blec_hci_h2c_cb, }; static ble_etf_config ble_etf_cfg = { .chan = 0, .payload_len = 37, .payload_type = 0, .phy = 0x01, .mod_index = 0x00, .power_level = 3, .power = 0xff, .hopping_enable = 0, }; OS_Semaphore_t ble_etf_sem; static uint8_t ble_etf_enable; static const char *ble_etf_help = "tx start tx test\n" "tx_stop stop tx test\n" "rx start rx test\n" "rx_stop stop rx test\n" "channel set chan\n" " 0~39 Frequency Range:2402 MHz to 2480 MHz\n" "rate set rate\n" " when tx: 0x01 phy 1M, 0x02 2M, 0x03 coded s=8, 0x04 coded s=2\n" " when rx, 0x01 phy 1M, 0x02 2M, 0x03 coded\n" "payload set payload type\n" " 0x00 Pseudo-Random bit sequence 9\n" " 0x01 Pattern of alternating bits '11110000'\n" " 0x02 Pattern of alternating bits '10101010'\n" " 0x03 Pseudo-Random bit sequence 15\n" " 0x04 Pattern of All '1' bits\n" " 0x05 Pattern of All '0' bits\n" " 0x06 Pattern of alternating bits '00001111'\n" " 0x07 Pattern of alternating bits '0101'\n" "len set payload len\n" " 0~251 Length in bytes of payload data in each packet.\n" "hopping start hopping when tx/rx\n" "hopping_stop stop hopping when tx/rx\n" "power_level set power level\n" " 0~12 power level.\n" "read_mem read mem value,example 0x60110404 4\n" " len must 4times and 0~128.\n" " addr must 4 times.\n" "write_mem write mem value,example 0x60110404 0x00000008\n" " addr must 4 times.\n" "set_channel_fec set test power fec." " pwr_fec must be -128 to 127"; static const char *bt_etf_help = "ble ble cmd, you can use to see cmd\n" "tone start send single tone\n" "tone_stop stop send single tone\n" "connect ble fw init\n" "disconnect ble fw deinit, sys reboot\n"; void ble_etf_hci_printf(uint8_t hci_type, uint8_t *buf, uint16_t len) { switch (hci_type) { case LE_ETF_HCI_CMD_PCKT: printf("C-CMD(ogf 0x%02x, ocf 0x%04x) [%d]\n", CMD_OGF(buf), CMD_OCF(buf), len); break; case LE_ETF_HCI_EVNT_PCKT: printf("C-EVT(ogf 0x%02x, ocf 0x%04x) [%d]\n", (((uint8_t)buf[4]) >> 2), (((((uint16_t)buf[4])&0x03) << 8)| ((uint16_t)buf[3])), len); break; case LE_ETF_HCI_ACL_DATA_PCKT: printf("C-ACL [%d]\n", len); break; default: printf("C-ERR [%d]\n", len); break; } for (uint16_t i = 0; i < len; i++) { printf("%02X ", *(buf + i)); if ((i % 16 == 0) && (i != 0)) printf("\n"); } printf("\n"); } static int cmd_ble_etf_parse_int(const char *value, int min, int max, int *dst) { int val; char *end; val = cmd_strtol(value, &end, 10); if (*end) { CMD_ERR("Invalid number '%s'", value); return -1; } if (val < min || val > max) { CMD_ERR("out of range value %d (%s), range is [%d, %d]\n", val, value, min, max); return -1; } *dst = val; return 0; } void etf_blec_hcic_init(void) { blec_hci_init(&ble_hci_hst); } int etf_blec_hci_h2c_cb(unsigned char status, const unsigned char *buff, unsigned int offset, unsigned int len) { //CMD_DBG("h2c_cb status %d, offset %d, len %d\n", status, offset, len); if (status != 0) { CMD_ERR("fw rx cmd err:%s status %d, offset %d, len %d\n", __func__, status, offset, len); } #if 0 int i = 0; for (i = 0; i < len; i++) { CMD_DBG("%02x ", buff[i]); } CMD_DBG("\n"); #endif return status; } uint32_t read_start_addr; /* Event_code | param_tot_len | num cmd pkt of host to control|opcode | status */ /* 1byte | 1 | 1 | 2 | 1 */ int etf_blec_hci_c2h(unsigned char hci_type, const unsigned char *buff, unsigned int offset, unsigned int len) { int status = 0; uint16_t opcode = 0; int event_status = 0; uint16_t rx_pkt_count = 0; int8_t rssi = 0; int i = 0; int read_mem_len = 0; uint8_t *read_mem_buff; ble_etf_hci_printf(hci_type, (uint8_t *)buff, len); if ((hci_type == LE_ETF_HCI_EVNT_PCKT) && (len >= 6)) { opcode = *((uint16_t *)&buff[3]); event_status = buff[5]; printf("event status %d\n", event_status); switch (opcode) { case LE_ETF_HCI_OP_LE_TEST_END: rx_pkt_count = *((uint16_t *)&buff[6]); printf("rx_pkt_count %u\n", rx_pkt_count); break; case LE_ETF_HCI_READ_RSSI: rssi = (int8_t)buff[6]; printf("rssi %u\n", rssi); break; case LE_ETF_HCI_DBG_RD_MEM_CMD_OPCODE: read_mem_buff = (uint8_t *)&buff[6]; read_mem_len = (uint8_t)buff[1]-4; printf("read len %d\n", read_mem_len); for (i = 0; i < read_mem_len; i += 4) { printf("addr:0x%08x, value:0x%08x\n", (read_start_addr + i), *((uint32_t *)(read_mem_buff + i))); } read_start_addr = 0; default: break; } } else { printf("err: not hci event\n"); } blec_hci_c2h_cb(0, buff, offset, len); OS_SemaphoreRelease(&ble_etf_sem); return status; } #if 0 static int ble_etf_tx(uint8_t chan, uint8_t payload_len, uint8_t payload) { int ret = -1; uint8_t buf[HCI_MAX_EVENT_SIZE]; uint8_t *ptr = buf; uint16_t opcode = LE_ETF_HCI_OP_LE_TX_TEST; uint8_t len = 0x03; uint32_t buff_len = 0; uint32_t buff_offset = 0; uint32_t hci_type = LE_ETF_HCI_CMD_PCKT; uint8_t *buff_start = buf; UINT16_TO_STREAM(ptr, opcode); UINT8_TO_STREAM(ptr, len); UINT8_TO_STREAM(ptr, chan); UINT8_TO_STREAM(ptr, payload_len); UINT8_TO_STREAM(ptr, payload); buff_len = 6; /*acording to up context*/ if (OS_SemaphoreWait(&ble_etf_sem, BLE_ETF_HCI_CMD_TIMEOUT) != OS_OK) { CMD_DBG("sem wait fail\n"); return -1; } ble_etf_hci_printf(hci_type, buff_start, buff_len); ret = blec_hci_h2c(hci_type, buff_start, buff_offset, buff_len); return ret; } static int ble_etf_rx(uint8_t chan) { int ret = -1; uint8_t buf[HCI_MAX_EVENT_SIZE]; uint8_t *ptr = buf; uint16_t opcode = LE_ETF_HCI_OP_LE_RX_TEST; uint8_t len = 0x01; uint32_t buff_len = 0; uint32_t buff_offset = 0; uint32_t hci_type = LE_ETF_HCI_CMD_PCKT; uint8_t *buff_start = buf; UINT16_TO_STREAM(ptr, opcode); UINT8_TO_STREAM(ptr, len); UINT8_TO_STREAM(ptr, chan); buff_len = 4; /*acording to up context*/ if (OS_SemaphoreWait(&ble_etf_sem, BLE_ETF_HCI_CMD_TIMEOUT) != OS_OK) { CMD_DBG("sem wait fail\n"); return -1; } ble_etf_hci_printf(hci_type, buff_start, buff_len); ret = blec_hci_h2c(hci_type, buff_start, buff_offset, buff_len); return ret; } #endif static int ble_etf_tx_rx_stop(void) { int ret; uint8_t buf[HCI_MAX_EVENT_SIZE]; uint8_t *ptr = buf; uint16_t opcode = LE_ETF_HCI_OP_LE_TEST_END; uint8_t len = 0x00; uint32_t buff_len = 0; uint32_t buff_offset = 0; uint32_t hci_type = LE_ETF_HCI_CMD_PCKT; uint8_t *buff_start = buf; UINT16_TO_STREAM(ptr, opcode); UINT8_TO_STREAM(ptr, len); buff_len = 3; /*acording to up context*/ if (OS_SemaphoreWait(&ble_etf_sem, BLE_ETF_HCI_CMD_TIMEOUT) != OS_OK) { CMD_DBG("sem wait fail\n"); return -1; } ble_etf_hci_printf(hci_type, buff_start, buff_len); ret = blec_hci_h2c(hci_type, buff_start, buff_offset, buff_len); return ret; } static int ble_etf_enhanced_tx(uint8_t chan, uint8_t payload_len, uint8_t payload_type, uint8_t phy) { int ret = -1; uint8_t buf[HCI_MAX_EVENT_SIZE]; uint8_t *ptr = buf; uint16_t opcode = LE_ETF_HCI_OP_LE_ENH_TX_TEST; uint8_t len = 0x04; uint32_t buff_len = 0; uint32_t buff_offset = 0; uint32_t hci_type = LE_ETF_HCI_CMD_PCKT; uint8_t *buff_start = buf; UINT16_TO_STREAM(ptr, opcode); UINT8_TO_STREAM(ptr, len); UINT8_TO_STREAM(ptr, chan); UINT8_TO_STREAM(ptr, payload_len); UINT8_TO_STREAM(ptr, payload_type); UINT8_TO_STREAM(ptr, phy); buff_len = 7; /*acording to up context*/ ble_etf_hci_printf(hci_type, buff_start, buff_len); if (OS_SemaphoreWait(&ble_etf_sem, BLE_ETF_HCI_CMD_TIMEOUT) != OS_OK) { CMD_DBG("sem wait fail\n"); return -1; } ret = blec_hci_h2c(hci_type, buff_start, buff_offset, buff_len); return ret; } static int ble_etf_enhanced_rx(uint8_t chan, uint8_t phy, uint8_t mod_index) { int ret = -1; uint8_t buf[HCI_MAX_EVENT_SIZE]; uint8_t *ptr = buf; uint16_t opcode = LE_ETF_HCI_OP_LE_ENH_RX_TEST; uint8_t len = 0x03; uint32_t buff_len = 0; uint32_t buff_offset = 0; uint32_t hci_type = LE_ETF_HCI_CMD_PCKT; uint8_t *buff_start = buf; if (phy == 0x04) { phy = 0x03; } UINT16_TO_STREAM(ptr, opcode); UINT8_TO_STREAM(ptr, len); UINT8_TO_STREAM(ptr, chan); UINT8_TO_STREAM(ptr, phy); UINT8_TO_STREAM(ptr, mod_index); /* fw no use*/ buff_len = 6; /*acording to up context*/ if (OS_SemaphoreWait(&ble_etf_sem, BLE_ETF_HCI_CMD_TIMEOUT) != OS_OK) { CMD_DBG("sem wait fail\n"); return -1; } ble_etf_hci_printf(hci_type, buff_start, buff_len); ret = blec_hci_h2c(hci_type, buff_start, buff_offset, buff_len); return ret; } static int ble_etf_stone(uint8_t chan) { int ret = -1; uint8_t buf[HCI_MAX_EVENT_SIZE]; uint8_t *ptr = buf; uint16_t opcode = LE_ETF_HCI_SINGLE_TONE_OPEN; uint8_t len = 0x03; uint8_t open = 0x01; uint8_t power = 0x01; /* power param no use*/ uint32_t buff_len = 0; uint32_t buff_offset = 0; uint32_t hci_type = LE_ETF_HCI_CMD_PCKT; uint8_t *buff_start = buf; UINT16_TO_STREAM(ptr, opcode); UINT8_TO_STREAM(ptr, len); UINT8_TO_STREAM(ptr, open); UINT8_TO_STREAM(ptr, chan); UINT8_TO_STREAM(ptr, power); buff_len = 6; /*acording to up context*/ if (OS_SemaphoreWait(&ble_etf_sem, BLE_ETF_HCI_CMD_TIMEOUT) != OS_OK) { CMD_DBG("sem wait fail\n"); return -1; } ble_etf_hci_printf(hci_type, buff_start, buff_len); ret = blec_hci_h2c(hci_type, buff_start, buff_offset, buff_len); return ret; } static int ble_etf_stone_stop(void) { int ret = -1; uint8_t buf[HCI_MAX_EVENT_SIZE]; uint8_t *ptr = buf; uint16_t opcode = LE_ETF_HCI_SINGLE_TONE_OPEN; uint8_t len = 0x01; uint8_t open = 0x00; uint32_t buff_len = 0; uint32_t buff_offset = 0; uint32_t hci_type = LE_ETF_HCI_CMD_PCKT; uint8_t *buff_start = buf; UINT16_TO_STREAM(ptr, opcode); UINT8_TO_STREAM(ptr, len); UINT8_TO_STREAM(ptr, open); buff_len = 4; /*acording to up context*/ if (OS_SemaphoreWait(&ble_etf_sem, BLE_ETF_HCI_CMD_TIMEOUT) != OS_OK) { CMD_DBG("sem wait fail\n"); return -1; } ble_etf_hci_printf(hci_type, buff_start, buff_len); ret = blec_hci_h2c(hci_type, buff_start, buff_offset, buff_len); return ret; } static int ble_etf_set_pwr_fec(int8_t pwr_fec_ch0, int8_t pwr_fec_ch20, int8_t pwr_fec_ch39) { int ret = -1; uint8_t buf[HCI_MAX_EVENT_SIZE]; uint8_t *ptr = buf; uint16_t opcode = LE_ETF_HCI_SET_TEST_PWR_FEC_OPCODE; uint8_t len = 0x03; uint32_t buff_len = 0; uint32_t buff_offset = 0; uint32_t hci_type = LE_ETF_HCI_CMD_PCKT; uint8_t *buff_start = buf; UINT16_TO_STREAM(ptr, opcode); UINT8_TO_STREAM(ptr, len); UINT8_TO_STREAM(ptr, (uint8_t)pwr_fec_ch0); UINT8_TO_STREAM(ptr, (uint8_t)pwr_fec_ch20); UINT8_TO_STREAM(ptr, (uint8_t)pwr_fec_ch39); buff_len = 6; /*acording to up context*/ ble_etf_hci_printf(hci_type, buff_start, buff_len); if (OS_SemaphoreWait(&ble_etf_sem, BLE_ETF_HCI_CMD_TIMEOUT) != OS_OK) { CMD_DBG("sem wait fail\n"); return -1; } ret = blec_hci_h2c(hci_type, buff_start, buff_offset, buff_len); return ret; } static int ble_etf_get_rssi(void) { int ret; uint8_t buf[HCI_MAX_EVENT_SIZE]; uint8_t *ptr = buf; uint16_t opcode = LE_ETF_HCI_READ_RSSI; uint8_t len = 0x00; uint32_t buff_len = 0; uint32_t buff_offset = 0; uint32_t hci_type = LE_ETF_HCI_CMD_PCKT; uint8_t *buff_start = buf; UINT16_TO_STREAM(ptr, opcode); UINT8_TO_STREAM(ptr, len); buff_len = 3; /*acording to up context*/ if (OS_SemaphoreWait(&ble_etf_sem, BLE_ETF_HCI_CMD_TIMEOUT) != OS_OK) { CMD_DBG("sem wait fail\n"); return -1; } ble_etf_hci_printf(hci_type, buff_start, buff_len); ret = blec_hci_h2c(hci_type, buff_start, buff_offset, buff_len); return ret; } static int ble_etf_set_power(uint8_t power) { int ret = -1; uint8_t buf[HCI_MAX_EVENT_SIZE]; uint8_t *ptr = buf; uint16_t opcode = LE_ETF_HCI_OP_LE_SET_POWER; uint8_t len = 0x01; uint32_t buff_len = 0; uint32_t buff_offset = 0; uint32_t hci_type = LE_ETF_HCI_CMD_PCKT; uint8_t *buff_start = buf; UINT16_TO_STREAM(ptr, opcode); UINT8_TO_STREAM(ptr, len); UINT8_TO_STREAM(ptr, power); buff_len = 4; /*acording to up context*/ if (OS_SemaphoreWait(&ble_etf_sem, BLE_ETF_HCI_CMD_TIMEOUT) != OS_OK) { CMD_DBG("sem wait fail\n"); return -1; } ble_etf_hci_printf(hci_type, buff_start, buff_len); ret = blec_hci_h2c(hci_type, buff_start, buff_offset, buff_len); return ret; } static int ble_etf_set_power_max(uint8_t power) { int ret = -1; uint8_t buf[HCI_MAX_EVENT_SIZE]; uint8_t *ptr = buf; uint16_t opcode = LE_ETF_HCI_OP_LE_SET_POWER_MAX; uint8_t len = 0x01; uint32_t buff_len = 0; uint32_t buff_offset = 0; uint32_t hci_type = LE_ETF_HCI_CMD_PCKT; uint8_t *buff_start = buf; UINT16_TO_STREAM(ptr, opcode); UINT8_TO_STREAM(ptr, len); UINT8_TO_STREAM(ptr, power); buff_len = 4; /*acording to up context*/ if (OS_SemaphoreWait(&ble_etf_sem, BLE_ETF_HCI_CMD_TIMEOUT) != OS_OK) { CMD_DBG("sem wait fail\n"); return -1; } ble_etf_hci_printf(hci_type, buff_start, buff_len); ret = blec_hci_h2c(hci_type, buff_start, buff_offset, buff_len); return ret; } static int ble_etf_read_mem(uint32_t start_addr, uint32_t read_len) { int ret = -1; uint8_t buf[HCI_MAX_EVENT_SIZE]; uint8_t *ptr = buf; uint16_t opcode = LE_ETF_HCI_DBG_RD_MEM_CMD_OPCODE; uint8_t len = 0; struct dbg_rd_mem_cmd param; read_start_addr = start_addr; param.start_addr = start_addr; param.type = _32_Bit; param.length = read_len; uint32_t buff_len = 0; uint32_t buff_offset = 0; uint32_t hci_type = LE_ETF_HCI_CMD_PCKT; uint8_t *buff_start = buf; UINT16_TO_STREAM(ptr, opcode); len = sizeof(struct dbg_rd_mem_cmd); UINT8_TO_STREAM(ptr, len); memcpy(ptr, ¶m, sizeof(struct dbg_rd_mem_cmd)); buff_len = 2 + 1 + sizeof(struct dbg_rd_mem_cmd); /*acording to up context*/ if (OS_SemaphoreWait(&ble_etf_sem, BLE_ETF_HCI_CMD_TIMEOUT) != OS_OK) { CMD_DBG("sem wait fail\n"); read_start_addr = 0; return -1; } ble_etf_hci_printf(hci_type, buff_start, buff_len); ret = blec_hci_h2c(hci_type, buff_start, buff_offset, buff_len); return ret; } static int ble_etf_write_mem(uint32_t start_addr, uint32_t value) { int ret = -1; uint8_t buf[HCI_MAX_EVENT_SIZE]; uint8_t *ptr = buf; uint16_t opcode = LE_ETF_HCI_DBG_WR_MEM_CMD_OPCODE; uint8_t len = 0; struct dbg_wr_mem_cmd param; param.start_addr = start_addr; param.type = _32_Bit; param.buf.length = 4; memset(param.buf.data, 0, HCI_TRACE_PRINTK_MAX_SIZE); *((uint32_t *)(¶m.buf.data[0])) = value; uint32_t buff_len = 0; uint32_t buff_offset = 0; uint32_t hci_type = LE_ETF_HCI_CMD_PCKT; uint8_t *buff_start = buf; UINT16_TO_STREAM(ptr, opcode); len = sizeof(struct dbg_wr_mem_cmd); UINT8_TO_STREAM(ptr, len); memcpy(ptr, ¶m, sizeof(struct dbg_wr_mem_cmd)); buff_len = 2 + 1 + sizeof(struct dbg_wr_mem_cmd); /*acording to up context*/ if (OS_SemaphoreWait(&ble_etf_sem, BLE_ETF_HCI_CMD_TIMEOUT) != OS_OK) { CMD_DBG("sem wait fail\n"); read_start_addr = 0; return -1; } ble_etf_hci_printf(hci_type, buff_start, param.buf.length); ret = blec_hci_h2c(hci_type, buff_start, buff_offset, buff_len); return ret; } static enum cmd_status cmd_ble_etf_tx_exec(char *cmd) { int ret = 0; BLE_ETF_ENABLE_CHECK(); ret = ble_etf_enhanced_tx(ble_etf_cfg.chan, ble_etf_cfg.payload_len, ble_etf_cfg.payload_type, ble_etf_cfg.phy); return (ret == 0) ? CMD_STATUS_OK : CMD_STATUS_FAIL; } static enum cmd_status cmd_ble_etf_tx_stop_exec(char *cmd) { int ret = 0; BLE_ETF_ENABLE_CHECK(); ret = ble_etf_tx_rx_stop(); return (ret == 0) ? CMD_STATUS_OK : CMD_STATUS_FAIL; } static enum cmd_status cmd_ble_etf_rx_exec(char *cmd) { int ret = 0; BLE_ETF_ENABLE_CHECK(); ret = ble_etf_enhanced_rx(ble_etf_cfg.chan, ble_etf_cfg.phy, 00); return (ret == 0) ? CMD_STATUS_OK : CMD_STATUS_FAIL; } static enum cmd_status cmd_ble_etf_rx_stop_exec(char *cmd) { int ret = 0; BLE_ETF_ENABLE_CHECK(); ble_etf_get_rssi(); ret = ble_etf_tx_rx_stop(); return (ret == 0) ? CMD_STATUS_OK : CMD_STATUS_FAIL; } static enum cmd_status cmd_ble_etf_set_chan_exec(char *cmd) { int ret = 0; int chan; BLE_ETF_ENABLE_CHECK(); ret = cmd_ble_etf_parse_int(cmd, 0, 39, &chan); if (ret == 0) { ble_etf_cfg.chan = chan; } return (ret == 0) ? CMD_STATUS_OK : CMD_STATUS_FAIL; } static enum cmd_status cmd_ble_etf_set_rate_exec(char *cmd) { int ret = 0; BLE_ETF_ENABLE_CHECK(); if (cmd_strcmp(cmd, "1M") == 0) { ble_etf_cfg.phy = 0x01; } else if (cmd_strcmp(cmd, "2M") == 0) { ble_etf_cfg.phy = 0x02; } else if (cmd_strcmp(cmd, "S8") == 0) { ble_etf_cfg.phy = 0x03; } else if (cmd_strcmp(cmd, "S2") == 0) { ble_etf_cfg.phy = 0x04; } else { if (cmd) { CMD_ERR("err:not support rate %s\n", cmd); } } return (ret == 0) ? CMD_STATUS_OK : CMD_STATUS_FAIL; } static enum cmd_status cmd_ble_etf_set_payload_exec(char *cmd) { int ret = 0; int payload; BLE_ETF_ENABLE_CHECK(); ret = cmd_ble_etf_parse_int(cmd, 0, 7, &payload); if (ret == 0) { ble_etf_cfg.payload_type = payload; } return (ret == 0) ? CMD_STATUS_OK : CMD_STATUS_FAIL; } static enum cmd_status cmd_ble_etf_set_payload_len_exec(char *cmd) { int ret = 0; int payload_len; BLE_ETF_ENABLE_CHECK(); ret = cmd_ble_etf_parse_int(cmd, 0, 251, &payload_len); if (ret == 0) { ble_etf_cfg.payload_len = payload_len; } return (ret == 0) ? CMD_STATUS_OK : CMD_STATUS_FAIL; } static OS_Thread_t g_hopping_thread; #define THREAD_STACK_SIZE (1 * 1024) uint8_t hopping_run_flag; HAL_Status HAL_PRNG_Generate(uint8_t *random, uint32_t size); static void hopping_task(void *arg) { uint8_t random_value = 0; uint8_t chan = 1; while (hopping_run_flag) { if (HAL_PRNG_Generate(&random_value, 1) == HAL_OK) { chan = random_value % 40; } else { CMD_DBG("get random value err\n"); } ble_etf_tx_rx_stop(); OS_MSleep(10); ble_etf_enhanced_tx(chan, ble_etf_cfg.payload_len, ble_etf_cfg.payload_type, ble_etf_cfg.phy); OS_MSleep(50); } OS_ThreadDelete(&g_hopping_thread); } static enum cmd_status cmd_ble_etf_hopping_exec(char *cmd) { int ret = 0; BLE_ETF_ENABLE_CHECK(); hopping_run_flag = 1; if (OS_ThreadCreate(&g_hopping_thread, "hopping", hopping_task, NULL, OS_THREAD_PRIO_APP, THREAD_STACK_SIZE) != OS_OK) { CMD_ERR("create ak thread failed\n"); ret = -1; } return (ret == 0) ? CMD_STATUS_OK : CMD_STATUS_FAIL; } static enum cmd_status cmd_ble_etf_hopping_stop_exec(char *cmd) { int ret = 0; BLE_ETF_ENABLE_CHECK(); hopping_run_flag = 0; OS_MSleep(50); ble_etf_tx_rx_stop(); return (ret == 0) ? CMD_STATUS_OK : CMD_STATUS_FAIL; } static enum cmd_status cmd_ble_etf_set_power_exec(char *cmd) { int ret = 0; int power_level; BLE_ETF_ENABLE_CHECK(); ret = cmd_ble_etf_parse_int(cmd, 0, 12, &power_level); if (ret == 0) { ret = ble_etf_set_power(power_level); if (ret == 0) ble_etf_cfg.power_level = power_level; } return (ret == 0) ? CMD_STATUS_OK : CMD_STATUS_FAIL; } static enum cmd_status cmd_ble_etf_set_power_max_value_exec(char *cmd) { int ret = 0; int power; BLE_ETF_ENABLE_CHECK(); ret = cmd_ble_etf_parse_int(cmd, 0, 255, &power); if (ret == 0) { ret = ble_etf_set_power_max(power); if (ret == 0) ble_etf_cfg.power = power; } return (ret == 0) ? CMD_STATUS_OK : CMD_STATUS_FAIL; } static enum cmd_status cmd_ble_etf_tone_exec(char *cmd) { int ret = 0; BLE_ETF_ENABLE_CHECK(); ret = ble_etf_stone(ble_etf_cfg.chan); return (ret == 0) ? CMD_STATUS_OK : CMD_STATUS_FAIL; } static enum cmd_status cmd_ble_etf_tone_stop_exec(char *cmd) { int ret = 0; BLE_ETF_ENABLE_CHECK(); ret = ble_etf_stone_stop(); return (ret == 0) ? CMD_STATUS_OK : CMD_STATUS_FAIL; } static enum cmd_status cmd_ble_etf_read_mem_exec(char *cmd) { int ret = 0; int32_t cnt; uint32_t addr; int len; cnt = cmd_sscanf(cmd, "0x%x %d", &addr, &len); if (cnt != 2) { CMD_ERR("example: 0x10 0x10\n"); return CMD_STATUS_INVALID_ARG; } if (addr % 4 != 0) { CMD_ERR("addr must be 4 byte align\n"); return CMD_STATUS_INVALID_ARG; } if ((len % 4 != 0) || (len <= 0) || (len > 128)) { CMD_ERR("len must be 4 times and 0~128\n"); return CMD_STATUS_INVALID_ARG; } BLE_ETF_ENABLE_CHECK(); ret = ble_etf_read_mem(addr, len); return (ret == 0) ? CMD_STATUS_OK : CMD_STATUS_FAIL; } static enum cmd_status cmd_ble_etf_write_mem_exec(char *cmd) { int ret = 0; int32_t cnt; uint32_t addr; uint32_t value; cnt = cmd_sscanf(cmd, "0x%x 0x%x", &addr, &value); if (cnt != 2) { CMD_ERR("example: 0x10 0x10\n"); return CMD_STATUS_INVALID_ARG; } if (addr % 4 != 0) { CMD_ERR("addr must be 4 byte align\n"); return CMD_STATUS_INVALID_ARG; } BLE_ETF_ENABLE_CHECK(); ret = ble_etf_write_mem(addr, value); return (ret == 0) ? CMD_STATUS_OK : CMD_STATUS_FAIL; } static enum cmd_status cmd_ble_etf_set_channel_fec_exec(char *cmd) { int ret = 0; int32_t cnt; int32_t pwr_fec_ch0; int32_t pwr_fec_ch20; int32_t pwr_fec_ch39; cnt = cmd_sscanf(cmd, "%d %d %d", &pwr_fec_ch0, &pwr_fec_ch20, &pwr_fec_ch39); if (cnt != 3) { CMD_ERR("example: -8 12 16\n"); return CMD_STATUS_INVALID_ARG; } if ((pwr_fec_ch0 < -128 || pwr_fec_ch0 > 127) || (pwr_fec_ch20 < -128 || pwr_fec_ch20 > 127) || (pwr_fec_ch39 < -128 || pwr_fec_ch39 > 127)) { CMD_ERR("value must be form -128 to 127\n"); return CMD_STATUS_INVALID_ARG; } BLE_ETF_ENABLE_CHECK(); ret = ble_etf_set_pwr_fec(pwr_fec_ch0, pwr_fec_ch20, pwr_fec_ch39); return (ret == 0) ? CMD_STATUS_OK : CMD_STATUS_FAIL; } static enum cmd_status cmd_bt_etf_help_exec(char *cmd) { printf("%s\n", bt_etf_help); return CMD_STATUS_OK; } static enum cmd_status cmd_ble_etf_help_exec(char *cmd) { printf("%s\n", ble_etf_help); return CMD_STATUS_OK; } static enum cmd_status cmd_ble_etf_connect_exec(char *cmd) { int ret = 0; if (OS_SemaphoreCreate(&ble_etf_sem, 1, 1) != OS_OK) { CMD_DBG("sem create fail\n"); ret = -1; } blec_init(); etf_blec_hcic_init(); ble_etf_enable = 1; return (ret == 0) ? CMD_STATUS_OK : CMD_STATUS_FAIL; } static enum cmd_status cmd_ble_etf_disconnect_exec(char *cmd) { BLE_ETF_ENABLE_CHECK(); OS_SemaphoreDelete(&ble_etf_sem); ble_etf_enable = 0; blec_hci_deinit(); blec_deinit(); return CMD_STATUS_OK; } static const struct cmd_data g_ble_etf_cmds[] = { { "tx", cmd_ble_etf_tx_exec }, { "tx_stop", cmd_ble_etf_tx_stop_exec }, { "rx", cmd_ble_etf_rx_exec }, { "rx_stop", cmd_ble_etf_rx_stop_exec }, { "channel", cmd_ble_etf_set_chan_exec }, { "rate", cmd_ble_etf_set_rate_exec }, { "payload", cmd_ble_etf_set_payload_exec }, { "len", cmd_ble_etf_set_payload_len_exec }, { "hopping", cmd_ble_etf_hopping_exec }, { "hopping_stop", cmd_ble_etf_hopping_stop_exec }, { "power_level", cmd_ble_etf_set_power_exec }, { "power", cmd_ble_etf_set_power_max_value_exec }, { "read_mem", cmd_ble_etf_read_mem_exec }, { "write_mem", cmd_ble_etf_write_mem_exec }, { "set_channel_fec", cmd_ble_etf_set_channel_fec_exec }, { "help", cmd_ble_etf_help_exec }, }; enum cmd_status cmd_ble_etf_exec(char *cmd) { return cmd_exec(cmd, g_ble_etf_cmds, cmd_nitems(g_ble_etf_cmds)); } static const struct cmd_data g_btetf_cmds[] = { { "ble", cmd_ble_etf_exec }, { "tone", cmd_ble_etf_tone_exec }, { "tone_stop", cmd_ble_etf_tone_stop_exec }, { "connect", cmd_ble_etf_connect_exec }, { "disconnect", cmd_ble_etf_disconnect_exec }, { "help", cmd_bt_etf_help_exec }, }; enum cmd_status cmd_btetf_exec(char *cmd) { return cmd_exec(cmd, g_btetf_cmds, cmd_nitems(g_btetf_cmds)); } #endif