/* * Copyright (C) 2017 Neo Nenaco * Copyright (C) 2017 Koen Zandberg * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level * directory for more details. */ /** * @ingroup drivers_mrf24j40 * @{ * * @file * @brief Implementation of public functions for MRF24J40 drivers * * @author Koen Zandberg * @author Neo Nenaco * * @} */ #include "luid.h" #include "byteorder.h" #include "net/gnrc.h" #include "mrf24j40_registers.h" #include "mrf24j40_internal.h" #include "mrf24j40_netdev.h" #include "xtimer.h" #define ENABLE_DEBUG (0) #include "debug.h" void mrf24j40_setup(mrf24j40_t *dev, const mrf24j40_params_t *params) { netdev_t *netdev = (netdev_t *)dev; netdev->driver = &mrf24j40_driver; /* initialize device descriptor */ memcpy(&dev->params, params, sizeof(mrf24j40_params_t)); } void mrf24j40_reset(mrf24j40_t *dev) { eui64_t addr_long; mrf24j40_init(dev); /* reset options and sequence number */ dev->netdev.seq = 0; dev->netdev.flags = 0; /* get an 8-byte unique ID to use as hardware address */ luid_get(addr_long.uint8, IEEE802154_LONG_ADDRESS_LEN); addr_long.uint8[0] &= ~(0x01); addr_long.uint8[0] |= (0x02); /* set short and long address */ mrf24j40_set_addr_long(dev, ntohll(addr_long.uint64.u64)); mrf24j40_set_addr_short(dev, ntohs(addr_long.uint16[0].u16)); /* set default PAN id */ mrf24j40_set_pan(dev, IEEE802154_DEFAULT_PANID); mrf24j40_set_chan(dev, IEEE802154_DEFAULT_CHANNEL); /* configure Immediate Sleep and Wake-Up mode */ mrf24j40_reg_write_short(dev, MRF24J40_REG_WAKECON, MRF24J40_WAKECON_IMMWAKE); /* set default options */ mrf24j40_set_option(dev, IEEE802154_FCF_PAN_COMP, true); mrf24j40_set_option(dev, NETDEV_IEEE802154_SRC_MODE_LONG, true); mrf24j40_set_option(dev, NETDEV_IEEE802154_ACK_REQ, true); mrf24j40_set_option(dev, MRF24J40_OPT_CSMA, true); mrf24j40_set_option(dev, MRF24J40_OPT_TELL_RX_START, false); mrf24j40_set_option(dev, MRF24J40_OPT_TELL_RX_END, true); #ifdef MODULE_NETSTATS_L2 mrf24j40_set_option(dev, MRF24J40_OPT_TELL_TX_END, true); #endif /* set default protocol */ #ifdef MODULE_GNRC_SIXLOWPAN dev->netdev.proto = GNRC_NETTYPE_SIXLOWPAN; #elif MODULE_GNRC dev->netdev.proto = GNRC_NETTYPE_UNDEF; #endif /* go into RX state */ mrf24j40_reset_tasks(dev); dev->state = 0; mrf24j40_set_state(dev, MRF24J40_PSEUDO_STATE_IDLE); DEBUG("mrf24j40_reset(): reset complete.\n"); } bool mrf24j40_cca(mrf24j40_t *dev) { uint8_t tmp_ccaedth; uint8_t status; uint8_t tmp_rssi; mrf24j40_assert_awake(dev); /* trigger CCA measurment */ /* take a look onto datasheet chapter 3.6.1 */ mrf24j40_reg_write_short(dev, MRF24J40_REG_BBREG6, MRF24J40_BBREG6_RSSIMODE1); /* wait for result to be ready */ do { status = mrf24j40_reg_read_short(dev, MRF24J40_REG_BBREG6); } while (!(status & MRF24J40_BBREG2_RSSIRDY)); mrf24j40_assert_sleep(dev); /* return according to measurement */ tmp_ccaedth = mrf24j40_reg_read_short(dev, MRF24J40_REG_CCAEDTH); /* Energy detection threshold */ tmp_rssi = mrf24j40_reg_read_long(dev, MRF24J40_REG_RSSI); if (tmp_rssi < tmp_ccaedth) { /* channel is clear */ return true; /* idle */ } else { /* channel is busy */ return false; } } void mrf24j40_tx_prepare(mrf24j40_t *dev) { DEBUG("[mrf24j40] TX_Prepare, Current state: %x\n", dev->state); do { mrf24j40_update_tasks(dev); } while (!(dev->pending & MRF24J40_TASK_TX_DONE)); mrf24j40_assert_awake(dev); dev->pending &= ~(MRF24J40_TASK_TX_DONE); dev->tx_frame_len = IEEE802154_FCS_LEN; } size_t mrf24j40_tx_load(mrf24j40_t *dev, uint8_t *data, size_t len, size_t offset) { DEBUG("[mrf24j40] TX_load, Current state: %x\n", dev->state); dev->tx_frame_len += (uint8_t)len; mrf24j40_tx_normal_fifo_write(dev, MRF24J40_TX_NORMAL_FIFO + offset + 2, data, len); return offset + len; } void mrf24j40_tx_exec(mrf24j40_t *dev) { netdev_t *netdev = (netdev_t *)dev; dev->tx_frame_len = dev->tx_frame_len - IEEE802154_FCS_LEN; /* write frame length field in FIFO */ mrf24j40_tx_normal_fifo_write(dev, MRF24J40_TX_NORMAL_FIFO + 1, &(dev->tx_frame_len), 1); /* write header length to FIFO address 0x00 */ /* from figure 3-11 datasheet: header length = 2 Bytes Frame Control * + 1 Byte Seq. No. * + 4 to 20 Bytes Addressing Fields */ mrf24j40_reg_write_long(dev, MRF24J40_TX_NORMAL_FIFO, dev->header_len); if (dev->netdev.flags & NETDEV_IEEE802154_ACK_REQ) { mrf24j40_reg_write_short(dev, MRF24J40_REG_TXNCON, MRF24J40_TXNCON_TXNACKREQ | MRF24J40_TXNCON_TXNTRIG); } else { mrf24j40_reg_write_short(dev, MRF24J40_REG_TXNCON, MRF24J40_TXNCON_TXNTRIG); } if (netdev->event_callback && (dev->netdev.flags & MRF24J40_OPT_TELL_TX_START)) { netdev->event_callback(netdev, NETDEV_EVENT_TX_STARTED); } }