diff --git a/Documentation/platforms/arm/nrf52/boards/nrf52840-dk/index.rst b/Documentation/platforms/arm/nrf52/boards/nrf52840-dk/index.rst index 04c565c507fd5..f48585f774a08 100644 --- a/Documentation/platforms/arm/nrf52/boards/nrf52840-dk/index.rst +++ b/Documentation/platforms/arm/nrf52/boards/nrf52840-dk/index.rst @@ -138,3 +138,20 @@ usbnsh ------ Basic NuttShell configuration (CDCACM console enabled in USB Port, at 115200 bps). + +ieee802154_6lowpan +------------------ + +Cheat Sheet. Here is a concise summary of all all the steps needed to +run the UDP test (C=Coordinator; E=Endpoint):: + + C: nsh> i8 wpan0 startpan cd:ab + C: nsh> i8 set saddr 0A:00 + C: nsh> i8 set ep_saddr 0B:00 + C: nsh> i8 acceptassoc + E: nsh> i8 wpan0 assoc + C: nsh> ifup wpan0 + C: nsh> ifconfig <-- To get the + E: nsh> ifup wpan0 + C: nsh> udpserver & + E: nsh> udpclient & diff --git a/Documentation/platforms/arm/nrf52/ieee802154.rst b/Documentation/platforms/arm/nrf52/ieee802154.rst new file mode 100644 index 0000000000000..65f801c34c82e --- /dev/null +++ b/Documentation/platforms/arm/nrf52/ieee802154.rst @@ -0,0 +1,44 @@ +========================== +Nordic nRF52 IEEE 802.15.4 +========================== + +.. note:: + + This driver is highly experimental. + Help with development and testing will be appreciated ;) + +Supported features: + +* frame transmission +* frame reception and filtering +* immediate ACK (incoming and outgoing) +* promiscuous mode +* delayed transmision +* radio events trace +* setting pending bit for all incoming Data Request frames +* un-slotted CSMA-CA + +Work in progres features (some logic is present, but needs more work): + +* slotted CSMA-CA +* GTS +* beacon transmision + +Fetures not implemented: + +* enhanced ACK (Enh-ACK) +* enhanced beacon +* low power mode +* advanced features from IEEE 802.15.4e + +Reserved peripherals +==================== + +This implementation reserves the following peripherals: + +* ``RADIO`` - used for radio operations + +* ``TIMER0`` - used as high resolution timer for ACK, IFS and other radio delays + +* ``RTC0`` - if superframe support is enabled, used as low power timer to hande + superframe events diff --git a/Documentation/platforms/arm/nrf52/index.rst b/Documentation/platforms/arm/nrf52/index.rst index 2bb73de03cf4e..912422ee17ec8 100644 --- a/Documentation/platforms/arm/nrf52/index.rst +++ b/Documentation/platforms/arm/nrf52/index.rst @@ -51,9 +51,9 @@ Peripheral Support The following list indicates peripherals supported in NuttX: -========== ======= ===== +========== ======= =============== Peripheral Support Notes -========== ======= ===== +========== ======= =============== GPIO Yes GPIOTE Yes I2S No @@ -64,7 +64,7 @@ PPI Yes PWM Yes QDEC No QSPI Yes -RADIO Yes Basic +RADIO Yes BLE, IEEE 802.15.4 RNG Yes RTC Yes SAADC Yes @@ -78,7 +78,7 @@ UART Yes UARTE No USBD Yes WDT Yes -========== ======= ===== +========== ======= =============== Peripherals such as AAR, ACL, CCM, ECB are not directly used by NuttX since they are part of BLE controller implementation (link). @@ -206,6 +206,11 @@ is provided with settings already set. Note that in this case, some peripherals (mostly those related to BLE) will be unavailable. Some PPI channels will also be ocuppied (``NRF52_PPI_NUM_CONFIGURABLE_CHANNELS`` will be set accordingly in this case). +IEEE 802.15.4 Support +===================== + +Details about IEEE 802.15.4 support for nRF52 can be found in :doc:`ieee802154`. + Supported Boards ================ @@ -214,3 +219,4 @@ Supported Boards :maxdepth: 1 boards/*/* + ieee802154.rst diff --git a/arch/arm/src/nrf52/CMakeLists.txt b/arch/arm/src/nrf52/CMakeLists.txt index 409db39c17766..80b8c844080ec 100644 --- a/arch/arm/src/nrf52/CMakeLists.txt +++ b/arch/arm/src/nrf52/CMakeLists.txt @@ -94,6 +94,20 @@ endif() if(CONFIG_NRF52_RADIO) list(APPEND SRCS nrf52_radio.c) + + if(CONFIG_NRF52_RADIO_IEEE802154) + list(APPEND SRCS nrf52_ieee802154_radio.c) + list(APPEND SRCS nrf52_ieee802154_tim.c) + list(APPEND SRCS nrf52_ieee802154.c) + + if(CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME) + list(APPEND SRCS nrf52_ieee802154_rtc.c) + endif() + + if(CONFIG_NRF52_RADIO_IEEE802154_TRACE) + list(APPEND SRCS nrf52_ieee802154_trace.c) + endif() + endif() endif() if(CONFIG_NRF52_TIMER) diff --git a/arch/arm/src/nrf52/Kconfig b/arch/arm/src/nrf52/Kconfig index 887404af28df6..5bd0a293bb182 100644 --- a/arch/arm/src/nrf52/Kconfig +++ b/arch/arm/src/nrf52/Kconfig @@ -629,6 +629,40 @@ config NRF52_RADIO_CUSTOM bool "RADIO uses custom IRQ handlers" default n +config NRF52_RADIO_IEEE802154 + bool "RADIO IEEE802.15.4 protocol" + default n + depends on NRF52_HAVE_IEEE802154 + select ARMV7M_USEBASEPRI + select ARCH_RAMVECTORS + select ARCH_IRQPRIO + select NRF52_RADIO_CUSTOM + select NRF52_TIMER0 + +if NRF52_RADIO_IEEE802154 + +config NRF52_RADIO_IEEE802154_SUPERFRAME + bool "RADIO IEEE802.15.4 superframe support" + default n + select NRF52_RTC0 + select NRF52_USE_LFCLK + +config NRF52_RADIO_IEEE802154_GTS_SLOTS + int "RADIO IEEE802.15.4 GTS slots" + default 2 + depends on NRF52_RADIO_IEEE802154_SUPERFRAME + +config NRF52_RADIO_IEEE802154_TRACE + bool "RADIO IEEE802.15.4 trace support" + default n + +config NRF52_RADIO_IEEE802154_TRACE_BUFSIZE + int "RADIO IEEE802.15.4 trace buffer size" + depends on NRF52_RADIO_IEEE802154_TRACE + default 1024 + +endif + endif #NRF52_RADIO endmenu # "RADIO Configuration" diff --git a/arch/arm/src/nrf52/Make.defs b/arch/arm/src/nrf52/Make.defs index c570f66ff4bcb..12650bc976b25 100644 --- a/arch/arm/src/nrf52/Make.defs +++ b/arch/arm/src/nrf52/Make.defs @@ -89,6 +89,17 @@ endif ifeq ($(CONFIG_NRF52_RADIO),y) CHIP_CSRCS += nrf52_radio.c +ifeq ($(CONFIG_NRF52_RADIO_IEEE802154),y) +CHIP_CSRCS += nrf52_ieee802154_radio.c +CHIP_CSRCS += nrf52_ieee802154_tim.c +CHIP_CSRCS += nrf52_ieee802154.c +ifeq ($(CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME),y) +CHIP_CSRCS += nrf52_ieee802154_rtc.c +endif +ifeq ($(CONFIG_NRF52_RADIO_IEEE802154_TRACE),y) +CHIP_CSRCS += nrf52_ieee802154_trace.c +endif +endif endif ifeq ($(CONFIG_NRF52_TIMER),y) diff --git a/arch/arm/src/nrf52/nrf52_ieee802154.c b/arch/arm/src/nrf52/nrf52_ieee802154.c new file mode 100644 index 0000000000000..28956ce75e28a --- /dev/null +++ b/arch/arm/src/nrf52/nrf52_ieee802154.c @@ -0,0 +1,999 @@ +/**************************************************************************** + * arch/arm/src/nrf52/nrf52_ieee802154.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include + +#include + +#include "nrf52_ieee802154_trace.h" + +#include "nrf52_ieee802154_priv.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_NRF52_RADIO_CUSTOM +# error RADIO custom interrupts must be enabled +#endif + +#ifndef CONFIG_SCHED_HPWORK +# error High priority work queue required in this driver +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* IEEE 802.15.4 radio data */ + +static struct nrf52_radioi8_dev_s g_nrf52_radioi8; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Set/get radio attributes */ + +static int nrf52_radioi8_setrxmode(struct nrf52_radioi8_dev_s *dev, + int mode); +static int nrf52_radioi8_setpanid(struct nrf52_radioi8_dev_s *dev, + const uint8_t *panid); +static int nrf52_radioi8_setsaddr(struct nrf52_radioi8_dev_s *dev, + const uint8_t *saddr); +static int nrf52_radioi8_seteaddr(struct nrf52_radioi8_dev_s *dev, + const uint8_t *eaddr); +static int nrf52_radioi8_setcoordsaddr(struct nrf52_radioi8_dev_s *dev, + const uint8_t *saddr); +static int nrf52_radioi8_setdevmode(struct nrf52_radioi8_dev_s *dev, + uint8_t mode); + +/* Radio ops */ + +static int nrf52_radioi8_bind(struct ieee802154_radio_s *radio, + struct ieee802154_radiocb_s *radiocb); +static int nrf52_radioi8_reset(struct ieee802154_radio_s *radio); +static int nrf52_radioi8_getattr(struct ieee802154_radio_s *radio, + enum ieee802154_attr_e attr, + union ieee802154_attr_u *attrval); +static int nrf52_radioi8_setattr(struct ieee802154_radio_s *radio, + enum ieee802154_attr_e attr, + const union ieee802154_attr_u *attrval); +static int nrf52_radioi8_txnotify(struct ieee802154_radio_s *radio, + bool gts); +static int nrf52_radioi8_txdelayed(struct ieee802154_radio_s *radio, + struct ieee802154_txdesc_s *txdesc, + uint32_t symboldelay); +static int nrf52_radioi8_rxenable(struct ieee802154_radio_s *radio, + bool enable); +static int nrf52_radioi8_setchannel(struct nrf52_radioi8_dev_s *dev, + uint8_t chan); +static int nrf52_radioi8_setcca(struct nrf52_radioi8_dev_s *dev, + struct ieee802154_cca_s *cca); +static int nrf52_radioi8_energydetect(struct ieee802154_radio_s *radio, + uint32_t nsymbols); + +static int +nrf52_radioi8_beaconstart(struct ieee802154_radio_s *radio, + const struct ieee802154_superframespec_s *sfspec, + struct ieee802154_beaconframe_s *beacon); +static int +nrf52_radioi8_beaconupdate(struct ieee802154_radio_s *radio, + struct ieee802154_beaconframe_s *beacon); +static int nrf52_radioi8_beaconstop(struct ieee802154_radio_s *radio); +static int +nrf52_radioi8_sfupdate(struct ieee802154_radio_s *radio, + const struct ieee802154_superframespec_s *sfspec); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf52_radioi8_setrxmode + * + * Description: + * Set the RX mode (normal, promiscuous, no CRC). + * + ****************************************************************************/ + +static int nrf52_radioi8_setrxmode(struct nrf52_radioi8_dev_s *dev, + int mode) +{ + wlinfo("setrxmode %d\n", mode); + + if (mode < NRF52_RXMODE_NORMAL || mode > NRF52_RXMODE_NOCRC) + { + return -EINVAL; + } + + dev->state.rxmode = mode; + + return OK; +} + +/**************************************************************************** + * Name: nrf52_radioi8_setpanid + * + * Description: + * Define the PAN ID the device is operating on. + * + ****************************************************************************/ + +static int nrf52_radioi8_setpanid(struct nrf52_radioi8_dev_s *dev, + const uint8_t *panid) +{ + wlinfo("setpanid: %02X:%02X\n", panid[0], panid[1]); + IEEE802154_PANIDCOPY(dev->state.addr.panid, panid); + return OK; +} + +/**************************************************************************** + * Name: nrf52_radioi8_setsaddr + * + * Description: + * Define the device short address. The following addresses are special: + * + * FFFEh : Broadcast + * FFFFh : Unspecified + * + ****************************************************************************/ + +static int nrf52_radioi8_setsaddr(struct nrf52_radioi8_dev_s *dev, + const uint8_t *saddr) +{ + wlinfo("setsaddr: %02X:%02X\n", saddr[0], saddr[1]); + IEEE802154_SADDRCOPY(dev->state.addr.saddr, saddr); + return OK; +} + +/**************************************************************************** + * Name: nrf52_radioi8_seteaddr + * + * Description: + * Define the device extended address. The following addresses are special: + * + * ffffffffffffffffh : Unspecified + * + ****************************************************************************/ + +static int nrf52_radioi8_seteaddr(struct nrf52_radioi8_dev_s *dev, + const uint8_t *eaddr) +{ + int i = 0; + + wlinfo("seteaddr: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + eaddr[0], eaddr[1], eaddr[2], eaddr[3], eaddr[4], eaddr[5], + eaddr[6], eaddr[7]); + + for (i = 0; i < 8; i++) + { + dev->state.addr.eaddr[i] = eaddr[i]; + } + + return OK; +} + +/**************************************************************************** + * Name: nrf52_radioi8_setcoordsaddr + * + * Description: + * Define the coordinator short address. The following addresses are + * special: + * + * FFFEh : Broadcast + * FFFFh : Unspecified + * + ****************************************************************************/ + +static int nrf52_radioi8_setcoordsaddr(struct nrf52_radioi8_dev_s *dev, + const uint8_t *saddr) +{ + IEEE802154_SADDRCOPY(dev->state.addr.saddr, saddr); + + wlinfo("setcoordsaddr: %02X:%02X\n", saddr[0], saddr[1]); + return OK; +} + +/**************************************************************************** + * Name: nrf52_radioi8_setcoordeaddr + * + * Description: + * Define the coordinator extended address. The following addresses are + * special: + * + * FFFFFFFFFFFFFFFFh : Unspecified + * + ****************************************************************************/ + +static int nrf52_radioi8_setcoordeaddr(struct nrf52_radioi8_dev_s *dev, + const uint8_t *eaddr) +{ + int i = 0; + + wlinfo("setcoordeaddr: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + eaddr[0], eaddr[1], eaddr[2], eaddr[3], eaddr[4], eaddr[5], + eaddr[6], eaddr[7]); + + for (i = 0; i < 8; i++) + { + dev->state.addr.eaddr[i] = eaddr[i]; + } + + return OK; +} + +/**************************************************************************** + * Name: nrf52_radioi8_setdevmode + * + * Description: + * Define the device behaviour: endpoint, coord or PAN coord. + * + ****************************************************************************/ + +static int nrf52_radioi8_setdevmode(struct nrf52_radioi8_dev_s *dev, + uint8_t mode) +{ + wlinfo("setdevmode %d\n", mode); + + if (mode < IEEE802154_DEVMODE_ENDPOINT || + mode > IEEE802154_DEVMODE_PANCOORD) + { + return -EINVAL; + } + + dev->state.devmode = mode; + return OK; +} + +/**************************************************************************** + * Name: nrf52_radioi8_bind + * + * Description: + * Bind radio callbacks. + * + ****************************************************************************/ + +static int nrf52_radioi8_bind(struct ieee802154_radio_s *radio, + struct ieee802154_radiocb_s *radiocb) +{ + struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)radio; + + DEBUGASSERT(dev != NULL); + dev->radiocb = radiocb; + return OK; +} + +/**************************************************************************** + * Name: nrf52_radioi8_reset + * + * Description: + * Reset radio. + * + ****************************************************************************/ + +static int nrf52_radioi8_reset(struct ieee802154_radio_s *radio) +{ + struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)radio; + struct ieee802154_cca_s cca; + int ret = OK; + +#ifdef CONFIG_NRF52_RADIO_IEEE802154_TRACE + /* Reset trace */ + + nrf52_radioi8_trace_init(); +#endif + + /* Reset radio state */ + + memset(&dev->state, 0, sizeof(struct nrf52_radioi8_state_s)); + + /* Initialize radio in IEEE 802.15.4 mode */ + + ret = dev->radio->ops->reset(dev->radio); + if (ret < 0) + { + goto errout; + } + + /* Reset TIMER */ + + dev->tim->ops->reset(dev); + +#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME + /* Reset RTC */ + + dev->rtc->ops->reset(dev); +#endif + + /* Set channel */ + + nrf52_radioi8_setchannel(dev, 11); + + /* Configure default CCA: + * - CCA mode ED + * - no carrier sense + * - recommenced ED threshold -69 dBm + */ + + cca.use_ed = 1; + cca.use_cs = 0; + cca.edth = 0x60; + cca.csth = 0x00; + nrf52_radioi8_setcca(dev, &cca); + + /* Configure initial RX mode */ + + nrf52_radioi8_setrxmode(dev, NRF52_RXMODE_NORMAL); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf52_radioi8_getattr + * + * Description: + * Get radio attribute. + * + ****************************************************************************/ + +static int nrf52_radioi8_getattr(struct ieee802154_radio_s *radio, + enum ieee802154_attr_e attr, + union ieee802154_attr_u *attrval) +{ + struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)radio; + int ret = OK; + + switch (attr) + { + case IEEE802154_ATTR_MAC_EADDR: + { + memcpy(&attrval->mac.eaddr[0], &dev->state.addr.eaddr[0], 8); + ret = IEEE802154_STATUS_SUCCESS; + break; + } + + case IEEE802154_ATTR_MAC_MAX_FRAME_WAITTIME: + { + attrval->mac.max_frame_waittime = + dev->radio->state.max_frame_waittime; + ret = IEEE802154_STATUS_SUCCESS; + break; + } + + case IEEE802154_ATTR_PHY_SYMBOL_DURATION: + { + attrval->phy.symdur_picosec = (IEEE802154_SYMBOL_US * 1000000); + ret = IEEE802154_STATUS_SUCCESS; + break; + } + + case IEEE802154_ATTR_PHY_CHAN: + { + attrval->phy.chan = dev->state.chan; + ret = IEEE802154_STATUS_SUCCESS; + break; + } + + case IEEE802154_ATTR_PHY_FCS_LEN: + { + attrval->phy.fcslen = 2; + ret = IEEE802154_STATUS_SUCCESS; + break; + } + + case IEEE802154_ATTR_PHY_REGDUMP: + { + NRF52_RADIO_DUMPREGS(dev->radio->lower); + break; + } + +#ifdef CONFIG_NRF52_RADIO_IEEE802154_TRACE + case IEEE802154_ATTR_PHY_TRACEDUMP: + { + nrf52_radioi8_trace_dump(); + break; + } +#endif + + default: + { + ret = IEEE802154_STATUS_UNSUPPORTED_ATTRIBUTE; + break; + } + } + + return ret; +} + +/**************************************************************************** + * Name: nrf52_radioi8_setattr + * + * Description: + * Set radio attribute. + * + ****************************************************************************/ + +static int nrf52_radioi8_setattr(struct ieee802154_radio_s *radio, + enum ieee802154_attr_e attr, + const union ieee802154_attr_u *attrval) +{ + struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)radio; + int ret = IEEE802154_STATUS_SUCCESS; + + switch (attr) + { + case IEEE802154_ATTR_MAC_PANID: + { + nrf52_radioi8_setpanid(dev, attrval->mac.panid); + break; + } + + case IEEE802154_ATTR_MAC_SADDR: + { + nrf52_radioi8_setsaddr(dev, attrval->mac.saddr); + break; + } + + case IEEE802154_ATTR_MAC_EADDR: + { + nrf52_radioi8_seteaddr(dev, attrval->mac.eaddr); + break; + } + + case IEEE802154_ATTR_MAC_COORD_SADDR: + { + nrf52_radioi8_setcoordsaddr(dev, attrval->mac.coordsaddr); + break; + } + + case IEEE802154_ATTR_MAC_COORD_EADDR: + { + nrf52_radioi8_setcoordeaddr(dev, attrval->mac.coordeaddr); + break; + } + + case IEEE802154_ATTR_MAC_PROMISCUOUS_MODE: + { + if (attrval->mac.promisc_mode) + { + nrf52_radioi8_setrxmode(dev, NRF52_RXMODE_PROMISC); + } + else + { + nrf52_radioi8_setrxmode(dev, NRF52_RXMODE_NORMAL); + } + break; + } + + case IEEE802154_ATTR_PHY_CHAN: + { + nrf52_radioi8_setchannel(dev, attrval->phy.chan); + break; + } + + case IEEE802154_ATTR_MAC_DEVMODE: + { + nrf52_radioi8_setdevmode(dev, attrval->mac.devmode); + break; + } + + default: + { + ret = IEEE802154_STATUS_UNSUPPORTED_ATTRIBUTE; + break; + } + } + + return ret; +} + +/**************************************************************************** + * Name: nrf52_radioi8_txnotify + * + * Description: + * Driver callback invoked when new TX data is available. This is a + * stimulus perform an out-of-cycle poll and, thereby, reduce the TX + * latency. + * + ****************************************************************************/ + +static int nrf52_radioi8_txnotify(struct ieee802154_radio_s *radio, + bool gts) +{ + struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)radio; + int ret = OK; + + if (gts) + { + ret = dev->radio->ops->gts_poll(dev); + } + else + { + ret = dev->radio->ops->csma_poll(dev); + } + + return ret; +} + +/**************************************************************************** + * Name: nrf52_radioi8_txdelayed + * + * Description: + * Transmit a packet without regard to supeframe structure after a certain + * number of symbols. This function is used to send Data Request + * responses. It can also be used to send data immediately if the delay + * is set to 0. + * + ****************************************************************************/ + +static int nrf52_radioi8_txdelayed(struct ieee802154_radio_s *radio, + struct ieee802154_txdesc_s *txdesc, + uint32_t symboldelay) +{ + struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)radio; + int ret = OK; + + /* Get exclusive access to the radio device */ + + ret = nxmutex_lock(&dev->lock); + if (ret < 0) + { + return ret; + } + + /* There should never be more than one of these transactions at once. */ + + DEBUGASSERT(!dev->state.txdelayed_busy); + + dev->state.txdelayed_desc = txdesc; + dev->state.txdelayed_busy = true; + + /* TODO: should we add txdelayed to queue ? */ + + if (dev->radio->state.csma_busy) + { + return -EBUSY; + } + + /* Wait for ACKTX done - we start transmition in + * nrf52_radioi8_state_acktx() + */ + + if (dev->radio->state.state == NRF52_RADIO_STATE_ACKTX) + { + goto out; + } + + /* Setup TX */ + + dev->radio->ops->norm_setup(dev, txdesc->frame, false); + + if (symboldelay == 0) + { + /* Send now */ + + dev->radio->ops->norm_trigger(dev); + } + else + { + /* Run TIMER - TX is handled in timer isr */ + + dev->tim->ops->setup(dev, NRF52_TIMER_CHAN_TXDELAY, symboldelay); + } + +out: + nxmutex_unlock(&dev->lock); + return OK; +} + +/**************************************************************************** + * Name: nrf52_radioi8_rxenable + * + * Description: + * Enable/Disable receiver. + * + ****************************************************************************/ + +static int nrf52_radioi8_rxenable(struct ieee802154_radio_s *radio, + bool enable) +{ + struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)radio; + + wlinfo("rxenable %d\n", enable); + return dev->radio->ops->rxenable(dev, enable); +} + +/**************************************************************************** + * Name: nrf52_radioi8_energydetect + * + * Description: + * Start the energy detect measurement. + * + ****************************************************************************/ + +static int nrf52_radioi8_energydetect(struct ieee802154_radio_s *radio, + uint32_t nsymbols) +{ + struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)radio; + + return dev->radio->ops->energydetect(dev, nsymbols); +} + +/**************************************************************************** + * Name: nrf52_radioi8_setchannel + * + * Description: + * Define the current radio channel the device is operating on. + * In the 2.4 GHz, there are 16 channels, each 2 MHz wide, 5 MHz spacing: + * + * Chan MHz Chan MHz Chan MHz Chan MHz + * 11 2405 15 2425 19 2445 23 2465 + * 12 2410 16 2430 20 2450 24 2470 + * 13 2415 17 2435 21 2455 25 2475 + * 14 2420 18 2440 22 2460 26 2480 + * + ****************************************************************************/ + +static int nrf52_radioi8_setchannel(struct nrf52_radioi8_dev_s *dev, + uint8_t chan) +{ + int ret = OK; + + wlinfo("setchannel: %u\n", (unsigned)chan); + + if (dev->state.chan == chan) + { + return OK; + } + + if (chan < 11 || chan > 26) + { + wlerr("Invalid chan: %d\n", chan); + return -EINVAL; + } + + ret = dev->radio->ops->setchannel(dev, chan); + if (ret < 0) + { + wlerr("dev->radio->ops->setchannel failed %d\n", ret); + return -EINVAL; + } + + dev->state.chan = chan; + + return OK; +} + +/**************************************************************************** + * Name: nrf52_radioi8_setcca + * + * Description: + * Define the Clear Channel Assessement method. + * + ****************************************************************************/ + +static int nrf52_radioi8_setcca(struct nrf52_radioi8_dev_s *dev, + struct ieee802154_cca_s *cca) +{ + int ret = OK; + + if (!cca->use_ed && !cca->use_cs) + { + return -EINVAL; + } + + if (cca->use_cs && cca->csth > 0x0f) + { + return -EINVAL; + } + + /* Configure CCA */ + + ret = dev->radio->ops->setcca(dev, cca); + if (ret < 0) + { + wlerr("dev->radio->ops->setcca failed %d\n", ret); + return -EINVAL; + } + + memcpy(&dev->state.cca, cca, sizeof(struct ieee802154_cca_s)); + + return OK; +} + +/**************************************************************************** + * Name: nrf52_radioi8_beaconstart + * + * Description: + * Start beacon. + * + ****************************************************************************/ + +static int +nrf52_radioi8_beaconstart(struct ieee802154_radio_s *radio, + const struct ieee802154_superframespec_s *sfspec, + struct ieee802154_beaconframe_s *beacon) +{ +#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME + struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)radio; + irqstate_t flags; + + if (sfspec->pancoord) + { + flags = enter_critical_section(); + + /* Local copy */ + + memcpy(&dev->state.sf, (void *)sfspec, + sizeof(struct ieee802154_superframespec_s)); + + /* Setup beacon transmition */ + + dev->radio->ops->beacon_setup(dev, beacon->bf_data, beacon->bf_len); + + /* Configure RTC events */ + + dev->rtc->ops->setup(dev, &dev->state.sf); + + /* Start RTC */ + + dev->rtc->ops->start(dev); + + leave_critical_section(flags); + } + else + { + /* TODO: missing logic for non-PAN coord */ + + return -ENOTTY; + } + + return OK; +#else + return -ENOTSUP; +#endif +} + +/**************************************************************************** + * Name: nrf52_radioi8_beaconupdate + * + * Description: + * Update beacon. + * + ****************************************************************************/ + +static int +nrf52_radioi8_beaconupdate(struct ieee802154_radio_s *radio, + struct ieee802154_beaconframe_s *beacon) +{ +#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME + struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)radio; + irqstate_t flags; + + flags = enter_critical_section(); + + /* Arm the beacon TX buffer */ + + memcpy(&dev->radio->beaconbuf[1], beacon->bf_data, beacon->bf_len); + + /* Length = Frame data + CRC */ + + dev->radio->beaconbuf[0] = beacon->bf_len + 2; + + leave_critical_section(flags); + + return OK; +#else + return -ENOTSUP; +#endif +} + +/**************************************************************************** + * Name: nrf52_radioi8_beaconstop + * + * Description: + * Stop beacon. + * + ****************************************************************************/ + +static int nrf52_radioi8_beaconstop(struct ieee802154_radio_s *radio) +{ +#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME + struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)radio; + irqstate_t flags; + + flags = enter_critical_section(); + + /* Stop RTC */ + + dev->rtc->ops->stop(dev); + + leave_critical_section(flags); + + return OK; +#else + return -ENOTSUP; +#endif +} + +/**************************************************************************** + * Name: nrf52_radioi8_sfupdate + * + * Description: + * Update super frame. + * + ****************************************************************************/ + +static int +nrf52_radioi8_sfupdate(struct ieee802154_radio_s *radio, + const struct ieee802154_superframespec_s *sfspec) +{ +#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME + struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)radio; + irqstate_t flags; + + flags = enter_critical_section(); + + /* Local copy */ + + memcpy(&dev->state.sf, (void *)sfspec, + sizeof(struct ieee802154_superframespec_s)); + + /* If we are operating on a beacon-enabled network, use slotted CSMA */ + + if (sfspec->beaconorder < 15) + { + /* Need slotted CSMA-CA */ + + dev->radio->state.slotted = true; + + /* Configure RTC */ + + dev->rtc->ops->setup(dev, &dev->state.sf); + + /* Wait for beacon to sync */ + + dev->radio->state.wait_for_beacon = true; + } + else + { + /* Need un-slotted CSMA-CA */ + + dev->radio->state.slotted = false; + } + + leave_critical_section(flags); + + return OK; +#else + return -ENOTSUP; +#endif +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf52_radioi8_register + * + * Description: + * Register NRF52 radio in IEE802154 mode. + * + ****************************************************************************/ + +struct ieee802154_radio_s * +nrf52_radioi8_register(struct nrf52_radio_board_s *board) +{ + struct nrf52_radioi8_dev_s *dev = &g_nrf52_radioi8; + + /* Reset data */ + + memset(&g_nrf52_radioi8, 0, sizeof(struct nrf52_radioi8_dev_s)); + + /* Allow exclusive access to the privmac struct */ + + nxmutex_init(&dev->lock); + + /* Initialize lower-half radio */ + + dev->radio = nrf52_radioi8_radio_init(dev, board); + if (dev->radio == NULL) + { + wlerr("nrf52_radioi8_radio_init failed %d\n", -errno); + return NULL; + } + + DEBUGASSERT(dev->radio->ops->txstart); + DEBUGASSERT(dev->radio->ops->notify_noack); + DEBUGASSERT(dev->radio->ops->ccastart); + DEBUGASSERT(dev->radio->ops->rxenable); + DEBUGASSERT(dev->radio->ops->energydetect); + DEBUGASSERT(dev->radio->ops->setchannel); + DEBUGASSERT(dev->radio->ops->setcca); + DEBUGASSERT(dev->radio->ops->norm_setup); + DEBUGASSERT(dev->radio->ops->norm_trigger); +#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME + DEBUGASSERT(dev->radio->ops->beacon_setup); + DEBUGASSERT(dev->radio->ops->beacon_tx); +#endif + DEBUGASSERT(dev->radio->ops->reset); + DEBUGASSERT(dev->radio->ops->csma_poll); + DEBUGASSERT(dev->radio->ops->gts_poll); + + /* Initialize TIMER */ + + dev->tim = nrf52_radioi8_tim_init(dev); + if (dev->tim == NULL) + { + wlerr("nrf52_radioi8_tim_init failed %d\n", -errno); + return NULL; + } + + DEBUGASSERT(dev->tim->ops->setup); + DEBUGASSERT(dev->tim->ops->stop); + DEBUGASSERT(dev->tim->ops->reset); + +#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME + /* Initialize RTC */ + + dev->rtc = nrf52_radioi8_rtc_init(dev); + if (dev->rtc == NULL) + { + wlerr("nrf52_radioi8_rtc_init failed %d\n", -errno); + return NULL; + } + + DEBUGASSERT(dev->rtc->ops->setup); + DEBUGASSERT(dev->rtc->ops->start); + DEBUGASSERT(dev->rtc->ops->stop); + DEBUGASSERT(dev->rtc->ops->reset); +#endif + + /* Connect MAC ops */ + + dev->macops.bind = nrf52_radioi8_bind; + dev->macops.reset = nrf52_radioi8_reset; + dev->macops.getattr = nrf52_radioi8_getattr; + dev->macops.setattr = nrf52_radioi8_setattr; + dev->macops.txnotify = nrf52_radioi8_txnotify; + dev->macops.txdelayed = nrf52_radioi8_txdelayed; + dev->macops.rxenable = nrf52_radioi8_rxenable; + dev->macops.energydetect = nrf52_radioi8_energydetect; + dev->macops.beaconstart = nrf52_radioi8_beaconstart; + dev->macops.beaconupdate = nrf52_radioi8_beaconupdate; + dev->macops.beaconstop = nrf52_radioi8_beaconstop; + dev->macops.sfupdate = nrf52_radioi8_sfupdate; + + return &dev->macops; +} diff --git a/arch/arm/src/nrf52/nrf52_ieee802154_priv.h b/arch/arm/src/nrf52/nrf52_ieee802154_priv.h new file mode 100644 index 0000000000000..04e542ee3aa6d --- /dev/null +++ b/arch/arm/src/nrf52/nrf52_ieee802154_priv.h @@ -0,0 +1,144 @@ +/**************************************************************************** + * arch/arm/src/nrf52/nrf52_ieee802154_priv.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_PRIV_H +#define __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_PRIV_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include + +#include "nrf52_ieee802154_radio.h" +#include "nrf52_ieee802154_rtc.h" +#include "nrf52_ieee802154_tim.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* GTS slots */ + +#ifndef CONFIG_NRF52_RADIO_IEEE802154_GTS_SLOTS +# define NRF52_GTS_SLOTS 0 +#else +# define NRF52_GTS_SLOTS CONFIG_NRF52_RADIO_IEEE802154_GTS_SLOTS +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* RX modes */ + +enum nrf52_ieee802154_rxmode_e +{ + NRF52_RXMODE_NORMAL, + NRF52_RXMODE_PROMISC, + NRF52_RXMODE_NOCRC +}; + +/* Device modes */ + +enum nrf52_ieee802154_devmode_e +{ + NRF52_DEVMODE_ENDPOINT, + NRF52_DEVMODE_COORD, + NRF52_DEVMODE_PANCOORD +}; + +/* IEEE 802.15.4 device state */ + +struct nrf52_radioi8_state_s +{ + /* MAC Attributes */ + + struct ieee802154_addr_s addr; /* Address */ + struct ieee802154_cca_s cca; /* Clear channel assessement method */ + + /* TX CSMA */ + + struct ieee802154_txdesc_s *txdelayed_desc; + struct ieee802154_txdesc_s *csma_desc; + + /* Radio state */ + + uint8_t chan; /* 11 to 26 for the 2.4 GHz band */ + uint8_t devmode; /* device mode: endpoint, coord, PAN coord */ + uint8_t rxmode; /* Reception mode: Normal, no CRC, promiscuous */ + + /* TX state */ + + bool txdelayed_busy; /* No CSMA transfer */ + +#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME + /* Superframe data */ + + struct ieee802154_superframespec_s sf; + + /* TX GTS */ + + struct ieee802154_txdesc_s *gts_desc[NRF52_GTS_SLOTS]; + bool gts_busy[NRF52_GTS_SLOTS]; +#endif +}; + +/* IEEE 802.15.4 radio device */ + +struct nrf52_radioi8_dev_s +{ + /* The public device instance - must be first */ + + struct ieee802154_radio_s macops; + + /* Registered callbacks */ + + struct ieee802154_radiocb_s *radiocb; + + /* Radio interface */ + + struct nrf52_radioi8_radio_s *radio; + + /* High resolution timer */ + + struct nrf52_radioi8_tim_s *tim; + + /* Low resolution, low power timer */ + +#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME + struct nrf52_radioi8_rtc_s *rtc; +#endif + + /* Radio state */ + + struct nrf52_radioi8_state_s state; + + /* Exclusive access to this struct */ + + mutex_t lock; +}; + +#endif /* __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_PRIV_H */ diff --git a/arch/arm/src/nrf52/nrf52_ieee802154_radio.c b/arch/arm/src/nrf52/nrf52_ieee802154_radio.c new file mode 100644 index 0000000000000..e3f1cefeb62d3 --- /dev/null +++ b/arch/arm/src/nrf52/nrf52_ieee802154_radio.c @@ -0,0 +1,2116 @@ +/**************************************************************************** + * arch/arm/src/nrf52/nrf52_ieee802154_radio.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include + +#include "nrf52_ieee802154_radio.h" +#include "nrf52_ieee802154_trace.h" + +#include "nrf52_ieee802154_priv.h" + +#include "hardware/nrf52_utils.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Constant from NRF52 manual */ + +#define NRF52_ED_RSSISCALE (4) + +/* ED configuration: + * - IRQ on EDEND event (sampling of energy detection complete) + * - shortcut between READY and EDSTART + * - shortcut between EDEND and DISABLE + * + * Set in nrf52_radioi8_energydetect() reset in nrf52_radioi8_isr_radio(). + * + * EDSTART task set in nrf52_radioi8_energydetect(). + */ + +#define IEEE802154_ED_INT (RADIO_INT_EDEND) +#define IEEE802154_ED_SHORTS (RADIO_SHORTS_READY_EDSTART | \ + RADIO_SHORTS_EDEND_DISABLE) + +/* RX configuration: + * - IRQ on END event (packet recveived) + * - shortcut between RXREADY and START + * - shortcut between END and DISABLE + * + * Set in nrf52_radioi8_rxenable() reset in nrf52_radioi8_rxenable(). + * + * RXEN task set in nrf52_radioi8_rxenable() and + * nrf52_radioi8_isr_radio() after RX handled and no pending ACKTX. + */ + +#define IEEE802154_RX_INT (RADIO_INT_END) +#define IEEE802154_RX_SHORTS (RADIO_SHORTS_RXREADY_START | \ + RADIO_SHORTS_END_DISABLE) + +/* NOTE: for TX we trigger interrupts on PHYEND event, not END! */ + +/* TX CCA un-slotted configuration: + * - IRQ on PHYEND event + * - IRQ on CCABUSY event + * - shortcut between TXREADY and START + * - shortcut between PHYEND and DISABLE + * - shortcut between RXREADY and CCASTART + * - shortcut between CCAIDLE and STOP + * - shortcut between CCAIDLE and TXEN + * + * Set in nrf52_radioi8_radio_norm_setup() reset in + * nrf52_radioi8_isr_radio(). + * + * CCASTART task set in nrf52_radioi8_isr_tim() when CCA transfer. + */ + +#define IEEE802154_TXCCAUNSLT_INT (RADIO_INT_PHYEND | \ + RADIO_INT_CCABUSY) +#define IEEE802154_TXCCAUNSLT_SHORTS (RADIO_SHORTS_TXREADY_START | \ + RADIO_SHORTS_PHYEND_DISABLE | \ + RADIO_SHORTS_RXREADY_CCASTART | \ + RADIO_SHORTS_CCAIDLE_STOP | \ + RADIO_SHORTS_CCAIDLE_TXEN) + +/* TX CCA slotted configuration: + * - IRQ on PHYEND event + * - IRQ on CCABUSY event + * - IRQ on CCAIDLE event + * - shortcut between TXREADY and START + * - shortcut between PHYEND and DISABLE + * + * Set in nrf52_radioi8_radio_norm_setup() reset in + * nrf52_radioi8_isr_radio(). + * + * CCASTART task set in nrf52_radioi8_isr_tim() when CCA transfer. + */ + +#define IEEE802154_TXCCASLT_INT (RADIO_INT_PHYEND | \ + RADIO_INT_CCAIDLE | \ + RADIO_INT_CCABUSY) +#define IEEE802154_TXCCASLT_SHORTS (RADIO_SHORTS_TXREADY_START | \ + RADIO_SHORTS_PHYEND_DISABLE | \ + RADIO_SHORTS_RXREADY_CCASTART) + +/* TX no-CCA configuration: + * - IRQ on PHYEND event + * - shortcut between TXREADY and START + * - shortcut between PHYEND and DISABLE + * + * Set in nrf52_radioi8_radio_norm_setup() reset in + * nrf52_radioi8_isr_radio(). + * + * TXEN task set in nrf52_radioi8_radio_norm_trigger() when non-CCA + * transfer or in nrf52_radioi8_isr_tim() for TXDELAY. + */ + +#define IEEE802154_TX_INT (RADIO_INT_PHYEND) +#define IEEE802154_TX_SHORTS (RADIO_SHORTS_TXREADY_START | \ + RADIO_SHORTS_PHYEND_DISABLE) + +/* ACK configuration: + * - IRQ on PHYEND event + * - shortcut between PHYEND and DISABLE + * + * Set in nrf52_radioi8_ack_transmit reset in nrf52_radioi8_isr_radio(). + * + * TXEN task set in nrf52_radioi8_ack_transmit(). + * START task set in nrf52_radioi8_isr_tim(). + */ + +#define IEEE802154_ACKTX_INT (RADIO_INT_PHYEND) +#define IEEE802154_ACKTX_SHORTS (RADIO_SHORTS_PHYEND_DISABLE) + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void nrf52_radioi8_rx_parse(struct nrf52_radioi8_dev_s *dev, + uint8_t *ftype, uint8_t *cmdtype); +static void nrf52_radioi8_ack_transmit(struct nrf52_radioi8_dev_s *dev); +static bool nrf52_radioi8_filter(struct nrf52_radioi8_dev_s *dev); +#if NRF52_GTS_SLOTS > 0 +static void nrf52_radioi8_gts_setup(struct nrf52_radioi8_dev_s *dev, + uint8_t fifo, struct iob_s *frame); +#endif + +/* Ops */ + +static void nrf52_radioi8_txstart(struct nrf52_radioi8_dev_s *dev); +static void nrf52_radioi8_ccastart(struct nrf52_radioi8_dev_s *dev); +static void nrf52_radioi8_notify_noack(struct nrf52_radioi8_dev_s *dev); +static int nrf52_radioi8_rxenable(struct nrf52_radioi8_dev_s *dev, + bool enable); +static int nrf52_radioi8_energydetect(struct nrf52_radioi8_dev_s *dev, + uint32_t nsymbols); +static int nrf52_radioi8_setchannel(struct nrf52_radioi8_dev_s *dev, + uint8_t chan); +static int nrf52_radioi8_setcca(struct nrf52_radioi8_dev_s *dev, + struct ieee802154_cca_s *cca); +static void nrf52_radioi8_norm_setup_buf(struct nrf52_radioi8_dev_s *dev, + uint8_t *buf, bool csma); +static void nrf52_radioi8_norm_setup(struct nrf52_radioi8_dev_s *dev, + struct iob_s *frame, bool csma); +static void nrf52_radioi8_norm_trigger(struct nrf52_radioi8_dev_s *dev); +#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME +static void nrf52_radioi8_beacon_setup(struct nrf52_radioi8_dev_s *dev, + uint8_t *data, uint8_t len); +static void nrf52_radioi8_beacon_tx(struct nrf52_radioi8_dev_s *dev); +#endif +static int nrf52_radioi8_reset(struct nrf52_radioi8_radio_s *dev); +static int nrf52_radioi8_csmapoll(struct nrf52_radioi8_dev_s *dev); +static int nrf52_radioi8_gtspoll(struct nrf52_radioi8_dev_s *dev); + +/* Interrupts logic */ + +static void nrf52_radioi8_work_noack(void *arg); +static void nrf52_radioi8_work_rx(void *arg); +static void nrf52_radioi8_work_tx(void *arg); +static void nrf52_radioi8_work_busy(void *arg); +static void nrf52_radioi8_work_ed(void *arg); +static void nrf52_radioi8_state_rx(struct nrf52_radioi8_dev_s *dev); +static void nrf52_radioi8_state_tx(struct nrf52_radioi8_dev_s *dev); +static void nrf52_radioi8_state_acktx(struct nrf52_radioi8_dev_s *dev); +static void nrf52_radioi8_state_ed(struct nrf52_radioi8_dev_s *dev); +static int nrf52_radioi8_isr_radio(int irq, void *context, void *arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Packet buffers - must be byte aligned in RAM. + * + * NOTE: The first byte is PHR, the last byte is LQI. + */ + +static uint8_t aligned_data(8) + g_nrf52_radioi8_rxbuf[IEEE802154_MAX_PHY_PACKET_SIZE + 2]; + +static uint8_t aligned_data(8) + g_nrf52_radioi8_txbuf[IEEE802154_MAX_PHY_PACKET_SIZE + 2]; + +static uint8_t aligned_data(8) + g_nrf52_radioi8_ackbuf[IEEE802154_ACK_FRAME_SIZE + 1]; + +#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME +static uint8_t aligned_data(8) + g_nrf52_radioi8_beaconbuf[IEEE802154_MAX_PHY_PACKET_SIZE + 2]; +#endif + +/* Radio ops */ + +struct nrf52_radioi8_radio_ops_s g_radioi8_radio_ops = +{ + .txstart = nrf52_radioi8_txstart, + .ccastart = nrf52_radioi8_ccastart, + .notify_noack = nrf52_radioi8_notify_noack, + .rxenable = nrf52_radioi8_rxenable, + .energydetect = nrf52_radioi8_energydetect, + .setchannel = nrf52_radioi8_setchannel, + .setcca = nrf52_radioi8_setcca, + .norm_setup = nrf52_radioi8_norm_setup, + .norm_trigger = nrf52_radioi8_norm_trigger, +#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME + .beacon_setup = nrf52_radioi8_beacon_setup, + .beacon_tx = nrf52_radioi8_beacon_tx, +#endif + .reset = nrf52_radioi8_reset, + .csma_poll = nrf52_radioi8_csmapoll, + .gts_poll = nrf52_radioi8_gtspoll +}; + +/* Radio interface */ + +struct nrf52_radioi8_radio_s g_radioi8_radio; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf52_radioi8_rx_parse + * + * Description: + * Get the RX frame type and command type if present. + * + ****************************************************************************/ + +static void nrf52_radioi8_rx_parse(struct nrf52_radioi8_dev_s *dev, + uint8_t *ftype, uint8_t *cmdtype) +{ + uint16_t *frame_ctrl = NULL; + uint8_t smode = 0; + uint8_t dmode = 0; + uint8_t panid_comp = 0; + int i = 0; + + /* Frame starts from offset 1 */ + + i = 1; + + /* Frame ctrl */ + + frame_ctrl = (uint16_t *)&dev->radio->rxbuf[i]; + i += sizeof(uint16_t); + + /* Frame seq */ + + i += 1; + + /* Return now if a given frame is not a command frame */ + + *ftype = ((*frame_ctrl & IEEE802154_FRAMECTRL_FTYPE) >> + IEEE802154_FRAMECTRL_SHIFT_FTYPE); + if (*ftype != IEEE802154_FRAME_COMMAND) + { + return; + } + + /* Now we have to find the offset for the frame command type */ + + smode = ((*frame_ctrl & IEEE802154_FRAMECTRL_SADDR) >> + IEEE802154_FRAMECTRL_SHIFT_SADDR); + + dmode = ((*frame_ctrl & IEEE802154_FRAMECTRL_DADDR) >> + IEEE802154_FRAMECTRL_SHIFT_DADDR); + + panid_comp = ((*frame_ctrl & IEEE802154_FRAMECTRL_PANIDCOMP) >> + IEEE802154_FRAMECTRL_SHIFT_PANIDCOMP); + + if (dmode != IEEE802154_ADDRMODE_NONE) + { + i += IEEE802154_PANIDSIZE; + + if (dmode == IEEE802154_ADDRMODE_SHORT) + { + i += IEEE802154_SADDRSIZE; + } + else if (dmode == IEEE802154_ADDRMODE_EXTENDED) + { + i += IEEE802154_EADDRSIZE; + } + } + + if (smode != IEEE802154_ADDRMODE_NONE) + { + if (!panid_comp) + { + i += IEEE802154_PANIDSIZE; + } + + if (smode == IEEE802154_ADDRMODE_SHORT) + { + i += IEEE802154_SADDRSIZE; + } + else if (smode == IEEE802154_ADDRMODE_EXTENDED) + { + i += IEEE802154_EADDRSIZE; + } + } + + *cmdtype = dev->radio->rxbuf[i]; +} + +/**************************************************************************** + * Name: nrf52_radioi8_ack_transmit + * + * Description: + * Transmit ACK. + * + ****************************************************************************/ + +static void nrf52_radioi8_ack_transmit(struct nrf52_radioi8_dev_s *dev) +{ + struct nrf52_radio_dev_s *lower = NULL; + uint8_t *ackbuf = dev->radio->ackbuf; + uint32_t regval = 0; + uint8_t ftype = 0; + uint8_t cmdtype = 0; + bool pending = false; + + DEBUGASSERT(dev); + lower = dev->radio->lower; + + /* Restore RX after ACK - we already are in DISABLE state so no need to + * disable RX + */ + + if (dev->radio->state.rxenabled) + { + dev->radio->state.rxrestore = true; + } + + /* Clear events */ + + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_READY_OFFSET, 0); + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_TXREADY_OFFSET, 0); + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_RXREADY_OFFSET, 0); + + /* Fill ACK buffer */ + + ackbuf[0] = IEEE802154_ACK_FRAME_SIZE; + ackbuf[1] = 0x02; + ackbuf[2] = 0; + ackbuf[3] = dev->radio->rxbuf[3]; + + /* Get RX frame type */ + + nrf52_radioi8_rx_parse(dev, &ftype, &cmdtype); + + /* If this is ACK for Data Request command - set frame pending flag */ + + if (dev->state.devmode != NRF52_DEVMODE_ENDPOINT && + ftype == IEEE802154_FRAME_COMMAND && + cmdtype == IEEE802154_CMD_DATA_REQ) + { + pending = true; + } + + /* Set frame pedning flag for this ACK */ + + if (pending) + { + ackbuf[1] |= 0x10; + } + + /* Configure shorts and interrupts */ + + NRF52_RADIO_SHRTSET(lower, IEEE802154_ACKTX_SHORTS); + NRF52_RADIO_INTEN(lower, IEEE802154_ACKTX_INT); + + /* Set packet pointer - buffer must be aligned */ + + regval = (uint32_t)ackbuf; + DEBUGASSERT(nrf52_easydma_valid(regval)); + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_PACKETPTR_OFFSET, regval); + + /* Set state to ACK */ + + dev->radio->state.state = NRF52_RADIO_STATE_ACKTX; + + /* Enable TX - start TX is called from timer interrupt */ + + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_TASKS_TXEN_OFFSET, 1); + + /* Run TIMER - TX is handled in timer isr */ + + nrf52_radioi8_trace_put(RADIO_TRACE_ACKTX, pending); + dev->tim->ops->setup(dev, NRF52_TIMER_CHAN_ACK, IEEE802154_ACKIFS_SYMBOLS); +} + +/**************************************************************************** + * Name: nrf52_radioi8_filter + * + * Description: + * Filter received frames. + * + ****************************************************************************/ + +static bool nrf52_radioi8_filter(struct nrf52_radioi8_dev_s *dev) +{ + struct ieee802154_addr_s addr; + uint8_t *rx = &dev->radio->rxbuf[1]; + uint16_t *fc = (uint16_t *)&rx[0]; + + /* Promiscuous mode */ + + if (dev->state.rxmode == NRF52_RXMODE_PROMISC) + { + return true; + } + + /* Beacon frame */ + + if (((*fc & IEEE802154_FRAMECTRL_FTYPE) == IEEE802154_FRAME_BEACON) && + IEEE802154_PANIDCMP(IEEE802154_PANID_UNSPEC, &dev->state.addr.panid)) + { + return true; + } + + /* Get destination address */ + + IEEE802154_PANIDCOPY(addr.panid, &rx[3]); + addr.mode = ((*fc & IEEE802154_FRAMECTRL_DADDR) >> + IEEE802154_FRAMECTRL_SHIFT_DADDR); + if (addr.mode == IEEE802154_ADDRMODE_SHORT) + { + IEEE802154_SADDRCOPY(addr.saddr, &rx[5]); + } + else if (addr.mode == IEEE802154_ADDRMODE_EXTENDED) + { + IEEE802154_EADDRCOPY(addr.eaddr, &rx[5]); + } + + /* PAN ID match */ + + if (!IEEE802154_PANIDCMP(IEEE802154_PANID_UNSPEC, dev->state.addr.panid) && + !IEEE802154_PANIDCMP(addr.panid, &dev->state.addr.panid)) + { + return false; + } + + /* Destination address match */ + + if (addr.mode == IEEE802154_ADDRMODE_SHORT) + { + if (IEEE802154_SADDRCMP(addr.saddr, + &dev->state.addr.saddr)) + { + return true; + } + + else if (IEEE802154_SADDRCMP(addr.saddr, + IEEE802154_SADDR_UNSPEC)) + { + return true; + } + } + else if (addr.mode == IEEE802154_ADDRMODE_EXTENDED) + { + if (IEEE802154_EADDRCMP(addr.eaddr, + &dev->state.addr.eaddr)) + { + return true; + } + + else if (IEEE802154_EADDRCMP(addr.eaddr, + IEEE802154_EADDR_UNSPEC)) + { + return true; + } + } + + /* Otherwise drop this frame */ + + return false; +} + +#if NRF52_GTS_SLOTS > 0 +/**************************************************************************** + * Name: nrf52_radioi8_gts_setup + * + * Description: + * Setup a GTS transaction. + * + ****************************************************************************/ + +static void nrf52_radioi8_gts_setup(struct nrf52_radioi8_dev_s *dev, + uint8_t fifo, struct iob_s *frame) +{ + /* Missing logic */ + + ASSERT(0); +} + +/**************************************************************************** + * Name: nrf52_radioi8_dopoll_gts + * + * Description: + * This function is called in order to perform an out-of-sequence TX poll. + * + ****************************************************************************/ + +static void nrf52_radioi8_dopoll_gts(void *arg) +{ + struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)arg; + int gts = 0; + int len = 0; + + /* Get exclusive access to the driver */ + + while (nxmutex_lock(&dev->lock) < 0) + { + } + + for (gts = 0; gts < NRF52_GTS_SLOTS; gts++) + { + if (!dev->state.gts_busy[gts]) + { + len = dev->radiocb->poll(dev->radiocb, true, + &dev->state.gts_desc[gts]); + + if (len > 0) + { + /* Now the txdesc is in use */ + + dev->state.gts_busy[gts] = 1; + + /* Setup the GTS transaction */ + + nrf52_radioi8_gts_setup(dev, gts, + dev->state.gts_desc[gts]->frame); + } + } + } + + nxmutex_unlock(&dev->lock); +} +#endif /* NRF52_GTS_SLOTS > 0 */ + +/**************************************************************************** + * Name: nrf52_radioi8_txstart + * + * Description: + * Start transmition, TX must be armed (TXEN must be set). + * + ****************************************************************************/ + +static void nrf52_radioi8_txstart(struct nrf52_radioi8_dev_s *dev) +{ + struct nrf52_radio_dev_s *lower = NULL; + + DEBUGASSERT(dev); + lower = dev->radio->lower; + + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_TASKS_START_OFFSET, 1); +} + +/**************************************************************************** + * Name: nrf52_radioi8_ccastart + * + * Description: + * Start CCA, RX must be armed (RXEN must be set). + * + ****************************************************************************/ + +static void nrf52_radioi8_ccastart(struct nrf52_radioi8_dev_s *dev) +{ + struct nrf52_radio_dev_s *lower = NULL; + + DEBUGASSERT(dev); + lower = dev->radio->lower; + + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_TASKS_CCASTART_OFFSET, 1); +} + +/**************************************************************************** + * Name: nrf52_radioi8_notify_noack + * + * Description: + * Notify Radio layer about noack event. + * + ****************************************************************************/ + +static void nrf52_radioi8_notify_noack(struct nrf52_radioi8_dev_s *dev) +{ + /* If flag is set - no ACK was received */ + + if (dev->radio->state.waitack == true) + { + /* Notify MAC layer */ + + DEBUGASSERT(work_available(&dev->radio->noackwork)); + work_queue(HPWORK, &dev->radio->noackwork, + nrf52_radioi8_work_noack, (void *)dev, 0); + + /* Clear flag */ + + dev->radio->state.waitack = false; + } +} + +/**************************************************************************** + * Name: nrf52_radioi8_rxenable + * + * Description: + * Enable/Disable receiver. + * + ****************************************************************************/ + +static int nrf52_radioi8_rxenable(struct nrf52_radioi8_dev_s *dev, + bool enable) +{ + struct nrf52_radio_dev_s *lower = NULL; + uint32_t regval = 0; + + DEBUGASSERT(dev); + lower = dev->radio->lower; + + if (enable) + { + nrf52_radioi8_trace_put(RADIO_TRACE_RXENABLE, 0); + + /* Clear events */ + + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_END_OFFSET, 0); + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_READY_OFFSET, 0); + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_PHYEND_OFFSET, 0); + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_TXREADY_OFFSET, 0); + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_RXREADY_OFFSET, 0); + + /* Configure shorts and interrupts */ + + NRF52_RADIO_SHRTSET(lower, IEEE802154_RX_SHORTS); + NRF52_RADIO_INTEN(lower, IEEE802154_RX_INT); + + /* Set packet pointer - buffer must be aligned */ + + regval = (uint32_t)dev->radio->rxbuf; + DEBUGASSERT(nrf52_easydma_valid(regval)); + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_PACKETPTR_OFFSET, regval); + + /* Set state to RX */ + + dev->radio->state.state = NRF52_RADIO_STATE_RX; + + /* Start RX */ + + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_TASKS_RXEN_OFFSET, 1); + } + else + { + nrf52_radioi8_trace_put(RADIO_TRACE_RXDISABLE, 0); + + /* Disalbe interrups and shorts */ + + NRF52_RADIO_INTCLR(lower, IEEE802154_RX_INT); + NRF52_RADIO_SHRTSET(lower, 0); + + /* Disable RX */ + + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_TASKS_DISABLE_OFFSET, 1); + } + + /* Store state */ + + dev->radio->state.rxenabled = enable; + + /* Data returned by callback in ISR */ + + return OK; +} + +/**************************************************************************** + * Name: nrf52_radioi8_energydetect + * + * Description: + * Start the energy detect measurement. + * + ****************************************************************************/ + +static int nrf52_radioi8_energydetect(struct nrf52_radioi8_dev_s *dev, + uint32_t nsymbols) +{ + struct nrf52_radio_dev_s *lower = NULL; + + DEBUGASSERT(dev); + lower = dev->radio->lower; + + /* Clear events */ + + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_EDEND_OFFSET, 0); + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_READY_OFFSET, 0); + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_RXREADY_OFFSET, 0); + + /* Configure shortucts and interrupts */ + + NRF52_RADIO_SHRTSET(lower, IEEE802154_ED_SHORTS); + NRF52_RADIO_INTEN(lower, IEEE802154_ED_INT); + + /* Configure ED symbols */ + + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EDCNT_OFFSET, nsymbols); + + /* Set state to ENERGY_DETECT (ED) */ + + dev->radio->state.state = NRF52_RADIO_STATE_ED; + + /* Start RX */ + + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_TASKS_RXEN_OFFSET, 1); + + /* Data returned by callback in ISR */ + + return OK; +} + +/**************************************************************************** + * Name: nrf52_radioi8_setchannel + * + * Description: + * Define the current radio channel the device is operating on. + * + ****************************************************************************/ + +static int nrf52_radioi8_setchannel(struct nrf52_radioi8_dev_s *dev, + uint8_t chan) +{ + struct nrf52_radio_dev_s *lower = NULL; + uint32_t freq = 2405 + 5 * (chan - 11); + + DEBUGASSERT(dev); + lower = dev->radio->lower; + + return NRF52_RADIO_FREQSET(lower, freq); +} + +/**************************************************************************** + * Name: nrf52_radioi8_setcca + * + * Description: + * Configure the Clear Channel Assessement. + * + ****************************************************************************/ + +static int nrf52_radioi8_setcca(struct nrf52_radioi8_dev_s *dev, + struct ieee802154_cca_s *cca) +{ + struct nrf52_radio_dev_s *lower = NULL; + struct nrf52_radio_cca_s c; + + DEBUGASSERT(dev); + lower = dev->radio->lower; + + /* Fill radio sturcture */ + + memset(&c, 0, sizeof(struct nrf52_radio_cca_s)); + + if (cca->use_ed && !cca->use_cs) + { + c.mode = NRF52_RADIO_CCA_ED; + } + else if (~cca->use_ed && cca->use_cs) + { + c.mode = NRF52_RADIO_CCA_CARRIER; + } + else if (cca->use_ed && cca->use_cs) + { + c.mode = NRF52_RADIO_CCA_CARRIER_AND_ED; + } + + c.edthres = cca->edth; + c.corrthres = cca->csth; + c.corrcnt = 5; + + /* Configure radio */ + + NRF52_RADIO_CCACFG(lower, &c); + + return OK; +} + +/**************************************************************************** + * Name: nrf52_radioi8_norm_setup_buf + * + * Description: + * Setup a normal transaction (non GTS) from buffer. + * + ****************************************************************************/ + +static void nrf52_radioi8_norm_setup_buf(struct nrf52_radioi8_dev_s *dev, + uint8_t *buf, bool csma) +{ + struct nrf52_radio_dev_s *lower = NULL; + uint32_t regval = 0; + + DEBUGASSERT(dev); + lower = dev->radio->lower; + + nrf52_radioi8_trace_put(RADIO_TRACE_CSMASETUP, csma); + + /* If RX is enabled - we have to temporarly disable it */ + + if (dev->radio->state.rxenabled) + { + dev->macops.rxenable((struct ieee802154_radio_s *)dev, false); + + /* Restore RX after TX completed */ + + dev->radio->state.rxrestore = true; + } + + /* Set packet pointer - buffer must be aligned */ + + regval = (uint32_t)buf; + DEBUGASSERT(nrf52_easydma_valid(regval)); + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_PACKETPTR_OFFSET, regval); + + if (csma) + { + /* Clear events */ + + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_END_OFFSET, 0); + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_READY_OFFSET, 0); + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_PHYEND_OFFSET, 0); + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_TXREADY_OFFSET, 0); + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_CCABUSY_OFFSET, 0); + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_CCAIDLE_OFFSET, 0); + + /* Configure shorts and interrupts */ + + if (dev->radio->state.slotted) + { +#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME + NRF52_RADIO_SHRTSET(lower, IEEE802154_TXCCASLT_SHORTS); + NRF52_RADIO_INTEN(lower, IEEE802154_TXCCASLT_INT); +#else + ASSERT(0); +#endif + } + else + { + NRF52_RADIO_SHRTSET(lower, IEEE802154_TXCCAUNSLT_SHORTS); + NRF52_RADIO_INTEN(lower, IEEE802154_TXCCAUNSLT_INT); + } + + dev->radio->state.state = NRF52_RADIO_STATE_TX_CSMA; + } + else + { + /* Clear events */ + + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_END_OFFSET, 0); + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_READY_OFFSET, 0); + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_PHYEND_OFFSET, 0); + + /* Configure shorts and interrupts */ + + NRF52_RADIO_SHRTSET(lower, IEEE802154_TX_SHORTS); + NRF52_RADIO_INTEN(lower, IEEE802154_TX_INT); + dev->radio->state.state = NRF52_RADIO_STATE_TX_NOCSMA; + } +} + +/**************************************************************************** + * Name: nrf52_radioi8_norm_setup + * + * Description: + * Setup a normal transaction (non GTS). + * + ****************************************************************************/ + +static void nrf52_radioi8_norm_setup(struct nrf52_radioi8_dev_s *dev, + struct iob_s *frame, bool csma) +{ + /* The first byte in TX buffer is PHR */ + + dev->radio->txbuf[0] = frame->io_len; + + /* Allocate space for CRC */ + + dev->radio->txbuf[0] += 2; + + /* Copy frame to RX buffer - we must send from aligned buffer */ + + memcpy(&dev->radio->txbuf[1], &frame->io_data[0], frame->io_len); + + /* Setup buffer */ + + nrf52_radioi8_norm_setup_buf(dev, dev->radio->txbuf, csma); +} + +/**************************************************************************** + * Name: nrf52_radioi8_trg_csma + * + * Description: + * Trigger transaction with CSMA-CA. + * + ****************************************************************************/ + +static void nrf52_radioi8_trg_csma(struct nrf52_radioi8_dev_s *dev) +{ + uint32_t delay = 0; + + /* Set state to TX */ + + dev->radio->state.state = NRF52_RADIO_STATE_TX; + + /* Need slotted CSMA-CA */ + + if (dev->radio->state.slotted) + { +#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME + if (!dev->radio->state.csma_busy) + { + /* Initial backoff state */ + + dev->radio->state.NB = 0; + dev->radio->state.CW = IEEE802154_CW0; + } + + /* Battery life extension */ + + if (dev->radio->state.ble) + { + dev->radio->state.BE = MIN(2, dev->radio->state.min_be); + } + else + { + dev->radio->state.BE = dev->radio->state.min_be; + } + + /* Get random unit backoff period delay */ + + delay = rand() % ((1 << dev->radio->state.BE) - 1); + + /* TODO: + * - locate backoff period boundary + * - perform CCA on backoff period boundary + */ + + ASSERT(0); +#else + ASSERT(0); +#endif + } + + /* Need un-slotted CSMA-CA */ + + else + { + if (!dev->radio->state.csma_busy) + { + /* Initial backoff state */ + + dev->radio->state.NB = 0; + dev->radio->state.BE = dev->radio->state.min_be; + } + + /* Get random unit backoff period delay */ + + delay = rand() % ((1 << dev->radio->state.BE) - 1); + } + + /* CSMA is in use */ + + dev->radio->state.csma_busy = true; + nrf52_radioi8_trace_put(RADIO_TRACE_CSMATRIGGER, delay); + + dev->tim->ops->setup(dev, NRF52_TIMER_CHAN_CSMADELAY, + delay * IEEE802154_UNIT_BACKOFF_PERIOD); +} + +/**************************************************************************** + * Name: nrf52_radioi8_trg_nocsma + * + * Description: + * Trigger transaction without CSMA-CA; + * + ****************************************************************************/ + +static void nrf52_radioi8_trg_nocsma(struct nrf52_radioi8_dev_s *dev) +{ + struct nrf52_radio_dev_s *lower = NULL; + + DEBUGASSERT(dev); + lower = dev->radio->lower; + + /* Set state to TX */ + + dev->radio->state.state = NRF52_RADIO_STATE_TX; + + /* Start TX - we transmit immediately */ + + nrf52_radioi8_trace_put(RADIO_TRACE_NOCSMATRIGGER, + dev->radio->state.state); + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_TASKS_TXEN_OFFSET, 1); +} + +/**************************************************************************** + * Name: nrf52_radioi8_norm_trigger + * + * Description: + * Trigger normal transaction (non GTS). + * + ****************************************************************************/ + +static void nrf52_radioi8_norm_trigger(struct nrf52_radioi8_dev_s *dev) +{ + /* Wait for ACK */ + + if (dev->radio->txbuf[1] & IEEE802154_FRAMECTRL_ACKREQ) + { + dev->radio->state.waitack = true; + } + + /* CSMA transmition */ + + if (dev->radio->state.state == NRF52_RADIO_STATE_TX_CSMA) + { + nrf52_radioi8_trg_csma(dev); + } + + /* No-CSMA transmition */ + + else if (dev->radio->state.state == NRF52_RADIO_STATE_TX_NOCSMA) + { + nrf52_radioi8_trg_nocsma(dev); + } + + /* Invalid state */ + + else + { + /* We should not be there */ + + DEBUGASSERT(0); + } +} + +#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME +/**************************************************************************** + * Name: nrf52_radioi8_beacon_setup + * + * Description: + * Setup a beacon frame transfer + * + ****************************************************************************/ + +static void nrf52_radioi8_beacon_setup(struct nrf52_radioi8_dev_s *dev, + uint8_t *data, uint8_t len) +{ + /* Set beacon TX buffer */ + + memcpy(&dev->radio->beaconbuf[1], data, len); + + /* Length = Frame data + CRC */ + + dev->radio->beaconbuf[0] = len + 2; +} + +/**************************************************************************** + * Name: nrf52_radioi8_beacon_tx + * + * Description: + * Transmit a beacon frame (non CSMA-CA transfer). + * + ****************************************************************************/ + +static void nrf52_radioi8_beacon_tx(struct nrf52_radioi8_dev_s *dev) +{ + /* Beacon buffer is ready to send - transmit as non CSMA-CA */ + + nrf52_radioi8_norm_setup_buf(dev, dev->radio->beaconbuf, false); + + /* Send now */ + + nrf52_radioi8_norm_trigger(dev); +} +#endif + +/**************************************************************************** + * Name: nrf52_radioi8_reset + * + * Description: + * Reset radio state to work with IEEE 802.15.4. + * + ****************************************************************************/ + +static int nrf52_radioi8_reset(struct nrf52_radioi8_radio_s *dev) +{ + struct nrf52_radio_dev_s *radio = NULL; + struct nrf52_radio_crc_s crc; + struct nrf52_radio_pktcfg_s pcfg; + int ret = OK; + + DEBUGASSERT(dev); + radio = dev->lower; + + /* Reset radio state */ + + memset(&dev->state, 0, sizeof(struct nrf52_radioi8_radio_data_s)); + + /* Reset radio */ + + NRF52_RADIO_RESET(radio); + + /* MAC prameters */ + + dev->state.max_frame_waittime = IEEE802154_MAX_FRAME_WAITTIME; + dev->state.max_csma_backoffs = IEEE802154_MAX_CSMA_BACKOFFS; + dev->state.min_be = IEEE802154_MIN_BE; + dev->state.max_be = IEEE802154_MAX_BE; + + /* Set radio IEEE 802.15.4 mode */ + + ret = NRF52_RADIO_MODESET(radio, NRF52_RADIO_MODE_IEEE802154); + if (ret < 0) + { + goto errout; + } + + /* Configure CRC */ + + crc.len = 2; + crc.skip = NRF52_RADIO_CRC_SKIPADDR_IEEE802154; + crc.poly = 0x011021; + crc.init = 0; + + ret = NRF52_RADIO_CRCCFG(radio, &crc); + if (ret < 0) + { + goto errout; + } + + /* Configure packet for IEEE 802.15.4 mode */ + + pcfg.max_len = IEEE802154_MAX_PHY_PACKET_SIZE; + pcfg.stat_len = 0; + pcfg.bal_len = 0; + pcfg.lf_len = 8; + pcfg.s0_len = 0; + pcfg.s1_len = 0; + pcfg.ci_len = 0; + pcfg.pl_len = NRF52_RADIO_PREAMBLE_32BITZERO; + pcfg.term_len = 0; + pcfg.crcinc = true; + pcfg.endian = false; + pcfg.whiteen = false; + + ret = NRF52_RADIO_PKTCFG(radio, &pcfg); + if (ret < 0) + { + goto errout; + } + + /* Disable hardware TIFS */ + + NRF52_RADIO_PUTREG(radio, NRF52_RADIO_MODECNF0_OFFSET, + RADIO_MODECNF0_RU); + + /* Set TX power */ + + NRF52_RADIO_TXPWRSET(radio, 0); + + /* TODO: Configure LNA/PA */ + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf52_radioi8_dopoll_csma + * + * Description: + * Out-of-sequence TX poll. + * + ****************************************************************************/ + +void nrf52_radioi8_dopoll_csma(void *arg) +{ + struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)arg; + int len = 0; + + /* Get exclusive access to the driver */ + + while (nxmutex_lock(&dev->lock) < 0) + { + } + + /* If this a CSMA transaction and we have room in the CSMA */ + + if (!dev->radio->state.csma_busy) + { + wlinfo("Polling for frame\n"); + len = dev->radiocb->poll(dev->radiocb, false, &dev->state.csma_desc); + + if (len > 0) + { + wlinfo("Frame received. Frame length: %d\n", len); + + /* Setup the CSMA transaction */ + + dev->radio->ops->norm_setup(dev, dev->state.csma_desc->frame, + true); + dev->radio->ops->norm_trigger(dev); + } + } + + nxmutex_unlock(&dev->lock); +} + +/**************************************************************************** + * Name: nrf52_radioi8_csmapoll + * + * Description: + * Handle CSMA poll. + * + ****************************************************************************/ + +static int nrf52_radioi8_csmapoll(struct nrf52_radioi8_dev_s *dev) +{ + /* Is our single work structure available? It may not be if there are + * pending interrupt actions and we will have to ignore the Tx + * availability action. + */ + + if (work_available(&dev->radio->csma_pollwork)) + { + /* Schedule to serialize the poll on the worker thread. */ + + work_queue(HPWORK, &dev->radio->csma_pollwork, + nrf52_radioi8_dopoll_csma, dev, 0); + } + + return OK; +} + +/**************************************************************************** + * Name: nrf52_radioi8_gtspoll + * + * Description: + * Handle GTS poll. + * + ****************************************************************************/ + +static int nrf52_radioi8_gtspoll(struct nrf52_radioi8_dev_s *dev) +{ +#if NRF52_GTS_SLOTS > 0 + /* Is our single work structure available? It may not be if there are + * pending interrupt actions and we will have to ignore the Tx + * availability action. + */ + + if (work_available(&dev->radio->gts_pollwork)) + { + /* Schedule to serialize the poll on the worker thread. */ + + work_queue(HPWORK, &dev->radio->gts_pollwork, + nrf52_radioi8_dopoll_gts, dev, 0); + } + + return OK; +#else + /* GTS not supported */ + + return -ENOTSUP; +#endif +} + +/**************************************************************************** + * Name: nrf52_radioi8_work_noack + * + * Description: + * Handle no ACK work. + * + ****************************************************************************/ + +static void nrf52_radioi8_work_noack(void *arg) +{ + struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)arg; + struct nrf52_radio_dev_s *lower = NULL; + struct ieee802154_txdesc_s *tx = NULL; + bool *busy = NULL; + bool csma = false; + + DEBUGASSERT(dev); + lower = dev->radio->lower; + + nrf52_radioi8_trace_put(RADIO_TRACE_WORK_NOACK, 0); + + /* Get exclusive access to the driver */ + + while (nxmutex_lock(&dev->lock) < 0) + { + } + + if (dev->state.txdelayed_busy) + { + tx = dev->state.txdelayed_desc; + busy = &dev->state.txdelayed_busy; + csma = false; + } + else + { + tx = dev->state.csma_desc; + busy = &dev->radio->state.csma_busy; + csma = true; + } + + if (tx->retrycount > 0) + { + /* Disable RX */ + + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_TASKS_DISABLE_OFFSET, 1); + + /* Try again */ + + tx->retrycount -= 1; + nrf52_radioi8_trace_put(RADIO_TRACE_TXRETRY, tx->retrycount); + nrf52_radioi8_norm_setup(dev, tx->frame, csma); + nrf52_radioi8_norm_trigger(dev); + } + else + { + nrf52_radioi8_trace_put(RADIO_TRACE_NOACK, 0); + + tx->conf->status = IEEE802154_STATUS_NO_ACK; + tx->framepending = false; + dev->radiocb->txdone(dev->radiocb, tx); + *busy = false; + } + + /* Unlock the radio device */ + + nxmutex_unlock(&dev->lock); +} + +/**************************************************************************** + * Name: nrf52_radioi8_work_irq + * + * Description: + * Handle RX work. + * + ****************************************************************************/ + +static void nrf52_radioi8_work_rx(void *arg) +{ + struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)arg; + struct nrf52_radio_dev_s *lower = NULL; + struct ieee802154_primitive_s *prim = NULL; + struct ieee802154_data_ind_s *ind = NULL; + uint8_t index = 0; + bool crcok = false; + + DEBUGASSERT(dev); + lower = dev->radio->lower; + + nrf52_radioi8_trace_put(RADIO_TRACE_WORK_RX, 0); + + /* Get exclusive access to the driver */ + + while (nxmutex_lock(&dev->lock) < 0) + { + } + + /* Check CRC */ + + crcok = NRF52_RADIO_GETREG(lower, NRF52_RADIO_CRCSTATUS_OFFSET); + if (dev->state.rxmode != NRF52_RXMODE_NOCRC && crcok == false) + { + goto out; + } + + /* Allocate a data_ind to put the frame in */ + + prim = ieee802154_primitive_allocate(); + ind = (struct ieee802154_data_ind_s *)prim; + if (ind == NULL) + { + wlerr("ERROR: Unable to allocate data_ind. Discarding frame\n"); + goto out; + } + + prim->type = IEEE802154_PRIMITIVE_IND_DATA; + + /* Allocate an IOB to put the frame into */ + + ind->frame = iob_alloc(false); + DEBUGASSERT(ind->frame != NULL); + + /* First byte is the PHR */ + + ind->frame->io_len = dev->radio->rxbuf[0]; + + /* Reduce len by 2, we only receive frames with correct crc, no check + * required. + */ + + ind->frame->io_len -= 2; + + for (index = 0; index < ind->frame->io_len; index++) + { + ind->frame->io_data[index] = dev->radio->rxbuf[index + 1]; + } + + /* Set CRC fields to 0 */ + + ind->frame->io_data[index + 1] = 0; + ind->frame->io_data[index + 2] = 0; + + /* LQI is the last byte in RAM */ + + ind->lqi = dev->radio->rxbuf[index + 1]; + + /* RSSI is non-standard field and is not supported here. + * TODO: get RSSI from LQI ? + */ + + ind->rssi = 0; + + /* Callback the receiver in the next highest layer */ + + dev->radiocb->rxframe(dev->radiocb, ind); + +out: + + /* Re-Enable RX if not handling ACK TX now */ + + if (dev->radio->state.state != NRF52_RADIO_STATE_ACKTX) + { + /* Enable packet reception */ + + dev->macops.rxenable((struct ieee802154_radio_s *)dev, true); + } + + /* Unlock the radio device */ + + nxmutex_unlock(&dev->lock); +} + +/**************************************************************************** + * Name: nrf52_radioi8_work_tx + * + * Description: + * Handle TX work. + * + ****************************************************************************/ + +static void nrf52_radioi8_work_tx(void *arg) +{ + struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)arg; + enum ieee802154_status_e status; + bool fpending = false; + + nrf52_radioi8_trace_put(RADIO_TRACE_WORK_TX, 0); + + /* Get exclusive access to the driver */ + + while (nxmutex_lock(&dev->lock) < 0) + { + } + + /* Get frame pending flag from the last TX ACK */ + + fpending = dev->radio->state.framepending; + dev->radio->state.framepending = false; + + status = IEEE802154_STATUS_SUCCESS; + + if (dev->state.txdelayed_busy) + { + /* Inform the next layer of the transmission success/failure */ + + dev->state.txdelayed_desc->conf->status = status; + dev->state.txdelayed_desc->framepending = fpending; + dev->radiocb->txdone(dev->radiocb, dev->state.txdelayed_desc); + dev->state.txdelayed_desc = NULL; + dev->state.txdelayed_busy = false; + } + else + { + /* Inform the next layer of the transmission success/failure */ + + dev->state.csma_desc->conf->status = status; + dev->state.csma_desc->framepending = fpending; + dev->radiocb->txdone(dev->radiocb, dev->state.csma_desc); + dev->state.csma_desc = NULL; + + /* We are now done with the transaction */ + + dev->radio->state.csma_busy = false; + + /* Must unlock the radio before calling poll */ + + nxmutex_unlock(&dev->lock); + nrf52_radioi8_dopoll_csma(dev); + while (nxmutex_lock(&dev->lock) < 0) + { + } + } + + /* Re-Enable RX if not handling ACK TX now */ + + if (dev->radio->state.state != NRF52_RADIO_STATE_ACKTX) + { + /* Enable packet reception */ + + dev->macops.rxenable((struct ieee802154_radio_s *)dev, true); + } + + /* Unlock the radio device */ + + nxmutex_unlock(&dev->lock); +} + +/**************************************************************************** + * Name: nrf52_radioi8_work_busy + * + * Description: + * Handle CCABUSY work. + * + ****************************************************************************/ + +static void nrf52_radioi8_work_busy(void *arg) +{ + struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)arg; + + nrf52_radioi8_trace_put(RADIO_TRACE_WORK_BUSY, 0); + + /* Get exclusive access to the driver */ + + while (nxmutex_lock(&dev->lock) < 0) + { + } + + dev->state.txdelayed_desc->conf->status = + IEEE802154_STATUS_CHANNEL_ACCESS_FAILURE; + + dev->radiocb->txdone(dev->radiocb, dev->state.txdelayed_desc); + + /* Unlock the radio device */ + + nxmutex_unlock(&dev->lock); +} + +/**************************************************************************** + * Name: nrf52_radioi8_work_ed + * + * Description: + * Handle ED work. + * + ****************************************************************************/ + +static void nrf52_radioi8_work_ed(void *arg) +{ + struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)arg; + struct nrf52_radio_dev_s *lower = NULL; + int ed = 0; + + DEBUGASSERT(dev); + lower = dev->radio->lower; + + nrf52_radioi8_trace_put(RADIO_TRACE_WORK_ED, 0); + + /* Get result */ + + ed = NRF52_RADIO_GETREG(lower, NRF52_RADIO_EDSAMPLE_OFFSET); + + /* Convert to IEEE 802.15.4 scale */ + + ed = ((ed > 63) ? 255: (ed * NRF52_ED_RSSISCALE)); + + /* Callback the receiver in the next highest layer */ + + dev->radiocb->edresult(dev->radiocb, ed); +} + +/**************************************************************************** + * Name: nrf52_radioi8_state_rx + * + * Description: + * Handle radio interrupt for RX state. + * + ****************************************************************************/ + +static void nrf52_radioi8_state_rx(struct nrf52_radioi8_dev_s *dev) +{ + uint8_t *rxbuf = dev->radio->rxbuf; + + /* Frame filter */ + + if (dev->radio->state.waitack == false) + { + if (!nrf52_radioi8_filter(dev)) + { + nrf52_radioi8_trace_put(RADIO_TRACE_DROPFRAME, 0); + + /* Enable RX and ignore this frame */ + + dev->macops.rxenable((struct ieee802154_radio_s *)dev, + true); + return; + } + } + +#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME + /* TODO: resync with beacon ? */ + + if (dev->radio->state.wait_for_beacon == true) + { + uint16_t *fc = (uint16_t *)&rxbuf[0]; + + /* TODO: NOT TESTES, should we check panid here ? */ + + if (((*fc & IEEE802154_FRAMECTRL_FTYPE) == IEEE802154_FRAME_BEACON) && + IEEE802154_PANIDCMP(IEEE802154_PANID_UNSPEC, + &dev->state.addr.panid)) + { + /* Start RTC */ + + dev->rtc->ops->start(dev); + + dev->radio->state.wait_for_beacon = false; + } + } +#endif + + /* Start ACK handling now - this must be done in isr */ + + if (dev->state.rxmode == NRF52_RXMODE_NORMAL && + rxbuf[1] & IEEE802154_FRAMECTRL_ACKREQ && + rxbuf[0] != IEEE802154_ACK_FRAME_SIZE) + { + nrf52_radioi8_ack_transmit(dev); + } + + /* Store RX frame long flag */ + + dev->radio->state.rxlong = rxbuf[0] > 18 ? true : false; + + /* We don't wait for TX ACK - forward this frame to MAC */ + + if (dev->radio->state.waitack == false) + { + nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_RXDONE, 0); + + /* Receive DONE */ + + if (work_available(&dev->radio->irqwork)) + { + work_queue(HPWORK, &dev->radio->irqwork, + nrf52_radioi8_work_rx, (void *)dev, 0); + } + } + + /* We wait for TX ACK and this frame is ACK - confirm TX to MAC */ + + else if (rxbuf[0] == IEEE802154_ACK_FRAME_SIZE && + dev->radio->state.waitack == true) + { + nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_RXACKDONE, 0); + + /* ACK frame received */ + + dev->radio->state.waitack = false; + + /* Get frame pedning flag */ + + dev->radio->state.framepending = rxbuf[1] & 0x10; + + /* Clear timer */ + + dev->tim->ops->stop(dev); + + /* This is ACK - notify MAC that TX complete */ + + if (work_available(&dev->radio->irqwork)) + { + work_queue(HPWORK, &dev->radio->irqwork, + nrf52_radioi8_work_tx, (void *)dev, 0); + } + } + + /* We wait for TX ACK and this is not ACK - notify TX failure */ + + else + { + /* Clear flag */ + + dev->radio->state.waitack = false; + + /* And notify MAC */ + + DEBUGASSERT(work_available(&dev->radio->noackwork)); + work_queue(HPWORK, &dev->radio->noackwork, + nrf52_radioi8_work_noack, (void *)dev, 0); + } +} + +/**************************************************************************** + * Name: nrf52_radioi8_state_tx + * + * Description: + * Handle radio interrupt for TX state. + * + ****************************************************************************/ + +static void nrf52_radioi8_state_tx(struct nrf52_radioi8_dev_s *dev) +{ + struct nrf52_radio_dev_s *lower = NULL; + + DEBUGASSERT(dev); + lower = dev->radio->lower; + + if (dev->radio->state.waitack == true) + { + nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_WAITACK, 0); + + /* Start timer and wait for ACK */ + + dev->tim->ops->setup(dev, NRF52_TIMER_CHAN_WAITACK, + IEEE802154_ACK_WAIT); + } + else + { + nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_TXDONE, 0); + + /* Transmit DONE */ + + if (work_available(&dev->radio->irqwork)) + { + work_queue(HPWORK, &dev->radio->irqwork, + nrf52_radioi8_work_tx, (void *)dev, 0); + } + } + + /* CCABUSY event for TX */ + + if (NRF52_RADIO_GETREG(lower, NRF52_RADIO_EVENTS_CCABUSY_OFFSET)) + { + nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_TXCCABUSY, 0); + + /* Clear event */ + + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_CCABUSY_OFFSET, 0); + + /* Slotted CSMA-CA */ + + if (dev->radio->state.slotted == true) + { +#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME + dev->radio->state.NB += 1; + dev->radio->state.CW = IEEE802154_CW0; + dev->radio->state.BE = MIN(2, dev->radio->state.min_be); + + if (dev->radio->state.NB > dev->radio->state.max_csma_backoffs) + { + /* Return fauilure to MAC */ + + if (work_available(&dev->radio->irqwork)) + { + work_queue(HPWORK, &dev->radio->irqwork, + nrf52_radioi8_work_busy, (void *)dev, 0); + } + } + else + { + /* Try again */ + + dev->radio->state.state = NRF52_RADIO_STATE_TX_CSMA; + nrf52_radioi8_norm_trigger(dev); + + /* Do not restore RX */ + + return; + } +#else + ASSERT(0); +#endif + } + + /* Un-slotted CSMA-CA */ + + else + { + /* Update backoff */ + + dev->radio->state.NB -= 1; + dev->radio->state.BE = MIN(dev->radio->state.BE + 1, + dev->radio->state.max_be); + + if (dev->radio->state.NB > dev->radio->state.max_csma_backoffs) + { + /* Return fauilure to MAC */ + + if (work_available(&dev->radio->irqwork)) + { + work_queue(HPWORK, &dev->radio->irqwork, + nrf52_radioi8_work_busy, (void *)dev, 0); + } + } + else + { + /* Try again */ + + dev->radio->state.state = NRF52_RADIO_STATE_TX_CSMA; + nrf52_radioi8_norm_trigger(dev); + + /* Do not restore RX */ + + return; + } + } + } + + /* CCAIDLE event for TX */ + + if (NRF52_RADIO_GETREG(lower, NRF52_RADIO_EVENTS_CCAIDLE_OFFSET)) + { + /* Clear event */ + + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_CCAIDLE_OFFSET, 0); + + /* Slotted CSMA-CA */ + + if (dev->radio->state.slotted == true) + { +#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME + dev->radio->state.CW -= 1; + + if (dev->radio->state.CW == 0) + { + /* Enable TX - short TXREADY-START is enabled */ + + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_TASKS_TXEN_OFFSET, 1); + } + else + { + /* Do not restore RX */ + + return; + } +#else + ASSERT(0); +#endif + } + + /* Un-slotted CSMA-CA */ + + else + { + /* Nothing here */ + } + } + + /* Restore RX */ + + if (dev->radio->state.rxrestore | dev->radio->state.waitack) + { + dev->macops.rxenable((struct ieee802154_radio_s *)dev, true); + dev->radio->state.rxrestore = false; + } +} + +/**************************************************************************** + * Name: nrf52_radioi8_state_acktx + * + * Description: + * Handle radio interrupt for ACKTX state. + * + ****************************************************************************/ + +static void nrf52_radioi8_state_acktx(struct nrf52_radioi8_dev_s *dev) +{ + nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_ACKTX, 0); + + /* Handle pending TX */ + + if (dev->state.txdelayed_busy) + { + nrf52_radioi8_norm_setup(dev, + dev->state.txdelayed_desc->frame, + false); + + /* Send with timer to keep IFS */ + + if (dev->radio->state.rxlong) + { + dev->tim->ops->setup(dev, NRF52_TIMER_CHAN_TXDELAY, + IEEE802154_LIFS_SYMBOLS); + } + else + { + dev->tim->ops->setup(dev, NRF52_TIMER_CHAN_TXDELAY, + IEEE802154_SIFS_SYMBOLS); + } + } + + /* Restore RX */ + + else if (dev->radio->state.rxrestore) + { + dev->macops.rxenable((struct ieee802154_radio_s *)dev, true); + dev->radio->state.rxrestore = false; + } +} + +/**************************************************************************** + * Name: nrf52_radioi8_state_ed + * + * Description: + * Handle radio interrupt for ED state. + * + ****************************************************************************/ + +static void nrf52_radioi8_state_ed(struct nrf52_radioi8_dev_s *dev) +{ + /* Energy detect DONE */ + + DEBUGASSERT(work_available(&dev->radio->irqwork)); + work_queue(HPWORK, &dev->radio->irqwork, + nrf52_radioi8_work_ed, (void *)dev, 0); +} + +/**************************************************************************** + * Name: nrf52_radioi8_isr_radio + * + * Description: + * Radio IEEE 802.15.4 interrupt handler. + * + ****************************************************************************/ + +static int nrf52_radioi8_isr_radio(int irq, void *context, void *arg) +{ + struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)arg; + struct nrf52_radio_dev_s *lower = NULL; + irqstate_t flags; + uint8_t state; + + DEBUGASSERT(dev != NULL); + lower = dev->radio->lower; + + flags = enter_critical_section(); + + nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_RADIO, 0); + + /* Get state */ + + state = dev->radio->state.state; + dev->radio->state.state = NRF52_RADIO_STATE_DISABLED; + + /* Always clear END and PHYEND events */ + + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_END_OFFSET, 0); + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_PHYEND_OFFSET, 0); + + /* Clear interrupts and shorts */ + + NRF52_RADIO_INTCLR(lower, 0xffffffff); + NRF52_RADIO_SHRTSET(lower, 0); + + /* If by chance radio is not disabled - disable it now. This should be + * handled by SHORTS, but this not always work... + */ + + if (NRF52_RADIO_GETREG(lower, NRF52_RADIO_STATE_OFFSET) + != RADIO_STATE_DISABLED) + { + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_TASKS_DISABLE_OFFSET, 1); + + /* Don't wait for the DISABLED event, hopefully the radio will be + * disabled by the time we use it again. Max delay is TX->DSIABLED + * and takes 21us. + */ + } + + /* Handle IRQ depending on the current state */ + + switch (state) + { + case NRF52_RADIO_STATE_RX: + { + nrf52_radioi8_state_rx(dev); + + break; + } + + case NRF52_RADIO_STATE_TX: + { + nrf52_radioi8_state_tx(dev); + + break; + } + + case NRF52_RADIO_STATE_ACKTX: + { + nrf52_radioi8_state_acktx(dev); + + break; + } + + case NRF52_RADIO_STATE_ED: + { + /* Clear event */ + + NRF52_RADIO_PUTREG(lower, NRF52_RADIO_EVENTS_EDEND_OFFSET, 0); + + nrf52_radioi8_state_ed(dev); + + break; + } + + default: + { + ASSERT(0); + break; + } + } + + leave_critical_section(flags); + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf52_radioi8_radio_init + * + * Description: + * Initialize RADIO for IEEE802154 operations. + * + ****************************************************************************/ + +struct nrf52_radioi8_radio_s * +nrf52_radioi8_radio_init(struct nrf52_radioi8_dev_s *dev, + struct nrf52_radio_board_s *board) +{ + struct nrf52_radio_dev_s *radio = NULL; + + /* Initialize lower-half radio */ + + radio = nrf52_radio_initialize(0, board); + if (radio == NULL) + { + wlerr("nrf52_radio_initialize failed %d\n", -errno); + return NULL; + } + + /* Attach custom RADIO interrupt */ + + irq_attach(radio->irq, nrf52_radioi8_isr_radio, dev); + up_enable_irq(radio->irq); + + /* Set interrupts priority */ + + up_prioritize_irq(radio->irq, 0); + + /* Connect radioer */ + + memset(&g_radioi8_radio, 0, sizeof(struct nrf52_radioi8_radio_s)); + g_radioi8_radio.ops = &g_radioi8_radio_ops; + g_radioi8_radio.lower = radio; + + /* Connect buffers */ + + g_radioi8_radio.rxbuf = g_nrf52_radioi8_rxbuf; + g_radioi8_radio.txbuf = g_nrf52_radioi8_txbuf; + g_radioi8_radio.ackbuf = g_nrf52_radioi8_ackbuf; +#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME + g_radioi8_radio.beaconbuf = g_nrf52_radioi8_beaconbuf; +#endif + + return &g_radioi8_radio; +} diff --git a/arch/arm/src/nrf52/nrf52_ieee802154_radio.h b/arch/arm/src/nrf52/nrf52_ieee802154_radio.h new file mode 100644 index 0000000000000..8dd9146bd07d2 --- /dev/null +++ b/arch/arm/src/nrf52/nrf52_ieee802154_radio.h @@ -0,0 +1,246 @@ +/**************************************************************************** + * arch/arm/src/nrf52/nrf52_ieee802154_radio.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_RADIO_H +#define __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_RADIO_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "hardware/nrf52_radio.h" + +#include "nrf52_radio.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* IEEE 802.15.4 constants */ + +#define IEEE802154_MAX_FRAME_WAITTIME (16 + 32 + 4064) +#define IEEE802154_MAX_CSMA_BACKOFFS (1) +#define IEEE802154_MIN_BE (3) +#define IEEE802154_MAX_BE (5) +#define IEEE802154_CW0 (2) + +/* ACK_SYM + turnaround symbols + backoff */ + +#define IEEE802154_ACK_WAIT (12+ \ + IEEE802154_TURN_AROUND_TIME+ \ + IEEE802154_UNIT_BACKOFF_PERIOD) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Radio state */ + +enum nrf52_radioi8_state_e +{ + NRF52_RADIO_STATE_DISABLED = 0, /* Radio disabled */ + NRF52_RADIO_STATE_TX_CSMA, /* CSMA TX armed */ + NRF52_RADIO_STATE_TX_NOCSMA, /* Non CSMA TX armed */ + NRF52_RADIO_STATE_TX, /* TX on the air */ + NRF52_RADIO_STATE_RX, /* RX active */ + NRF52_RADIO_STATE_ACKTX, /* Transmiting ACK now */ + NRF52_RADIO_STATE_ED, /* Energy detection now */ +}; + +/* Radio data */ + +struct nrf52_radioi8_radio_data_s +{ + /* Radio state */ + + uint8_t state; + + /* CSMA-CA */ + + uint8_t NB; /* Number of required back offs */ + uint8_t CW; /* Contention window length */ + uint8_t BE; /* Backoff exponent */ + + /* RX state */ + + bool rxenabled; /* RX enabled now */ + bool rxrestore; /* RX needs to be restored */ + bool rxlong; /* Last RX frame was long */ + + /* TX state */ + + bool waitack; /* TX needs ACK */ + bool framepending; /* Frame pending from the last TX ACK */ + bool csma_busy; /* Un-slotted CSMA busy */ + bool slotted; /* Slotted CSMA-CA */ + + /* Radio configuration */ + + uint32_t max_frame_waittime; /* Max Frame wait time */ + uint8_t max_csma_backoffs; /* Max CSMA backoffs */ + uint8_t min_be; /* Min backoff exponent (BE) */ + uint8_t max_be; /* Max backoff exponent (BE) */ + +#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME + /* Superframe data */ + + bool wait_for_beacon; /* Device wait for beacon */ + bool ble; /* Batter life extension */ +#endif +}; + +/* Forward reference */ + +struct nrf52_radioi8_radio_s; +struct ieee802154_radio_s; +struct nrf52_radioi8_dev_s; +struct ieee802154_cca_s; + +/* Radio ops */ + +struct nrf52_radioi8_radio_ops_s +{ + /* Start transmition - TX must be armed (TXEN set) */ + + void (*txstart)(struct nrf52_radioi8_dev_s *dev); + + /* Start CCA - RX must be armed (RXEN set) */ + + void (*ccastart)(struct nrf52_radioi8_dev_s *dev); + + /* Notify MAC about no ACK */ + + void (*notify_noack)(struct nrf52_radioi8_dev_s *dev); + + /* Enable/Disable receiver */ + + int (*rxenable)(struct nrf52_radioi8_dev_s *dev, bool enable); + + /* Start the energy detect measurement */ + + int (*energydetect)(struct nrf52_radioi8_dev_s *dev, uint32_t nsymbols); + + /* Define the current radio channel the device is operating on */ + + int (*setchannel)(struct nrf52_radioi8_dev_s *dev, uint8_t chan); + + /* Configure the Clear Channel Assessement */ + + int (*setcca)(struct nrf52_radioi8_dev_s *dev, + struct ieee802154_cca_s *cca); + + /* Setup a normal transaction (non GTS) */ + + void (*norm_setup)(struct nrf52_radioi8_dev_s *dev, + struct iob_s *frame, bool csma); + + /* Trigger normal transaction (non GTS) */ + + void (*norm_trigger)(struct nrf52_radioi8_dev_s *dev); + +#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME + /* Setup a beacon frame transfe */ + + void (*beacon_setup)(struct nrf52_radioi8_dev_s *dev, + uint8_t *data, uint8_t len); + + /* Transmit a beacon frame (non CSMA-CA transfer) */ + + void (*beacon_tx)(struct nrf52_radioi8_dev_s *dev); +#endif + + /* Reset radio state to work with IEEE 802.15.4 */ + + int (*reset)(struct nrf52_radioi8_radio_s *dev); + + /* Handle TX poll (no GTS) */ + + int (*csma_poll)(struct nrf52_radioi8_dev_s *dev); + + /* Handle GTS poll */ + + int (*gts_poll)(struct nrf52_radioi8_dev_s *dev); +}; + +/* Radio interface */ + +struct nrf52_radioi8_radio_s +{ + /* Radio lower-half */ + + struct nrf52_radio_dev_s *lower; + + /* IEEE 802.15.4 radio operations */ + + struct nrf52_radioi8_radio_ops_s *ops; + + /* Packet buffers */ + + uint8_t *rxbuf; + uint8_t *txbuf; + uint8_t *ackbuf; +#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME + uint8_t *beaconbuf; +#endif + + /* For deferring interrupts work */ + + struct work_s irqwork; + + /* For deferring no ACK work */ + + struct work_s noackwork; + + /* For deferring poll work to the work queue */ + + struct work_s csma_pollwork; + +#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME + /* For deferring poll work to the work queue */ + + struct work_s gts_pollwork; +#endif + + /* Radio data */ + + struct nrf52_radioi8_radio_data_s state; +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf52_radioi8_radio_init + * + * Description: + * Initialize RADIO for IEEE802154 operations. + * + ****************************************************************************/ + +struct nrf52_radioi8_radio_s * +nrf52_radioi8_radio_init(struct nrf52_radioi8_dev_s *dev, + struct nrf52_radio_board_s *board); + +#endif /* __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_RADIO_H */ diff --git a/arch/arm/src/nrf52/nrf52_ieee802154_rtc.c b/arch/arm/src/nrf52/nrf52_ieee802154_rtc.c new file mode 100644 index 0000000000000..7d32b3df78cee --- /dev/null +++ b/arch/arm/src/nrf52/nrf52_ieee802154_rtc.c @@ -0,0 +1,392 @@ +/**************************************************************************** + * arch/arm/src/nrf52/nrf52_ieee802154_rtc.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include + +#include + +#include "nrf52_ieee802154_rtc.h" +#include "nrf52_ieee802154_trace.h" + +#include "nrf52_ieee802154_priv.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME +# warning Beacon and superframe support work in progress +#endif + +#ifndef CONFIG_NRF52_RTC0 +# error CONFIG_NRF52_RTC0 is needed to handle radio timings +#endif + +/* RTC instance - 0 */ + +#define NRF52_IEEE802154_RTC0 (0) + +/* RTC prescaler set to 0, freq = 32.768kHz, resolution = 30.517 us */ + +#define NRF52_RTC_PRESCALER (0) +#define NRF52_RTC_FREQUENCY (32768) + +#define NRF52_RTC_RESOLUTION_NS (30517) + +/* 31 * 30.517us = 946.027us */ + +#define NRF52_RTC_TIMESLOT_CC (31) + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* RTC ops */ + +static int nrf52_radioi8_rtc(struct nrf52_radioi8_dev_s *dev, + struct ieee802154_superframespec_s *sfspec); +static int nrf52_radioi8_rtc_start(struct nrf52_radioi8_dev_s *dev); +static int nrf52_radioi8_rtc_stop(struct nrf52_radioi8_dev_s *dev); +static void nrf52_radioi8_rtc_reset(struct nrf52_radioi8_dev_s *dev); + +/* Interrupts logic */ + +static void nrf52_radioi8_work_inactive(void *arg); +static int nrf52_radioi8_isr_rtc(int irq, void *context, void *arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* RTC ops */ + +static struct nrf52_radioi8_rtc_ops_s g_radioi8_rtc_ops = +{ + .setup = nrf52_radioi8_rtc, + .start = nrf52_radioi8_rtc_start, + .stop = nrf52_radioi8_rtc_stop, + .reset = nrf52_radioi8_rtc_reset +}; + +/* RTC instance */ + +static struct nrf52_radioi8_rtc_s g_radioi8_rtc; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf52_radioi8_rtc + * + * Description: + * Configure RTC events according to superframe spec. + * + ****************************************************************************/ + +static int nrf52_radioi8_rtc(struct nrf52_radioi8_dev_s *dev, + struct ieee802154_superframespec_s *sfspec) +{ + uint32_t bi = 0; + uint32_t sd = 0; + uint32_t cap = 0; + irqstate_t flags; + + flags = enter_critical_section(); + + /* Stop RTC and clear the counter */ + + NRF52_RTC_STOP(dev->rtc->rtc); + NRF52_RTC_CLEAR(dev->rtc->rtc); + + /* Initialize BI counter */ + + bi = ((IEEE802154_BASE_SUPERFRAME_DURATION * + (2 << sfspec->beaconorder) * + IEEE802154_SYMBOL_US * 1000) / + NRF52_RTC_RESOLUTION_NS); + NRF52_RTC_SETCC(dev->rtc->rtc, NRF52_RTC_BI, bi); + + /* Initialize SD counter */ + + sd = ((IEEE802154_BASE_SUPERFRAME_DURATION * + (2 << sfspec->sforder) * + IEEE802154_SYMBOL_US * 1000) / + NRF52_RTC_RESOLUTION_NS); + NRF52_RTC_SETCC(dev->rtc->rtc, NRF52_RTC_SD, sd); + + /* Initialize CAP counter */ + + cap = ((sfspec->final_capslot * + IEEE802154_TIMESLOT_US * 1000) / + NRF52_RTC_RESOLUTION_NS); + NRF52_RTC_SETCC(dev->rtc->rtc, NRF52_RTC_CAP, cap); + + /* Initialize timeslot counter */ + + dev->rtc->rtc_timeslot = NRF52_RTC_TIMESLOT_CC; + NRF52_RTC_SETCC(dev->rtc->rtc, NRF52_RTC_TIMESLOT, dev->rtc->rtc_timeslot); + + /* Configure interupts */ + + NRF52_RTC_ENABLEINT(dev->rtc->rtc, NRF52_RTC_BI); + NRF52_RTC_ENABLEINT(dev->rtc->rtc, NRF52_RTC_SD); + NRF52_RTC_ENABLEINT(dev->rtc->rtc, NRF52_RTC_CAP); + NRF52_RTC_ENABLEINT(dev->rtc->rtc, NRF52_RTC_TIMESLOT); + + /* Configure events */ + + NRF52_RTC_ENABLEEVT(dev->rtc->rtc, NRF52_RTC_BI); + NRF52_RTC_ENABLEEVT(dev->rtc->rtc, NRF52_RTC_SD); + NRF52_RTC_ENABLEEVT(dev->rtc->rtc, NRF52_RTC_CAP); + NRF52_RTC_ENABLEEVT(dev->rtc->rtc, NRF52_RTC_TIMESLOT); + + leave_critical_section(flags); + + return OK; +} + +/**************************************************************************** + * Name: nrf52_radioi8_rtc_start + * + * Description: + * Start RTC. + * + ****************************************************************************/ + +static int nrf52_radioi8_rtc_start(struct nrf52_radioi8_dev_s *dev) +{ + NRF52_RTC_START(dev->rtc->rtc); + return OK; +} + +/**************************************************************************** + * Name: nrf52_radioi8_rtc_stop + * + * Description: + * Stop RTC. + * + ****************************************************************************/ + +static int nrf52_radioi8_rtc_stop(struct nrf52_radioi8_dev_s *dev) +{ + NRF52_RTC_STOP(dev->rtc->rtc); + return OK; +} + +/**************************************************************************** + * Name: nrf52_radioi8_rtc_reset + * + * Description: + * Reset RTC. + * + ****************************************************************************/ + +static void nrf52_radioi8_rtc_reset(struct nrf52_radioi8_dev_s *dev) +{ + /* Configure RTC - freq = 32.768 kHz */ + + NRF52_RTC_STOP(dev->rtc->rtc); + NRF52_RTC_SETPRE(dev->rtc->rtc, NRF52_RTC_PRESCALER); + + /* Reset data */ + + dev->rtc->rtc_timeslot = 0; +} + +/**************************************************************************** + * Name: nrf52_radioi8_work_inactive + * + * Description: + * Work when we enter inactive state. + * + ****************************************************************************/ + +static void nrf52_radioi8_work_inactive(void *arg) +{ + struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)arg; + enum ieee802154_sfevent_e sfevent; + + /* Notify MAC */ + + sfevent = IEEE802154_SFEVENT_ENDOFACTIVE; + dev->radiocb->sfevent(dev->radiocb, sfevent); +} + +/**************************************************************************** + * Name: nrf52_radioi8_isr_rtc + * + * Description: + * Helper RTC0 interrupt handler. + * + ****************************************************************************/ + +static int nrf52_radioi8_isr_rtc(int irq, void *context, void *arg) +{ + struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)arg; + struct nrf52_radioi8_rtc_s *rtc = NULL; + irqstate_t flags; + + DEBUGASSERT(dev != NULL); + rtc = dev->rtc; + + flags = enter_critical_section(); + + /* End of CAP */ + + if (NRF52_RTC_CHECKINT(rtc->rtc, NRF52_RTC_CAP)) + { + nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_RTCCAP, 0); + + /* TODO */ + + /* Clear event */ + + NRF52_RTC_ACKINT(rtc->rtc, NRF52_RTC_CAP); + } + + /* End of active portion */ + + else if (NRF52_RTC_CHECKINT(rtc->rtc, NRF52_RTC_SD)) + { + nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_RTCSD, 0); + + /* Schedule work */ + + DEBUGASSERT(work_available(&dev->rtc->inactive_work)); + work_queue(HPWORK, &dev->rtc->inactive_work, + nrf52_radioi8_work_inactive, dev, 0); + + /* Reset timeslot */ + + rtc->rtc_timeslot = NRF52_RTC_TIMESLOT_CC; + + /* Clear event */ + + NRF52_RTC_ACKINT(rtc->rtc, NRF52_RTC_SD); + } + + /* Beacon interval */ + + else if (NRF52_RTC_CHECKINT(rtc->rtc, NRF52_RTC_BI)) + { + nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_RTCBI, 0); + + /* Transmit beacon if we are not endpoint */ + + if (dev->state.devmode != NRF52_DEVMODE_ENDPOINT) + { + /* Transmit data from beaconbuf */ + + dev->radio->ops->beacon_tx(dev); + } + + /* Clear event */ + + NRF52_RTC_ACKINT(rtc->rtc, NRF52_RTC_BI); + + /* Next cycle */ + + NRF52_RTC_TRGOVRFLW(rtc->rtc); + + /* TODO: resync with beacon ? */ + } + + /* Timeslot in active portion */ + + if (NRF52_RTC_CHECKINT(rtc->rtc, NRF52_RTC_TIMESLOT)) + { + nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_RTCTIMESLOT, 0); + + /* TODO: how to sync transmition with timeslot ? + * do we need count every timeslot here ? + * or wait for the timeslot we are interested in ? + * or just use txdelay ? + */ + + /* Update timeslot */ + + rtc->rtc_timeslot += NRF52_RTC_TIMESLOT_CC; + NRF52_RTC_SETCC(rtc->rtc, NRF52_RTC_TIMESLOT, rtc->rtc_timeslot); + + /* Clear event */ + + NRF52_RTC_ACKINT(rtc->rtc, NRF52_RTC_TIMESLOT); + } + + leave_critical_section(flags); + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf52_radioi8_rtc_init + * + * Description: + * Initialize low resoluton, low power timer for IEEE802154 operations. + * Used to handle superframe timings. + * + ****************************************************************************/ + +struct nrf52_radioi8_rtc_s * +nrf52_radioi8_rtc_init(struct nrf52_radioi8_dev_s *dev) +{ + struct nrf52_rtc_dev_s *rtc = NULL; + + /* Reserve RTC0 */ + + rtc = nrf52_rtc_init(NRF52_IEEE802154_RTC0); + if (rtc == NULL) + { + wlerr("nrf52_rtc_init(0) failed %d\n", -errno); + return NULL; + } + + /* Atach RTC interrupt */ + + NRF52_RTC_SETISR(rtc, nrf52_radioi8_isr_rtc, dev); + + /* Set interrupts priority */ + + up_prioritize_irq(NRF52_IRQ_RTC0, 0); + + /* Connect RTC */ + + memset(&g_radioi8_rtc, 0, sizeof(struct nrf52_radioi8_rtc_s)); + g_radioi8_rtc.ops = &g_radioi8_rtc_ops; + g_radioi8_rtc.rtc = rtc; + + return &g_radioi8_rtc; +} diff --git a/arch/arm/src/nrf52/nrf52_ieee802154_rtc.h b/arch/arm/src/nrf52/nrf52_ieee802154_rtc.h new file mode 100644 index 0000000000000..de6f475ff2dc9 --- /dev/null +++ b/arch/arm/src/nrf52/nrf52_ieee802154_rtc.h @@ -0,0 +1,116 @@ +/**************************************************************************** + * arch/arm/src/nrf52/nrf52_ieee802154_rtc.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_RTC_H +#define __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_RTC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "nrf52_rtc.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* RTC events */ + +enum nrf52_ieee802154_rtc_e +{ + NRF52_RTC_BI = 0, /* Beacon Interval interval (BI) */ + NRF52_RTC_TIMESLOT = 1, /* Time slot */ + NRF52_RTC_CAP = 2, /* Contention Access Period (CAP) */ + NRF52_RTC_SD = 3 /* Super Frame Duration (SD) */ +}; + +/* Forward reference */ + +struct nrf52_radioi8_rtc_s; +struct nrf52_radioi8_dev_s; + +/* RTC ops */ + +struct nrf52_radioi8_rtc_ops_s +{ + /* Configure RTC events according to superframe spec */ + + int (*setup)(struct nrf52_radioi8_dev_s *dev, + struct ieee802154_superframespec_s *sfspec); + + /* Start RTC */ + + int (*start)(struct nrf52_radioi8_dev_s *dev); + + /* Stop RTC */ + + int (*stop)(struct nrf52_radioi8_dev_s *dev); + + /* Reset RTC */ + + void (*reset)(struct nrf52_radioi8_dev_s *dev); +}; + +/* RTC interface */ + +struct nrf52_radioi8_rtc_s +{ + /* RTC lower-half */ + + struct nrf52_rtc_dev_s *rtc; + + /* IEEE 802.15.4 RTC operations */ + + struct nrf52_radioi8_rtc_ops_s *ops; + +#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME + /* For deferring inactive state work to the work queue */ + + struct work_s inactive_work; + + /* RTC state */ + + uint32_t rtc_timeslot; +#endif +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf52_radioi8_rtc_init + * + * Description: + * Initialize low resoluton, low power timer for IEEE802154 operations. + * Used to handle superframe timings. + * + ****************************************************************************/ + +struct nrf52_radioi8_rtc_s * +nrf52_radioi8_rtc_init(struct nrf52_radioi8_dev_s *dev); + +#endif /* __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_RTC_H */ diff --git a/arch/arm/src/nrf52/nrf52_ieee802154_tim.c b/arch/arm/src/nrf52/nrf52_ieee802154_tim.c new file mode 100644 index 0000000000000..7e8dd5749cbad --- /dev/null +++ b/arch/arm/src/nrf52/nrf52_ieee802154_tim.c @@ -0,0 +1,347 @@ +/**************************************************************************** + * arch/arm/src/nrf52/nrf52_ieee802154_tim.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include + +#include "nrf52_ieee802154_tim.h" +#include "nrf52_ieee802154_trace.h" + +#include "nrf52_ieee802154_priv.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_NRF52_TIMER0 +# error CONFIG_NRF52_TIMER0 is needed to handle radio timings +#endif + +/* Timer instance - 0 */ + +#define NRF52_IEEE802154_TIMER0 (0) + +/* Timer period set to 16us (symbol duration) */ + +#define NRF52_TIMER_FREQUENCY (1000000 / 16) + +/* 16MHz / (2 ** 8) = 62500 */ + +#define NRF52_TIMER_PRESCALER (8) + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* RTC ops */ + +static int nrf52_radioi8_tim(struct nrf52_radioi8_dev_s *dev, uint8_t chan, + uint32_t val); +static void nrf52_radioi8_tim_stop(struct nrf52_radioi8_dev_s *dev); +static void nrf52_radioi8_tim_reset(struct nrf52_radioi8_dev_s *dev); + +/* Interrupts logic */ + +static int nrf52_radioi8_isr_tim(int irq, void *context, void *arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Timer ops */ + +static struct nrf52_radioi8_tim_ops_s g_radioi8_tim_ops = +{ + .setup = nrf52_radioi8_tim, + .stop = nrf52_radioi8_tim_stop, + .reset = nrf52_radioi8_tim_reset +}; + +/* Timer instance */ + +static struct nrf52_radioi8_tim_s g_radioi8_tim; + +/**************************************************************************** + * Private Function + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf52_radioi8_tim + * + * Description: + * Configure TIMER event. + * + ****************************************************************************/ + +static int nrf52_radioi8_tim(struct nrf52_radioi8_dev_s *dev, uint8_t chan, + uint32_t val) +{ + struct nrf52_radioi8_tim_s *tim = NULL; + irqstate_t flags; + + DEBUGASSERT(dev != NULL); + tim = dev->tim; + + flags = enter_critical_section(); + + if (tim->tim_pending == true) + { + wlerr("TIMER busy! drop %" PRId8 " %" PRId32 " request\n", chan, val); + ASSERT(0); + return -EBUSY; + } + + /* Stop timer and clear the counter */ + + NRF52_TIM_STOP(tim->tim); + NRF52_TIM_CLEAR(tim->tim); + + /* Clear the previous event */ + + NRF52_TIM_ACKINT(tim->tim, chan); + + /* Set compare register */ + + NRF52_TIM_SETCC(tim->tim, chan, val); + + /* Configure interupt */ + + NRF52_TIM_ENABLEINT(tim->tim, chan); + + /* Set TIMER pending flag and used channel */ + + tim->tim_pending = true; + tim->tim_now = chan; + + /* Start timer */ + + nrf52_radioi8_trace_put(RADIO_TRACE_TIMSTART, chan); + + if (val > 0) + { + NRF52_TIM_START(tim->tim); + } + else + { + /* Call handler now */ + + nrf52_radioi8_isr_tim(0, NULL, dev); + } + + leave_critical_section(flags); + + return OK; +} + +/**************************************************************************** + * Name: nrf52_radioi8_tim_stop + * + * Description: + * Stop timer. + * + ****************************************************************************/ + +static void nrf52_radioi8_tim_stop(struct nrf52_radioi8_dev_s *dev) +{ + NRF52_TIM_STOP(dev->tim->tim); + NRF52_TIM_DISABLEINT(dev->tim->tim, dev->tim->tim_now); + + /* Reset state */ + + dev->tim->tim_pending = false; + dev->tim->tim_now = -1; +} + +/**************************************************************************** + * Name: nrf52_radioi8_tim_reset + * + * Description: + * Reset TIMER. + * + ****************************************************************************/ + +static void nrf52_radioi8_tim_reset(struct nrf52_radioi8_dev_s *dev) +{ + /* Configure TIMER - freq = 62500 */ + + NRF52_TIM_STOP(dev->tim->tim); + NRF52_TIM_CONFIGURE(dev->tim->tim, NRF52_TIM_MODE_TIMER, + NRF52_TIM_WIDTH_32B); + NRF52_TIM_SETPRE(dev->tim->tim, NRF52_TIMER_PRESCALER); + + /* Reset state */ + + dev->tim->tim_pending = false; + dev->tim->tim_now = -1; +} + +/**************************************************************************** + * Name: nrf52_radioi8_isr_tim + * + * Description: + * Helper tim interrupt handler. + * + ****************************************************************************/ + +static int nrf52_radioi8_isr_tim(int irq, void *context, void *arg) +{ + struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)arg; + struct nrf52_radioi8_tim_s *tim = NULL; + irqstate_t flags; + + DEBUGASSERT(dev != NULL); + tim = dev->tim; + + flags = enter_critical_section(); + + switch (tim->tim_now) + { + /* RX ACK handler */ + + case NRF52_TIMER_CHAN_ACK: + { + nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_TIMACKTX, 0); + + /* Start TX */ + + dev->radio->ops->txstart(dev); + + break; + } + + /* Delayed TX handler */ + + case NRF52_TIMER_CHAN_TXDELAY: + { + nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_TIMTXDELAY, 0); + + /* Trigger TX */ + + dev->radio->ops->norm_trigger(dev); + + break; + } + + /* ACK wait handler */ + + case NRF52_TIMER_CHAN_WAITACK: + { + nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_TIMWAITACK, 0); + + /* Notify radio layer */ + + dev->radio->ops->notify_noack(dev); + + break; + } + + case NRF52_TIMER_CHAN_CSMADELAY: + { + nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_TIMCSMADELAY, 0); + + /* Start CCA - we transmit immediately after the CCA procedure ends + * (CCAIDLE_TXEN short), or CCABUSY interrupt happen. + */ + + dev->radio->ops->ccastart(dev); + + break; + } + + default: + { + ASSERT(0); + break; + } + } + + /* Stop timer */ + + NRF52_TIM_STOP(tim->tim); + + /* Disable and clear interrupts */ + + NRF52_TIM_DISABLEINT(tim->tim, tim->tim_now); + NRF52_TIM_ACKINT(tim->tim, tim->tim_now); + + /* Clear TIMER pending flag and used channel */ + + tim->tim_pending = false; + tim->tim_now = -1; + + leave_critical_section(flags); + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf52_radioi8_tim_init + * + * Description: + * Initialize high resoluton timer for IEEE802154 operations. + * Used to handle short radio timeouts like ACK, IFS or delayed + * transmitions. + * + ****************************************************************************/ + +struct nrf52_radioi8_tim_s * +nrf52_radioi8_tim_init(struct nrf52_radioi8_dev_s *dev) +{ + struct nrf52_tim_dev_s *tim = NULL; + + /* Reserve TIMER0 */ + + tim = nrf52_tim_init(NRF52_IEEE802154_TIMER0); + if (tim == NULL) + { + wlerr("nrf52_tim_init(0) failed %d\n", -errno); + return NULL; + } + + /* Atach TIMER interrupt */ + + NRF52_TIM_SETISR(tim, nrf52_radioi8_isr_tim, dev); + + /* Set interrupts priority */ + + up_prioritize_irq(NRF52_IRQ_TIMER0, 0); + + /* Connect timer */ + + memset(&g_radioi8_tim, 0, sizeof(struct nrf52_radioi8_tim_s)); + g_radioi8_tim.ops = &g_radioi8_tim_ops; + g_radioi8_tim.tim = tim; + + return &g_radioi8_tim; +} diff --git a/arch/arm/src/nrf52/nrf52_ieee802154_tim.h b/arch/arm/src/nrf52/nrf52_ieee802154_tim.h new file mode 100644 index 0000000000000..0821353475b39 --- /dev/null +++ b/arch/arm/src/nrf52/nrf52_ieee802154_tim.h @@ -0,0 +1,105 @@ +/**************************************************************************** + * arch/arm/src/nrf52/nrf52_ieee802154_tim.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_TIM_H +#define __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_TIM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "nrf52_tim.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +enum nrf52_ieee802154_timer_e +{ + NRF52_TIMER_CHAN_ACK = 0, /* Handle ACK time */ + NRF52_TIMER_CHAN_TXDELAY = 1, /* Handle TX delay */ + NRF52_TIMER_CHAN_WAITACK = 2, /* Handle ACK wait */ + NRF52_TIMER_CHAN_CSMADELAY = 3, /* Handle CSMA wait */ +}; + +/* Forward reference */ + +struct nrf52_radioi8_tim_s; +struct nrf52_radioi8_dev_s; + +/* Timer ops */ + +struct nrf52_radioi8_tim_ops_s +{ + /* Configure TIMER event */ + + int (*setup)(struct nrf52_radioi8_dev_s *dev, uint8_t chan, uint32_t val); + + /* Stop timer */ + + void (*stop)(struct nrf52_radioi8_dev_s *dev); + + /* Reset timer */ + + void (*reset)(struct nrf52_radioi8_dev_s *dev); +}; + +/* Timer interface */ + +struct nrf52_radioi8_tim_s +{ + /* Timer lower-half */ + + struct nrf52_tim_dev_s *tim; + + /* IEEE 802.15.4 timer operations */ + + struct nrf52_radioi8_tim_ops_s *ops; + + /* Timer state */ + + int8_t tim_now; + bool tim_pending; +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf52_radioi8_tim_init + * + * Description: + * Initialize high resoluton timer for IEEE802154 operations. + * Used to handle short radio timeouts like ACK, IFS or delayed + * transmitions. + * + ****************************************************************************/ + +struct nrf52_radioi8_tim_s * +nrf52_radioi8_tim_init(struct nrf52_radioi8_dev_s *dev); + +#endif /* __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_TIM_H */ diff --git a/arch/arm/src/nrf52/nrf52_ieee802154_trace.c b/arch/arm/src/nrf52/nrf52_ieee802154_trace.c new file mode 100644 index 0000000000000..eff1438e4364a --- /dev/null +++ b/arch/arm/src/nrf52/nrf52_ieee802154_trace.c @@ -0,0 +1,154 @@ +/**************************************************************************** + * arch/arm/src/nrf52/nrf52_ieee802154_trace.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include + +#include "nrf52_ieee802154_trace.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* This must match enum radio_trace_type_e */ + +const static char *g_radio_trace_str[] = +{ + "RADIO IRQ", + "RADIO IRQ: RX DONE", + "RADIO IRQ: TX DONE", + "RADIO IRQ: ACK TX", + "RADIO IRQ: WAIT ACK", + "RADIO IRQ: RX ACK DONE", + "RADIO IRQ: TX CCA BUSY", + + "TIM IRQ: TIM ACK TX", + "TIM IRQ; TIM TX DELAY", + "TIM IRQ: TIM WAIT ACK", + "TIM IRQ: TIM CSMA DELAY", + "RTC IRQ: RTC SD", + "RTC IRQ: RTC CAP", + "RTC IRQ: RTC TIMESLOT", + "RTC IRQ: RTC BI", + + "WORK: RX", + "WORK: TX", + "WORK: BUSY", + "WORK: ED", + "WORK: NO ACK", + + "ACKTX", + "TIMSTART", + "RXENABLE", + "RXDISABLE", + "CSMASETUP", + "CSMATRIGGER", + "NOCSMATRIGGER", + "NOACK", + "DROPFRAME", + "TXTRYAGAIN", +}; + +/* Trace data */ + +volatile static size_t g_radio_trace_cntr = 0; +volatile static struct radio_trace_s +g_radio_trace[CONFIG_NRF52_RADIO_IEEE802154_TRACE_BUFSIZE]; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf52_radioi8_trace_init + * + * Description: + * Initialize trace interface. + * + ****************************************************************************/ + +void nrf52_radioi8_trace_init(void) +{ + g_radio_trace_cntr = 0; + memset((void *)g_radio_trace, 0, sizeof(g_radio_trace)); +} + +/**************************************************************************** + * Name: nrf52_radioi8_trace_put + * + * Description: + * Put trace event. + * + ****************************************************************************/ + +void nrf52_radioi8_trace_put(uint8_t type, uint32_t arg) +{ + if (g_radio_trace_cntr >= CONFIG_NRF52_RADIO_IEEE802154_TRACE_BUFSIZE) + { + g_radio_trace_cntr = 0; + } + + g_radio_trace[g_radio_trace_cntr].time = perf_gettime(); + g_radio_trace[g_radio_trace_cntr].str = g_radio_trace_str[type]; + g_radio_trace[g_radio_trace_cntr].arg = arg; + g_radio_trace_cntr += 1; +} + +/**************************************************************************** + * Name: nrf52_radioi8_trace_dump + * + * Description: + * Dump radio trace. + * + ****************************************************************************/ + +void nrf52_radioi8_trace_dump(void) +{ + int i = 0; + + printf("NRF52 Radio IEEE 802.15.4 Trace dump:\n"); + printf("CPU freq: %d\n\n", BOARD_SYSTICK_CLOCK); + + for (i = 0; i < g_radio_trace_cntr; i += 1) + { + printf("[%lu]: %s %lu\n\n", + g_radio_trace[i].time, + g_radio_trace[i].str, + g_radio_trace[i].arg); + } + + /* Reset trace buffer */ + + g_radio_trace_cntr = 0; + memset((void *)g_radio_trace, 0, sizeof(g_radio_trace)); +} diff --git a/arch/arm/src/nrf52/nrf52_ieee802154_trace.h b/arch/arm/src/nrf52/nrf52_ieee802154_trace.h new file mode 100644 index 0000000000000..a43daa8c10b98 --- /dev/null +++ b/arch/arm/src/nrf52/nrf52_ieee802154_trace.h @@ -0,0 +1,106 @@ +/**************************************************************************** + * arch/arm/src/nrf52/nrf52_ieee802154_trace.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_TRACE_H +#define __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_TRACE_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Trace item */ + +struct radio_trace_s +{ + clock_t time; /* Event timestamp */ + const char *str; /* Event string */ + uint32_t arg; /* Optional data */ +}; + +/* This must match char *g_radio_trace_str[] */ + +enum radio_trace_type_e +{ + /* Radio interupts */ + + RADIO_TRACE_IRQ_RADIO, + RADIO_TRACE_IRQ_RXDONE, + RADIO_TRACE_IRQ_TXDONE, + RADIO_TRACE_IRQ_ACKTX, + RADIO_TRACE_IRQ_WAITACK, + RADIO_TRACE_IRQ_RXACKDONE, + RADIO_TRACE_IRQ_TXCCABUSY, + + /* Timer interrupts */ + + RADIO_TRACE_IRQ_TIMACKTX, + RADIO_TRACE_IRQ_TIMTXDELAY, + RADIO_TRACE_IRQ_TIMWAITACK, + RADIO_TRACE_IRQ_TIMCSMADELAY, + RADIO_TRACE_IRQ_RTCSD, + RADIO_TRACE_IRQ_RTCCAP, + RADIO_TRACE_IRQ_RTCTIMESLOT, + RADIO_TRACE_IRQ_RTCBI, + + /* Works */ + + RADIO_TRACE_WORK_RX, + RADIO_TRACE_WORK_TX, + RADIO_TRACE_WORK_BUSY, + RADIO_TRACE_WORK_ED, + RADIO_TRACE_WORK_NOACK, + + /* Various events */ + + RADIO_TRACE_ACKTX, + RADIO_TRACE_TIMSTART, + RADIO_TRACE_RXENABLE, + RADIO_TRACE_RXDISABLE, + RADIO_TRACE_CSMASETUP, + RADIO_TRACE_CSMATRIGGER, + RADIO_TRACE_NOCSMATRIGGER, + RADIO_TRACE_NOACK, + RADIO_TRACE_DROPFRAME, + RADIO_TRACE_TXRETRY, +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef CONFIG_NRF52_RADIO_IEEE802154_TRACE +void nrf52_radioi8_trace_init(void); +void nrf52_radioi8_trace_put(uint8_t type, uint32_t arg); +void nrf52_radioi8_trace_dump(void); +#else +# define nrf52_radioi8_trace_put(...) +#endif + +#endif /* __ARCH_ARM_SRC_NRF52_NRF52_IEEE802154_TRACE_H */ diff --git a/arch/arm/src/nrf52/nrf52_radio_ieee802154.h b/arch/arm/src/nrf52/nrf52_radio_ieee802154.h new file mode 100644 index 0000000000000..7160378a50efd --- /dev/null +++ b/arch/arm/src/nrf52/nrf52_radio_ieee802154.h @@ -0,0 +1,53 @@ +/**************************************************************************** + * arch/arm/src/nrf52/nrf52_radio_ieee802154.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_NRF52_NRF52_RADIO_IEEE802154_H +#define __ARCH_ARM_SRC_NRF52_NRF52_RADIO_IEEE802154_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "nrf52_radio.h" + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf52_radioi8_register + * + * Description: + * Register NRF52 radio in IEEE802154 mode + * + ****************************************************************************/ + +struct ieee802154_radio_s * +nrf52_radioi8_register(struct nrf52_radio_board_s *board); + +#endif /* __ARCH_ARM_SRC_NRF52_NRF52_RADIO_IEEE802154_H */ diff --git a/boards/Kconfig b/boards/Kconfig index 5fed6ec4c0aaa..fe94e4ba1a97f 100644 --- a/boards/Kconfig +++ b/boards/Kconfig @@ -3650,6 +3650,15 @@ endif if ARCH_BOARD_NRF52840_DK source "boards/arm/nrf52/nrf52840-dk/Kconfig" endif +if ARCH_BOARD_THINGY52 +source "boards/arm/nrf52/thingy52/Kconfig" +endif +if ARCH_BOARD_THINGY91_NRF52 +source "boards/arm/nrf52/thingy91-nrf52/Kconfig" +endif +if ARCH_BOARD_NRF9160_DK_NRF52 +source "boards/arm/nrf52/nrf9160-dk-nrf52/Kconfig" +endif if ARCH_BOARD_NUTINY_NUC120 source "boards/arm/nuc1xx/nutiny-nuc120/Kconfig" endif diff --git a/boards/arm/nrf52/common/include/nrf52_ieee802154.h b/boards/arm/nrf52/common/include/nrf52_ieee802154.h new file mode 100644 index 0000000000000..187348bf9eb6a --- /dev/null +++ b/boards/arm/nrf52/common/include/nrf52_ieee802154.h @@ -0,0 +1,50 @@ +/**************************************************************************** + * boards/arm/nrf52/common/include/nrf52_ieee802154.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __BOARDS_ARM_NRF52_COMMON_INCLUDE_NRF52_IEEE802154_H +#define __BOARDS_ARM_NRF52_COMMON_INCLUDE_NRF52_IEEE802154_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Public Functions Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf52_ieee802154_initialize + * + * Description: + * Initialize IEEE802154 network. + * + * Returned Value: + * Zero is returned on success. Otherwise, a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ + +#ifdef CONFIG_NRF52_RADIO_IEEE802154 +int nrf52_ieee802154_initialize(void); +#endif + +#endif /* __BOARDS_ARM_NRF52_COMMON_INCLUDE_NRF52_IEEE802154_H */ diff --git a/boards/arm/nrf52/common/include/nrf52_mrf24j40.h b/boards/arm/nrf52/common/include/nrf52_mrf24j40.h new file mode 100644 index 0000000000000..cde0af36881c9 --- /dev/null +++ b/boards/arm/nrf52/common/include/nrf52_mrf24j40.h @@ -0,0 +1,67 @@ +/**************************************************************************** + * boards/arm/nrf52/common/include/nrf52_mrf24j40.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __BOARDS_ARM_NRF52_COMMON_INCLUDE_NRF52_MRF24J40_H +#define __BOARDS_ARM_NRF52_COMMON_INCLUDE_NRF52_MRF24J40_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct nrf52_mrf24j40_s +{ + struct mrf24j40_lower_s dev; + xcpt_t handler; + void *arg; + uint32_t intcfg; + uint8_t spidev; +}; + +/**************************************************************************** + * Public Functions Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf52_mrf24j40_devsetup + * + * Description: + * Initialize one the MRF24J40 device in one mikroBUS slot + * + * Returned Value: + * Zero is returned on success. Otherwise, a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ + +#ifdef CONFIG_IEEE802154_MRF24J40 +int nrf52_mrf24j40_devsetup(struct nrf52_mrf24j40_s *priv); +#endif + +#endif /* __BOARDS_ARM_NRF52_COMMON_INCLUDE_NRF52_MRF24J40_H */ diff --git a/boards/arm/nrf52/common/src/CMakeLists.txt b/boards/arm/nrf52/common/src/CMakeLists.txt index fa869af2fdd66..ade42fdd19d7c 100644 --- a/boards/arm/nrf52/common/src/CMakeLists.txt +++ b/boards/arm/nrf52/common/src/CMakeLists.txt @@ -40,6 +40,14 @@ if(CONFIG_ARCH_BOARD_COMMON) list(APPEND SRCS nrf52_reset.c) endif() + if(CONFIG_NRF52_RADIO_IEEE802154) + list(APPEND SRCS nrf52_ieee802154.c) + endif() + + if(CONFIG_IEEE802154_MRF24J40) + list(APPEND SRCS nrf52_mrf24j40.c) + endif() + target_sources(board PRIVATE ${SRCS}) endif() diff --git a/boards/arm/nrf52/common/src/Make.defs b/boards/arm/nrf52/common/src/Make.defs index f7870690a7eeb..90031c5cf2f14 100644 --- a/boards/arm/nrf52/common/src/Make.defs +++ b/boards/arm/nrf52/common/src/Make.defs @@ -40,6 +40,14 @@ ifeq ($(CONFIG_BOARDCTL_RESET),y) CSRCS += nrf52_reset.c endif +ifeq ($(CONFIG_NRF52_RADIO_IEEE802154),y) +CSRCS += nrf52_ieee802154.c +endif + +ifeq ($(CONFIG_IEEE802154_MRF24J40),y) +CSRCS += nrf52_mrf24j40.c +endif + DEPPATH += --dep-path src VPATH += :src CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)src diff --git a/boards/arm/nrf52/common/src/nrf52_ieee802154.c b/boards/arm/nrf52/common/src/nrf52_ieee802154.c new file mode 100644 index 0000000000000..d2dcedd086162 --- /dev/null +++ b/boards/arm/nrf52/common/src/nrf52_ieee802154.c @@ -0,0 +1,106 @@ +/**************************************************************************** + * boards/arm/nrf52/common/src/nrf52_ieee802154.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include + +#include "nrf52_radio_ieee802154.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf52_ieee802154_initialize + * + * Description: + * Initialize the IEEE 802.15.4 network. + * + * Returned Value: + * Zero is returned on success. Otherwise, a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ + +int nrf52_ieee802154_initialize(void) +{ + struct ieee802154_radio_s *radio; + MACHANDLE mac; + int ret; + + /* Initialize and register the SPI MRF24J40 device */ + + radio = nrf52_radioi8_register(NULL); + if (radio == NULL) + { + wlerr("ERROR: Failed to initialize radio\n"); + return -ENODEV; + } + + /* Create a 802.15.4 MAC device from a 802.15.4 compatible radio device. */ + + mac = mac802154_create(radio); + if (mac == NULL) + { + wlerr("ERROR: Failed to initialize IEEE802.15.4 MAC\n"); + return -ENODEV; + } + +#ifdef CONFIG_IEEE802154_NETDEV + /* Use the IEEE802.15.4 MAC interface instance to create a 6LoWPAN + * network interface by wrapping the MAC intrface instance in a + * network device driver via mac802154dev_register(). + */ + + ret = mac802154netdev_register(mac); + if (ret < 0) + { + wlerr("ERROR: Failed to register the MAC network driver wpan%d: %d\n", + 0, ret); + return ret; + } +#endif + +#ifdef CONFIG_IEEE802154_MACDEV + /* If want to call these APIs from userspace, you have to wrap the MAC + * interface in a character device viamac802154dev_register(). + */ + + ret = mac802154dev_register(mac, 0); + if (ret < 0) + { + wlerr("ERROR:"); + wlerr(" Failed to register the MAC character driver /dev/ieee%d: %d\n", + 0, ret); + return ret; + } +#endif + + UNUSED(ret); + return OK; +} diff --git a/boards/arm/nrf52/common/src/nrf52_mrf24j40.c b/boards/arm/nrf52/common/src/nrf52_mrf24j40.c new file mode 100644 index 0000000000000..dcfbf40840f34 --- /dev/null +++ b/boards/arm/nrf52/common/src/nrf52_mrf24j40.c @@ -0,0 +1,136 @@ +/**************************************************************************** + * boards/arm/nrf52/common/src/nrf52_mrf24j40.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "nrf52_gpio.h" +#include "nrf52_spi.h" + +#include "nrf52_mrf24j40.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_DRIVERS_WIRELESS +# error Wireless support requires CONFIG_DRIVERS_WIRELESS +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf52_mrf24j40_devsetup + * + * Description: + * Initialize one the MRF24J40 device in one mikroBUS slot + * + * Returned Value: + * Zero is returned on success. Otherwise, a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ + +int nrf52_mrf24j40_devsetup(struct nrf52_mrf24j40_s *priv) +{ + struct ieee802154_radio_s *radio; + MACHANDLE mac; + struct spi_dev_s *spi; + int ret; + + /* Configure pins */ + + nrf52_gpio_config(priv->intcfg); + + /* Initialize the SPI bus and get an instance of the SPI interface */ + + spi = nrf52_spibus_initialize(priv->spidev); + if (spi == NULL) + { + wlerr("Failed to initialize SPI bus %d\n", priv->spidev); + return -ENODEV; + } + + /* Initialize and register the SPI MRF24J40 device */ + + radio = mrf24j40_init(spi, &priv->dev); + if (radio == NULL) + { + wlerr("Failed to initialize SPI bus %d\n", priv->spidev); + return -ENODEV; + } + + /* Create a 802.15.4 MAC device from a 802.15.4 compatible radio device. */ + + mac = mac802154_create(radio); + if (mac == NULL) + { + wlerr("Failed to initialize IEEE802.15.4 MAC\n"); + return -ENODEV; + } + +#ifdef CONFIG_IEEE802154_NETDEV + /* Use the IEEE802.15.4 MAC interface instance to create a 6LoWPAN + * network interface by wrapping the MAC intrface instance in a + * network device driver via mac802154dev_register(). + */ + + ret = mac802154netdev_register(mac); + if (ret < 0) + { + wlerr("Failed to register the MAC network driver wpan%d: %d\n", + 0, ret); + return ret; + } +#endif + +#ifdef CONFIG_IEEE802154_MACDEV + /* If want to call these APIs from userspace, you have to wrap the MAC + * interface in a character device viamac802154dev_register(). + */ + + ret = mac802154dev_register(mac, 0); + if (ret < 0) + { + wlerr("Failed to register the MAC character driver /dev/ieee%d: %d\n", + 0, ret); + return ret; + } +#endif + + UNUSED(ret); + return OK; +} diff --git a/boards/arm/nrf52/nrf52832-dk/configs/mrf24j40_6lowpan/defconfig b/boards/arm/nrf52/nrf52832-dk/configs/mrf24j40_6lowpan/defconfig new file mode 100644 index 0000000000000..f0c31e2a45d19 --- /dev/null +++ b/boards/arm/nrf52/nrf52832-dk/configs/mrf24j40_6lowpan/defconfig @@ -0,0 +1,81 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_FPU is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="nrf52832-dk" +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_BOARD_NRF52832_DK=y +CONFIG_ARCH_CHIP="nrf52" +CONFIG_ARCH_CHIP_NRF52832=y +CONFIG_ARCH_CHIP_NRF52=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARCH_STDARG_H=y +CONFIG_BOARDCTL_RESET=y +CONFIG_BOARD_LOOPSPERMSEC=5500 +CONFIG_BUILTIN=y +CONFIG_DRIVERS_IEEE802154=y +CONFIG_DRIVERS_WIRELESS=y +CONFIG_EXAMPLES_NETTEST=y +CONFIG_EXAMPLES_NETTEST_DEVNAME="wpan0" +CONFIG_EXAMPLES_NETTEST_SERVER_PORTNO=61616 +CONFIG_EXAMPLES_NETTEST_TARGET2=y +CONFIG_EXAMPLES_UDP=y +CONFIG_EXAMPLES_UDP_CLIENT_PORTNO=61617 +CONFIG_EXAMPLES_UDP_DEVNAME="wpan0" +CONFIG_EXAMPLES_UDP_IPv6=y +CONFIG_EXAMPLES_UDP_SERVER_PORTNO=61616 +CONFIG_EXAMPLES_UDP_TARGET2=y +CONFIG_EXPERIMENTAL=y +CONFIG_FS_PROCFS=y +CONFIG_IDLETHREAD_STACKSIZE=2048 +CONFIG_IEEE802154_I8SAK=y +CONFIG_IEEE802154_MAC=y +CONFIG_IEEE802154_MACDEV=y +CONFIG_IEEE802154_MRF24J40=y +CONFIG_IEEE802154_NETDEV=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_MAC802154_NTXDESC=36 +CONFIG_MM_REGIONS=2 +CONFIG_NET=y +CONFIG_NETDEV_HPWORK_THREAD=y +CONFIG_NETDEV_LATEINIT=y +CONFIG_NETDEV_STATISTICS=y +CONFIG_NETDEV_WIRELESS_IOCTL=y +CONFIG_NETINIT_NETLOCAL=y +CONFIG_NETINIT_NOMAC=y +CONFIG_NETUTILS_TELNETD=y +CONFIG_NET_6LOWPAN=y +CONFIG_NET_BROADCAST=y +CONFIG_NET_IPv6=y +CONFIG_NET_SOCKOPTS=y +CONFIG_NET_STATISTICS=y +CONFIG_NET_TCP=y +CONFIG_NET_TCPBACKLOG=y +CONFIG_NET_TCP_WRITE_BUFFERS=y +CONFIG_NET_UDP=y +CONFIG_NRF52_GPIOTE=y +CONFIG_NRF52_SPI0_MASTER=y +CONFIG_NRF52_UART0=y +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_PROMPT_STRING="nsh-mrf> " +CONFIG_NSH_READLINE=y +CONFIG_RAM_SIZE=65535 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_SPI=y +CONFIG_SYMTAB_ORDEREDBYNAME=y +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_TELNET_CLIENT=y +CONFIG_UART0_SERIAL_CONSOLE=y +CONFIG_WIRELESS=y +CONFIG_WIRELESS_IEEE802154=y diff --git a/boards/arm/nrf52/nrf52832-dk/configs/mrf24j40_mac/defconfig b/boards/arm/nrf52/nrf52832-dk/configs/mrf24j40_mac/defconfig new file mode 100644 index 0000000000000..0b3a93261d496 --- /dev/null +++ b/boards/arm/nrf52/nrf52832-dk/configs/mrf24j40_mac/defconfig @@ -0,0 +1,60 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_FPU is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="nrf52832-dk" +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_BOARD_NRF52832_DK=y +CONFIG_ARCH_CHIP="nrf52" +CONFIG_ARCH_CHIP_NRF52832=y +CONFIG_ARCH_CHIP_NRF52=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARCH_STDARG_H=y +CONFIG_BOARDCTL_RESET=y +CONFIG_BOARD_LOOPSPERMSEC=5500 +CONFIG_BUILTIN=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DRIVERS_IEEE802154=y +CONFIG_DRIVERS_WIRELESS=y +CONFIG_FS_PROCFS=y +CONFIG_IDLETHREAD_STACKSIZE=2048 +CONFIG_IEEE802154_I8SAK=y +CONFIG_IEEE802154_MAC=y +CONFIG_IEEE802154_MACDEV=y +CONFIG_IEEE802154_MRF24J40=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_MM_REGIONS=2 +CONFIG_NRF52_GPIOTE=y +CONFIG_NRF52_SPI0_MASTER=y +CONFIG_NRF52_UART0=y +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_PROMPT_STRING="nsh-mrf> " +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=65535 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_SPI=y +CONFIG_STACK_COLORATION=y +CONFIG_STACK_USAGE=y +CONFIG_START_DAY=26 +CONFIG_START_MONTH=3 +CONFIG_SYMTAB_ORDEREDBYNAME=y +CONFIG_SYSTEM_NSH=y +CONFIG_TASK_NAME_SIZE=0 +CONFIG_UART0_SERIAL_CONSOLE=y +CONFIG_WIRELESS=y +CONFIG_WIRELESS_IEEE802154=y diff --git a/boards/arm/nrf52/nrf52832-dk/include/board.h b/boards/arm/nrf52/nrf52832-dk/include/board.h index b77688958215c..092a3a0e10bd5 100644 --- a/boards/arm/nrf52/nrf52832-dk/include/board.h +++ b/boards/arm/nrf52/nrf52832-dk/include/board.h @@ -107,4 +107,16 @@ #define BOARD_UART0_RX_PIN (GPIO_INPUT | GPIO_PORT0 | GPIO_PIN(8)) #define BOARD_UART0_TX_PIN (GPIO_OUTPUT | GPIO_VALUE_ONE | GPIO_PORT0 | GPIO_PIN(6)) +/* SPI Pins *****************************************************************/ + +/* SPI0 - Arduino PINs + * SPI0_SCK - P0.25 (P13) + * SPI0_MISO - P0.24 (D12) + * SPI0_MOSI - P0.23 (D11) + */ + +#define BOARD_SPI0_SCK_PIN (GPIO_OUTPUT | GPIO_VALUE_ONE | GPIO_PORT0 | GPIO_PIN(25)) +#define BOARD_SPI0_MISO_PIN (GPIO_INPUT | GPIO_PORT0 | GPIO_PIN(24)) +#define BOARD_SPI0_MOSI_PIN (GPIO_OUTPUT | GPIO_PORT0 | GPIO_PIN(23)) + #endif /* __BOARDS_ARM_NRF52_NRF52832_DK_INCLUDE_BOARD_H */ diff --git a/boards/arm/nrf52/nrf52832-dk/src/CMakeLists.txt b/boards/arm/nrf52/nrf52832-dk/src/CMakeLists.txt index 7e61a0d0a9e85..d09591c71e5dc 100644 --- a/boards/arm/nrf52/nrf52832-dk/src/CMakeLists.txt +++ b/boards/arm/nrf52/nrf52832-dk/src/CMakeLists.txt @@ -34,6 +34,14 @@ if(CONFIG_ARCH_BUTTONS) list(APPEND SRCS nrf52_buttons.c) endif() +if(CONFIG_NRF52_SPI_MASTER) + list(APPEND SRCS nrf52_spi.c) +endif() + +if(CONFIG_IEEE802154_MRF24J40) + list(APPEND SRCS nrf52_ieee802154_mrf24j40.c) +endif() + target_sources(board PRIVATE ${SRCS}) if(CONFIG_ARCH_BOARD_COMMON) diff --git a/boards/arm/nrf52/nrf52832-dk/src/Make.defs b/boards/arm/nrf52/nrf52832-dk/src/Make.defs index 7e4e6508fab84..7b6364940c3b0 100644 --- a/boards/arm/nrf52/nrf52832-dk/src/Make.defs +++ b/boards/arm/nrf52/nrf52832-dk/src/Make.defs @@ -36,6 +36,14 @@ ifeq ($(CONFIG_ARCH_BUTTONS),y) CSRCS += nrf52_buttons.c endif +ifeq ($(CONFIG_NRF52_SPI_MASTER),y) +CSRCS += nrf52_spi.c +endif + +ifeq ($(CONFIG_IEEE802154_MRF24J40),y) +CSRCS += nrf52_ieee802154_mrf24j40.c +endif + DEPPATH += --dep-path board VPATH += :board CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)board diff --git a/boards/arm/nrf52/nrf52832-dk/src/nrf52832-dk.h b/boards/arm/nrf52/nrf52832-dk/src/nrf52832-dk.h index bdf5c8f0ad79d..c857ac3e5d524 100644 --- a/boards/arm/nrf52/nrf52832-dk/src/nrf52832-dk.h +++ b/boards/arm/nrf52/nrf52832-dk/src/nrf52832-dk.h @@ -64,6 +64,16 @@ #define GPIO_BUTTON3 (GPIO_INPUT | GPIO_PULLUP | GPIO_PORT0 | GPIO_PIN(15)) #define GPIO_BUTTON4 (GPIO_INPUT | GPIO_PULLUP | GPIO_PORT0 | GPIO_PIN(16)) +/* GPIO definitions *********************************************************/ + +/* MRF24J40 pins + * CS - P0.11 + * INT - P0.12 + */ + +#define GPIO_MRF24J40_CS (GPIO_OUTPUT | GPIO_VALUE_ONE | GPIO_PORT0 | GPIO_PIN(11)) +#define GPIO_MRF24J40_INT (GPIO_INPUT | GPIO_PORT0 | GPIO_PIN(12)) + /**************************************************************************** * Public Types ****************************************************************************/ @@ -94,5 +104,33 @@ int nrf52_bringup(void); +/**************************************************************************** + * Name: nrf52_spidev_initialize + * + * Description: + * Called to configure SPI chip select GPIO pins for the nrf52840-dk board. + * + ****************************************************************************/ + +#ifdef CONFIG_NRF52_SPI_MASTER +void nrf52_spidev_initialize(void); +#endif + +/**************************************************************************** + * Name: nrf52_mrf24j40_initialize + * + * Description: + * Initialize the MRF24J40 device. + * + * Returned Value: + * Zero is returned on success. Otherwise, a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ + +#ifdef CONFIG_IEEE802154_MRF24J40 +int nrf52_mrf24j40_initialize(void); +#endif + #endif /* __ASSEMBLY__ */ #endif /* __BOARDS_ARM_NRF52_NRF52832_DK_SRC_NRF52832_DK_H */ diff --git a/boards/arm/nrf52/nrf52832-dk/src/nrf52_boot.c b/boards/arm/nrf52/nrf52832-dk/src/nrf52_boot.c index a23cf76ca90c1..aeaf57d6305f9 100644 --- a/boards/arm/nrf52/nrf52832-dk/src/nrf52_boot.c +++ b/boards/arm/nrf52/nrf52832-dk/src/nrf52_boot.c @@ -54,6 +54,12 @@ void nrf52_board_initialize(void) #ifdef CONFIG_ARCH_LEDS board_autoled_initialize(); #endif + +#ifdef CONFIG_NRF52_SPI_MASTER + /* Configure SPI chip selects */ + + nrf52_spidev_initialize(); +#endif } /**************************************************************************** diff --git a/boards/arm/nrf52/nrf52832-dk/src/nrf52_bringup.c b/boards/arm/nrf52/nrf52832-dk/src/nrf52_bringup.c index 3526a9f93066c..aca8f50019c28 100644 --- a/boards/arm/nrf52/nrf52832-dk/src/nrf52_bringup.c +++ b/boards/arm/nrf52/nrf52832-dk/src/nrf52_bringup.c @@ -53,6 +53,10 @@ # include "nrf52_sdc.h" #endif +#ifdef CONFIG_IEEE802154_MRF24J40 +# include "nrf52_mrf24j40.h" +#endif + #include "nrf52832-dk.h" /**************************************************************************** @@ -152,6 +156,17 @@ int nrf52_bringup(void) } #endif /* CONFIG_MTD */ +#ifdef CONFIG_IEEE802154_MRF24J40 + /* Configure MRF24J40 wireless */ + + ret = nrf52_mrf24j40_initialize(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: nrf52_mrf24j40_initialize() failed: %d\n", + ret); + } +#endif + UNUSED(ret); return OK; } diff --git a/boards/arm/nrf52/nrf52832-dk/src/nrf52_ieee802154_mrf24j40.c b/boards/arm/nrf52/nrf52832-dk/src/nrf52_ieee802154_mrf24j40.c new file mode 100644 index 0000000000000..0d9d308e52b7e --- /dev/null +++ b/boards/arm/nrf52/nrf52832-dk/src/nrf52_ieee802154_mrf24j40.c @@ -0,0 +1,177 @@ +/**************************************************************************** + * boards/arm/nrf52/nrf52832-dk/src/nrf52_mrf24j40.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "nrf52_gpio.h" +#include "nrf52_gpiote.h" +#include "nrf52_spi.h" + +#include "nrf52_mrf24j40.h" + +#include "nrf52832-dk.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_NRF52_SPI0_MASTER +# error this driver requires CONFIG_NRF52_SPI0_MASTER +#endif + +#define NRF52_MRF24J40_SPI (0) + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* IRQ/GPIO access callbacks. These operations all hidden behind callbacks + * to isolate the MRF24J40 driver from differences in GPIO interrupt handling + * varying boards and MCUs. + * + * irq_attach - Attach the MRF24J40 interrupt handler to the GPIO + * interrupt + * irq_enable - Enable or disable the GPIO interrupt + */ + +static int nrf52_attach_irq(const struct mrf24j40_lower_s *lower, + xcpt_t handler, void *arg); +static void nrf52_enable_irq(const struct mrf24j40_lower_s *lower, + bool state); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* A reference to a structure of this type must be passed to the MRF24J40 + * driver. This structure provides information about the configuration + * of the MRF24J40 and provides some board-specific hooks. + * + * Memory for this structure is provided by the caller. It is not copied + * by the driver and is presumed to persist while the driver is active. The + * memory must be writable because, under certain circumstances, the driver + * may modify frequency or X plate resistance values. + */ + +static struct nrf52_mrf24j40_s g_mrf24j40_priv = +{ + .dev.attach = nrf52_attach_irq, + .dev.enable = nrf52_enable_irq, + .handler = NULL, + .arg = NULL, + .intcfg = GPIO_MRF24J40_INT, + .spidev = NRF52_MRF24J40_SPI, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf52_attach_irq + * + * Description: + * Attach the MRF24J40 interrupt handler to the GPIO interrupt. + * + ****************************************************************************/ + +static int nrf52_attach_irq(const struct mrf24j40_lower_s *lower, + xcpt_t handler, void *arg) +{ + struct nrf52_mrf24j40_s *priv = (struct nrf52_mrf24j40_s *)lower; + + DEBUGASSERT(priv != NULL); + + /* Just save the handler for use when the interrupt is enabled */ + + priv->handler = handler; + priv->arg = arg; + return OK; +} + +/**************************************************************************** + * Name: nrf52_enable_irq + * + * Description: + * Enable or disable the GPIO interrupt + * + ****************************************************************************/ + +static void nrf52_enable_irq(const struct mrf24j40_lower_s *lower, + bool state) +{ + struct nrf52_mrf24j40_s *priv = (struct nrf52_mrf24j40_s *)lower; + + /* The caller should not attempt to enable interrupts if the handler + * has not yet been 'attached' + */ + + DEBUGASSERT(priv != NULL && (priv->handler != NULL || !state)); + + wlinfo("state:%d\n", (int)state); + + /* Attach and enable, or detach and disable */ + + if (state) + { + nrf52_gpiote_set_event(priv->intcfg, false, true, + priv->handler, priv->arg); + } + else + { + nrf52_gpiote_set_event(priv->intcfg, false, false, + priv->handler, priv->arg); + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf52_mrf24j40_initialize + * + * Description: + * Initialize the MRF24J40 device. + * + * Returned Value: + * Zero is returned on success. Otherwise, a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ + +int nrf52_mrf24j40_initialize(void) +{ + int ret; + + ret = nrf52_mrf24j40_devsetup(&g_mrf24j40_priv); + if (ret < 0) + { + wlerr("Failed to initialize mrf24j40: %d\n", ret); + } + + return ret; +} diff --git a/boards/arm/nrf52/nrf52832-dk/src/nrf52_spi.c b/boards/arm/nrf52/nrf52832-dk/src/nrf52_spi.c new file mode 100644 index 0000000000000..7e8e6d3adfae3 --- /dev/null +++ b/boards/arm/nrf52/nrf52832-dk/src/nrf52_spi.c @@ -0,0 +1,177 @@ +/**************************************************************************** + * boards/arm/nrf52/nrf52832-dk/src/nrf52_spi.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include + +#include "arm_internal.h" +#include "chip.h" +#include "nrf52_gpio.h" +#include "nrf52_spi.h" + +#include "nrf52832-dk.h" +#include + +#ifdef CONFIG_NRF52_SPI_MASTER + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf52_spidev_initialize + * + * Description: + * Called to configure SPI chip select GPIO pins for the Nucleo-144 board. + * + ****************************************************************************/ + +void nrf52_spidev_initialize(void) +{ +#ifdef CONFIG_NRF52_SPI0_MASTER +# ifdef CONFIG_IEEE802154_MRF24J40 + /* Configure the SPI-based MRF24J40 chip select GPIO */ + + spiinfo("Configure GPIO for MRF24J40 SPI1/CS\n"); + + nrf52_gpio_config(GPIO_MRF24J40_CS); + nrf52_gpio_write(GPIO_MRF24J40_CS, true); +# endif +#endif +} + +/**************************************************************************** + * Name: nrf52_spi0/1/2/3/select and nrf52_spi0/1/2/3/status + * + * Description: + * The external functions, nrf52_spi0/1/2/3select and + * nrf52_spi0/1/2/3status must be provided by board-specific logic. + * They are implementations of the select and status methods of the SPI + * interface defined by struct spi_ops_s (see include/nuttx/spi/spi.h). + * All other methods (including nrf52_spibus_initialize()) are provided + * by common NRF52 logic. To use this common SPI logic on your board: + * + * 1. Provide logic in nrf52_boardinitialize() to configure SPI chip select + * pins. + * 2. Provide nrf52_spi0/1/2/3select() and nrf52_spi0/1/2/3status() + * functions in your board-specific logic. These functions will perform + * chip selection and status operations using GPIOs in the way your + * board is configured. + * 3. Add a calls to nrf52_spibus_initialize() in your low level + * application initialization logic + * 4. The handle returned by nrf52_spibus_initialize() may then be used to + * bind the SPI driver to higher level logic (e.g., calling + * mmcsd_spislotinitialize(), for example, will bind the SPI driver to + * the SPI MMC/SD driver). + * + ****************************************************************************/ + +#ifdef CONFIG_NRF52_SPI0_MASTER +void nrf52_spi0select(struct spi_dev_s *dev, uint32_t devid, + bool selected) +{ + spiinfo("devid: %08lx CS: %s\n", + (unsigned long)devid, selected ? "assert" : "de-assert"); + + switch (devid) + { +#ifdef CONFIG_IEEE802154_MRF24J40 + case SPIDEV_IEEE802154(0): + { + spiinfo("MRF24J40 device %s\n", + selected ? "asserted" : "de-asserted"); + + /* Set the GPIO low to select and high to de-select */ + + nrf52_gpio_write(GPIO_MRF24J40_CS, !selected); + break; + } +#endif + + default: + { + break; + } + } +} + +uint8_t nrf52_spi0status(struct spi_dev_s *dev, uint32_t devid) +{ + uint8_t status = 0; + + switch (devid) + { +#ifdef CONFIG_IEEE802154_MRF24J40 + case SPIDEV_IEEE802154(0): + { + status |= SPI_STATUS_PRESENT; + break; + } +#endif + + default: + { + break; + } + } + + return status; +} +#endif + +#ifdef CONFIG_NRF52_SPI1_MASTER +void nrf52_spi1select(struct spi_dev_s *dev, uint32_t devid, + bool selected) +{ + spiinfo("devid: %08lx CS: %s\n", + (unsigned long)devid, selected ? "assert" : "de-assert"); +} + +uint8_t nrf52_spi1status(struct spi_dev_s *dev, uint32_t devid) +{ + return 0; +} +#endif + +#ifdef CONFIG_nrf52_SPI2_MASTER +void nrf52_spi2select(struct spi_dev_s *dev, uint32_t devid, + bool selected) +{ + spiinfo("devid: %08lx CS: %s\n", + (unsigned long)devid, selected ? "assert" : "de-assert"); +} + +uint8_t nrf52_spi2status(struct spi_dev_s *dev, uint32_t devid) +{ + return 0; +} +#endif + +#endif /* CONFIG_NRF52_SPI_MASTER */ diff --git a/boards/arm/nrf52/nrf52840-dk/configs/ieee802154_6lowpan/defconfig b/boards/arm/nrf52/nrf52840-dk/configs/ieee802154_6lowpan/defconfig new file mode 100644 index 0000000000000..6afe61de129e8 --- /dev/null +++ b/boards/arm/nrf52/nrf52840-dk/configs/ieee802154_6lowpan/defconfig @@ -0,0 +1,81 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_FPU is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="nrf52840-dk" +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_BOARD_NRF52840_DK=y +CONFIG_ARCH_CHIP="nrf52" +CONFIG_ARCH_CHIP_NRF52840=y +CONFIG_ARCH_CHIP_NRF52=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARCH_STDARG_H=y +CONFIG_BOARDCTL_RESET=y +CONFIG_BOARD_LOOPSPERMSEC=5500 +CONFIG_BUILTIN=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DRIVERS_IEEE802154=y +CONFIG_DRIVERS_WIRELESS=y +CONFIG_EXAMPLES_NETTEST=y +CONFIG_EXAMPLES_NETTEST_DEVNAME="wpan0" +CONFIG_EXAMPLES_NETTEST_SERVER_PORTNO=61616 +CONFIG_EXAMPLES_NETTEST_TARGET2=y +CONFIG_EXAMPLES_UDP=y +CONFIG_EXAMPLES_UDP_CLIENT_PORTNO=61617 +CONFIG_EXAMPLES_UDP_DEVNAME="wpan0" +CONFIG_EXAMPLES_UDP_IPv6=y +CONFIG_EXAMPLES_UDP_SERVER_PORTNO=61616 +CONFIG_EXAMPLES_UDP_TARGET2=y +CONFIG_EXPERIMENTAL=y +CONFIG_FS_PROCFS=y +CONFIG_IEEE802154_I8SAK=y +CONFIG_IEEE802154_MAC=y +CONFIG_IEEE802154_MACDEV=y +CONFIG_IEEE802154_NETDEV=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_MAC802154_NTXDESC=36 +CONFIG_MM_REGIONS=2 +CONFIG_NET=y +CONFIG_NETDEV_HPWORK_THREAD=y +CONFIG_NETDEV_LATEINIT=y +CONFIG_NETDEV_STATISTICS=y +CONFIG_NETDEV_WIRELESS_IOCTL=y +CONFIG_NETINIT_NETLOCAL=y +CONFIG_NETINIT_NOMAC=y +CONFIG_NETUTILS_TELNETD=y +CONFIG_NET_6LOWPAN=y +CONFIG_NET_BROADCAST=y +CONFIG_NET_IPv6=y +CONFIG_NET_SOCKOPTS=y +CONFIG_NET_STATISTICS=y +CONFIG_NET_TCP=y +CONFIG_NET_TCPBACKLOG=y +CONFIG_NET_TCP_WRITE_BUFFERS=y +CONFIG_NET_UDP=y +CONFIG_NRF52_HFCLK_XTAL=y +CONFIG_NRF52_RADIO=y +CONFIG_NRF52_RADIO_IEEE802154=y +CONFIG_NRF52_UART0=y +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_PROMPT_STRING="nsh-nrf52> " +CONFIG_NSH_READLINE=y +CONFIG_RAM_SIZE=262144 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_SYMTAB_ORDEREDBYNAME=y +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_TELNET_CLIENT=y +CONFIG_UART0_SERIAL_CONSOLE=y +CONFIG_WIRELESS=y +CONFIG_WIRELESS_IEEE802154=y diff --git a/boards/arm/nrf52/nrf52840-dk/configs/ieee802154_mac/defconfig b/boards/arm/nrf52/nrf52840-dk/configs/ieee802154_mac/defconfig new file mode 100644 index 0000000000000..4d9a842623e5b --- /dev/null +++ b/boards/arm/nrf52/nrf52840-dk/configs/ieee802154_mac/defconfig @@ -0,0 +1,61 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_FPU is not set +# CONFIG_NSH_DISABLE_IFCONFIG is not set +# CONFIG_NSH_DISABLE_PS is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="nrf52840-dk" +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_BOARD_NRF52840_DK=y +CONFIG_ARCH_CHIP="nrf52" +CONFIG_ARCH_CHIP_NRF52840=y +CONFIG_ARCH_CHIP_NRF52=y +CONFIG_ARCH_PERF_EVENTS=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARCH_STDARG_H=y +CONFIG_BOARDCTL_RESET=y +CONFIG_BOARD_LOOPSPERMSEC=5500 +CONFIG_BUILTIN=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DRIVERS_IEEE802154=y +CONFIG_DRIVERS_WIRELESS=y +CONFIG_EXPERIMENTAL=y +CONFIG_IDLETHREAD_STACKSIZE=4096 +CONFIG_IEEE802154_I8SAK=y +CONFIG_IEEE802154_MAC=y +CONFIG_IEEE802154_MACDEV=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_MM_REGIONS=2 +CONFIG_NRF52_HFCLK_XTAL=y +CONFIG_NRF52_RADIO=y +CONFIG_NRF52_RADIO_IEEE802154=y +CONFIG_NRF52_TIMER1=y +CONFIG_NRF52_UART0=y +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_PROMPT_STRING="nsh-nrf52> " +CONFIG_NSH_READLINE=y +CONFIG_RAM_SIZE=262144 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_BACKTRACE=y +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_HPWORKSTACKSIZE=4096 +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_LPWORKSTACKSIZE=4096 +CONFIG_SCHED_WAITPID=y +CONFIG_STACK_CANARIES=y +CONFIG_STACK_COLORATION=y +CONFIG_STACK_USAGE=y +CONFIG_SYMTAB_ORDEREDBYNAME=y +CONFIG_SYSTEM_NSH=y +CONFIG_UART0_SERIAL_CONSOLE=y +CONFIG_WIRELESS=y +CONFIG_WIRELESS_IEEE802154=y diff --git a/boards/arm/nrf52/nrf52840-dk/configs/nrfradio/defconfig b/boards/arm/nrf52/nrf52840-dk/configs/nrfradio/defconfig new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c b/boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c index 4bc740ff011ba..26e8ea89ae135 100644 --- a/boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c +++ b/boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c @@ -61,13 +61,17 @@ # include "nrf52_lsm9ds1.h" #endif +#ifdef CONFIG_NRF52_RADIO_IEEE802154 +# include "nrf52_ieee802154.h" +#endif + #include "nrf52840-dk.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ -#define NRF52_TIMER (1) +#define NRF52_TIMER (2) #define LMS9DS1_I2CBUS (0) /**************************************************************************** @@ -309,6 +313,15 @@ int nrf52_bringup(void) } #endif /* CONFIG_SENSORS_LSM6DSL */ +#ifdef CONFIG_NRF52_RADIO_IEEE802154 + ret = nrf52_ieee802154_initialize(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to initialize IEE802154 radio: %d\n", + ret); + } +#endif + UNUSED(ret); return OK; } diff --git a/boards/arm/nrf52/nrf52840-dongle/configs/ieee802154_mac/defconfig b/boards/arm/nrf52/nrf52840-dongle/configs/ieee802154_mac/defconfig new file mode 100644 index 0000000000000..3e3a0a98d22a5 --- /dev/null +++ b/boards/arm/nrf52/nrf52840-dongle/configs/ieee802154_mac/defconfig @@ -0,0 +1,65 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_FPU is not set +# CONFIG_DEV_CONSOLE is not set +# CONFIG_NSH_DISABLE_IFCONFIG is not set +# CONFIG_NSH_DISABLE_PS is not set +# CONFIG_SYSLOG_DEFAULT is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="nrf52840-dongle" +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_BOARD_NRF52840_DONGLE=y +CONFIG_ARCH_CHIP="nrf52" +CONFIG_ARCH_CHIP_NRF52840=y +CONFIG_ARCH_CHIP_NRF52=y +CONFIG_ARCH_PERF_EVENTS=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARCH_STDARG_H=y +CONFIG_BOARDCTL_RESET=y +CONFIG_BOARDCTL_USBDEVCTRL=y +CONFIG_BOARD_LOOPSPERMSEC=5500 +CONFIG_BUILTIN=y +CONFIG_CDCACM=y +CONFIG_CDCACM_CONSOLE=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DRIVERS_IEEE802154=y +CONFIG_DRIVERS_WIRELESS=y +CONFIG_EXPERIMENTAL=y +CONFIG_IDLETHREAD_STACKSIZE=4096 +CONFIG_IEEE802154_I8SAK=y +CONFIG_IEEE802154_MAC=y +CONFIG_IEEE802154_MACDEV=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_MM_REGIONS=2 +CONFIG_NRF52_HFCLK_XTAL=y +CONFIG_NRF52_RADIO=y +CONFIG_NRF52_RADIO_IEEE802154=y +CONFIG_NRF52_TIMER1=y +CONFIG_NRF52_USBDEV=y +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_PROMPT_STRING="nsh-dongle> " +CONFIG_NSH_READLINE=y +CONFIG_RAM_SIZE=262144 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_BACKTRACE=y +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_HPWORKSTACKSIZE=4096 +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_LPWORKSTACKSIZE=4096 +CONFIG_SCHED_WAITPID=y +CONFIG_STACK_CANARIES=y +CONFIG_STACK_COLORATION=y +CONFIG_STACK_USAGE=y +CONFIG_SYMTAB_ORDEREDBYNAME=y +CONFIG_SYSTEM_NSH=y +CONFIG_WIRELESS=y +CONFIG_WIRELESS_IEEE802154=y diff --git a/boards/arm/nrf52/nrf52840-dongle/src/nrf52840-dongle.h b/boards/arm/nrf52/nrf52840-dongle/src/nrf52840-dongle.h index e2f688fb5a8cf..6c1791738343d 100644 --- a/boards/arm/nrf52/nrf52840-dongle/src/nrf52840-dongle.h +++ b/boards/arm/nrf52/nrf52840-dongle/src/nrf52840-dongle.h @@ -34,6 +34,18 @@ * Pre-processor Definitions ****************************************************************************/ +/* Configuration ************************************************************/ + +/* procfs File System */ + +#ifdef CONFIG_FS_PROCFS +# ifdef CONFIG_NSH_PROC_MOUNTPOINT +# define NRF52_PROCFS_MOUNTPOINT CONFIG_NSH_PROC_MOUNTPOINT +# else +# define NRF52_PROCFS_MOUNTPOINT "/proc" +# endif +#endif + /* LED definitions **********************************************************/ /* Definitions to configure LED GPIO as outputs */ diff --git a/boards/arm/nrf52/nrf52840-dongle/src/nrf52_bringup.c b/boards/arm/nrf52/nrf52840-dongle/src/nrf52_bringup.c index 1ad015a417544..fbcf6b4475ede 100644 --- a/boards/arm/nrf52/nrf52840-dongle/src/nrf52_bringup.c +++ b/boards/arm/nrf52/nrf52840-dongle/src/nrf52_bringup.c @@ -31,6 +31,10 @@ # include #endif +#ifdef CONFIG_NRF52_RADIO_IEEE802154 +# include "nrf52_ieee802154.h" +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -53,6 +57,17 @@ int nrf52_bringup(void) { int ret; +#ifdef CONFIG_FS_PROCFS + /* Mount the procfs file system */ + + ret = nx_mount(NULL, NRF52_PROCFS_MOUNTPOINT, "procfs", 0, NULL); + if (ret < 0) + { + syslog(LOG_ERR, + "ERROR: Failed to mount the PROC filesystem: %d\n", ret); + } +#endif /* CONFIG_FS_PROCFS */ + #ifdef CONFIG_USERLED /* Register the LED driver */ @@ -63,6 +78,15 @@ int nrf52_bringup(void) } #endif +#ifdef CONFIG_NRF52_RADIO_IEEE802154 + ret = nrf52_ieee802154_initialize(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to initialize IEE802154 radio: %d\n", + ret); + } +#endif + UNUSED(ret); return OK; } diff --git a/boards/arm/nrf52/nrf9160-dk-nrf52/configs/ieee802154_6lowpan/defconfig b/boards/arm/nrf52/nrf9160-dk-nrf52/configs/ieee802154_6lowpan/defconfig new file mode 100644 index 0000000000000..473979b0702c8 --- /dev/null +++ b/boards/arm/nrf52/nrf9160-dk-nrf52/configs/ieee802154_6lowpan/defconfig @@ -0,0 +1,81 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_FPU is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="nrf9160-dk-nrf52" +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_BOARD_NRF9160_DK_NRF52=y +CONFIG_ARCH_CHIP="nrf52" +CONFIG_ARCH_CHIP_NRF52840=y +CONFIG_ARCH_CHIP_NRF52=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARCH_STDARG_H=y +CONFIG_BOARDCTL_RESET=y +CONFIG_BOARD_LOOPSPERMSEC=5500 +CONFIG_BUILTIN=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DRIVERS_IEEE802154=y +CONFIG_DRIVERS_WIRELESS=y +CONFIG_EXAMPLES_NETTEST=y +CONFIG_EXAMPLES_NETTEST_DEVNAME="wpan0" +CONFIG_EXAMPLES_NETTEST_SERVER_PORTNO=61616 +CONFIG_EXAMPLES_NETTEST_TARGET2=y +CONFIG_EXAMPLES_UDP=y +CONFIG_EXAMPLES_UDP_CLIENT_PORTNO=61617 +CONFIG_EXAMPLES_UDP_DEVNAME="wpan0" +CONFIG_EXAMPLES_UDP_IPv6=y +CONFIG_EXAMPLES_UDP_SERVER_PORTNO=61616 +CONFIG_EXAMPLES_UDP_TARGET2=y +CONFIG_EXPERIMENTAL=y +CONFIG_FS_PROCFS=y +CONFIG_IEEE802154_I8SAK=y +CONFIG_IEEE802154_MAC=y +CONFIG_IEEE802154_MACDEV=y +CONFIG_IEEE802154_NETDEV=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_MAC802154_NTXDESC=36 +CONFIG_MM_REGIONS=2 +CONFIG_NET=y +CONFIG_NETDEV_HPWORK_THREAD=y +CONFIG_NETDEV_LATEINIT=y +CONFIG_NETDEV_STATISTICS=y +CONFIG_NETDEV_WIRELESS_IOCTL=y +CONFIG_NETINIT_NETLOCAL=y +CONFIG_NETINIT_NOMAC=y +CONFIG_NETUTILS_TELNETD=y +CONFIG_NET_6LOWPAN=y +CONFIG_NET_BROADCAST=y +CONFIG_NET_IPv6=y +CONFIG_NET_SOCKOPTS=y +CONFIG_NET_STATISTICS=y +CONFIG_NET_TCP=y +CONFIG_NET_TCPBACKLOG=y +CONFIG_NET_TCP_WRITE_BUFFERS=y +CONFIG_NET_UDP=y +CONFIG_NRF52_HFCLK_XTAL=y +CONFIG_NRF52_RADIO=y +CONFIG_NRF52_RADIO_IEEE802154=y +CONFIG_NRF52_UART0=y +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_PROMPT_STRING="nsh-nrf91> " +CONFIG_NSH_READLINE=y +CONFIG_RAM_SIZE=262144 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_SYMTAB_ORDEREDBYNAME=y +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_TELNET_CLIENT=y +CONFIG_UART0_SERIAL_CONSOLE=y +CONFIG_WIRELESS=y +CONFIG_WIRELESS_IEEE802154=y diff --git a/boards/arm/nrf52/nrf9160-dk-nrf52/configs/ieee802154_mac/defconfig b/boards/arm/nrf52/nrf9160-dk-nrf52/configs/ieee802154_mac/defconfig new file mode 100644 index 0000000000000..1725e9d4d418b --- /dev/null +++ b/boards/arm/nrf52/nrf9160-dk-nrf52/configs/ieee802154_mac/defconfig @@ -0,0 +1,56 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_FPU is not set +# CONFIG_NSH_DISABLE_IFCONFIG is not set +# CONFIG_NSH_DISABLE_PS is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="nrf9160-dk-nrf52" +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_BOARD_NRF9160_DK_NRF52=y +CONFIG_ARCH_CHIP="nrf52" +CONFIG_ARCH_CHIP_NRF52840=y +CONFIG_ARCH_CHIP_NRF52=y +CONFIG_ARCH_PERF_EVENTS=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARCH_STDARG_H=y +CONFIG_BOARDCTL_RESET=y +CONFIG_BOARD_LOOPSPERMSEC=5500 +CONFIG_BUILTIN=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DRIVERS_IEEE802154=y +CONFIG_DRIVERS_WIRELESS=y +CONFIG_EXPERIMENTAL=y +CONFIG_IDLETHREAD_STACKSIZE=2048 +CONFIG_IEEE802154_I8SAK=y +CONFIG_IEEE802154_MAC=y +CONFIG_IEEE802154_MACDEV=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_MM_REGIONS=2 +CONFIG_NRF52_HFCLK_XTAL=y +CONFIG_NRF52_RADIO=y +CONFIG_NRF52_RADIO_IEEE802154=y +CONFIG_NRF52_UART0=y +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_PROMPT_STRING="nsh-nrf91> " +CONFIG_NSH_READLINE=y +CONFIG_RAM_SIZE=262144 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_STACK_COLORATION=y +CONFIG_STACK_USAGE=y +CONFIG_SYMTAB_ORDEREDBYNAME=y +CONFIG_SYSTEM_NSH=y +CONFIG_UART0_SERIAL_CONSOLE=y +CONFIG_WIRELESS=y +CONFIG_WIRELESS_IEEE802154=y diff --git a/boards/arm/nrf52/nrf9160-dk-nrf52/src/nrf52_bringup.c b/boards/arm/nrf52/nrf9160-dk-nrf52/src/nrf52_bringup.c index d5bb51e64471c..095fb9d4962d4 100644 --- a/boards/arm/nrf52/nrf9160-dk-nrf52/src/nrf52_bringup.c +++ b/boards/arm/nrf52/nrf9160-dk-nrf52/src/nrf52_bringup.c @@ -27,6 +27,14 @@ #include #include +#include + +#ifdef CONFIG_NRF52_RADIO_IEEE802154 +# include "nrf52_ieee802154.h" +#endif + +#include "nrf9160-dk-nrf52.h" + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -49,6 +57,26 @@ int nrf52_bringup(void) { int ret; +#ifdef CONFIG_FS_PROCFS + /* Mount the procfs file system */ + + ret = nx_mount(NULL, NRF52_PROCFS_MOUNTPOINT, "procfs", 0, NULL); + if (ret < 0) + { + syslog(LOG_ERR, + "ERROR: Failed to mount the PROC filesystem: %d\n", ret); + } +#endif /* CONFIG_FS_PROCFS */ + +#ifdef CONFIG_NRF52_RADIO_IEEE802154 + ret = nrf52_ieee802154_initialize(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to initialize IEE802154 radio: %d\n", + ret); + } +#endif + UNUSED(ret); return OK; } diff --git a/boards/arm/nrf52/nrf9160-dk-nrf52/src/nrf9160-dk-nrf52.h b/boards/arm/nrf52/nrf9160-dk-nrf52/src/nrf9160-dk-nrf52.h index 82fe34c862c52..95744c9424315 100644 --- a/boards/arm/nrf52/nrf9160-dk-nrf52/src/nrf9160-dk-nrf52.h +++ b/boards/arm/nrf52/nrf9160-dk-nrf52/src/nrf9160-dk-nrf52.h @@ -34,6 +34,18 @@ * Pre-processor Definitions ****************************************************************************/ +/* Configuration ************************************************************/ + +/* procfs File System */ + +#ifdef CONFIG_FS_PROCFS +# ifdef CONFIG_NSH_PROC_MOUNTPOINT +# define NRF52_PROCFS_MOUNTPOINT CONFIG_NSH_PROC_MOUNTPOINT +# else +# define NRF52_PROCFS_MOUNTPOINT "/proc" +# endif +#endif + /**************************************************************************** * Public Types ****************************************************************************/ diff --git a/include/nuttx/wireless/ieee802154/ieee802154_mac.h b/include/nuttx/wireless/ieee802154/ieee802154_mac.h index 2a998d035ccff..35f345ab23878 100644 --- a/include/nuttx/wireless/ieee802154/ieee802154_mac.h +++ b/include/nuttx/wireless/ieee802154/ieee802154_mac.h @@ -219,6 +219,7 @@ #define IEEE802154_MAX_PHY_PACKET_SIZE 127 #define IEEE802154_TURN_AROUND_TIME 12 /* symbol periods*/ +#define IEEE802154_SYMBOL_US 16 /* 16us */ /* IEEE 802.15.4 MAC constants */ @@ -251,6 +252,11 @@ #define IEEE802154_MAX_SIFS_FRAME_SIZE 18 #define IEEE802154_MIN_CAP_LENGTH 440 #define IEEE802154_UNIT_BACKOFF_PERIOD 20 +#define IEEE802154_LIFS_SYMBOLS 40 +#define IEEE802154_SIFS_SYMBOLS 12 +#define IEEE802154_ACKIFS_SYMBOLS 12 +#define IEEE802154_TIMESLOT_US (16 * 60) +#define IEEE802154_ACK_FRAME_SIZE 5 /* ACK length (FCF + Seq + FCS) */ /* IEEE 802.15.4 MAC PIB Attribute Defaults */