From 1c0ed946018e4f1ee4b766d5db811d097f44f2ba Mon Sep 17 00:00:00 2001 From: Yuriy Vynnychek Date: Thu, 29 Jul 2021 15:53:57 +0300 Subject: [PATCH] drivers: ieee802154: introduce new Telink B91 IEEE802154 driver IEEE802154 driver basic support for Telink B91 platform. Signed-off-by: Yuriy Vynnychek --- CODEOWNERS | 1 + drivers/ieee802154/CMakeLists.txt | 1 + drivers/ieee802154/Kconfig | 2 + drivers/ieee802154/Kconfig.b91 | 62 +++ drivers/ieee802154/ieee802154_b91.c | 618 ++++++++++++++++++++++++++++ drivers/ieee802154/ieee802154_b91.h | 107 +++++ 6 files changed, 791 insertions(+) create mode 100644 drivers/ieee802154/Kconfig.b91 create mode 100644 drivers/ieee802154/ieee802154_b91.c create mode 100644 drivers/ieee802154/ieee802154_b91.h diff --git a/CODEOWNERS b/CODEOWNERS index 9c1c338c08a..50cb2f78984 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -243,6 +243,7 @@ /drivers/i2s/i2s_ll_stm32* @avisconti /drivers/i2s/*nrfx* @anangl /drivers/ieee802154/ @rlubos @tbursztyka +/drivers/ieee802154/*b91* @yurvyn /drivers/ieee802154/ieee802154_rf2xx* @tbursztyka @nandojve /drivers/ieee802154/ieee802154_cc13xx* @bwitherspoon @cfriedt /drivers/interrupt_controller/ @dcpleung @nashif diff --git a/drivers/ieee802154/CMakeLists.txt b/drivers/ieee802154/CMakeLists.txt index 87311d9c483..db25b1fc4ad 100644 --- a/drivers/ieee802154/CMakeLists.txt +++ b/drivers/ieee802154/CMakeLists.txt @@ -1,5 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_sources_ifdef(CONFIG_IEEE802154_TELINK_B91 ieee802154_b91.c) zephyr_sources_ifdef(CONFIG_IEEE802154_CC2520 ieee802154_cc2520.c) zephyr_sources_ifdef(CONFIG_IEEE802154_KW41Z ieee802154_kw41z.c) zephyr_sources_ifdef(CONFIG_IEEE802154_UPIPE ieee802154_uart_pipe.c) diff --git a/drivers/ieee802154/Kconfig b/drivers/ieee802154/Kconfig index 1202545e33d..6843c98ad39 100644 --- a/drivers/ieee802154/Kconfig +++ b/drivers/ieee802154/Kconfig @@ -57,6 +57,8 @@ config IEEE802154_VENDOR_OUI endif # IEEE802154_VENDOR_OUI_ENABLE +source "drivers/ieee802154/Kconfig.b91" + source "drivers/ieee802154/Kconfig.cc2520" source "drivers/ieee802154/Kconfig.kw41z" diff --git a/drivers/ieee802154/Kconfig.b91 b/drivers/ieee802154/Kconfig.b91 new file mode 100644 index 00000000000..dbe5732fd00 --- /dev/null +++ b/drivers/ieee802154/Kconfig.b91 @@ -0,0 +1,62 @@ +# Copyright (c) 2021 Telink Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +# Telink B91 RF configuration options + +menuconfig IEEE802154_TELINK_B91 + bool "Telink B91 RF driver" + depends on NETWORKING + +if IEEE802154_TELINK_B91 + +config IEEE802154_B91_DRV_NAME + string "b91 IEEE 802.15.4 Driver's name" + default "IEEE802154_b91" + help + This option sets the driver name + +config IEEE802154_B91_INIT_PRIO + int "Telink B91 IEEE 802.15.4 initialization priority" + default 80 + help + Set the initialization priority number. Do not mess with it unless + you know what you are doing. + +config IEEE802154_B91_RANDOM_MAC + bool "Random MAC address" + default y + help + Generate a random MAC address dynamically. + +if ! IEEE802154_B91_RANDOM_MAC + +config IEEE802154_B91_MAC4 + hex "MAC Address Byte 4" + default 0 + range 0 0xff + help + This is the byte 4 of the MAC address. + +config IEEE802154_B91_MAC5 + hex "MAC Address Byte 5" + default 0 + range 0 0xff + help + This is the byte 5 of the MAC address. + +config IEEE802154_B91_MAC6 + hex "MAC Address Byte 6" + default 0 + range 0 0xff + help + This is the byte 6 of the MAC address. + +config IEEE802154_B91_MAC7 + hex "MAC Address Byte 7" + default 0 + range 0 0xff + help + This is the byte 7 of the MAC address. + +endif # ! IEEE802154_B91_RANDOM_MAC +endif # IEEE802154_TELINK_B91 diff --git a/drivers/ieee802154/ieee802154_b91.c b/drivers/ieee802154/ieee802154_b91.c new file mode 100644 index 00000000000..716b34773f8 --- /dev/null +++ b/drivers/ieee802154/ieee802154_b91.c @@ -0,0 +1,618 @@ +/* + * Copyright (c) 2021 Telink Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT telink_b91_zb + +#include "rf.h" +#include "stimer.h" + +#define LOG_MODULE_NAME ieee802154_b91 +#if defined(CONFIG_IEEE802154_DRIVER_LOG_LEVEL) +#define LOG_LEVEL CONFIG_IEEE802154_DRIVER_LOG_LEVEL +#else +#define LOG_LEVEL LOG_LEVEL_NONE +#endif + +#include +LOG_MODULE_REGISTER(LOG_MODULE_NAME); + +#include +#include +#if defined(CONFIG_NET_L2_OPENTHREAD) +#include +#endif + +#include "ieee802154_b91.h" + + +/* B91 data structure */ +static struct b91_data data; + +/* Set filter PAN ID */ +static int b91_set_pan_id(uint16_t pan_id) +{ + uint8_t pan_id_le[B91_PAN_ID_SIZE]; + + sys_put_le16(pan_id, pan_id_le); + memcpy(data.filter_pan_id, pan_id_le, B91_PAN_ID_SIZE); + + return 0; +} + +/* Set filter short address */ +static int b91_set_short_addr(uint16_t short_addr) +{ + uint8_t short_addr_le[B91_SHORT_ADDRESS_SIZE]; + + sys_put_le16(short_addr, short_addr_le); + memcpy(data.filter_short_addr, short_addr_le, B91_SHORT_ADDRESS_SIZE); + + return 0; +} + +/* Set filter IEEE address */ +static int b91_set_ieee_addr(const uint8_t *ieee_addr) +{ + memcpy(data.filter_ieee_addr, ieee_addr, B91_IEEE_ADDRESS_SIZE); + + return 0; +} + +/* Filter PAN ID, short address and IEEE address */ +static bool b91_run_filter(uint8_t *rx_buffer) +{ + /* Check destination PAN Id */ + if (memcmp(&rx_buffer[B91_PAN_ID_OFFSET], data.filter_pan_id, + B91_PAN_ID_SIZE) != 0 && + memcmp(&rx_buffer[B91_PAN_ID_OFFSET], B91_BROADCAST_ADDRESS, + B91_PAN_ID_SIZE) != 0) { + return false; + } + + /* Check destination address */ + switch (rx_buffer[B91_DEST_ADDR_TYPE_OFFSET] & B91_DEST_ADDR_TYPE_MASK) { + case B91_DEST_ADDR_TYPE_SHORT: + /* First check if the destination is broadcast */ + /* If not broadcast, check if length and address matches */ + if (memcmp(&rx_buffer[B91_DEST_ADDR_OFFSET], B91_BROADCAST_ADDRESS, + B91_SHORT_ADDRESS_SIZE) != 0 && + memcmp(&rx_buffer[B91_DEST_ADDR_OFFSET], data.filter_short_addr, + B91_SHORT_ADDRESS_SIZE) != 0) { + return false; + } + break; + + case B91_DEST_ADDR_TYPE_IEEE: + /* If not broadcast, check if length and address matches */ + if ((net_if_get_link_addr(data.iface)->len != B91_IEEE_ADDRESS_SIZE) || + memcmp(&rx_buffer[B91_DEST_ADDR_OFFSET], data.filter_ieee_addr, + B91_IEEE_ADDRESS_SIZE) != 0) { + return false; + } + break; + + default: + return false; + } + + return true; +} + +/* Get MAC address */ +static inline uint8_t *b91_get_mac(const struct device *dev) +{ + struct b91_data *b91 = dev->data; + +#if defined(CONFIG_IEEE802154_B91_RANDOM_MAC) + uint32_t *ptr = (uint32_t *)(b91->mac_addr); + + UNALIGNED_PUT(sys_rand32_get(), ptr); + ptr = (uint32_t *)(b91->mac_addr + 4); + UNALIGNED_PUT(sys_rand32_get(), ptr); + + /* + * Clear bit 0 to ensure it isn't a multicast address and set + * bit 1 to indicate address is locally administered and may + * not be globally unique. + */ + b91->mac_addr[0] = (b91->mac_addr[0] & ~0x01) | 0x02; +#else + /* Vendor Unique Identifier */ + b91->mac_addr[0] = 0xC4; + b91->mac_addr[1] = 0x19; + b91->mac_addr[2] = 0xD1; + b91->mac_addr[3] = 0x00; + + /* Extended Unique Identifier */ + b91->mac_addr[4] = CONFIG_IEEE802154_B91_MAC4; + b91->mac_addr[5] = CONFIG_IEEE802154_B91_MAC5; + b91->mac_addr[6] = CONFIG_IEEE802154_B91_MAC6; + b91->mac_addr[7] = CONFIG_IEEE802154_B91_MAC7; +#endif + + return b91->mac_addr; +} + +/* Convert RSSI to LQI */ +static uint8_t b91_convert_rssi_to_lqi(int8_t rssi) +{ + uint32_t lqi32 = 0; + + /* check for MIN value */ + if (rssi < B91_RSSI_TO_LQI_MIN) { + return 0; + } + + /* convert RSSI to LQI */ + lqi32 = B91_RSSI_TO_LQI_SCALE * (rssi - B91_RSSI_TO_LQI_MIN); + + /* check for MAX value */ + if (lqi32 > 0xFF) { + lqi32 = 0xFF; + } + + return (uint8_t)lqi32; +} + +/* Update RSSI and LQI parameters */ +static void b91_update_rssi_and_lqi(struct net_pkt *pkt) +{ + int8_t rssi; + uint8_t lqi; + + rssi = ((signed char)(data.rx_buffer + [data.rx_buffer[B91_LENGTH_OFFSET] + B91_RSSI_OFFSET])) - 110; + lqi = b91_convert_rssi_to_lqi(rssi); + + net_pkt_set_ieee802154_lqi(pkt, lqi); + net_pkt_set_ieee802154_rssi(pkt, rssi); +} + +/* Prepare TX buffer */ +static void b91_set_tx_payload(uint8_t *payload, uint8_t payload_len) +{ + unsigned char rf_data_len; + unsigned int rf_tx_dma_len; + + rf_data_len = payload_len + 1; + rf_tx_dma_len = rf_tx_packet_dma_len(rf_data_len); + data.tx_buffer[0] = rf_tx_dma_len & 0xff; + data.tx_buffer[1] = (rf_tx_dma_len >> 8) & 0xff; + data.tx_buffer[2] = (rf_tx_dma_len >> 16) & 0xff; + data.tx_buffer[3] = (rf_tx_dma_len >> 24) & 0xff; + data.tx_buffer[4] = payload_len + 2; + memcpy(data.tx_buffer + B91_PAYLOAD_OFFSET, payload, payload_len); +} + +/* Enable ack handler */ +static void b91_handle_ack_en(void) +{ + data.ack_handler_en = true; +} + +/* Disable ack handler */ +static void b91_handle_ack_dis(void) +{ + data.ack_handler_en = false; +} + +/* Handle acknowledge packet */ +static void b91_handle_ack(void) +{ + struct net_pkt *ack_pkt; + + /* allocate ack packet */ + ack_pkt = net_pkt_alloc_with_buffer(data.iface, B91_ACK_FRAME_LEN, + AF_UNSPEC, 0, K_NO_WAIT); + if (!ack_pkt) { + LOG_ERR("No free packet available."); + return; + } + + /* update packet data */ + if (net_pkt_write(ack_pkt, data.rx_buffer + B91_PAYLOAD_OFFSET, + B91_ACK_FRAME_LEN) < 0) { + LOG_ERR("Failed to write to a packet."); + goto out; + } + + /* update RSSI and LQI */ + b91_update_rssi_and_lqi(ack_pkt); + + /* init net cursor */ + net_pkt_cursor_init(ack_pkt); + + /* handle ack */ + if (ieee802154_radio_handle_ack(data.iface, ack_pkt) != NET_OK) { + LOG_INF("ACK packet not handled - releasing."); + } + + /* release ack_wait semaphore */ + k_sem_give(&data.ack_wait); + +out: + net_pkt_unref(ack_pkt); +} + +/* Send acknowledge packet */ +static void b91_send_ack(uint8_t seq_num) +{ + uint8_t ack_buf[] = { B91_ACK_TYPE, 0, seq_num }; + + b91_set_tx_payload(ack_buf, sizeof(ack_buf)); + rf_set_txmode(); + delay_us(B91_SET_TRX_MODE_DELAY_US); + rf_tx_pkt(data.tx_buffer); +} + +/* RX IRQ handler */ +static void b91_rf_rx_isr(void) +{ + uint8_t status; + uint8_t length; + uint8_t *payload; + struct net_pkt *pkt; + + /* disable DMA and clread IRQ flag */ + dma_chn_dis(DMA1); + rf_clr_irq_status(FLD_RF_IRQ_RX); + + /* check CRC */ + if (rf_zigbee_packet_crc_ok(data.rx_buffer)) { + /* get payload length */ + if (IS_ENABLED(CONFIG_IEEE802154_RAW_MODE) || + IS_ENABLED(CONFIG_NET_L2_OPENTHREAD)) { + length = data.rx_buffer[B91_LENGTH_OFFSET]; + } else { + length = data.rx_buffer[B91_LENGTH_OFFSET] - B91_FCS_LENGTH; + } + + /* check length */ + if ((length < B91_PAYLOAD_MIN) || (length > B91_PAYLOAD_MAX)) { + LOG_ERR("Invalid length\n"); + goto exit; + } + + /* get payload */ + payload = (uint8_t *)(data.rx_buffer + B91_PAYLOAD_OFFSET); + + /* handle acknowledge packet if enabled */ + if ((length == (B91_ACK_FRAME_LEN + B91_FCS_LENGTH)) && + (payload[B91_FRAME_TYPE_OFFSET] == B91_ACK_TYPE)) { + if (data.ack_handler_en) { + b91_handle_ack(); + } + goto exit; + } + + /* run filter (check PAN ID and destination address) */ + if (b91_run_filter(payload) == false) { + LOG_DBG("Packet received is not addressed to me"); + goto exit; + } + + /* send ack if requested */ + if (payload[B91_FRAME_TYPE_OFFSET] & B91_ACK_REQUEST) { + b91_send_ack(payload[B91_DSN_OFFSET]); + } + + /* get packet pointer from NET stack */ + pkt = net_pkt_alloc_with_buffer(data.iface, length, AF_UNSPEC, 0, K_NO_WAIT); + if (!pkt) { + LOG_ERR("No pkt available"); + goto exit; + } + + /* update packet data */ + if (net_pkt_write(pkt, payload, length)) { + LOG_ERR("Failed to write to a packet."); + goto exit; + } + + /* update RSSI and LQI prameters */ + b91_update_rssi_and_lqi(pkt); + + /* transfer data to NET stack */ + status = net_recv_data(data.iface, pkt); + if (status < 0) { + LOG_ERR("RCV Packet dropped by NET stack: %d", status); + net_pkt_unref(pkt); + } + } + +exit: + dma_chn_en(DMA1); +} + +/* TX IRQ handler */ +static void b91_rf_tx_isr(void) +{ + /* clear irq status */ + rf_clr_irq_status(FLD_RF_IRQ_TX); + + /* release tx semaphore */ + k_sem_give(&data.tx_wait); + + /* set to rx mode */ + rf_set_rxmode(); +} + +/* IRQ handler */ +static void b91_rf_isr(void) +{ + if (rf_get_irq_status(FLD_RF_IRQ_RX)) { + b91_rf_rx_isr(); + } else if (rf_get_irq_status(FLD_RF_IRQ_TX)) { + b91_rf_tx_isr(); + } +} + +/* Driver initialization */ +static int b91_init(const struct device *dev) +{ + struct b91_data *b91 = dev->data; + + /* init semaphores */ + k_sem_init(&b91->tx_wait, 0, 1); + k_sem_init(&b91->ack_wait, 0, 1); + + /* init rf module */ + rf_mode_init(); + rf_set_zigbee_250K_mode(); + rf_set_tx_dma(2, B91_TRX_LENGTH); + rf_set_rx_dma(data.rx_buffer, 3, B91_TRX_LENGTH); + rf_set_rxmode(); + + /* init IRQs */ + IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), b91_rf_isr, 0, 0); + riscv_plic_irq_enable(DT_INST_IRQN(0)); + riscv_plic_set_priority(DT_INST_IRQN(0), DT_INST_IRQ(0, priority)); + rf_set_irq_mask(FLD_RF_IRQ_RX | FLD_RF_IRQ_TX); + + /* init data variables */ + data.is_started = true; + data.ack_handler_en = false; + + return 0; +} + +/* API implementation: iface_init */ +static void b91_iface_init(struct net_if *iface) +{ + const struct device *dev = net_if_get_device(iface); + struct b91_data *b91 = dev->data; + uint8_t *mac = b91_get_mac(dev); + + net_if_set_link_addr(iface, mac, B91_IEEE_ADDRESS_SIZE, NET_LINK_IEEE802154); + + b91->iface = iface; + + ieee802154_init(iface); +} + +/* API implementation: get_capabilities */ +static enum ieee802154_hw_caps b91_get_capabilities(const struct device *dev) +{ + ARG_UNUSED(dev); + + return IEEE802154_HW_FCS | IEEE802154_HW_2_4_GHZ | + IEEE802154_HW_FILTER | IEEE802154_HW_TX_RX_ACK; +} + +/* API implementation: cca */ +static int b91_cca(const struct device *dev) +{ + ARG_UNUSED(dev); + + unsigned int t1 = stimer_get_tick(); + + while (!clock_time_exceed(t1, B91_CCA_TIME_MAX_US)) { + if (rf_get_rssi() < B91_CCA_RSSI_MIN) { + return 0; + } + } + + return -EBUSY; +} + +/* API implementation: set_channel */ +static int b91_set_channel(const struct device *dev, uint16_t channel) +{ + ARG_UNUSED(dev); + + if (channel < 11 || channel > 26) { + return -EINVAL; + } + + rf_set_chn(B91_LOGIC_CHANNEL_TO_PHYSICAL(channel)); + + return 0; +} + +/* API implementation: filter */ +static int b91_filter(const struct device *dev, + bool set, + enum ieee802154_filter_type type, + const struct ieee802154_filter *filter) +{ + if (!set) { + return -ENOTSUP; + } + + if (type == IEEE802154_FILTER_TYPE_IEEE_ADDR) { + return b91_set_ieee_addr(filter->ieee_addr); + } else if (type == IEEE802154_FILTER_TYPE_SHORT_ADDR) { + return b91_set_short_addr(filter->short_addr); + } else if (type == IEEE802154_FILTER_TYPE_PAN_ID) { + return b91_set_pan_id(filter->pan_id); + } + + return -ENOTSUP; +} + +/* API implementation: set_txpower */ +static int b91_set_txpower(const struct device *dev, int16_t dbm) +{ + ARG_UNUSED(dev); + + /* check for supported Min/Max range */ + if (dbm < B91_TX_POWER_MIN) { + dbm = B91_TX_POWER_MIN; + } else if (dbm > B91_TX_POWER_MAX) { + dbm = B91_TX_POWER_MAX; + } + + /* set TX power */ + rf_set_power_level(b91_tx_pwr_lt[dbm - B91_TX_POWER_MIN]); + + return 0; +} + +/* API implementation: start */ +static int b91_start(const struct device *dev) +{ + ARG_UNUSED(dev); + + /* check if RF is already started */ + if (!data.is_started) { + rf_set_rxmode(); + delay_us(B91_SET_TRX_MODE_DELAY_US); + riscv_plic_irq_enable(DT_INST_IRQN(0)); + data.is_started = true; + } + + return 0; +} + +/* API implementation: stop */ +static int b91_stop(const struct device *dev) +{ + ARG_UNUSED(dev); + + /* check if RF is already stopped */ + if (data.is_started) { + riscv_plic_irq_disable(DT_INST_IRQN(0)); + rf_set_tx_rx_off(); + delay_us(B91_SET_TRX_MODE_DELAY_US); + data.is_started = false; + } + + return 0; +} + +/* API implementation: tx */ +static int b91_tx(const struct device *dev, + enum ieee802154_tx_mode mode, + struct net_pkt *pkt, + struct net_buf *frag) +{ + ARG_UNUSED(pkt); + + int status; + struct b91_data *b91 = dev->data; + + /* check for supported mode */ + if (mode != IEEE802154_TX_MODE_DIRECT) { + LOG_DBG("TX mode %d not supported", mode); + return -ENOTSUP; + } + + /* prepare tx buffer */ + b91_set_tx_payload(frag->data, frag->len); + + /* reset semaphores */ + k_sem_reset(&b91->tx_wait); + k_sem_reset(&b91->ack_wait); + + /* start transmission */ + rf_set_txmode(); + delay_us(B91_SET_TRX_MODE_DELAY_US); + rf_tx_pkt(data.tx_buffer); + + /* wait for tx done */ + status = k_sem_take(&b91->tx_wait, K_MSEC(B91_TX_WAIT_TIME_MS)); + if (status != 0) { + rf_set_rxmode(); + return -EIO; + } + + /* wait for ACK if requested */ + if (frag->data[B91_FRAME_TYPE_OFFSET] & B91_ACK_REQUEST) { + b91_handle_ack_en(); + status = k_sem_take(&b91->ack_wait, K_MSEC(B91_ACK_WAIT_TIME_MS)); + b91_handle_ack_dis(); + } + + return status; +} + +/* API implementation: ed_scan */ +static int b91_ed_scan(const struct device *dev, uint16_t duration, + energy_scan_done_cb_t done_cb) +{ + ARG_UNUSED(dev); + ARG_UNUSED(duration); + ARG_UNUSED(done_cb); + + /* ed_scan not supported */ + + return -ENOTSUP; +} + +/* API implementation: configure */ +static int b91_configure(const struct device *dev, + enum ieee802154_config_type type, + const struct ieee802154_config *config) +{ + ARG_UNUSED(dev); + ARG_UNUSED(type); + ARG_UNUSED(config); + + /* configure not supported */ + + return -ENOTSUP; +} + +/* IEEE802154 driver APIs structure */ +static struct ieee802154_radio_api b91_radio_api = { + .iface_api.init = b91_iface_init, + .get_capabilities = b91_get_capabilities, + .cca = b91_cca, + .set_channel = b91_set_channel, + .filter = b91_filter, + .set_txpower = b91_set_txpower, + .start = b91_start, + .stop = b91_stop, + .tx = b91_tx, + .ed_scan = b91_ed_scan, + .configure = b91_configure, +}; + + +#if defined(CONFIG_NET_L2_IEEE802154) +#define L2 IEEE802154_L2 +#define L2_CTX_TYPE NET_L2_GET_CTX_TYPE(IEEE802154_L2) +#define MTU 125 +#elif defined(CONFIG_NET_L2_OPENTHREAD) +#define L2 OPENTHREAD_L2 +#define L2_CTX_TYPE NET_L2_GET_CTX_TYPE(OPENTHREAD_L2) +#define MTU 1280 +#endif + + +/* IEEE802154 driver registration */ +#if defined(CONFIG_NET_L2_IEEE802154) || defined(CONFIG_NET_L2_OPENTHREAD) +NET_DEVICE_INIT(b91_154_radio, CONFIG_IEEE802154_B91_DRV_NAME, + b91_init, NULL, &data, NULL, + CONFIG_IEEE802154_B91_INIT_PRIO, + &b91_radio_api, L2, + L2_CTX_TYPE, MTU); +#else +DEVICE_DEFINE(b91_154_radio, CONFIG_IEEE802154_B91_DRV_NAME, + b91_init, NULL, &data, NULL, + POST_KERNEL, CONFIG_IEEE802154_B91_INIT_PRIO, + &b91_radio_api); +#endif diff --git a/drivers/ieee802154/ieee802154_b91.h b/drivers/ieee802154/ieee802154_b91.h new file mode 100644 index 00000000000..8d5f4a82d46 --- /dev/null +++ b/drivers/ieee802154/ieee802154_b91.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2021 Telink Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_IEEE802154_IEEE802154_B91_H_ +#define ZEPHYR_DRIVERS_IEEE802154_IEEE802154_B91_H_ + +/* Timeouts */ +#define B91_TX_WAIT_TIME_MS (10) +#define B91_ACK_WAIT_TIME_MS (10) +#define B91_SET_TRX_MODE_DELAY_US (100) + +/* Received data parsing */ +#define B91_PAYLOAD_OFFSET (5) +#define B91_PAYLOAD_MIN (5) +#define B91_PAYLOAD_MAX (127) +#define B91_FRAME_TYPE_OFFSET (0) +#define B91_DEST_ADDR_TYPE_OFFSET (1) +#define B91_DEST_ADDR_TYPE_MASK (0x0c) +#define B91_DEST_ADDR_TYPE_SHORT (8) +#define B91_DEST_ADDR_TYPE_IEEE (0x0c) +#define B91_PAN_ID_OFFSET (3) +#define B91_PAN_ID_SIZE (2) +#define B91_DEST_ADDR_OFFSET (5) +#define B91_SHORT_ADDRESS_SIZE (2) +#define B91_IEEE_ADDRESS_SIZE (8) +#define B91_LENGTH_OFFSET (4) +#define B91_RSSI_OFFSET (11) +#define B91_BROADCAST_ADDRESS ((uint8_t [2]) { 0xff, 0xff }) +#define B91_ACK_FRAME_LEN (3) +#define B91_ACK_TYPE (2) +#define B91_ACK_REQUEST (1 << 5) +#define B91_DSN_OFFSET (2) +#define B91_FCS_LENGTH (2) + +/* Generic */ +#define B91_TRX_LENGTH (256) +#define B91_RSSI_TO_LQI_SCALE (3) +#define B91_RSSI_TO_LQI_MIN (-87) +#define B91_CCA_RSSI_MIN (-60) +#define B91_CCA_TIME_MAX_US (200) +#define B91_LOGIC_CHANNEL_TO_PHYSICAL(p) (((p) - 10) * 5) + +/* TX power lookup table */ +#define B91_TX_POWER_MIN (-30) +#define B91_TX_POWER_MAX (9) +static const uint8_t b91_tx_pwr_lt[] = { + RF_POWER_N30dBm, /* -30.0 dBm: -30 */ + RF_POWER_N30dBm, /* -30.0 dBm: -29 */ + RF_POWER_N30dBm, /* -30.0 dBm: -28 */ + RF_POWER_N30dBm, /* -30.0 dBm: -27 */ + RF_POWER_N30dBm, /* -30.0 dBm: -26 */ + RF_POWER_N23p54dBm, /* -23.5 dBm: -25 */ + RF_POWER_N23p54dBm, /* -23.5 dBm: -24 */ + RF_POWER_N23p54dBm, /* -23.5 dBm: -23 */ + RF_POWER_N23p54dBm, /* -23.5 dBm: -22 */ + RF_POWER_N23p54dBm, /* -23.5 dBm: -21 */ + RF_POWER_N17p83dBm, /* -17.8 dBm: -20 */ + RF_POWER_N17p83dBm, /* -17.8 dBm: -19 */ + RF_POWER_N17p83dBm, /* -17.8 dBm: -18 */ + RF_POWER_N17p83dBm, /* -17.8 dBm: -17 */ + RF_POWER_N17p83dBm, /* -17.8 dBm: -16 */ + RF_POWER_N12p06dBm, /* -12.0 dBm: -15 */ + RF_POWER_N12p06dBm, /* -12.0 dBm: -14 */ + RF_POWER_N12p06dBm, /* -12.0 dBm: -13 */ + RF_POWER_N12p06dBm, /* -12.0 dBm: -12 */ + RF_POWER_N12p06dBm, /* -12.0 dBm: -11 */ + RF_POWER_N8p78dBm, /* -8.7 dBm: -10 */ + RF_POWER_N8p78dBm, /* -8.7 dBm: -9 */ + RF_POWER_N8p78dBm, /* -8.7 dBm: -8 */ + RF_POWER_N6p54dBm, /* -6.5 dBm: -7 */ + RF_POWER_N6p54dBm, /* -6.5 dBm: -6 */ + RF_POWER_N4p77dBm, /* -4.7 dBm: -5 */ + RF_POWER_N4p77dBm, /* -4.7 dBm: -4 */ + RF_POWER_N3p37dBm, /* -3.3 dBm: -3 */ + RF_POWER_N2p01dBm, /* -2.0 dBm: -2 */ + RF_POWER_N1p37dBm, /* -1.3 dBm: -1 */ + RF_POWER_P0p01dBm, /* 0.0 dBm: 0 */ + RF_POWER_P0p80dBm, /* 0.8 dBm: 1 */ + RF_POWER_P2p32dBm, /* 2.3 dBm: 2 */ + RF_POWER_P3p25dBm, /* 3.2 dBm: 3 */ + RF_POWER_P4p35dBm, /* 4.3 dBm: 4 */ + RF_POWER_P5p68dBm, /* 5.6 dBm: 5 */ + RF_POWER_P5p68dBm, /* 5.6 dBm: 6 */ + RF_POWER_P6p98dBm, /* 6.9 dBm: 7 */ + RF_POWER_P8p05dBm, /* 8.0 dBm: 8 */ + RF_POWER_P9p11dBm, /* 9.1 dBm: 9 */ +}; + +/* data structure */ +struct b91_data { + uint8_t mac_addr[B91_IEEE_ADDRESS_SIZE]; + uint8_t rx_buffer[B91_TRX_LENGTH]; + uint8_t tx_buffer[B91_TRX_LENGTH]; + struct net_if *iface; + struct k_sem tx_wait; + struct k_sem ack_wait; + uint8_t filter_pan_id[B91_PAN_ID_SIZE]; + uint8_t filter_short_addr[B91_SHORT_ADDRESS_SIZE]; + uint8_t filter_ieee_addr[B91_IEEE_ADDRESS_SIZE]; + bool is_started; + bool ack_handler_en; +}; + +#endif