426 lines
11 KiB
C
426 lines
11 KiB
C
|
/****************************************************************************
|
|||
|
* drivers/wireless/ieee802154/mrf24j40/mrf24j40_getset.c
|
|||
|
*
|
|||
|
* Copyright (C) 2015-2016 Sebastien Lorquet. All rights reserved.
|
|||
|
* Copyright (C) 2017 Verge Inc. All rights reserved.
|
|||
|
* Author: Sebastien Lorquet <sebastien@lorquet.fr>
|
|||
|
* Author: Anthony Merlino <anthony@vergeaero.com>
|
|||
|
*
|
|||
|
* Redistribution and use in source and binary forms, with or without
|
|||
|
* modification, are permitted provided that the following conditions
|
|||
|
* are met:
|
|||
|
*
|
|||
|
* 1. Redistributions of source code must retain the above copyright
|
|||
|
* notice, this list of conditions and the following disclaimer.
|
|||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|||
|
* notice, this list of conditions and the following disclaimer in
|
|||
|
* the documentation and/or other materials provided with the
|
|||
|
* distribution.
|
|||
|
* 3. Neither the name NuttX nor the names of its contributors may be
|
|||
|
* used to endorse or promote products derived from this software
|
|||
|
* without specific prior written permission.
|
|||
|
*
|
|||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|||
|
* POSSIBILITY OF SUCH DAMAGE.
|
|||
|
*
|
|||
|
****************************************************************************/
|
|||
|
|
|||
|
/****************************************************************************
|
|||
|
* Included Files
|
|||
|
****************************************************************************/
|
|||
|
|
|||
|
#include <nuttx/config.h>
|
|||
|
#include <assert.h>
|
|||
|
#include <debug.h>
|
|||
|
|
|||
|
#include "mrf24j40.h"
|
|||
|
#include "mrf24j40_reg.h"
|
|||
|
#include "mrf24j40_regops.h"
|
|||
|
#include "mrf24j40_getset.h"
|
|||
|
|
|||
|
/****************************************************************************
|
|||
|
* Name: mrf24j40_setrxmode
|
|||
|
*
|
|||
|
* Description:
|
|||
|
* Set the RX mode (normal, promiscuous, no CRC)
|
|||
|
*
|
|||
|
****************************************************************************/
|
|||
|
|
|||
|
int mrf24j40_setrxmode(FAR struct mrf24j40_radio_s *dev, int mode)
|
|||
|
{
|
|||
|
uint8_t reg;
|
|||
|
|
|||
|
if (mode < MRF24J40_RXMODE_NORMAL || mode > MRF24J40_RXMODE_NOCRC)
|
|||
|
{
|
|||
|
return -EINVAL;
|
|||
|
}
|
|||
|
|
|||
|
reg = mrf24j40_getreg(dev->spi, MRF24J40_RXMCR);
|
|||
|
reg &= ~0x03;
|
|||
|
reg |= mode;
|
|||
|
|
|||
|
/* Set mode options */
|
|||
|
|
|||
|
if (mode != MRF24J40_RXMODE_NORMAL)
|
|||
|
{
|
|||
|
/* Promisc and error modes: Disable auto ACK */
|
|||
|
|
|||
|
reg |= MRF24J40_RXMCR_NOACKRSP;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/* Normal mode : enable auto-ACK */
|
|||
|
|
|||
|
reg &= ~MRF24J40_RXMCR_NOACKRSP;
|
|||
|
}
|
|||
|
|
|||
|
mrf24j40_setreg(dev->spi, MRF24J40_RXMCR, reg);
|
|||
|
|
|||
|
dev->rxmode = mode;
|
|||
|
wlinfo("%u\n", (unsigned)mode);
|
|||
|
return OK;
|
|||
|
}
|
|||
|
|
|||
|
/****************************************************************************
|
|||
|
* Name: mrf24j40_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
|
|||
|
*
|
|||
|
****************************************************************************/
|
|||
|
|
|||
|
int mrf24j40_setchannel(FAR struct mrf24j40_radio_s *dev, uint8_t chan)
|
|||
|
{
|
|||
|
if (chan < 11 || chan > 26)
|
|||
|
{
|
|||
|
wlerr("ERROR: Invalid chan: %d\n",chan);
|
|||
|
return -EINVAL;
|
|||
|
}
|
|||
|
|
|||
|
/* 15. Set channel – See Section 3.4 “Channel Selection”. */
|
|||
|
|
|||
|
mrf24j40_setreg(dev->spi, MRF24J40_RFCON0, (chan - 11) << 4 | 0x03);
|
|||
|
|
|||
|
/* 17. RFCTL (0x36) = 0x04 – Reset RF state machine.
|
|||
|
* 18. RFCTL (0x36) = 0x00.
|
|||
|
*/
|
|||
|
|
|||
|
mrf24j40_resetrfsm(dev);
|
|||
|
|
|||
|
dev->chan = chan;
|
|||
|
wlinfo("%u\n", (unsigned)chan);
|
|||
|
|
|||
|
return OK;
|
|||
|
}
|
|||
|
|
|||
|
/****************************************************************************
|
|||
|
* Name: mrf24j40_setpanid
|
|||
|
*
|
|||
|
* Description:
|
|||
|
* Define the PAN ID the device is operating on.
|
|||
|
*
|
|||
|
****************************************************************************/
|
|||
|
|
|||
|
int mrf24j40_setpanid(FAR struct mrf24j40_radio_s *dev,
|
|||
|
FAR const uint8_t *panid)
|
|||
|
{
|
|||
|
mrf24j40_setreg(dev->spi, MRF24J40_PANIDL, panid[0]);
|
|||
|
mrf24j40_setreg(dev->spi, MRF24J40_PANIDH, panid[1]);
|
|||
|
|
|||
|
IEEE802154_PANIDCOPY(dev->addr.panid, panid);
|
|||
|
wlinfo("%02X:%02X\n", panid[0], panid[1]);
|
|||
|
|
|||
|
return OK;
|
|||
|
}
|
|||
|
|
|||
|
/****************************************************************************
|
|||
|
* Name: mrf24j40_setsaddr
|
|||
|
*
|
|||
|
* Description:
|
|||
|
* Define the device short address. The following addresses are special:
|
|||
|
* FFFEh : Broadcast
|
|||
|
* FFFFh : Unspecified
|
|||
|
*
|
|||
|
****************************************************************************/
|
|||
|
|
|||
|
int mrf24j40_setsaddr(FAR struct mrf24j40_radio_s *dev,
|
|||
|
FAR const uint8_t *saddr)
|
|||
|
{
|
|||
|
mrf24j40_setreg(dev->spi, MRF24J40_SADRL, saddr[0]);
|
|||
|
mrf24j40_setreg(dev->spi, MRF24J40_SADRH, saddr[1]);
|
|||
|
|
|||
|
IEEE802154_SADDRCOPY(dev->addr.saddr, saddr);
|
|||
|
|
|||
|
wlinfo("%02X:%02X\n", saddr[0], saddr[1]);
|
|||
|
return OK;
|
|||
|
}
|
|||
|
|
|||
|
/****************************************************************************
|
|||
|
* Name: mrf24j40_seteaddr
|
|||
|
*
|
|||
|
* Description:
|
|||
|
* Define the device extended address. The following addresses are special:
|
|||
|
* FFFFFFFFFFFFFFFFh : Unspecified
|
|||
|
*
|
|||
|
****************************************************************************/
|
|||
|
|
|||
|
int mrf24j40_seteaddr(FAR struct mrf24j40_radio_s *dev,
|
|||
|
FAR const uint8_t *eaddr)
|
|||
|
{
|
|||
|
int i;
|
|||
|
|
|||
|
for (i = 0; i < 8; i++)
|
|||
|
{
|
|||
|
mrf24j40_setreg(dev->spi, MRF24J40_EADR0 + i, eaddr[i]);
|
|||
|
dev->addr.eaddr[i] = eaddr[i];
|
|||
|
}
|
|||
|
wlinfo("%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]);
|
|||
|
|
|||
|
return OK;
|
|||
|
}
|
|||
|
|
|||
|
/****************************************************************************
|
|||
|
* Name: mrf24j40_setcoordsaddr
|
|||
|
*
|
|||
|
* Description:
|
|||
|
* Define the coordinator short address. The following addresses are special:
|
|||
|
* FFFEh : Broadcast
|
|||
|
* FFFFh : Unspecified
|
|||
|
*
|
|||
|
****************************************************************************/
|
|||
|
|
|||
|
int mrf24j40_setcoordsaddr(FAR struct mrf24j40_radio_s *dev,
|
|||
|
FAR const uint8_t *saddr)
|
|||
|
{
|
|||
|
mrf24j40_setreg(dev->spi, MRF24J40_ASSOSADR0, saddr[0]);
|
|||
|
mrf24j40_setreg(dev->spi, MRF24J40_ASSOSADR1, saddr[1]);
|
|||
|
|
|||
|
IEEE802154_SADDRCOPY(dev->addr.saddr, saddr);
|
|||
|
|
|||
|
wlinfo("%02X:%02X\n", saddr[0], saddr[1]);
|
|||
|
return OK;
|
|||
|
}
|
|||
|
|
|||
|
/****************************************************************************
|
|||
|
* Name: mrf24j40_setcoordeaddr
|
|||
|
*
|
|||
|
* Description:
|
|||
|
* Define the coordinator extended address. The following addresses are special:
|
|||
|
* FFFFFFFFFFFFFFFFh : Unspecified
|
|||
|
*
|
|||
|
****************************************************************************/
|
|||
|
|
|||
|
int mrf24j40_setcoordeaddr(FAR struct mrf24j40_radio_s *dev,
|
|||
|
FAR const uint8_t *eaddr)
|
|||
|
{
|
|||
|
int i;
|
|||
|
|
|||
|
for (i = 0; i < 8; i++)
|
|||
|
{
|
|||
|
mrf24j40_setreg(dev->spi, MRF24J40_ASSOEADR0 + i, eaddr[i]);
|
|||
|
dev->addr.eaddr[i] = eaddr[i];
|
|||
|
}
|
|||
|
|
|||
|
wlinfo("%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]);
|
|||
|
return OK;
|
|||
|
}
|
|||
|
|
|||
|
/****************************************************************************
|
|||
|
* Name: mrf24j40_setdevmode
|
|||
|
*
|
|||
|
* Description:
|
|||
|
* Define the device behaviour: normal end device or coordinator
|
|||
|
*
|
|||
|
****************************************************************************/
|
|||
|
|
|||
|
int mrf24j40_setdevmode(FAR struct mrf24j40_radio_s *dev,
|
|||
|
uint8_t mode)
|
|||
|
{
|
|||
|
int ret = OK;
|
|||
|
uint8_t reg;
|
|||
|
|
|||
|
/* Disable slotted mode until I decide to implement slotted mode */
|
|||
|
|
|||
|
reg = mrf24j40_getreg(dev->spi, MRF24J40_TXMCR);
|
|||
|
reg &= ~MRF24J40_TXMCR_SLOTTED;
|
|||
|
mrf24j40_setreg(dev->spi, MRF24J40_TXMCR, reg);
|
|||
|
mrf24j40_setreg(dev->spi, MRF24J40_ORDER, 0xFF);
|
|||
|
|
|||
|
/* Define dev mode */
|
|||
|
|
|||
|
reg = mrf24j40_getreg(dev->spi, MRF24J40_RXMCR);
|
|||
|
|
|||
|
if (mode == MRF24J40_MODE_PANCOORD)
|
|||
|
{
|
|||
|
reg |= MRF24J40_RXMCR_PANCOORD;
|
|||
|
reg &= ~MRF24J40_RXMCR_COORD;
|
|||
|
}
|
|||
|
else if (mode == MRF24J40_MODE_COORD)
|
|||
|
{
|
|||
|
reg |= MRF24J40_RXMCR_COORD;
|
|||
|
reg &= ~MRF24J40_RXMCR_PANCOORD;
|
|||
|
}
|
|||
|
else if (mode == MRF24J40_MODE_DEVICE)
|
|||
|
{
|
|||
|
reg &= ~MRF24J40_RXMCR_PANCOORD;
|
|||
|
reg &= ~MRF24J40_RXMCR_COORD;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return -EINVAL;
|
|||
|
}
|
|||
|
|
|||
|
mrf24j40_setreg(dev->spi, MRF24J40_RXMCR, reg);
|
|||
|
dev->devmode = mode;
|
|||
|
return ret;
|
|||
|
}
|
|||
|
|
|||
|
/****************************************************************************
|
|||
|
* Name: mrf24j40_settxpower
|
|||
|
*
|
|||
|
* Description:
|
|||
|
* Define the transmit power. Value is passed in mBm, it is rounded to
|
|||
|
* the nearest value. Some MRF modules have a power amplifier, this routine
|
|||
|
* does not care about this. We only change the CHIP output power.
|
|||
|
*
|
|||
|
****************************************************************************/
|
|||
|
|
|||
|
int mrf24j40_settxpower(FAR struct mrf24j40_radio_s *dev,
|
|||
|
int32_t txpwr)
|
|||
|
{
|
|||
|
uint8_t reg;
|
|||
|
int save_txpwr = txpwr;
|
|||
|
|
|||
|
if (txpwr <= -3000 && txpwr > -3630)
|
|||
|
{
|
|||
|
reg = 0xC0;
|
|||
|
txpwr += 3000;
|
|||
|
}
|
|||
|
else if (txpwr <= -2000)
|
|||
|
{
|
|||
|
reg = 0x80;
|
|||
|
txpwr += 2000;
|
|||
|
}
|
|||
|
else if (txpwr <= -1000)
|
|||
|
{
|
|||
|
reg = 0x40;
|
|||
|
txpwr += 1000;
|
|||
|
}
|
|||
|
else if (txpwr <= 0)
|
|||
|
{
|
|||
|
reg = 0x00;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return -EINVAL;
|
|||
|
}
|
|||
|
|
|||
|
wlinfo("Remaining attenuation: %d mBm\n",txpwr);
|
|||
|
|
|||
|
switch(txpwr/100)
|
|||
|
{
|
|||
|
case -9:
|
|||
|
case -8:
|
|||
|
case -7:
|
|||
|
case -6:
|
|||
|
reg |= 0x07;
|
|||
|
break;
|
|||
|
|
|||
|
case -5:
|
|||
|
reg |= 0x06;
|
|||
|
break;
|
|||
|
|
|||
|
case -4:
|
|||
|
reg |= 0x05;
|
|||
|
break;
|
|||
|
|
|||
|
case -3:
|
|||
|
reg |= 0x04;
|
|||
|
break;
|
|||
|
|
|||
|
case -2:
|
|||
|
reg |= 0x03;
|
|||
|
break;
|
|||
|
|
|||
|
case -1:
|
|||
|
reg |= 0x02;
|
|||
|
break;
|
|||
|
|
|||
|
case 0:
|
|||
|
reg |= 0x00; /* value 0x01 is 0.5 db, not used */
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
|
|||
|
return -EINVAL;
|
|||
|
}
|
|||
|
|
|||
|
mrf24j40_setreg(dev->spi, MRF24J40_RFCON3, reg);
|
|||
|
|
|||
|
dev->txpower = save_txpwr;
|
|||
|
|
|||
|
return OK;
|
|||
|
}
|
|||
|
|
|||
|
/****************************************************************************
|
|||
|
* Name: mrf24j40_setcca
|
|||
|
*
|
|||
|
* Description:
|
|||
|
* Define the Clear Channel Assessement method.
|
|||
|
*
|
|||
|
****************************************************************************/
|
|||
|
|
|||
|
int mrf24j40_setcca(FAR struct mrf24j40_radio_s *dev,
|
|||
|
FAR struct ieee802154_cca_s *cca)
|
|||
|
{
|
|||
|
uint8_t mode;
|
|||
|
|
|||
|
if (!cca->use_ed && !cca->use_cs)
|
|||
|
{
|
|||
|
return -EINVAL;
|
|||
|
}
|
|||
|
|
|||
|
if (cca->use_cs && cca->csth > 0x0f)
|
|||
|
{
|
|||
|
return -EINVAL;
|
|||
|
}
|
|||
|
|
|||
|
mode = mrf24j40_getreg(dev->spi, MRF24J40_BBREG2);
|
|||
|
mode &= 0x03;
|
|||
|
|
|||
|
if (cca->use_ed)
|
|||
|
{
|
|||
|
mode |= MRF24J40_BBREG2_CCAMODE_ED;
|
|||
|
mrf24j40_setreg(dev->spi, MRF24J40_CCAEDTH, cca->edth);
|
|||
|
}
|
|||
|
|
|||
|
if (cca->use_cs)
|
|||
|
{
|
|||
|
mode |= MRF24J40_BBREG2_CCAMODE_CS;
|
|||
|
mode |= cca->csth << 2;
|
|||
|
}
|
|||
|
|
|||
|
mrf24j40_setreg(dev->spi, MRF24J40_BBREG2, mode);
|
|||
|
|
|||
|
memcpy(&dev->cca, cca, sizeof(struct ieee802154_cca_s));
|
|||
|
return OK;
|
|||
|
}
|