762 lines
23 KiB
C
762 lines
23 KiB
C
/****************************************************************************
|
|
* drivers/wireless/ieee802154/mrf24j40/mrf24j40_radif.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 <nuttx/config.h>
|
|
|
|
#include <assert.h>
|
|
#include <debug.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
|
|
#include <nuttx/arch.h>
|
|
#include <nuttx/wireless/ieee802154/ieee802154_radio.h>
|
|
#include <nuttx/wireless/ieee802154/ieee802154_mac.h>
|
|
|
|
#include "mrf24j40.h"
|
|
#include "mrf24j40_reg.h"
|
|
#include "mrf24j40_getset.h"
|
|
#include "mrf24j40_regops.h"
|
|
|
|
/****************************************************************************
|
|
* Pre-processor Definitions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Private Types
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Private Function Prototypes
|
|
****************************************************************************/
|
|
|
|
static void mrf24j40_mactimer(FAR struct mrf24j40_radio_s *dev,
|
|
int numsymbols);
|
|
static void mrf24j40_setorder(FAR struct mrf24j40_radio_s *dev, uint8_t bo,
|
|
uint8_t so);
|
|
static void mrf24j40_slpclkcal(FAR struct mrf24j40_radio_s *dev);
|
|
|
|
/****************************************************************************
|
|
* Private Data
|
|
****************************************************************************/
|
|
|
|
static const uint8_t g_allones[8] =
|
|
{
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
|
};
|
|
|
|
/****************************************************************************
|
|
* Public Data
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
|
|
static void mrf24j40_mactimer(FAR struct mrf24j40_radio_s *dev,
|
|
int numsymbols)
|
|
{
|
|
uint16_t nhalfsym;
|
|
uint8_t reg;
|
|
|
|
nhalfsym = (numsymbols << 1);
|
|
|
|
/* Disable the interrupt, clear the timer count */
|
|
|
|
reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON);
|
|
reg |= MRF24J40_INTCON_HSYMTMRIE;
|
|
mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg);
|
|
|
|
mrf24j40_setreg(dev->spi, MRF24J40_HSYMTMRL, 0x00);
|
|
mrf24j40_setreg(dev->spi, MRF24J40_HSYMTMRH, 0x00);
|
|
|
|
reg &= ~MRF24J40_INTCON_HSYMTMRIE;
|
|
mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg);
|
|
|
|
/* Set the timer count and enable interrupts */
|
|
|
|
reg = (nhalfsym & 0xff);
|
|
mrf24j40_setreg(dev->spi, MRF24J40_HSYMTMRL, reg);
|
|
|
|
reg = (nhalfsym >> 8) & 0xff;
|
|
mrf24j40_setreg(dev->spi, MRF24J40_HSYMTMRH, reg);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: mrf24j40_setorder
|
|
*
|
|
* Description:
|
|
* Configures the timers and sets the ORDER register
|
|
****************************************************************************/
|
|
|
|
static void mrf24j40_setorder(FAR struct mrf24j40_radio_s *dev, uint8_t bo,
|
|
uint8_t so)
|
|
{
|
|
uint32_t bi = MRF24J40_BEACONINTERVAL_NSEC(bo);
|
|
uint32_t sfduration = MRF24J40_SUPERFRAMEDURATION_NSEC(so);
|
|
uint32_t maincnt;
|
|
uint32_t remcnt;
|
|
|
|
wlinfo("bo: %d, so: %d\n", bo, so);
|
|
|
|
if (bo < 15)
|
|
{
|
|
if (dev->devmode == IEEE802154_DEVMODE_ENDPOINT)
|
|
{
|
|
wlinfo("Configuring sleep for inactive period\n");
|
|
maincnt = (bi - sfduration) / dev->slpclkper;
|
|
remcnt = ((bi - sfduration) - (maincnt * dev->slpclkper)) / 50;
|
|
}
|
|
else
|
|
{
|
|
wlinfo("Configuring sleep for beacon interval\n");
|
|
maincnt = bi / dev->slpclkper;
|
|
remcnt = (bi - (maincnt * dev->slpclkper)) / 50;
|
|
}
|
|
|
|
wlinfo("MAINCNT: %" PRIu32 ", REMCNT: %" PRIu32 "\n", maincnt, remcnt);
|
|
|
|
/* Program the Main Counter, MAINCNT (0x229<1:0>, 0x228, 0x227,
|
|
* 0x226), and Remain Counter, REMCNT (0x225, 0x224), according to BO
|
|
* and SO values. Refer to Section 3.15.1.3 "Sleep Mode * Counters"
|
|
*/
|
|
|
|
mrf24j40_setreg(dev->spi, MRF24J40_REMCNTL, (remcnt & 0xff));
|
|
mrf24j40_setreg(dev->spi, MRF24J40_REMCNTH, ((remcnt >> 8) & 0xff));
|
|
|
|
mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT0, (maincnt & 0xff));
|
|
mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT1, ((maincnt >> 8) & 0xff));
|
|
mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT2, ((maincnt >> 16) & 0xff));
|
|
mrf24j40_setreg(dev->spi, MRF24J40_MAINCNT3, ((maincnt >> 24) & 0x03));
|
|
}
|
|
|
|
/* Configure the BO (ORDER 0x10<7:4>) and SO (ORDER 0x10<3:0>) values.
|
|
* After configuring BO and SO, the beacon frame will be sent immediately.
|
|
*/
|
|
|
|
mrf24j40_setreg(dev->spi, MRF24J40_ORDER,
|
|
((bo << 4) & 0xf0) | (so & 0x0f));
|
|
}
|
|
|
|
static void mrf24j40_slpclkcal(FAR struct mrf24j40_radio_s *dev)
|
|
{
|
|
uint8_t reg;
|
|
|
|
/* Select the source of SLPCLK (internal 100kHz) */
|
|
|
|
mrf24j40_setreg(dev->spi, MRF24J40_RFCON7, MRF24J40_RFCON7_SEL_100KHZ);
|
|
|
|
/* If the Sleep Clock Selection, SLPCLKSEL (0x207<7:6), is the internal
|
|
* oscillator (100 kHz), set SLPCLKDIV to a minimum value of 0x01.
|
|
*/
|
|
|
|
mrf24j40_setreg(dev->spi, MRF24J40_SLPCON1,
|
|
0x01 | MRF24J40_SLPCON1_CLKOUT_DISABLED);
|
|
|
|
/* Begin calibration by setting the SLPCALEN bit (SLPCAL2 0x20b<4>) to
|
|
* '1'. Sixteen samples of the SLPCLK are counted and stored in the
|
|
* SLPCAL register. No need to mask, this is the only writable bit
|
|
*/
|
|
|
|
mrf24j40_setreg(dev->spi, MRF24J40_SLPCAL2, MRF24J40_SLPCAL2_SLPCALEN);
|
|
|
|
/* Calibration is complete when the SLPCALRDY bit (SLPCAL2 0x20b<7>) is
|
|
* set to '1'.
|
|
*/
|
|
|
|
while (!(mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL2) &
|
|
MRF24J40_SLPCAL2_SLPCALRDY))
|
|
{
|
|
up_udelay(1);
|
|
}
|
|
|
|
reg = mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL0);
|
|
dev->slpclkper = reg;
|
|
reg = mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL1);
|
|
dev->slpclkper |= (reg << 8);
|
|
reg = mrf24j40_getreg(dev->spi, MRF24J40_SLPCAL2) & 0x0f;
|
|
dev->slpclkper |= (reg << 16);
|
|
|
|
dev->slpclkper = (dev->slpclkper * 50 / 16);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
int mrf24j40_bind(FAR struct ieee802154_radio_s *radio,
|
|
FAR struct ieee802154_radiocb_s *radiocb)
|
|
{
|
|
FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio;
|
|
|
|
DEBUGASSERT(dev != NULL);
|
|
dev->radiocb = radiocb;
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Function: mrf24j40_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.
|
|
*
|
|
* Input Parameters:
|
|
* radio - Reference to the radio driver state structure
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
* Assumptions:
|
|
*
|
|
****************************************************************************/
|
|
|
|
int mrf24j40_txnotify(FAR struct ieee802154_radio_s *radio, bool gts)
|
|
{
|
|
FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio;
|
|
|
|
if (gts)
|
|
{
|
|
/* 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->gts_pollwork))
|
|
{
|
|
/* Schedule to serialize the poll on the worker thread. */
|
|
|
|
work_queue(HPWORK, &dev->gts_pollwork,
|
|
mrf24j40_dopoll_gts, dev, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* 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->csma_pollwork))
|
|
{
|
|
/* Schedule to serialize the poll on the worker thread. */
|
|
|
|
work_queue(HPWORK, &dev->csma_pollwork, mrf24j40_dopoll_csma,
|
|
dev, 0);
|
|
}
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Function: mrf24j40_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.
|
|
*
|
|
* Input Parameters:
|
|
* radio - Reference to the radio driver state structure
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
* Assumptions:
|
|
*
|
|
****************************************************************************/
|
|
|
|
int mrf24j40_txdelayed(FAR struct ieee802154_radio_s *radio,
|
|
FAR struct ieee802154_txdesc_s *txdesc,
|
|
uint32_t symboldelay)
|
|
{
|
|
FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio;
|
|
uint8_t reg;
|
|
int ret;
|
|
|
|
/* 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->txdelayed_busy);
|
|
|
|
dev->txdelayed_desc = txdesc;
|
|
dev->txdelayed_busy = true;
|
|
|
|
/* Disable the TX norm interrupt and clear it */
|
|
|
|
reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON);
|
|
reg |= MRF24J40_INTCON_TXNIE;
|
|
mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg);
|
|
|
|
/* If after disabling the interrupt, the irqworker is not scheduled, there
|
|
* are no interrupts to worry about. However, if there is work scheduled,
|
|
* we need to process it before going any further.
|
|
* FIXME: I think this could be done cleaner.
|
|
*/
|
|
|
|
if (!work_available(&dev->irqwork))
|
|
{
|
|
nxmutex_unlock(&dev->lock);
|
|
mrf24j40_irqworker((FAR void *)dev);
|
|
|
|
/* Get exclusive access to the radio device */
|
|
|
|
ret = nxmutex_lock(&dev->lock);
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
if (dev->csma_busy)
|
|
{
|
|
dev->reschedule_csma = true;
|
|
}
|
|
|
|
mrf24j40_norm_setup(dev, txdesc->frame, false);
|
|
|
|
if (symboldelay == 0)
|
|
{
|
|
mrf24j40_norm_trigger(dev);
|
|
}
|
|
else
|
|
{
|
|
mrf24j40_mactimer(dev, symboldelay);
|
|
}
|
|
|
|
nxmutex_unlock(&dev->lock);
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: mrf24j40_rxenable
|
|
*
|
|
* Description:
|
|
* Enable/Disable receiver.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int mrf24j40_rxenable(FAR struct ieee802154_radio_s *radio, bool enable)
|
|
{
|
|
FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio;
|
|
uint8_t reg;
|
|
|
|
dev->rxenabled = enable;
|
|
|
|
if (enable)
|
|
{
|
|
/* Disable packet reception. See pg. 109 of datasheet */
|
|
|
|
mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, MRF24J40_BBREG1_RXDECINV);
|
|
|
|
/* Enable rx int */
|
|
|
|
reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON);
|
|
reg &= ~MRF24J40_INTCON_RXIE;
|
|
mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg);
|
|
|
|
/* Purge the RX buffer */
|
|
|
|
reg = mrf24j40_getreg(dev->spi, MRF24J40_RXFLUSH);
|
|
reg |= MRF24J40_RXFLUSH_RXFLUSH;
|
|
mrf24j40_setreg(dev->spi, MRF24J40_RXFLUSH, reg);
|
|
|
|
/* Re-enable packet reception. See pg. 109 of datasheet */
|
|
|
|
mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, 0);
|
|
}
|
|
else
|
|
{
|
|
/* Disable rx int */
|
|
|
|
reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON);
|
|
reg |= MRF24J40_INTCON_RXIE;
|
|
mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg);
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
int mrf24j40_energydetect(FAR struct ieee802154_radio_s *radio,
|
|
uint32_t nsymbols)
|
|
{
|
|
return -ENOTTY;
|
|
}
|
|
|
|
int mrf24j40_reset(FAR struct ieee802154_radio_s *radio)
|
|
{
|
|
FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio;
|
|
struct ieee802154_cca_s cca;
|
|
int reg;
|
|
|
|
/* Software reset */
|
|
|
|
mrf24j40_setreg(dev->spi, MRF24J40_SOFTRST , 0x07); /* 00000111 Reset */
|
|
while (mrf24j40_getreg(dev->spi, MRF24J40_SOFTRST) & 0x07);
|
|
|
|
/* Apply recommended settings */
|
|
|
|
mrf24j40_setreg(dev->spi, MRF24J40_PACON2 , 0x98); /* 10011000 Enable FIFO (default), TXONTS=6 (recommended), TXONT<8:7>=0 */
|
|
mrf24j40_setreg(dev->spi, MRF24J40_TXSTBL , 0x95); /* 10010101 set the SIFS period. RFSTBL=9, MSIFS=5, aMinSIFSPeriod=14 (min 12) */
|
|
mrf24j40_setreg(dev->spi, MRF24J40_TXPEND , 0x7c); /* 01111100 set the LIFS period, MLIFS=1Fh=31 aMinLIFSPeriod=40 (min 40) */
|
|
mrf24j40_setreg(dev->spi, MRF24J40_TXTIME , 0x30); /* 00110000 set the turnaround time, TURNTIME=3 aTurnAroundTime=12 */
|
|
mrf24j40_setreg(dev->spi, MRF24J40_RFCON1 , 0x02); /* 00000010 VCO optimization, recommended value */
|
|
mrf24j40_setreg(dev->spi, MRF24J40_RFCON2 , 0x80); /* 10000000 Enable PLL */
|
|
mrf24j40_setreg(dev->spi, MRF24J40_RFCON6 , 0x90); /* 10010000 TX filter enable, fast 20M recovery, No bat monitor */
|
|
mrf24j40_setreg(dev->spi, MRF24J40_RFCON7 , 0x80); /* 10000000 Sleep clock on internal 100 kHz */
|
|
mrf24j40_setreg(dev->spi, MRF24J40_RFCON8 , 0x10); /* 00010000 VCO control bit, as recommended */
|
|
mrf24j40_setreg(dev->spi, MRF24J40_BBREG6 , 0x40); /* 01000000 Append RSSI to rx packets */
|
|
|
|
/* Calibrate the Sleep Clock (SLPCLK) frequency. Refer to Section 3.15.1.2
|
|
* "Sleep Clock Calibration".
|
|
*/
|
|
|
|
mrf24j40_slpclkcal(dev);
|
|
|
|
/* For now, we want to always just have the frame pending bit set when
|
|
* acknowledging a Data Request command. The standard says that the
|
|
* coordinator* can do this if it needs time to figure out whether it has
|
|
* data or not
|
|
*/
|
|
|
|
mrf24j40_setreg(dev->spi, MRF24J40_ACKTMOUT,
|
|
0x39 | MRF24J40_ACKTMOUT_DRPACK);
|
|
|
|
/* Set WAKETIME to recommended value for 100kHz SLPCLK Source.
|
|
*
|
|
* NOTE!!!: The datasheet specifies that WAKETIME > WAKECNT. It appears
|
|
* that it is even sensitive to the order in which you set WAKECNT and
|
|
* WAKETIME. Meaning, if you set WAKECNT first and it goes higher than
|
|
* WAKETIME, and then raise WAKETIME above WAKECNT, the device will not
|
|
* function correctly. Therefore, be careful when changing these registers
|
|
*/
|
|
|
|
mrf24j40_setreg(dev->spi, MRF24J40_WAKETIMEL, 0xd2);
|
|
mrf24j40_setreg(dev->spi, MRF24J40_WAKETIMEH, 0x00);
|
|
|
|
/* Set WAKECNT (SLPACK 0x35<6:0>) value = 0x5f to set the main oscillator
|
|
* (20 MHz) start-up timer value.
|
|
*/
|
|
|
|
mrf24j40_setreg(dev->spi, MRF24J40_SLPACK,
|
|
(0x0c8 & MRF24J40_SLPACK_WAKECNT0_6));
|
|
reg = mrf24j40_getreg(dev->spi, MRF24J40_RFCTL);
|
|
reg &= ~MRF24J40_RFCTRL_WAKECNT7_8;
|
|
reg |= ((0x0c8 >> 7) & 0x03) << 3;
|
|
mrf24j40_setreg(dev->spi, MRF24J40_RFCTL, reg);
|
|
|
|
/* Enable the SLPIF and WAKEIF flags */
|
|
|
|
reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON);
|
|
reg &= ~(MRF24J40_INTCON_SLPIE | MRF24J40_INTCON_WAKEIE);
|
|
mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg);
|
|
|
|
mrf24j40_setorder(dev, 15, 15);
|
|
|
|
dev->rxenabled = false;
|
|
|
|
mrf24j40_setchannel(dev, 11);
|
|
mrf24j40_setpanid(dev, g_allones);
|
|
mrf24j40_setsaddr(dev, g_allones);
|
|
mrf24j40_seteaddr(dev, g_allones);
|
|
|
|
dev->max_frame_waittime = MRF24J40_DEFAULT_MAX_FRAME_WAITTIME;
|
|
dev->bsn = 0;
|
|
|
|
/* Default device params */
|
|
|
|
cca.use_ed = 1;
|
|
cca.use_cs = 0;
|
|
cca.edth = 0x60; /* CCA mode ED, no carrier sense, recommenced ED threshold -69 dBm */
|
|
mrf24j40_setcca(dev, &cca);
|
|
|
|
mrf24j40_setrxmode(dev, MRF24J40_RXMODE_NORMAL);
|
|
|
|
mrf24j40_settxpower(dev, 0); /* 16. Set transmitter power. */
|
|
|
|
mrf24j40_setpamode(dev, MRF24J40_PA_AUTO);
|
|
|
|
return OK;
|
|
}
|
|
|
|
int mrf24j40_getattr(FAR struct ieee802154_radio_s *radio,
|
|
enum ieee802154_attr_e attr,
|
|
FAR union ieee802154_attr_u *attrval)
|
|
{
|
|
FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio;
|
|
int ret;
|
|
|
|
switch (attr)
|
|
{
|
|
case IEEE802154_ATTR_MAC_EADDR:
|
|
{
|
|
memcpy(&attrval->mac.eaddr[0], &dev->addr.eaddr[0], 8);
|
|
ret = IEEE802154_STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
|
|
case IEEE802154_ATTR_MAC_MAX_FRAME_WAITTIME:
|
|
{
|
|
attrval->mac.max_frame_waittime = dev->max_frame_waittime;
|
|
ret = IEEE802154_STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
|
|
case IEEE802154_ATTR_PHY_SYMBOL_DURATION:
|
|
{
|
|
attrval->phy.symdur_picosec = MRF24J40_SYMBOL_DURATION_PS;
|
|
ret = IEEE802154_STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
|
|
case IEEE802154_ATTR_PHY_CHAN:
|
|
{
|
|
attrval->phy.chan = dev->chan;
|
|
ret = IEEE802154_STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
|
|
case IEEE802154_ATTR_PHY_FCS_LEN:
|
|
{
|
|
attrval->phy.fcslen = 2;
|
|
ret = IEEE802154_STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ret = IEEE802154_STATUS_UNSUPPORTED_ATTRIBUTE;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int mrf24j40_setattr(FAR struct ieee802154_radio_s *radio,
|
|
enum ieee802154_attr_e attr,
|
|
FAR const union ieee802154_attr_u *attrval)
|
|
{
|
|
FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio;
|
|
int ret = IEEE802154_STATUS_SUCCESS;
|
|
|
|
switch (attr)
|
|
{
|
|
case IEEE802154_ATTR_MAC_PANID:
|
|
{
|
|
mrf24j40_setpanid(dev, attrval->mac.panid);
|
|
}
|
|
break;
|
|
|
|
case IEEE802154_ATTR_MAC_SADDR:
|
|
{
|
|
mrf24j40_setsaddr(dev, attrval->mac.saddr);
|
|
}
|
|
break;
|
|
|
|
case IEEE802154_ATTR_MAC_EADDR:
|
|
{
|
|
mrf24j40_seteaddr(dev, attrval->mac.eaddr);
|
|
}
|
|
break;
|
|
|
|
case IEEE802154_ATTR_MAC_COORD_SADDR:
|
|
{
|
|
mrf24j40_setcoordsaddr(dev, attrval->mac.coordsaddr);
|
|
}
|
|
break;
|
|
|
|
case IEEE802154_ATTR_MAC_COORD_EADDR:
|
|
{
|
|
mrf24j40_setcoordeaddr(dev, attrval->mac.coordeaddr);
|
|
}
|
|
break;
|
|
|
|
case IEEE802154_ATTR_MAC_PROMISCUOUS_MODE:
|
|
{
|
|
if (attrval->mac.promisc_mode)
|
|
{
|
|
mrf24j40_setrxmode(dev, MRF24J40_RXMODE_PROMISC);
|
|
}
|
|
else
|
|
{
|
|
mrf24j40_setrxmode(dev, MRF24J40_RXMODE_NORMAL);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IEEE802154_ATTR_PHY_CHAN:
|
|
{
|
|
mrf24j40_setchannel(dev, attrval->phy.chan);
|
|
}
|
|
break;
|
|
|
|
case IEEE802154_ATTR_MAC_DEVMODE:
|
|
{
|
|
mrf24j40_setdevmode(dev, attrval->mac.devmode);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ret = IEEE802154_STATUS_UNSUPPORTED_ATTRIBUTE;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int mrf24j40_beaconstart(FAR struct ieee802154_radio_s *radio,
|
|
FAR const struct ieee802154_superframespec_s *sfspec,
|
|
FAR struct ieee802154_beaconframe_s *beacon)
|
|
{
|
|
FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio;
|
|
int reg;
|
|
|
|
if (sfspec->pancoord)
|
|
{
|
|
/* Set the PANCOORD (RXMCR 0x00<3>) bit = 1to configure as
|
|
* PAN coordinator
|
|
*/
|
|
|
|
reg = mrf24j40_getreg(dev->spi, MRF24J40_RXMCR);
|
|
reg |= MRF24J40_RXMCR_PANCOORD;
|
|
mrf24j40_setreg(dev->spi, MRF24J40_RXMCR, reg);
|
|
|
|
/* Set the SLOTTED (TXMCR 0x11<5>) bit = 1 to use
|
|
* Slotted CSMA-CA mode
|
|
*/
|
|
|
|
reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR);
|
|
reg |= MRF24J40_TXMCR_SLOTTED;
|
|
mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg);
|
|
|
|
/* Load the beacon frame into the TXBFIFO (0x080-0x0ff). */
|
|
|
|
mrf24j40_setup_fifo(dev, beacon->bf_data, beacon->bf_len,
|
|
MRF24J40_BEACON_FIFO);
|
|
|
|
/* The radio layer is responsible for setting the BSN. */
|
|
|
|
dev->bsn = 0;
|
|
mrf24j40_setreg(dev->spi, MRF24J40_BEACON_FIFO + 4, dev->bsn++);
|
|
|
|
/* Set the TXBMSK (TXBCON1 0x25<7>) bit = 1 to mask the beacon
|
|
* interrupt mask
|
|
*/
|
|
|
|
reg = mrf24j40_getreg(dev->spi, MRF24J40_TXBCON1);
|
|
reg |= MRF24J40_TXBCON1_TXBMSK;
|
|
mrf24j40_setreg(dev->spi, MRF24J40_TXBCON1, reg);
|
|
|
|
/* Set INTL (WAKECON 0x22<5:0>) value to 0x03. */
|
|
|
|
reg = mrf24j40_getreg(dev->spi, MRF24J40_WAKECON);
|
|
reg &= ~MRF24J40_WAKECON_INTL;
|
|
reg |= 0x03 & MRF24J40_WAKECON_INTL;
|
|
mrf24j40_setreg(dev->spi, MRF24J40_WAKECON, reg);
|
|
|
|
/* Program the CAP end slot (ESLOTG1 0x13<3:0>) value. */
|
|
|
|
reg = mrf24j40_getreg(dev->spi, MRF24J40_ESLOTG1);
|
|
reg &= ~MRF24J40_ESLOTG1_CAP;
|
|
reg |= sfspec->final_capslot & MRF24J40_ESLOTG1_CAP;
|
|
mrf24j40_setreg(dev->spi, MRF24J40_ESLOTG1, reg);
|
|
|
|
/* TODO: Add GTS related code. See pg 100 of datasheet */
|
|
|
|
mrf24j40_setorder(dev, sfspec->beaconorder, sfspec->sforder);
|
|
}
|
|
else
|
|
{
|
|
return -ENOTTY;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
int mrf24j40_beaconupdate(FAR struct ieee802154_radio_s *radio,
|
|
FAR struct ieee802154_beaconframe_s *beacon)
|
|
{
|
|
FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio;
|
|
|
|
mrf24j40_setup_fifo(dev, beacon->bf_data, beacon->bf_len,
|
|
MRF24J40_BEACON_FIFO);
|
|
mrf24j40_beacon_trigger(dev);
|
|
|
|
return OK;
|
|
}
|
|
|
|
int mrf24j40_beaconstop(FAR struct ieee802154_radio_s *radio)
|
|
{
|
|
return -ENOTTY;
|
|
}
|
|
|
|
int mrf24j40_sfupdate(FAR struct ieee802154_radio_s *radio,
|
|
FAR const struct ieee802154_superframespec_s *sfspec)
|
|
{
|
|
FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio;
|
|
int reg;
|
|
|
|
/* If we are operating on a beacon-enabled network, use slotted CSMA */
|
|
|
|
reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR);
|
|
if (sfspec->beaconorder < 15)
|
|
{
|
|
reg |= MRF24J40_TXMCR_SLOTTED;
|
|
|
|
if (dev->devmode == IEEE802154_DEVMODE_ENDPOINT)
|
|
{
|
|
mrf24j40_setreg(dev->spi, MRF24J40_FRMOFFSET, 0x15);
|
|
}
|
|
else
|
|
{
|
|
mrf24j40_setreg(dev->spi, MRF24J40_FRMOFFSET, 0x00);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
reg &= ~MRF24J40_TXMCR_SLOTTED;
|
|
}
|
|
|
|
mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg);
|
|
|
|
mrf24j40_setorder(dev, sfspec->beaconorder, sfspec->sforder);
|
|
|
|
/* Program the CAP end slot (ESLOTG1 0x13<3:0>) value. */
|
|
|
|
reg = mrf24j40_getreg(dev->spi, MRF24J40_ESLOTG1);
|
|
reg &= ~MRF24J40_ESLOTG1_CAP;
|
|
reg |= sfspec->final_capslot & MRF24J40_ESLOTG1_CAP;
|
|
mrf24j40_setreg(dev->spi, MRF24J40_ESLOTG1, reg);
|
|
|
|
return OK;
|
|
}
|