From c9f4d6abf9560ca89dccbae0296a32f508744270 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sat, 1 Jun 2013 08:03:55 -0600 Subject: Add NSRF42L01 driver. From Laurent Latil --- nuttx/drivers/wireless/ISM1_868MHzGFSK100kbps.c | 123 ++ nuttx/drivers/wireless/ISM2_905MHzGFSK250kbps.c | 121 ++ nuttx/drivers/wireless/Kconfig | 52 + nuttx/drivers/wireless/Make.defs | 14 +- nuttx/drivers/wireless/cc1101.c | 856 ++++++++++ .../wireless/cc1101/ISM1_868MHzGFSK100kbps.c | 113 -- .../wireless/cc1101/ISM2_905MHzGFSK250kbps.c | 111 -- nuttx/drivers/wireless/cc1101/Kconfig | 4 - nuttx/drivers/wireless/cc1101/cc1101.c | 812 --------- nuttx/drivers/wireless/nrf24l01.c | 1772 ++++++++++++++++++++ nuttx/drivers/wireless/nrf24l01.h | 183 ++ 11 files changed, 3117 insertions(+), 1044 deletions(-) create mode 100644 nuttx/drivers/wireless/ISM1_868MHzGFSK100kbps.c create mode 100644 nuttx/drivers/wireless/ISM2_905MHzGFSK250kbps.c create mode 100644 nuttx/drivers/wireless/cc1101.c delete mode 100644 nuttx/drivers/wireless/cc1101/ISM1_868MHzGFSK100kbps.c delete mode 100644 nuttx/drivers/wireless/cc1101/ISM2_905MHzGFSK250kbps.c delete mode 100644 nuttx/drivers/wireless/cc1101/Kconfig delete mode 100644 nuttx/drivers/wireless/cc1101/cc1101.c create mode 100644 nuttx/drivers/wireless/nrf24l01.c create mode 100644 nuttx/drivers/wireless/nrf24l01.h (limited to 'nuttx/drivers/wireless') diff --git a/nuttx/drivers/wireless/ISM1_868MHzGFSK100kbps.c b/nuttx/drivers/wireless/ISM1_868MHzGFSK100kbps.c new file mode 100644 index 000000000..a02b2838a --- /dev/null +++ b/nuttx/drivers/wireless/ISM1_868MHzGFSK100kbps.c @@ -0,0 +1,123 @@ +/**************************************************************************** + * drivers/wireless/ISM1_868MHzGFSK100kbps.c + * + * Copyright (C) 2011 Uros Platise. All rights reserved. + * Copyright (C) 2011 Ales Verbic. All rights reserved. + * + * Authors: Uros Platise + * Ales Verbic + * + * 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 + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/** Settings for 868 MHz, GFSK at 100kbps + * + * ISM Region 1 (Europe) only, Band 868–870 MHz + * + * Frequency ERP Duty Cycle Bandwidth Remarks + * 868 – 868.6 MHz +14 dBm < 1% No limits + * 868.7 – 869.2 MHz +14 dBm < 0.1% No limits + * 869.3 – 869.4 MHz +10 dBm No limits < 25 kHz Appropriate access protocol required + * 869.4 – 869.65 MHz +27 dBm < 10% < 25 kHz Channels may be combined to one high speed channel + * 869.7 -870 MHz +7 dBm No limits No limits + * + * Deviation = 46.142578 + * Base frequency = 867.999985 + * Carrier frequency = 867.999985 + * Channel number = 0 + * Carrier frequency = 867.999985 + * Modulated = true + * Modulation format = GFSK + * Manchester enable = false + * Sync word qualifier mode = 30/32 sync word bits detected + * Preamble count = 4 + * Channel spacing = 199.813843 + * Carrier frequency = 867.999985 + * Data rate = 99.9069 + * RX filter BW = 210.937500 + * Data format = Normal mode + * Length config = Fixed packet length mode. Length configured in PKTLEN register + * CRC enable = true + * Packet length = 62 + * Device address = 00 + * Address config = NO Address check, no broadcast + * CRC autoflush = true + * PA ramping = false + * TX power = 0 + */ + +const struct c1101_rfsettings_s cc1101_rfsettings_ISM1_868MHzGFSK100kbps = +{ + .FSCTRL1 = 0x08, /* FSCTRL1 Frequency Synthesizer Control */ + .FSCTRL0 = 0x00, /* FSCTRL0 Frequency Synthesizer Control */ + + .FREQ2 = 0x20, /* FREQ2 Frequency Control Word, High Byte */ + .FREQ1 = 0x25, /* FREQ1 Frequency Control Word, Middle Byte */ + .FREQ0 = 0xED, /* FREQ0 Frequency Control Word, Low Byte */ + + .MDMCFG4 = 0x8B, /* MDMCFG4 Modem Configuration */ + .MDMCFG3 = 0xE5, /* MDMCFG3 Modem Configuration */ + .MDMCFG2 = 0x13, /* MDMCFG2 Modem Configuration */ + .MDMCFG1 = 0x22, /* MDMCFG1 Modem Configuration */ + .MDMCFG0 = 0xE5, /* MDMCFG0 Modem Configuration */ + + .DEVIATN = 0x46, /* DEVIATN Modem Deviation Setting */ + + .FOCCFG = 0x1D, /* FOCCFG Frequency Offset Compensation Configuration */ + + .BSCFG = 0x1C, /* BSCFG Bit Synchronization Configuration */ + + .AGCCTRL2= 0xC7, /* AGCCTRL2 AGC Control */ + .AGCCTRL1= 0x00, /* AGCCTRL1 AGC Control */ + .AGCCTRL0= 0xB2, /* AGCCTRL0 AGC Control */ + + .FREND1 = 0xB6, /* FREND1 Front End RX Configuration */ + .FREND0 = 0x10, /* FREND0 Front End TX Configuration */ + + .FSCAL3 = 0xEA, /* FSCAL3 Frequency Synthesizer Calibration */ + .FSCAL2 = 0x2A, /* FSCAL2 Frequency Synthesizer Calibration */ + .FSCAL1 = 0x00, /* FSCAL1 Frequency Synthesizer Calibration */ + .FSCAL0 = 0x1F, /* FSCAL0 Frequency Synthesizer Calibration */ + + .CHMIN = 0, /* Fix at 9th channel: 869.80 MHz +- 100 kHz RF Bandwidth */ + .CHMAX = 9, /* single channel */ + + .PAMAX = 8, /* 0 means power OFF, 8 represents PA[7] */ + .PA = {0x03, 0x0F, 0x1E, 0x27, 0x67, 0x50, 0x81, 0xC2} +}; diff --git a/nuttx/drivers/wireless/ISM2_905MHzGFSK250kbps.c b/nuttx/drivers/wireless/ISM2_905MHzGFSK250kbps.c new file mode 100644 index 000000000..c78cee586 --- /dev/null +++ b/nuttx/drivers/wireless/ISM2_905MHzGFSK250kbps.c @@ -0,0 +1,121 @@ +/**************************************************************************** + * drivers/wireless/ISM2_905MHzGFSK250kbps.c + * + * Copyright (C) 2011 Uros Platise. All rights reserved. + * Copyright (C) 2011 Ales Verbic. All rights reserved. + * + * Authors: Uros Platise + * Ales Verbic + * + * 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 + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/** Settings for 905 MHz, GFSK at 250kbps + * + * ISM Region 2 (America) only, Band 902–928 MHz + * + * Cordless phones 1 W + * Microwave ovens 750 W + * Industrial heaters 100 kW + * Military radar 1000 kW + * + * Deviation = 126.953125 + * Base frequency = 901.999969 + * Carrier frequency = 905.998993 + * Channel number = 20 + * Carrier frequency = 905.998993 + * Modulated = true + * Modulation format = GFSK + * Manchester enable = false + * Sync word qualifier mode = 30/32 sync word bits detected + * Preamble count = 4 + * Channel spacing = 199.951172 + * Carrier frequency = 905.998993 + * Data rate = 249.939 + * RX filter BW = 541.666667 + * Data format = Normal mode + * Length config = Variable packet length mode. Packet length configured by the first byte after sync word + * CRC enable = true + * Packet length = 61 + * Device address = 0 + * Address config = No address check + * CRC autoflush = false + * PA ramping = false + * TX power = 0 + */ + +const struct c1101_rfsettings_s cc1101_rfsettings_ISM2_905MHzGFSK250kbps = +{ + .FSCTRL1 = 0x0C, /* FSCTRL1 Frequency Synthesizer Control */ + .FSCTRL0 = 0x00, /* FSCTRL0 Frequency Synthesizer Control */ + + .FREQ2 = 0x22, /* FREQ2 Frequency Control Word, High Byte */ + .FREQ1 = 0xB1, /* FREQ1 Frequency Control Word, Middle Byte */ + .FREQ0 = 0x3B, /* FREQ0 Frequency Control Word, Low Byte */ + + .MDMCFG4 = 0x2D, /* MDMCFG4 Modem Configuration */ + .MDMCFG3 = 0x3B, /* MDMCFG3 Modem Configuration */ + .MDMCFG2 = 0x13, /* MDMCFG2 Modem Configuration */ + .MDMCFG1 = 0x22, /* MDMCFG1 Modem Configuration */ + .MDMCFG0 = 0xF8, /* MDMCFG0 Modem Configuration */ + + .DEVIATN = 0x62, /* DEVIATN Modem Deviation Setting */ + + .FOCCFG = 0x1D, /* FOCCFG Frequency Offset Compensation Configuration */ + + .BSCFG = 0x1C, /* BSCFG Bit Synchronization Configuration */ + + .AGCCTRL2= 0xC7, /* AGCCTRL2 AGC Control */ + .AGCCTRL1= 0x00, /* AGCCTRL1 AGC Control */ + .AGCCTRL0= 0xB0, /* AGCCTRL0 AGC Control */ + + .FREND1 = 0xB6, /* FREND1 Front End RX Configuration */ + .FREND0 = 0x10, /* FREND0 Front End TX Configuration */ + + .FSCAL3 = 0xEA, /* FSCAL3 Frequency Synthesizer Calibration */ + .FSCAL2 = 0x2A, /* FSCAL2 Frequency Synthesizer Calibration */ + .FSCAL1 = 0x00, /* FSCAL1 Frequency Synthesizer Calibration */ + .FSCAL0 = 0x1F, /* FSCAL0 Frequency Synthesizer Calibration */ + + .CHMIN = 0, /* VERIFY REGULATIONS! */ + .CHMAX = 0xFF, + + .PAMAX = 8, /* 0 means power OFF, 8 represents PA[7] */ + .PA = {0x03, 0x0E, 0x1E, 0x27, 0x39, 0x8E, 0xCD, 0xC0} +}; diff --git a/nuttx/drivers/wireless/Kconfig b/nuttx/drivers/wireless/Kconfig index ae2bf3130..9e0c09625 100644 --- a/nuttx/drivers/wireless/Kconfig +++ b/nuttx/drivers/wireless/Kconfig @@ -2,3 +2,55 @@ # For a description of the syntax of this configuration file, # see misc/tools/kconfig-language.txt. # + +config WL_CC1101 + bool "CC1101 RF transceiver support" + default n + select SPI + +config WL_NRF24L01 + bool "nRF24l01+ transceiver support" + default n + select SPI + ---help--- + This options adds driver support for the Nordic nRF24L01+ chip. + +if WL_NRF24L01 + +config WL_NRF24L01_DFLT_ADDR_WIDTH + int "Default address width" + default 5 + range 3 5 + ---help--- + Default address width to be used by the nRF24l01+ driver. + Note that this default can be changed through the driver API. + +config WL_NRF24L01_CHECK_PARAMS + bool "Check call parameters" + default y + ---help--- + This option adds some sanity check code to parameters given in the + driver API functions. If this option is disabled, parameter + values are passed 'as is' to the module hardware registers. + +config WL_NRF24L01_RXSUPPORT + bool "Support messages reception" + default y + ---help--- + If this opion is disabled the driver supports only the transmission of messages. + Reception of messages will be disabled (and corresponding functions removed). + Note: this option is intended to reduce driver code size for 'transmission + only' devices. + +if WL_NRF24L01_RXSUPPORT + +config WL_NRF24L01_RXFIFO_LEN + int "RX fifo length" + default 128 + range 34 2048 + ---help--- + Length of the software based fifo used to store content of + received messages. + +endif +endif diff --git a/nuttx/drivers/wireless/Make.defs b/nuttx/drivers/wireless/Make.defs index fa8e8acb5..3e7126acc 100644 --- a/nuttx/drivers/wireless/Make.defs +++ b/nuttx/drivers/wireless/Make.defs @@ -37,11 +37,17 @@ ifeq ($(CONFIG_WIRELESS),y) # Include wireless drivers +ifeq ($(CONFIG_WL_CC1101),y) CSRCS += cc1101.c ISM1_868MHzGFSK100kbps.c ISM2_905MHzGFSK250kbps.c +endif + +ifeq ($(CONFIG_WL_NRF24L01),y) +CSRCS += nrf24l01.c +endif -# Include wireless build support +# Include wireless devices build support -DEPPATH += --dep-path wireless$(DELIM)cc1101 -VPATH += :wireless$(DELIM)cc1101 -CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)wireless$(DELIM)cc1101} +DEPPATH += --dep-path wireless +VPATH += :wireless +CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)wireless} endif diff --git a/nuttx/drivers/wireless/cc1101.c b/nuttx/drivers/wireless/cc1101.c new file mode 100644 index 000000000..b573a5342 --- /dev/null +++ b/nuttx/drivers/wireless/cc1101.c @@ -0,0 +1,856 @@ +/**************************************************************************** + * drivers/wireless/cc1101.c + * + * Copyright (C) 2011 Uros Platise. All rights reserved. + * + * Authors: Uros Platise + * + * 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. + * + ****************************************************************************/ + +/* Features: + * - Maximum data length: 61 bytes CC1101_PACKET_MAXDATALEN + * - Packet length includes two additional bytes: CC1101_PACKET_MAXTOTALLEN + * - Requires one GDO to trigger end-of-packets in RX and TX modes. + * - Variable packet length with data payload between 1..61 bytes + * (three bytes are reserved for packet length, and RSSI and LQI + * appended at the end of RXFIFO after each reception) + * - Support for General Digital Outputs with overload protection + * (single XOSC pin is allowed, otherwise error is returned) + * - Loadable RF settings, one for ISM Region 1 (Europe) and one for + * ISM Region 2 (Complete America) + * + * Todo: + * - Extend max packet length up to 255 bytes or rather infinite < 4096 bytes + * - Power up/down modes + * - Sequencing between states or add protection for correct termination of + * various different state (so that CC1101 does not block in case of improper use) + * + * RSSI and LQI value interpretation + * + * The LQI can be read from the LQI status register or it can be appended + * to the received packet in the RX FIFO. LQI is a metric of the current + * quality of the received signal. The LQI gives an estimate of how easily + * a received signal can be demodulated by accumulating the magnitude of + * the error between ideal constellations and the received signal over + * the 64 symbols immediately following the sync word. LQI is best used + * as a relative measurement of the link quality (a high value indicates + * a better link than what a low value does), since the value is dependent + * on the modulation format. + * + * To simplify: If the received modulation is FSK or GFSK, the receiver + * will measure the frequency of each "bit" and compare it with the + * expected frequency based on the channel frequency and the deviation + * and the measured frequency offset. If other modulations are used, the + * error of the modulated parameter (frequency for FSK/GFSK, phase for + * MSK, amplitude for ASK etc) will be measured against the expected + * ideal value + * + * RSSI (Received Signal Strength Indicator) is a signal strength + * indication. It does not care about the "quality" or "correctness" of + * the signal. LQI does not care about the actual signal strength, but + * the signal quality often is linked to signal strength. This is because + * a strong signal is likely to be less affected by noise and thus will + * be seen as "cleaner" or more "correct" by the receiver. + * + * There are four to five "extreme cases" that can be used to illustrate + * how RSSI and LQI work: + * 1. A weak signal in the presence of noise may give low RSSI and low LQI. + * 2. A weak signal in "total" absence of noise may give low RSSI and high LQI. + * 3. Strong noise (usually coming from an interferer) may give high RSSI and low LQI. + * 4. A strong signal without much noise may give high RSSI and high LQI. + * 5. A very strong signal that causes the receiver to saturate may give + * high RSSI and low LQI. + * + * Note that both RSSI and LQI are best used as relative measurements since + * the values are dependent on the modulation format. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include +#include + +/**************************************************************************** + * Pre-rocessor Definitions + ****************************************************************************/ + +#define CC1101_SPIFREQ_BURST 6500000 /* Hz, no delay */ +#define CC1101_SPIFREQ_SINGLE 9000000 /* Hz, single access only - no delay */ + +#define CC1101_MCSM0_VALUE 0x1C + +/**************************************************************************** + * Chipcon CC1101 Internal Registers + ****************************************************************************/ + +/* Configuration Registers */ + +#define CC1101_IOCFG2 0x00 /* GDO2 output pin configuration */ +#define CC1101_IOCFG1 0x01 /* GDO1 output pin configuration */ +#define CC1101_IOCFG0 0x02 /* GDO0 output pin configuration */ +#define CC1101_FIFOTHR 0x03 /* RX FIFO and TX FIFO thresholds */ +#define CC1101_SYNC1 0x04 /* Sync word, high byte */ +#define CC1101_SYNC0 0x05 /* Sync word, low byte */ +#define CC1101_PKTLEN 0x06 /* Packet length */ +#define CC1101_PKTCTRL1 0x07 /* Packet automation control */ +#define CC1101_PKTCTRL0 0x08 /* Packet automation control */ +#define CC1101_ADDR 0x09 /* Device address */ +#define CC1101_CHANNR 0x0A /* Channel number */ +#define CC1101_FSCTRL1 0x0B /* Frequency synthesizer control */ +#define CC1101_FSCTRL0 0x0C /* Frequency synthesizer control */ +#define CC1101_FREQ2 0x0D /* Frequency control word, high byte */ +#define CC1101_FREQ1 0x0E /* Frequency control word, middle byte */ +#define CC1101_FREQ0 0x0F /* Frequency control word, low byte */ +#define CC1101_MDMCFG4 0x10 /* Modem configuration */ +#define CC1101_MDMCFG3 0x11 /* Modem configuration */ +#define CC1101_MDMCFG2 0x12 /* Modem configuration */ +#define CC1101_MDMCFG1 0x13 /* Modem configuration */ +#define CC1101_MDMCFG0 0x14 /* Modem configuration */ +#define CC1101_DEVIATN 0x15 /* Modem deviation setting */ +#define CC1101_MCSM2 0x16 /* Main Radio Cntrl State Machine config */ +#define CC1101_MCSM1 0x17 /* Main Radio Cntrl State Machine config */ +#define CC1101_MCSM0 0x18 /* Main Radio Cntrl State Machine config */ +#define CC1101_FOCCFG 0x19 /* Frequency Offset Compensation config */ +#define CC1101_BSCFG 0x1A /* Bit Synchronization configuration */ +#define CC1101_AGCCTRL2 0x1B /* AGC control */ +#define CC1101_AGCCTRL1 0x1C /* AGC control */ +#define CC1101_AGCCTRL0 0x1D /* AGC control */ +#define CC1101_WOREVT1 0x1E /* High byte Event 0 timeout */ +#define CC1101_WOREVT0 0x1F /* Low byte Event 0 timeout */ +#define CC1101_WORCTRL 0x20 /* Wake On Radio control */ +#define CC1101_FREND1 0x21 /* Front end RX configuration */ +#define CC1101_FREND0 0x22 /* Front end TX configuration */ +#define CC1101_FSCAL3 0x23 /* Frequency synthesizer calibration */ +#define CC1101_FSCAL2 0x24 /* Frequency synthesizer calibration */ +#define CC1101_FSCAL1 0x25 /* Frequency synthesizer calibration */ +#define CC1101_FSCAL0 0x26 /* Frequency synthesizer calibration */ +#define CC1101_RCCTRL1 0x27 /* RC oscillator configuration */ +#define CC1101_RCCTRL0 0x28 /* RC oscillator configuration */ +#define CC1101_FSTEST 0x29 /* Frequency synthesizer cal control */ +#define CC1101_PTEST 0x2A /* Production test */ +#define CC1101_AGCTEST 0x2B /* AGC test */ +#define CC1101_TEST2 0x2C /* Various test settings */ +#define CC1101_TEST1 0x2D /* Various test settings */ +#define CC1101_TEST0 0x2E /* Various test settings */ + +/* Status registers */ + +#define CC1101_PARTNUM (0x30 | 0xc0) /* Part number */ +#define CC1101_VERSION (0x31 | 0xc0) /* Current version number */ +#define CC1101_FREQEST (0x32 | 0xc0) /* Frequency offset estimate */ +#define CC1101_LQI (0x33 | 0xc0) /* Demodulator estimate for link quality */ +#define CC1101_RSSI (0x34 | 0xc0) /* Received signal strength indication */ +#define CC1101_MARCSTATE (0x35 | 0xc0) /* Control state machine state */ +#define CC1101_WORTIME1 (0x36 | 0xc0) /* High byte of WOR timer */ +#define CC1101_WORTIME0 (0x37 | 0xc0) /* Low byte of WOR timer */ +#define CC1101_PKTSTATUS (0x38 | 0xc0) /* Current GDOx status and packet status */ +#define CC1101_VCO_VC_DAC (0x39 | 0xc0) /* Current setting from PLL cal module */ +#define CC1101_TXBYTES (0x3A | 0xc0) /* Underflow and # of bytes in TXFIFO */ +#define CC1101_RXBYTES (0x3B | 0xc0) /* Overflow and # of bytes in RXFIFO */ +#define CC1101_RCCTRL1_STATUS (0x3C | 0xc0) /* Last RC oscilator calibration results */ +#define CC1101_RCCTRL0_STATUS (0x3D | 0xc0) /* Last RC oscilator calibration results */ + +/* Multi byte memory locations */ + +#define CC1101_PATABLE 0x3E +#define CC1101_TXFIFO 0x3F +#define CC1101_RXFIFO 0x3F + +/* Definitions for burst/single access to registers */ + +#define CC1101_WRITE_BURST 0x40 +#define CC1101_READ_SINGLE 0x80 +#define CC1101_READ_BURST 0xC0 + +/* Strobe commands */ + +#define CC1101_SRES 0x30 /* Reset chip. */ +#define CC1101_SFSTXON 0x31 /* Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL=1). */ +#define CC1101_SXOFF 0x32 /* Turn off crystal oscillator. */ +#define CC1101_SCAL 0x33 /* Calibrate frequency synthesizer and turn it off */ +#define CC1101_SRX 0x34 /* Enable RX. Perform calibration first if switching from IDLE and MCSM0.FS_AUTOCAL=1. */ +#define CC1101_STX 0x35 /* Enable TX. Perform calibration first if IDLE and MCSM0.FS_AUTOCAL=1. */ + /* If switching from RX state and CCA is enabled then go directly to TX if channel is clear. */ +#define CC1101_SIDLE 0x36 /* Exit RX / TX, turn off frequency synthesizer and exit Wake-On-Radio mode if applicable. */ +#define CC1101_SAFC 0x37 /* Perform AFC adjustment of the frequency synthesizer */ +#define CC1101_SWOR 0x38 /* Start automatic RX polling sequence (Wake-on-Radio) */ +#define CC1101_SPWD 0x39 /* Enter power down mode when CSn goes high. */ +#define CC1101_SFRX 0x3A /* Flush the RX FIFO buffer. */ +#define CC1101_SFTX 0x3B /* Flush the TX FIFO buffer. */ +#define CC1101_SWORRST 0x3C /* Reset real time clock. */ +#define CC1101_SNOP 0x3D /* No operation. */ + +/* Modem Control */ + +#define CC1101_MCSM0_XOSC_FORCE_ON 0x01 + +/* + * Chip Status Byte + */ + +/* Bit fields in the chip status byte */ + +#define CC1101_STATUS_CHIP_RDYn_BM 0x80 +#define CC1101_STATUS_STATE_BM 0x70 +#define CC1101_STATUS_FIFO_BYTES_AVAILABLE_BM 0x0F + +/* Chip states */ + +#define CC1101_STATE_MASK 0x70 +#define CC1101_STATE_IDLE 0x00 +#define CC1101_STATE_RX 0x10 +#define CC1101_STATE_TX 0x20 +#define CC1101_STATE_FSTXON 0x30 +#define CC1101_STATE_CALIBRATE 0x40 +#define CC1101_STATE_SETTLING 0x50 +#define CC1101_STATE_RX_OVERFLOW 0x60 +#define CC1101_STATE_TX_UNDERFLOW 0x70 + +/* Values of the MACRSTATE register */ + +#define CC1101_MARCSTATE_SLEEP 0x00 +#define CC1101_MARCSTATE_IDLE 0x01 +#define CC1101_MARCSTATE_XOFF 0x02 +#define CC1101_MARCSTATE_VCOON_MC 0x03 +#define CC1101_MARCSTATE_REGON_MC 0x04 +#define CC1101_MARCSTATE_MANCAL 0x05 +#define CC1101_MARCSTATE_VCOON 0x06 +#define CC1101_MARCSTATE_REGON 0x07 +#define CC1101_MARCSTATE_STARTCAL 0x08 +#define CC1101_MARCSTATE_BWBOOST 0x09 +#define CC1101_MARCSTATE_FS_LOCK 0x0A +#define CC1101_MARCSTATE_IFADCON 0x0B +#define CC1101_MARCSTATE_ENDCAL 0x0C +#define CC1101_MARCSTATE_RX 0x0D +#define CC1101_MARCSTATE_RX_END 0x0E +#define CC1101_MARCSTATE_RX_RST 0x0F +#define CC1101_MARCSTATE_TXRX_SWITCH 0x10 +#define CC1101_MARCSTATE_RXFIFO_OVERFLOW 0x11 +#define CC1101_MARCSTATE_FSTXON 0x12 +#define CC1101_MARCSTATE_TX 0x13 +#define CC1101_MARCSTATE_TX_END 0x14 +#define CC1101_MARCSTATE_RXTX_SWITCH 0x15 +#define CC1101_MARCSTATE_TXFIFO_UNDERFLOW 0x16 + +/* Part number and version */ + +#define CC1101_PARTNUM_VALUE 0x00 +#define CC1101_VERSION_VALUE 0x04 + +/* + * Others ... + */ + +#define CC1101_LQI_CRC_OK_BM 0x80 +#define CC1101_LQI_EST_BM 0x7F + + +/**************************************************************************** + * Private Data Types + ****************************************************************************/ + +#define FLAGS_RXONLY 1 /* Indicates receive operation only */ +#define FLAGS_XOSCENABLED 2 /* Indicates that one pin is configured as XOSC/n */ + +struct cc1101_dev_s +{ + const struct c1101_rfsettings_s *rfsettings; + + struct spi_dev_s * spi; + uint8_t isrpin; /* CC1101 pin used to trigger interrupts */ + uint32_t pinset; /* GPIO of the MCU */ + uint8_t flags; + uint8_t channel; + uint8_t power; +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +void cc1101_access_begin(struct cc1101_dev_s * dev) +{ + (void)SPI_LOCK(dev->spi, true); + SPI_SELECT(dev->spi, SPIDEV_WIRELESS, true); + SPI_SETMODE(dev->spi, SPIDEV_MODE0); /* CPOL=0, CPHA=0 */ + SPI_SETBITS(dev->spi, 8); +} + +void cc1101_access_end(struct cc1101_dev_s * dev) +{ + SPI_SELECT(dev->spi, SPIDEV_WIRELESS, false); + (void)SPI_LOCK(dev->spi, false); +} + +/** CC1101 Access with Range Check + * + * \param dev CC1101 Private Structure + * \param addr CC1101 Address + * \param buf Pointer to buffer, either for read or write access + * \param length when >0 it denotes read access, when <0 it denotes write + * access of -length. abs(length) greater of 1 implies burst mode, + * however + * \return OK on success or errno is set. + */ + +int cc1101_access(struct cc1101_dev_s * dev, uint8_t addr, uint8_t *buf, int length) +{ + int stabyte; + + /* Address cannot explicitly define READ command while length WRITE. + * Also access to these cells is only permitted as one byte, eventhough + * transfer is marked as BURST! + */ + + if ((addr & CC1101_READ_SINGLE) && length != 1) + return ERROR; + + /* Prepare SPI */ + + cc1101_access_begin(dev); + + if (length>1 || length < -1) + SPI_SETFREQUENCY(dev->spi, CC1101_SPIFREQ_BURST); + else SPI_SETFREQUENCY(dev->spi, CC1101_SPIFREQ_SINGLE); + + /* Transfer */ + + if (length <= 0) { /* 0 length are command strobes */ + if (length < -1) + addr |= CC1101_WRITE_BURST; + + stabyte = SPI_SEND(dev->spi, addr); + if (length) { + SPI_SNDBLOCK(dev->spi, buf, -length); + } + } + else { + addr |= CC1101_READ_SINGLE; + if (length > 1) + addr |= CC1101_READ_BURST; + + stabyte = SPI_SEND(dev->spi, addr); + SPI_RECVBLOCK(dev->spi, buf, length); + } + + cc1101_access_end(dev); + + return stabyte; +} + + +/** Strobes command and returns chip status byte + * + * By default commands are send as Write. To a command, + * CC1101_READ_SINGLE may be OR'ed to obtain the number of RX bytes + * pending in RX FIFO. + */ +inline uint8_t cc1101_strobe(struct cc1101_dev_s * dev, uint8_t command) +{ + uint8_t status; + + cc1101_access_begin(dev); + SPI_SETFREQUENCY(dev->spi, CC1101_SPIFREQ_SINGLE); + + status = SPI_SEND(dev->spi, command); + + cc1101_access_end(dev); + + return status; +} + + +int cc1101_reset(struct cc1101_dev_s * dev) +{ + cc1101_strobe(dev, CC1101_SRES); + return OK; +} + + +int cc1101_checkpart(struct cc1101_dev_s * dev) +{ + uint8_t partnum, version; + + if (cc1101_access(dev, CC1101_PARTNUM, &partnum, 1) < 0 || + cc1101_access(dev, CC1101_VERSION, &version, 1) < 0) + return ERROR; + + if (partnum == CC1101_PARTNUM_VALUE && version == CC1101_VERSION_VALUE) + return OK; + + return ERROR; +} + + +void cc1101_dumpregs(struct cc1101_dev_s * dev, uint8_t addr, uint8_t length) +{ + uint8_t buf[0x30], i; + + cc1101_access(dev, addr, buf, length); + + printf("CC1101[%2x]: ", addr); + for (i=0; i RX, RX -> RX: 0x3F */ + values[2] = CC1101_MCSM0_VALUE; /* Calibrate on IDLE -> RX/TX, OSC Timeout = ~500 us + TODO: has XOSC_FORCE_ON */ + cc1101_access(dev, CC1101_MCSM2, values, -3); + + /* Wake-On Radio Control */ + + // Not used yet. + + // WOREVT1:WOREVT0 - 16-bit timeout register +} + + +/**************************************************************************** + * Callbacks + ****************************************************************************/ + +volatile int cc1101_interrupt = 0; + +/** External line triggers this callback + * + * The concept todo is: + * - GPIO provides EXTI Interrupt + * - It should handle EXTI Interrupts in ISR, to which chipcon can + * register a callback (and others). The ISR then foreach() calls a + * its callback, and it is up to peripheral to find, whether the cause + * of EXTI ISR was itself. + **/ + +int cc1101_eventcb(int irq, FAR void *context) +{ + cc1101_interrupt++; + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +struct cc1101_dev_s * cc1101_init(struct spi_dev_s * spi, uint8_t isrpin, + uint32_t pinset, const struct c1101_rfsettings_s * rfsettings) +{ + struct cc1101_dev_s * dev; + + ASSERT(spi); + + if ((dev = kmalloc(sizeof(struct cc1101_dev_s))) == NULL) + { + errno = ENOMEM; + return NULL; + } + + dev->rfsettings = rfsettings; + dev->spi = spi; + dev->isrpin = isrpin; + dev->pinset = pinset; + dev->flags = 0; + dev->channel = rfsettings->CHMIN; + dev->power = rfsettings->PAMAX; + + /* Reset chip, check status bytes */ + + if (cc1101_reset(dev) < 0) + { + kfree(dev); + errno = EFAULT; + return NULL; + } + + /* Check part compatibility */ + + if (cc1101_checkpart(dev) < 0) + { + kfree(dev); + errno = ENODEV; + return NULL; + } + + /* Configure CC1101: + * - disable GDOx for best performance + * - load RF + * - and packet control + */ + + cc1101_setgdo(dev, CC1101_PIN_GDO0, CC1101_GDO_HIZ); + cc1101_setgdo(dev, CC1101_PIN_GDO1, CC1101_GDO_HIZ); + cc1101_setgdo(dev, CC1101_PIN_GDO2, CC1101_GDO_HIZ); + cc1101_setrf(dev, rfsettings); + cc1101_setpacketctrl(dev); + + /* Set the ISR to be triggerred on falling edge of the: + * + * 6 (0x06) Asserts when sync word has been sent / received, and + * de-asserts at the end of the packet. In RX, the pin will de-assert + * when the optional address check fails or the RX FIFO overflows. + * In TX the pin will de-assert if the TX FIFO underflows. + */ + + cc1101_setgdo(dev, dev->isrpin, CC1101_GDO_SYNC); + + /* Bind to external interrupt line */ + + /* depends on STM32: TODO: Make that config within pinset and + * provide general gpio interface + * stm32_gpiosetevent(pinset, false, true, true, cc1101_eventcb); + */ + + return dev; +} + +int cc1101_deinit(struct cc1101_dev_s * dev) +{ + ASSERT(dev); + + /* Release interrupt */ + /* stm32_gpiosetevent(pinset, false, false, false, NULL); */ + + /* Power down chip */ + + cc1101_powerdown(dev); + + /* Release external interrupt line */ + + kfree(dev); + return 0; +} + +int cc1101_powerup(struct cc1101_dev_s * dev) +{ + ASSERT(dev); + return 0; +} + +int cc1101_powerdown(struct cc1101_dev_s * dev) +{ + ASSERT(dev); + return 0; +} + +int cc1101_setgdo(struct cc1101_dev_s * dev, uint8_t pin, uint8_t function) +{ + ASSERT(dev); + ASSERT(pin <= CC1101_IOCFG0); + + if (function >= CC1101_GDO_CLK_XOSC1) + { + /* Only one pin can be enabled at a time as XOSC/n */ + + if (dev->flags & FLAGS_XOSCENABLED) + { + return -EPERM; + } + + /* Force XOSC to stay active even in sleep mode */ + + int value = CC1101_MCSM0_VALUE | CC1101_MCSM0_XOSC_FORCE_ON; + cc1101_access(dev, CC1101_MCSM0, &value, -1); + + dev->flags |= FLAGS_XOSCENABLED; + } + else if (dev->flags & FLAGS_XOSCENABLED) + { + /* Disable XOSC in sleep mode */ + + int value = CC1101_MCSM0_VALUE; + cc1101_access(dev, CC1101_MCSM0, &value, -1); + + dev->flags &= ~FLAGS_XOSCENABLED; + } + + return cc1101_access(dev, pin, &function, -1); +} + +int cc1101_setrf(struct cc1101_dev_s * dev, const struct c1101_rfsettings_s *settings) +{ + ASSERT(dev); + ASSERT(settings); + + if (cc1101_access(dev, CC1101_FSCTRL1, &settings->FSCTRL1, -11) < 0) + { + return ERROR; + } + + if (cc1101_access(dev, CC1101_FOCCFG, &settings->FOCCFG, -5) < 0) + { + return ERROR; + } + + if (cc1101_access(dev, CC1101_FREND1, &settings->FREND1, -6) < 0) + { + return ERROR; + } + + /* Load Power Table */ + + if (cc1101_access(dev, CC1101_PATABLE, settings->PA, -8) < 0) + { + return ERROR; + } + + /* If channel is out of valid range, mark that. Limit power. + * We are not allowed to send any data, but are allowed to listen + * and receive. + */ + + cc1101_setchannel(dev, dev->channel); + cc1101_setpower(dev, dev->power); + + return OK; +} + +int cc1101_setchannel(struct cc1101_dev_s * dev, uint8_t channel) +{ + ASSERT(dev); + + /* Store localy in further checks */ + + dev->channel = channel; + + /* If channel is out of valid, we are allowed to listen and receive only */ + + if (channel < dev->rfsettings->CHMIN || channel > dev->rfsettings->CHMAX) + { + dev->flags |= FLAGS_RXONLY; + } + else + { + dev->flags &= ~FLAGS_RXONLY; + } + + cc1101_access(dev, CC1101_CHANNR, &dev->channel, -1); + return dev->flags & FLAGS_RXONLY; +} + +uint8_t cc1101_setpower(struct cc1101_dev_s * dev, uint8_t power) +{ + ASSERT(dev); + + if (power > dev->rfsettings->PAMAX) + { + power = dev->rfsettings->PAMAX; + } + + dev->power = power; + + if (power == 0) + { + dev->flags |= FLAGS_RXONLY; + return 0; + } + else + { + dev->flags &= ~FLAGS_RXONLY; + } + + /* Add remaining part from RF table (to get rid of readback) */ + + power--; + power |= dev->rfsettings->FREND0; + + /* On error, report that as zero power */ + + if (cc1101_access(dev, CC1101_FREND0, &power, -1) < 0) + { + dev->power = 0; + } + + return dev->power; +} + +int cc1101_calcRSSIdBm(int rssi) +{ + if (rssi >= 128) + { + rssi -= 256; + } + + return (rssi >> 1) - 74; +} + +int cc1101_receive(struct cc1101_dev_s * dev) +{ + ASSERT(dev); + + /* \todo Wait for IDLE before going into another state? */ + + cc1101_interrupt = 0; + + cc1101_strobe(dev, CC1101_SRX | CC1101_READ_SINGLE); + + return 0; +} + +int cc1101_read(struct cc1101_dev_s * dev, uint8_t * buf, size_t size) +{ + ASSERT(dev); + + if (buf==NULL) + { + if (size==0) + { + return 64; + } + + /* else received packet size */ + + return 0; + } + + if (cc1101_interrupt == 0) + { + return 0; + } + + int status = cc1101_strobe(dev, CC1101_SNOP | CC1101_READ_SINGLE); + + if (status & CC1101_STATUS_FIFO_BYTES_AVAILABLE_BM && + (status & CC1101_STATE_MASK) == CC1101_STATE_IDLE) + { + uint8_t nbytes; + + cc1101_access(dev, CC1101_RXFIFO, &nbytes, 1); + + nbytes += 2; /* RSSI and LQI */ + + cc1101_access(dev, CC1101_RXFIFO, buf, (nbytes > size) ? size : nbytes); + + /* Flush remaining bytes, if there is no room to receive + * or if there is a BAD CRC + */ + + if (nbytes > size || (nbytes <= size && !(buf[nbytes-1]&0x80))) + { + printf("Flushing RX FIFO\n"); + cc1101_strobe(dev, CC1101_SFRX); + } + + return nbytes; + } + + return 0; +} + +int cc1101_write(struct cc1101_dev_s * dev, const uint8_t * buf, size_t size) +{ + uint8_t packetlen; + + ASSERT(dev); + ASSERT(buf); + + if (dev->flags & FLAGS_RXONLY) + { + return -EPERM; + } + + /* Present limit */ + + if (size > CC1101_PACKET_MAXDATALEN) + { + packetlen = CC1101_PACKET_MAXDATALEN; + } + else + { + packetlen = size; + } + + cc1101_access(dev, CC1101_TXFIFO, &packetlen, -1); + cc1101_access(dev, CC1101_TXFIFO, buf, -size); + + return 0; +} + +int cc1101_send(struct cc1101_dev_s * dev) +{ + ASSERT(dev); + + if (dev->flags & FLAGS_RXONLY) + { + return -EPERM; + } + + cc1101_interrupt = 0; + + cc1101_strobe(dev, CC1101_STX); + + /* wait until send, going to IDLE */ + + while (cc1101_interrupt == 0); + + return 0; +} + +int cc1101_idle(struct cc1101_dev_s * dev) +{ + ASSERT(dev); + cc1101_strobe(dev, CC1101_SIDLE); + return 0; +} diff --git a/nuttx/drivers/wireless/cc1101/ISM1_868MHzGFSK100kbps.c b/nuttx/drivers/wireless/cc1101/ISM1_868MHzGFSK100kbps.c deleted file mode 100644 index 5c4c58ab2..000000000 --- a/nuttx/drivers/wireless/cc1101/ISM1_868MHzGFSK100kbps.c +++ /dev/null @@ -1,113 +0,0 @@ -/**************************************************************************** - * drivers/wireless/cc1101/ISM1_868MHzGFSK100kbps.c - * - * Copyright (C) 2011 Uros Platise. All rights reserved. - * Copyright (C) 2011 Ales Verbic. All rights reserved. - * - * Authors: Uros Platise - * Ales Verbic - * - * 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. - * - ****************************************************************************/ - -#include - -/** Settings for 868 MHz, GFSK at 100kbps - * - * ISM Region 1 (Europe) only, Band 868–870 MHz - * - * Frequency ERP Duty Cycle Bandwidth Remarks - * 868 – 868.6 MHz +14 dBm < 1% No limits - * 868.7 – 869.2 MHz +14 dBm < 0.1% No limits - * 869.3 – 869.4 MHz +10 dBm No limits < 25 kHz Appropriate access protocol required - * 869.4 – 869.65 MHz +27 dBm < 10% < 25 kHz Channels may be combined to one high speed channel - * 869.7 -870 MHz +7 dBm No limits No limits - * - * Deviation = 46.142578 - * Base frequency = 867.999985 - * Carrier frequency = 867.999985 - * Channel number = 0 - * Carrier frequency = 867.999985 - * Modulated = true - * Modulation format = GFSK - * Manchester enable = false - * Sync word qualifier mode = 30/32 sync word bits detected - * Preamble count = 4 - * Channel spacing = 199.813843 - * Carrier frequency = 867.999985 - * Data rate = 99.9069 - * RX filter BW = 210.937500 - * Data format = Normal mode - * Length config = Fixed packet length mode. Length configured in PKTLEN register - * CRC enable = true - * Packet length = 62 - * Device address = 00 - * Address config = NO Address check, no broadcast - * CRC autoflush = true - * PA ramping = false - * TX power = 0 - */ -const struct c1101_rfsettings_s cc1101_rfsettings_ISM1_868MHzGFSK100kbps = { - .FSCTRL1 = 0x08, // FSCTRL1 Frequency Synthesizer Control - .FSCTRL0 = 0x00, // FSCTRL0 Frequency Synthesizer Control - - .FREQ2 = 0x20, // FREQ2 Frequency Control Word, High Byte - .FREQ1 = 0x25, // FREQ1 Frequency Control Word, Middle Byte - .FREQ0 = 0xED, // FREQ0 Frequency Control Word, Low Byte - - .MDMCFG4 = 0x8B, // MDMCFG4 Modem Configuration - .MDMCFG3 = 0xE5, // MDMCFG3 Modem Configuration - .MDMCFG2 = 0x13, // MDMCFG2 Modem Configuration - .MDMCFG1 = 0x22, // MDMCFG1 Modem Configuration - .MDMCFG0 = 0xE5, // MDMCFG0 Modem Configuration - - .DEVIATN = 0x46, // DEVIATN Modem Deviation Setting - - .FOCCFG = 0x1D, // FOCCFG Frequency Offset Compensation Configuration - - .BSCFG = 0x1C, // BSCFG Bit Synchronization Configuration - - .AGCCTRL2= 0xC7, // AGCCTRL2 AGC Control - .AGCCTRL1= 0x00, // AGCCTRL1 AGC Control - .AGCCTRL0= 0xB2, // AGCCTRL0 AGC Control - - .FREND1 = 0xB6, // FREND1 Front End RX Configuration - .FREND0 = 0x10, // FREND0 Front End TX Configuration - - .FSCAL3 = 0xEA, // FSCAL3 Frequency Synthesizer Calibration - .FSCAL2 = 0x2A, // FSCAL2 Frequency Synthesizer Calibration - .FSCAL1 = 0x00, // FSCAL1 Frequency Synthesizer Calibration - .FSCAL0 = 0x1F, // FSCAL0 Frequency Synthesizer Calibration - - .CHMIN = 0, // Fix at 9th channel: 869.80 MHz +- 100 kHz RF Bandwidth - .CHMAX = 9, // single channel - - .PAMAX = 8, // 0 means power OFF, 8 represents PA[7] - .PA = {0x03, 0x0F, 0x1E, 0x27, 0x67, 0x50, 0x81, 0xC2} -}; diff --git a/nuttx/drivers/wireless/cc1101/ISM2_905MHzGFSK250kbps.c b/nuttx/drivers/wireless/cc1101/ISM2_905MHzGFSK250kbps.c deleted file mode 100644 index e5655bed6..000000000 --- a/nuttx/drivers/wireless/cc1101/ISM2_905MHzGFSK250kbps.c +++ /dev/null @@ -1,111 +0,0 @@ -/**************************************************************************** - * drivers/wireless/cc1101/ISM2_905MHzGFSK250kbps.c - * - * Copyright (C) 2011 Uros Platise. All rights reserved. - * Copyright (C) 2011 Ales Verbic. All rights reserved. - * - * Authors: Uros Platise - * Ales Verbic - * - * 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. - * - ****************************************************************************/ - -#include - -/** Settings for 905 MHz, GFSK at 250kbps - * - * ISM Region 2 (America) only, Band 902–928 MHz - * - * Cordless phones 1 W - * Microwave ovens 750 W - * Industrial heaters 100 kW - * Military radar 1000 kW - * - * Deviation = 126.953125 - * Base frequency = 901.999969 - * Carrier frequency = 905.998993 - * Channel number = 20 - * Carrier frequency = 905.998993 - * Modulated = true - * Modulation format = GFSK - * Manchester enable = false - * Sync word qualifier mode = 30/32 sync word bits detected - * Preamble count = 4 - * Channel spacing = 199.951172 - * Carrier frequency = 905.998993 - * Data rate = 249.939 - * RX filter BW = 541.666667 - * Data format = Normal mode - * Length config = Variable packet length mode. Packet length configured by the first byte after sync word - * CRC enable = true - * Packet length = 61 - * Device address = 0 - * Address config = No address check - * CRC autoflush = false - * PA ramping = false - * TX power = 0 - */ -const struct c1101_rfsettings_s cc1101_rfsettings_ISM2_905MHzGFSK250kbps = { - .FSCTRL1 = 0x0C, // FSCTRL1 Frequency Synthesizer Control - .FSCTRL0 = 0x00, // FSCTRL0 Frequency Synthesizer Control - - .FREQ2 = 0x22, // FREQ2 Frequency Control Word, High Byte - .FREQ1 = 0xB1, // FREQ1 Frequency Control Word, Middle Byte - .FREQ0 = 0x3B, // FREQ0 Frequency Control Word, Low Byte - - .MDMCFG4 = 0x2D, // MDMCFG4 Modem Configuration - .MDMCFG3 = 0x3B, // MDMCFG3 Modem Configuration - .MDMCFG2 = 0x13, // MDMCFG2 Modem Configuration - .MDMCFG1 = 0x22, // MDMCFG1 Modem Configuration - .MDMCFG0 = 0xF8, // MDMCFG0 Modem Configuration - - .DEVIATN = 0x62, // DEVIATN Modem Deviation Setting - - .FOCCFG = 0x1D, // FOCCFG Frequency Offset Compensation Configuration - - .BSCFG = 0x1C, // BSCFG Bit Synchronization Configuration - - .AGCCTRL2= 0xC7, // AGCCTRL2 AGC Control - .AGCCTRL1= 0x00, // AGCCTRL1 AGC Control - .AGCCTRL0= 0xB0, // AGCCTRL0 AGC Control - - .FREND1 = 0xB6, // FREND1 Front End RX Configuration - .FREND0 = 0x10, // FREND0 Front End TX Configuration - - .FSCAL3 = 0xEA, // FSCAL3 Frequency Synthesizer Calibration - .FSCAL2 = 0x2A, // FSCAL2 Frequency Synthesizer Calibration - .FSCAL1 = 0x00, // FSCAL1 Frequency Synthesizer Calibration - .FSCAL0 = 0x1F, // FSCAL0 Frequency Synthesizer Calibration - - .CHMIN = 0, // VERIFY REGULATIONS! - .CHMAX = 0xFF, - - .PAMAX = 8, // 0 means power OFF, 8 represents PA[7] - .PA = {0x03, 0x0E, 0x1E, 0x27, 0x39, 0x8E, 0xCD, 0xC0} -}; diff --git a/nuttx/drivers/wireless/cc1101/Kconfig b/nuttx/drivers/wireless/cc1101/Kconfig deleted file mode 100644 index ae2bf3130..000000000 --- a/nuttx/drivers/wireless/cc1101/Kconfig +++ /dev/null @@ -1,4 +0,0 @@ -# -# For a description of the syntax of this configuration file, -# see misc/tools/kconfig-language.txt. -# diff --git a/nuttx/drivers/wireless/cc1101/cc1101.c b/nuttx/drivers/wireless/cc1101/cc1101.c deleted file mode 100644 index 45faaecd2..000000000 --- a/nuttx/drivers/wireless/cc1101/cc1101.c +++ /dev/null @@ -1,812 +0,0 @@ -/**************************************************************************** - * drivers/wireless/cc1101/cc1101.c - * - * Copyright (C) 2011 Uros Platise. All rights reserved. - * - * Authors: Uros Platise - * - * 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. - * - ****************************************************************************/ - -/** \file - * \author Uros Platise - * \brief Chipcon CC1101 Device Driver - * - * Features: - * - Maximum data length: 61 bytes CC1101_PACKET_MAXDATALEN - * - Packet length includes two additional bytes: CC1101_PACKET_MAXTOTALLEN - * - Requires one GDO to trigger end-of-packets in RX and TX modes. - * - Variable packet length with data payload between 1..61 bytes - * (three bytes are reserved for packet length, and RSSI and LQI - * appended at the end of RXFIFO after each reception) - * - Support for General Digital Outputs with overload protection - * (single XOSC pin is allowed, otherwise error is returned) - * - Loadable RF settings, one for ISM Region 1 (Europe) and one for - * ISM Region 2 (Complete America) - * - * Todo: - * - Extend max packet length up to 255 bytes or rather infinite < 4096 bytes - * - Power up/down modes - * - Sequencing between states or add protection for correct termination of - * various different state (so that CC1101 does not block in case of improper use) - * - * \par RSSI and LQI value interpretation - * - * The LQI can be read from the LQI status register or it can be appended - * to the received packet in the RX FIFO. LQI is a metric of the current - * quality of the received signal. The LQI gives an estimate of how easily - * a received signal can be demodulated by accumulating the magnitude of - * the error between ideal constellations and the received signal over - * the 64 symbols immediately following the sync word. LQI is best used - * as a relative measurement of the link quality (a high value indicates - * a better link than what a low value does), since the value is dependent - * on the modulation format. - * - * To simplify: If the received modulation is FSK or GFSK, the receiver - * will measure the frequency of each "bit" and compare it with the - * expected frequency based on the channel frequency and the deviation - * and the measured frequency offset. If other modulations are used, the - * error of the modulated parameter (frequency for FSK/GFSK, phase for - * MSK, amplitude for ASK etc) will be measured against the expected - * ideal value - * - * RSSI (Received Signal Strength Indicator) is a signal strength - * indication. It does not care about the "quality" or "correctness" of - * the signal. LQI does not care about the actual signal strength, but - * the signal quality often is linked to signal strength. This is because - * a strong signal is likely to be less affected by noise and thus will - * be seen as "cleaner" or more "correct" by the receiver. - * - * There are four to five "extreme cases" that can be used to illustrate - * how RSSI and LQI work: - * 1. A weak signal in the presence of noise may give low RSSI and low LQI. - * 2. A weak signal in "total" absence of noise may give low RSSI and high LQI. - * 3. Strong noise (usually coming from an interferer) may give high RSSI and low LQI. - * 4. A strong signal without much noise may give high RSSI and high LQI. - * 5. A very strong signal that causes the receiver to saturate may give - * high RSSI and low LQI. - * - * Note that both RSSI and LQI are best used as relative measurements since - * the values are dependent on the modulation format. - **/ - -#include -#include -#include -#include -#include -#include - -#include -#include - - -/**************************************************************************** - * Declarations - ****************************************************************************/ - -#define CC1101_SPIFREQ_BURST 6500000 /* Hz, no delay */ -#define CC1101_SPIFREQ_SINGLE 9000000 /* Hz, single access only - no delay */ - -#define CC1101_MCSM0_VALUE 0x1C - -/**************************************************************************** - * Chipcon CC1101 Internal Registers - ****************************************************************************/ - -/* Configuration Registers */ - -#define CC1101_IOCFG2 0x00 /* GDO2 output pin configuration */ -#define CC1101_IOCFG1 0x01 /* GDO1 output pin configuration */ -#define CC1101_IOCFG0 0x02 /* GDO0 output pin configuration */ -#define CC1101_FIFOTHR 0x03 /* RX FIFO and TX FIFO thresholds */ -#define CC1101_SYNC1 0x04 /* Sync word, high byte */ -#define CC1101_SYNC0 0x05 /* Sync word, low byte */ -#define CC1101_PKTLEN 0x06 /* Packet length */ -#define CC1101_PKTCTRL1 0x07 /* Packet automation control */ -#define CC1101_PKTCTRL0 0x08 /* Packet automation control */ -#define CC1101_ADDR 0x09 /* Device address */ -#define CC1101_CHANNR 0x0A /* Channel number */ -#define CC1101_FSCTRL1 0x0B /* Frequency synthesizer control */ -#define CC1101_FSCTRL0 0x0C /* Frequency synthesizer control */ -#define CC1101_FREQ2 0x0D /* Frequency control word, high byte */ -#define CC1101_FREQ1 0x0E /* Frequency control word, middle byte */ -#define CC1101_FREQ0 0x0F /* Frequency control word, low byte */ -#define CC1101_MDMCFG4 0x10 /* Modem configuration */ -#define CC1101_MDMCFG3 0x11 /* Modem configuration */ -#define CC1101_MDMCFG2 0x12 /* Modem configuration */ -#define CC1101_MDMCFG1 0x13 /* Modem configuration */ -#define CC1101_MDMCFG0 0x14 /* Modem configuration */ -#define CC1101_DEVIATN 0x15 /* Modem deviation setting */ -#define CC1101_MCSM2 0x16 /* Main Radio Cntrl State Machine config */ -#define CC1101_MCSM1 0x17 /* Main Radio Cntrl State Machine config */ -#define CC1101_MCSM0 0x18 /* Main Radio Cntrl State Machine config */ -#define CC1101_FOCCFG 0x19 /* Frequency Offset Compensation config */ -#define CC1101_BSCFG 0x1A /* Bit Synchronization configuration */ -#define CC1101_AGCCTRL2 0x1B /* AGC control */ -#define CC1101_AGCCTRL1 0x1C /* AGC control */ -#define CC1101_AGCCTRL0 0x1D /* AGC control */ -#define CC1101_WOREVT1 0x1E /* High byte Event 0 timeout */ -#define CC1101_WOREVT0 0x1F /* Low byte Event 0 timeout */ -#define CC1101_WORCTRL 0x20 /* Wake On Radio control */ -#define CC1101_FREND1 0x21 /* Front end RX configuration */ -#define CC1101_FREND0 0x22 /* Front end TX configuration */ -#define CC1101_FSCAL3 0x23 /* Frequency synthesizer calibration */ -#define CC1101_FSCAL2 0x24 /* Frequency synthesizer calibration */ -#define CC1101_FSCAL1 0x25 /* Frequency synthesizer calibration */ -#define CC1101_FSCAL0 0x26 /* Frequency synthesizer calibration */ -#define CC1101_RCCTRL1 0x27 /* RC oscillator configuration */ -#define CC1101_RCCTRL0 0x28 /* RC oscillator configuration */ -#define CC1101_FSTEST 0x29 /* Frequency synthesizer cal control */ -#define CC1101_PTEST 0x2A /* Production test */ -#define CC1101_AGCTEST 0x2B /* AGC test */ -#define CC1101_TEST2 0x2C /* Various test settings */ -#define CC1101_TEST1 0x2D /* Various test settings */ -#define CC1101_TEST0 0x2E /* Various test settings */ - -/* Status registers */ - -#define CC1101_PARTNUM (0x30 | 0xc0) /* Part number */ -#define CC1101_VERSION (0x31 | 0xc0) /* Current version number */ -#define CC1101_FREQEST (0x32 | 0xc0) /* Frequency offset estimate */ -#define CC1101_LQI (0x33 | 0xc0) /* Demodulator estimate for link quality */ -#define CC1101_RSSI (0x34 | 0xc0) /* Received signal strength indication */ -#define CC1101_MARCSTATE (0x35 | 0xc0) /* Control state machine state */ -#define CC1101_WORTIME1 (0x36 | 0xc0) /* High byte of WOR timer */ -#define CC1101_WORTIME0 (0x37 | 0xc0) /* Low byte of WOR timer */ -#define CC1101_PKTSTATUS (0x38 | 0xc0) /* Current GDOx status and packet status */ -#define CC1101_VCO_VC_DAC (0x39 | 0xc0) /* Current setting from PLL cal module */ -#define CC1101_TXBYTES (0x3A | 0xc0) /* Underflow and # of bytes in TXFIFO */ -#define CC1101_RXBYTES (0x3B | 0xc0) /* Overflow and # of bytes in RXFIFO */ -#define CC1101_RCCTRL1_STATUS (0x3C | 0xc0) /* Last RC oscilator calibration results */ -#define CC1101_RCCTRL0_STATUS (0x3D | 0xc0) /* Last RC oscilator calibration results */ - -/* Multi byte memory locations */ - -#define CC1101_PATABLE 0x3E -#define CC1101_TXFIFO 0x3F -#define CC1101_RXFIFO 0x3F - -/* Definitions for burst/single access to registers */ - -#define CC1101_WRITE_BURST 0x40 -#define CC1101_READ_SINGLE 0x80 -#define CC1101_READ_BURST 0xC0 - -/* Strobe commands */ - -#define CC1101_SRES 0x30 /* Reset chip. */ -#define CC1101_SFSTXON 0x31 /* Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL=1). */ -#define CC1101_SXOFF 0x32 /* Turn off crystal oscillator. */ -#define CC1101_SCAL 0x33 /* Calibrate frequency synthesizer and turn it off */ -#define CC1101_SRX 0x34 /* Enable RX. Perform calibration first if switching from IDLE and MCSM0.FS_AUTOCAL=1. */ -#define CC1101_STX 0x35 /* Enable TX. Perform calibration first if IDLE and MCSM0.FS_AUTOCAL=1. */ - /* If switching from RX state and CCA is enabled then go directly to TX if channel is clear. */ -#define CC1101_SIDLE 0x36 /* Exit RX / TX, turn off frequency synthesizer and exit Wake-On-Radio mode if applicable. */ -#define CC1101_SAFC 0x37 /* Perform AFC adjustment of the frequency synthesizer */ -#define CC1101_SWOR 0x38 /* Start automatic RX polling sequence (Wake-on-Radio) */ -#define CC1101_SPWD 0x39 /* Enter power down mode when CSn goes high. */ -#define CC1101_SFRX 0x3A /* Flush the RX FIFO buffer. */ -#define CC1101_SFTX 0x3B /* Flush the TX FIFO buffer. */ -#define CC1101_SWORRST 0x3C /* Reset real time clock. */ -#define CC1101_SNOP 0x3D /* No operation. */ - -/* Modem Control */ - -#define CC1101_MCSM0_XOSC_FORCE_ON 0x01 - - -/* - * Chip Status Byte - */ - -/* Bit fields in the chip status byte */ - -#define CC1101_STATUS_CHIP_RDYn_BM 0x80 -#define CC1101_STATUS_STATE_BM 0x70 -#define CC1101_STATUS_FIFO_BYTES_AVAILABLE_BM 0x0F - -/* Chip states */ - -#define CC1101_STATE_MASK 0x70 -#define CC1101_STATE_IDLE 0x00 -#define CC1101_STATE_RX 0x10 -#define CC1101_STATE_TX 0x20 -#define CC1101_STATE_FSTXON 0x30 -#define CC1101_STATE_CALIBRATE 0x40 -#define CC1101_STATE_SETTLING 0x50 -#define CC1101_STATE_RX_OVERFLOW 0x60 -#define CC1101_STATE_TX_UNDERFLOW 0x70 - -/* Values of the MACRSTATE register */ - -#define CC1101_MARCSTATE_SLEEP 0x00 -#define CC1101_MARCSTATE_IDLE 0x01 -#define CC1101_MARCSTATE_XOFF 0x02 -#define CC1101_MARCSTATE_VCOON_MC 0x03 -#define CC1101_MARCSTATE_REGON_MC 0x04 -#define CC1101_MARCSTATE_MANCAL 0x05 -#define CC1101_MARCSTATE_VCOON 0x06 -#define CC1101_MARCSTATE_REGON 0x07 -#define CC1101_MARCSTATE_STARTCAL 0x08 -#define CC1101_MARCSTATE_BWBOOST 0x09 -#define CC1101_MARCSTATE_FS_LOCK 0x0A -#define CC1101_MARCSTATE_IFADCON 0x0B -#define CC1101_MARCSTATE_ENDCAL 0x0C -#define CC1101_MARCSTATE_RX 0x0D -#define CC1101_MARCSTATE_RX_END 0x0E -#define CC1101_MARCSTATE_RX_RST 0x0F -#define CC1101_MARCSTATE_TXRX_SWITCH 0x10 -#define CC1101_MARCSTATE_RXFIFO_OVERFLOW 0x11 -#define CC1101_MARCSTATE_FSTXON 0x12 -#define CC1101_MARCSTATE_TX 0x13 -#define CC1101_MARCSTATE_TX_END 0x14 -#define CC1101_MARCSTATE_RXTX_SWITCH 0x15 -#define CC1101_MARCSTATE_TXFIFO_UNDERFLOW 0x16 - -/* Part number and version */ - -#define CC1101_PARTNUM_VALUE 0x00 -#define CC1101_VERSION_VALUE 0x04 - -/* - * Others ... - */ - -#define CC1101_LQI_CRC_OK_BM 0x80 -#define CC1101_LQI_EST_BM 0x7F - - -/**************************************************************************** - * Private Data Types - ****************************************************************************/ - -#define FLAGS_RXONLY 1 /* Indicates receive operation only */ -#define FLAGS_XOSCENABLED 2 /* Indicates that one pin is configured as XOSC/n */ - -struct cc1101_dev_s { - const struct c1101_rfsettings_s *rfsettings; - - struct spi_dev_s * spi; - uint8_t isrpin; /* CC1101 pin used to trigger interrupts */ - uint32_t pinset; /* GPIO of the MCU */ - uint8_t flags; - uint8_t channel; - uint8_t power; -}; - - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -void cc1101_access_begin(struct cc1101_dev_s * dev) -{ - (void)SPI_LOCK(dev->spi, true); - SPI_SELECT(dev->spi, SPIDEV_WIRELESS, true); - SPI_SETMODE(dev->spi, SPIDEV_MODE0); /* CPOL=0, CPHA=0 */ - SPI_SETBITS(dev->spi, 8); -} - - -void cc1101_access_end(struct cc1101_dev_s * dev) -{ - SPI_SELECT(dev->spi, SPIDEV_WIRELESS, false); - (void)SPI_LOCK(dev->spi, false); -} - - -/** CC1101 Access with Range Check - * - * \param dev CC1101 Private Structure - * \param addr CC1101 Address - * \param buf Pointer to buffer, either for read or write access - * \param length when >0 it denotes read access, when <0 it denotes write - * access of -length. abs(length) greater of 1 implies burst mode, - * however - * \return OK on success or errno is set. - */ -int cc1101_access(struct cc1101_dev_s * dev, uint8_t addr, uint8_t *buf, int length) -{ - int stabyte; - - /* Address cannot explicitly define READ command while length WRITE. - * Also access to these cells is only permitted as one byte, eventhough - * transfer is marked as BURST! - */ - - if ( (addr & CC1101_READ_SINGLE) && length != 1 ) - return ERROR; - - /* Prepare SPI */ - - cc1101_access_begin(dev); - - if (length>1 || length < -1) - SPI_SETFREQUENCY(dev->spi, CC1101_SPIFREQ_BURST); - else SPI_SETFREQUENCY(dev->spi, CC1101_SPIFREQ_SINGLE); - - /* Transfer */ - - if (length <= 0) { /* 0 length are command strobes */ - if (length < -1) - addr |= CC1101_WRITE_BURST; - - stabyte = SPI_SEND(dev->spi, addr); - if (length) { - SPI_SNDBLOCK(dev->spi, buf, -length); - } - } - else { - addr |= CC1101_READ_SINGLE; - if (length > 1) - addr |= CC1101_READ_BURST; - - stabyte = SPI_SEND(dev->spi, addr); - SPI_RECVBLOCK(dev->spi, buf, length); - } - - cc1101_access_end(dev); - - return stabyte; -} - - -/** Strobes command and returns chip status byte - * - * By default commands are send as Write. To a command, - * CC1101_READ_SINGLE may be OR'ed to obtain the number of RX bytes - * pending in RX FIFO. - */ -inline uint8_t cc1101_strobe(struct cc1101_dev_s * dev, uint8_t command) -{ - uint8_t status; - - cc1101_access_begin(dev); - SPI_SETFREQUENCY(dev->spi, CC1101_SPIFREQ_SINGLE); - - status = SPI_SEND(dev->spi, command); - - cc1101_access_end(dev); - - return status; -} - - -int cc1101_reset(struct cc1101_dev_s * dev) -{ - cc1101_strobe(dev, CC1101_SRES); - return OK; -} - - -int cc1101_checkpart(struct cc1101_dev_s * dev) -{ - uint8_t partnum, version; - - if (cc1101_access(dev, CC1101_PARTNUM, &partnum, 1) < 0 || - cc1101_access(dev, CC1101_VERSION, &version, 1) < 0) - return ERROR; - - if (partnum == CC1101_PARTNUM_VALUE && version == CC1101_VERSION_VALUE) - return OK; - - return ERROR; -} - - -void cc1101_dumpregs(struct cc1101_dev_s * dev, uint8_t addr, uint8_t length) -{ - uint8_t buf[0x30], i; - - cc1101_access(dev, addr, buf, length); - - printf("CC1101[%2x]: ", addr); - for (i=0; i RX, RX -> RX: 0x3F */ - values[2] = CC1101_MCSM0_VALUE; /* Calibrate on IDLE -> RX/TX, OSC Timeout = ~500 us - TODO: has XOSC_FORCE_ON */ - cc1101_access(dev, CC1101_MCSM2, values, -3); - - /* Wake-On Radio Control */ - - // Not used yet. - - // WOREVT1:WOREVT0 - 16-bit timeout register -} - - -/**************************************************************************** - * Callbacks - ****************************************************************************/ - -volatile int cc1101_interrupt = 0; - -/** External line triggers this callback - * - * The concept todo is: - * - GPIO provides EXTI Interrupt - * - It should handle EXTI Interrupts in ISR, to which chipcon can - * register a callback (and others). The ISR then foreach() calls a - * its callback, and it is up to peripheral to find, whether the cause - * of EXTI ISR was itself. - **/ - -int cc1101_eventcb(int irq, FAR void *context) -{ - cc1101_interrupt++; - return OK; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -struct cc1101_dev_s * cc1101_init(struct spi_dev_s * spi, uint8_t isrpin, - uint32_t pinset, const struct c1101_rfsettings_s * rfsettings) -{ - struct cc1101_dev_s * dev; - - ASSERT(spi); - - if ( (dev = kmalloc( sizeof(struct cc1101_dev_s) )) == NULL) { - errno = ENOMEM; - return NULL; - } - - dev->rfsettings = rfsettings; - dev->spi = spi; - dev->isrpin = isrpin; - dev->pinset = pinset; - dev->flags = 0; - dev->channel = rfsettings->CHMIN; - dev->power = rfsettings->PAMAX; - - /* Reset chip, check status bytes */ - - if ( cc1101_reset(dev) < 0 ) { - kfree(dev); - errno = EFAULT; - return NULL; - } - - /* Check part compatibility */ - - if ( cc1101_checkpart(dev) < 0 ) { - kfree(dev); - errno = ENODEV; - return NULL; - } - - /* Configure CC1101: - * - disable GDOx for best performance - * - load RF - * - and packet control - */ - - cc1101_setgdo(dev, CC1101_PIN_GDO0, CC1101_GDO_HIZ); - cc1101_setgdo(dev, CC1101_PIN_GDO1, CC1101_GDO_HIZ); - cc1101_setgdo(dev, CC1101_PIN_GDO2, CC1101_GDO_HIZ); - cc1101_setrf(dev, rfsettings); - cc1101_setpacketctrl(dev); - - /* Set the ISR to be triggerred on falling edge of the: - * - * 6 (0x06) Asserts when sync word has been sent / received, and - * de-asserts at the end of the packet. In RX, the pin will de-assert - * when the optional address check fails or the RX FIFO overflows. - * In TX the pin will de-assert if the TX FIFO underflows. - */ - - cc1101_setgdo(dev, dev->isrpin, CC1101_GDO_SYNC); - - /* Bind to external interrupt line */ - - // depends on STM32: TODO: Make that config within pinset and - // provide general gpio interface - //stm32_gpiosetevent(pinset, false, true, true, cc1101_eventcb); - - return dev; -} - - -int cc1101_deinit(struct cc1101_dev_s * dev) -{ - ASSERT(dev); - - /* Release interrupt */ - //stm32_gpiosetevent(pinset, false, false, false, NULL); - - /* Power down chip */ - cc1101_powerdown(dev); - - /* Release external interrupt line */ - kfree(dev); - - return 0; -} - - -int cc1101_powerup(struct cc1101_dev_s * dev) -{ - ASSERT(dev); - return 0; -} - - -int cc1101_powerdown(struct cc1101_dev_s * dev) -{ - ASSERT(dev); - return 0; -} - - -int cc1101_setgdo(struct cc1101_dev_s * dev, uint8_t pin, uint8_t function) -{ - ASSERT(dev); - ASSERT(pin <= CC1101_IOCFG0); - - if (function >= CC1101_GDO_CLK_XOSC1) { - - /* Only one pin can be enabled at a time as XOSC/n */ - - if (dev->flags & FLAGS_XOSCENABLED) return -EPERM; - - /* Force XOSC to stay active even in sleep mode */ - - int value = CC1101_MCSM0_VALUE | CC1101_MCSM0_XOSC_FORCE_ON; - cc1101_access(dev, CC1101_MCSM0, &value, -1); - - dev->flags |= FLAGS_XOSCENABLED; - } - else if (dev->flags & FLAGS_XOSCENABLED) { - - /* Disable XOSC in sleep mode */ - - int value = CC1101_MCSM0_VALUE; - cc1101_access(dev, CC1101_MCSM0, &value, -1); - - dev->flags &= ~FLAGS_XOSCENABLED; - } - - return cc1101_access(dev, pin, &function, -1); -} - - -int cc1101_setrf(struct cc1101_dev_s * dev, const struct c1101_rfsettings_s *settings) -{ - ASSERT(dev); - ASSERT(settings); - - if (cc1101_access(dev, CC1101_FSCTRL1, &settings->FSCTRL1, -11) < 0) return ERROR; - if (cc1101_access(dev, CC1101_FOCCFG, &settings->FOCCFG, -5) < 0) return ERROR; - if (cc1101_access(dev, CC1101_FREND1, &settings->FREND1, -6) < 0) return ERROR; - - /* Load Power Table */ - - if (cc1101_access(dev, CC1101_PATABLE, settings->PA, -8) < 0) return ERROR; - - /* If channel is out of valid range, mark that. Limit power. - * We are not allowed to send any data, but are allowed to listen - * and receive. - */ - - cc1101_setchannel(dev, dev->channel); - cc1101_setpower(dev, dev->power); - - return OK; -} - - -int cc1101_setchannel(struct cc1101_dev_s * dev, uint8_t channel) -{ - ASSERT(dev); - - /* Store localy in further checks */ - - dev->channel = channel; - - /* If channel is out of valid, we are allowed to listen and receive only */ - - if (channel < dev->rfsettings->CHMIN || channel > dev->rfsettings->CHMAX) - dev->flags |= FLAGS_RXONLY; - else dev->flags &= ~FLAGS_RXONLY; - - cc1101_access(dev, CC1101_CHANNR, &dev->channel, -1); - - return dev->flags & FLAGS_RXONLY; -} - - -uint8_t cc1101_setpower(struct cc1101_dev_s * dev, uint8_t power) -{ - ASSERT(dev); - - if (power > dev->rfsettings->PAMAX) - power = dev->rfsettings->PAMAX; - - dev->power = power; - - if (power == 0) { - dev->flags |= FLAGS_RXONLY; - return 0; - } - else dev->flags &= ~FLAGS_RXONLY; - - /* Add remaining part from RF table (to get rid of readback) */ - - power--; - power |= dev->rfsettings->FREND0; - - /* On error, report that as zero power */ - - if (cc1101_access(dev, CC1101_FREND0, &power, -1) < 0) - dev->power = 0; - - return dev->power; -} - - -int cc1101_calcRSSIdBm(int rssi) -{ - if (rssi >= 128) rssi -= 256; - return (rssi >> 1) - 74; -} - - -int cc1101_receive(struct cc1101_dev_s * dev) -{ - ASSERT(dev); - - /* \todo Wait for IDLE before going into another state? */ - - cc1101_interrupt = 0; - - cc1101_strobe(dev, CC1101_SRX | CC1101_READ_SINGLE); - - return 0; -} - - -int cc1101_read(struct cc1101_dev_s * dev, uint8_t * buf, size_t size) -{ - ASSERT(dev); - - if (buf==NULL) { - if (size==0) return 64; - // else received packet size - return 0; - } - - if (cc1101_interrupt == 0) return 0; - - int status = cc1101_strobe(dev, CC1101_SNOP | CC1101_READ_SINGLE); - - if (status & CC1101_STATUS_FIFO_BYTES_AVAILABLE_BM && - (status & CC1101_STATE_MASK) == CC1101_STATE_IDLE) { - - uint8_t nbytes; - - cc1101_access(dev, CC1101_RXFIFO, &nbytes, 1); - - nbytes += 2; /* RSSI and LQI */ - - cc1101_access(dev, CC1101_RXFIFO, buf, (nbytes > size) ? size : nbytes); - - /* Flush remaining bytes, if there is no room to receive - * or if there is a BAD CRC - */ - - if (nbytes > size || (nbytes <= size && !(buf[nbytes-1]&0x80)) ) { - printf("Flushing RX FIFO\n"); - cc1101_strobe(dev, CC1101_SFRX); - } - - return nbytes; - } - - return 0; -} - - -int cc1101_write(struct cc1101_dev_s * dev, const uint8_t * buf, size_t size) -{ - uint8_t packetlen; - - ASSERT(dev); - ASSERT(buf); - - if (dev->flags & FLAGS_RXONLY) return -EPERM; - - /* Present limit */ - if (size > CC1101_PACKET_MAXDATALEN) - packetlen = CC1101_PACKET_MAXDATALEN; - else packetlen = size; - - cc1101_access(dev, CC1101_TXFIFO, &packetlen, -1); - cc1101_access(dev, CC1101_TXFIFO, buf, -size); - - return 0; -} - - -int cc1101_send(struct cc1101_dev_s * dev) -{ - ASSERT(dev); - - if (dev->flags & FLAGS_RXONLY) return -EPERM; - - cc1101_interrupt = 0; - - cc1101_strobe(dev, CC1101_STX); - - /* wait until send, going to IDLE */ - - while( cc1101_interrupt == 0 ); - - return 0; -} - - -int cc1101_idle(struct cc1101_dev_s * dev) -{ - ASSERT(dev); - cc1101_strobe(dev, CC1101_SIDLE); - return 0; -} diff --git a/nuttx/drivers/wireless/nrf24l01.c b/nuttx/drivers/wireless/nrf24l01.c new file mode 100644 index 000000000..abb71e725 --- /dev/null +++ b/nuttx/drivers/wireless/nrf24l01.c @@ -0,0 +1,1772 @@ +/**************************************************************************** + * drivers/wireless/nrf24l01/nrf24l01.c + * + * Copyright (C) 2013 Laurent Latil. All rights reserved. + * Authors: Laurent Latil + * + * 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. + * + ****************************************************************************/ + +/* Features: + * - Fixed length and dynamically sized payloads (1 - 32 bytes) + * - Management of the 6 receiver pipes + * - Configuration of each pipe: address, packet length, auto-acknowledge, etc. + * - Use a FIFO buffer to store the received packets + * + * Todo: + * - Add support for payloads in ACK packets (?) + * - Add compatibility with nRF24L01 (not +) hardware (?) + * + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef CONFIG_WL_NRF24L01_RXSUPPORT +# include +#endif + +#include +#include "nrf24l01.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_WL_NRF24L01_DFLT_ADDR_WIDTH +# define CONFIG_WL_NRF24L01_DFLT_ADDR_WIDTH 5 +#endif + +#ifndef CONFIG_WL_NRF24L01_RXFIFO_LEN +# define CONFIG_WL_NRF24L01_RXFIFO_LEN 128 +#endif + +#ifdef CONFIG_WL_NRF24L01_CHECK_PARAMS +# define CHECK_ARGS(cond) do { if (!(cond)) return -EINVAL; } while(0) +#else +# define CHECK_ARGS(cond) +#endif + +/* Default SPI bus frequency (in Hz) */ +#define NRF24L01_SPIFREQ 9000000 /* Can go up to 10 Mbs according to datasheet */ + +/* power-down -> standby transition timing (in us). Note: this value is probably larger than required. */ +#define NRF24L01_TPD2STBY_DELAY 4500 + +#define FIFO_PKTLEN_MASK 0x1F /* 5 ls bits used to store packet length */ +#define FIFO_PKTLEN_SHIFT 0 +#define FIFO_PIPENO_MASK 0xE0 /* 3 ms bits used to store pipe # */ +#define FIFO_PIPENO_SHIFT 4 + +#define FIFO_PKTLEN(dev) (((dev->rx_fifo[dev->nxt_read] & FIFO_PKTLEN_MASK) >> FIFO_PKTLEN_SHIFT) + 1) +#define FIFO_PIPENO(dev) (((dev->rx_fifo[dev->nxt_read] & FIFO_PIPENO_MASK) >> FIFO_PIPENO_SHIFT)) +#define FIFO_HEADER(pktlen,pipeno) ((pktlen - 1) | (pipeno << FIFO_PIPENO_SHIFT)) + +#define DEV_NAME "/dev/nrf24l01" + +/**************************************************************************** + * Private Data Types + ****************************************************************************/ + +typedef enum +{ + MODE_READ, + MODE_WRITE +} nrf24l01_access_mode_t; + +#define FL_AA_ENABLED (1 << 0) + +struct nrf24l01_dev_s +{ + FAR struct spi_dev_s *spi; /* Reference to SPI bus device */ + FAR struct nrf24l01_config_s *config; /* Board specific GPIO functions */ + + nrf24l01_state_t state; /* Current state of the nRF24L01 */ + + uint8_t en_aa; /* Cache EN_AA register value */ + uint8_t en_pipes; /* Cache EN_RXADDR register value */ + bool ce_enabled; /* Cache the value of CE pin */ + uint8_t lastxmitcount; /* Retransmit count of the last succeeded AA transmission */ + uint8_t addrlen; /* Address width (3-5) */ + uint8_t pipedatalen[NRF24L01_PIPE_COUNT]; + + uint8_t pipe0addr[NRF24L01_MAX_ADDR_LEN]; /* Configured address on pipe 0 */ + + uint8_t last_recvpipeno; + sem_t sem_tx; + +#ifdef CONFIG_WL_NRF24L01_RXSUPPORT + uint8_t *rx_fifo; /* Circular RX buffer. [pipe# / pkt_len] [packet data...] */ + uint16_t fifo_len; /* Number of bytes stored in fifo */ + uint16_t nxt_read; /* Next read index */ + uint16_t nxt_write; /* Next write index */ + sem_t sem_fifo; /* Protect access to rx fifo */ + sem_t sem_rx; /* Wait for availability of received data */ + + struct work_s irq_work; /* Interrupt handling "bottom half" */ +#endif + + uint8_t nopens; /* Number of times the device has been opened */ + sem_t devsem; /* Ensures exclusive access to this structure */ +#ifndef CONFIG_DISABLE_POLL + FAR struct pollfd *pfd; /* Polled file descr (or NULL if any) */ +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ +/* Low-level SPI helpers */ + +#ifdef CONFIG_SPI_OWNBUS +static inline void nrf24l01_configspi(FAR struct spi_dev_s *spi); +# define nrf24l01_lock(spi) +# define nrf24l01_unlock(spi) +#else +# define nrf24l01_configspi(spi); +static void nrf24l01_lock(FAR struct spi_dev_s *spi); +static void nrf24l01_unlock(FAR struct spi_dev_s *spi); +#endif + +static uint8_t nrf24l01_access(FAR struct nrf24l01_dev_s *dev, + nrf24l01_access_mode_t mode, uint8_t cmd, uint8_t *buf, int length); + +static uint8_t nrf24l01_flush_rx(FAR struct nrf24l01_dev_s *dev); + +static uint8_t nrf24l01_flush_tx(FAR struct nrf24l01_dev_s *dev); + +/* Read register from nrf24 */ + +static uint8_t nrf24l01_readreg(FAR struct nrf24l01_dev_s *dev, uint8_t reg, + uint8_t *value, int len); + +/* Read single byte value from a register of nrf24 */ + +static uint8_t nrf24l01_readregbyte(FAR struct nrf24l01_dev_s *dev, + uint8_t reg); + +static void nrf24l01_writeregbyte(FAR struct nrf24l01_dev_s *dev, uint8_t reg, + uint8_t value); + +static uint8_t nrf24l01_setregbit(FAR struct nrf24l01_dev_s *dev, uint8_t reg, + uint8_t value, bool set); + +static void nrf24l01_tostate(FAR struct nrf24l01_dev_s *dev, nrf24l01_state_t state); + +static int nrf24l01_irqhandler(FAR int irq, FAR void *context); + +static inline int nrf24l01_attachirq(FAR struct nrf24l01_dev_s *dev, xcpt_t isr); + +static int dosend(FAR struct nrf24l01_dev_s *dev, FAR const uint8_t *data, size_t datalen); + +static int nrf24l01_unregister(FAR struct nrf24l01_dev_s *dev); + +#ifdef CONFIG_WL_NRF24L01_RXSUPPORT + +void fifoput(struct nrf24l01_dev_s *dev, uint8_t pipeno, uint8_t *buffer, uint8_t buflen); + +uint8_t fifoget(struct nrf24l01_dev_s *dev, uint8_t *buffer, uint8_t buflen, uint8_t *pipeno); + +static void nrf24l01_worker(FAR void *arg); + +#endif + +/* POSIX API */ + +static int nrf24l01_open(FAR struct file *filep); + +static int nrf24l01_close(FAR struct file *filep); + +static ssize_t nrf24l01_read(FAR struct file *filep, FAR char *buffer, size_t buflen); + +static ssize_t nrf24l01_write(FAR struct file *filep, FAR const char *buffer, size_t buflen); + +static int nrf24l01_ioctl(FAR struct file *filep, int cmd, unsigned long arg); + +static int nrf24l01_poll(FAR struct file *filep, FAR struct pollfd *fds, + bool setup); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static FAR struct nrf24l01_dev_s *g_nrf24l01dev; + +static const struct file_operations nrf24l01_fops = +{ + .open = nrf24l01_open, /* open */ + .close = nrf24l01_close, /* close */ + .read = nrf24l01_read, /* read */ + .write = nrf24l01_write, /* write */ + .seek = NULL, /* seek */ + .ioctl = nrf24l01_ioctl, /* ioctl */ +#ifndef CONFIG_DISABLE_POLL + .poll = nrf24l01_poll /* poll */ +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#ifndef CONFIG_SPI_OWNBUS +static void nrf24l01_lock(FAR struct spi_dev_s *spi) +{ + /* Lock the SPI bus because there are multiple devices competing for the + * SPI bus + */ + + (void)SPI_LOCK(spi, true); + + /* We have the lock. Now make sure that the SPI bus is configured for the + * NRF24L01 (it might have gotten configured for a different device while + * unlocked) + */ + + SPI_SELECT(spi, SPIDEV_WIRELESS, true); + SPI_SETMODE(spi, SPIDEV_MODE0); + SPI_SETBITS(spi, 8); + SPI_SETFREQUENCY(spi, NRF24L01_SPIFREQ); + SPI_SELECT(spi, SPIDEV_WIRELESS, false); +} +#endif + +/**************************************************************************** + * Function: nrf24l01_unlock + * + * Description: + * If we are sharing the SPI bus with other devices (CONFIG_SPI_OWNBUS + * undefined) then we need to un-lock the SPI bus for each transfer, + * possibly losing the current configuration. + * + * Parameters: + * spi - Reference to the SPI driver structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +#ifndef CONFIG_SPI_OWNBUS +static void nrf24l01_unlock(FAR struct spi_dev_s *spi) +{ + /* Relinquish the SPI bus. */ + + (void)SPI_LOCK(spi, false); +} +#endif + +/**************************************************************************** + * Function: nrf24l01_configspi + * + * Description: + * Configure the SPI for use with the NRF24L01. This function should be + * called once during touchscreen initialization to configure the SPI + * bus. Note that if CONFIG_SPI_OWNBUS is not defined, then this function + * does nothing. + * + * Parameters: + * spi - Reference to the SPI driver structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +#ifdef CONFIG_SPI_OWNBUS +static inline void nrf24l01_configspi(FAR struct spi_dev_s *spi) +{ + /* Configure SPI for the NRF24L01 module. + * As we own the SPI bus this method is called just once. + */ + + SPI_SELECT(spi, SPIDEV_WIRELESS, true); // Useful ? + SPI_SETMODE(spi, SPIDEV_MODE0); + SPI_SETBITS(spi, 8); + SPI_SETFREQUENCY(spi, NRF24L01_SPIFREQ); + SPI_SELECT(spi, SPIDEV_WIRELESS, false); +} +#endif + +static inline void nrf24l01_select(struct nrf24l01_dev_s * dev) +{ + SPI_SELECT(dev->spi, SPIDEV_WIRELESS, true); +} + +static inline void nrf24l01_deselect(struct nrf24l01_dev_s * dev) +{ + SPI_SELECT(dev->spi, SPIDEV_WIRELESS, false); +} + +static uint8_t nrf24l01_access(FAR struct nrf24l01_dev_s *dev, + nrf24l01_access_mode_t mode, uint8_t cmd, FAR uint8_t *buf, int length) +{ + uint8_t status; + + /* Prepare SPI */ + + nrf24l01_select(dev); + + /* Transfer */ + + status = SPI_SEND(dev->spi, cmd); + + switch (mode) + { + case MODE_WRITE: + if (length > 0) + { + SPI_SNDBLOCK(dev->spi, buf, length); + } + break; + + case MODE_READ: + SPI_RECVBLOCK(dev->spi, buf, length); + break; + } + + nrf24l01_deselect(dev); + return status; +} + +static inline uint8_t nrf24l01_flush_rx(struct nrf24l01_dev_s *dev) +{ + return nrf24l01_access(dev, MODE_WRITE, NRF24L01_FLUSH_RX, NULL, 0); +} + +static inline uint8_t nrf24l01_flush_tx(struct nrf24l01_dev_s *dev) +{ + return nrf24l01_access(dev, MODE_WRITE, NRF24L01_FLUSH_TX, NULL, 0); +} + +/* Read register from nrf24l01 */ + +static inline uint8_t nrf24l01_readreg(struct nrf24l01_dev_s *dev, uint8_t reg, + uint8_t *value, int len) +{ + return nrf24l01_access(dev, MODE_READ, reg | NRF24L01_R_REGISTER, value, len); +} + +/* Read single byte value from a register of nrf24l01 */ + +static inline uint8_t nrf24l01_readregbyte(struct nrf24l01_dev_s *dev, + uint8_t reg) +{ + uint8_t val; + nrf24l01_readreg(dev, reg, &val, 1); + return val; +} + +/* Write value to a register of nrf24l01 */ + +static inline int nrf24l01_writereg(FAR struct nrf24l01_dev_s *dev, uint8_t reg, + FAR const uint8_t *value, int len) +{ + return nrf24l01_access(dev, MODE_WRITE, reg | NRF24L01_W_REGISTER, (FAR uint8_t *)value, len); +} + +/* Write single byte value to a register of nrf24l01 */ + +static inline void nrf24l01_writeregbyte(struct nrf24l01_dev_s *dev, uint8_t reg, + uint8_t value) +{ + nrf24l01_writereg(dev, reg, &value, 1); +} + +static uint8_t nrf24l01_setregbit(struct nrf24l01_dev_s *dev, uint8_t reg, + uint8_t value, bool set) +{ + uint8_t val; + + nrf24l01_readreg(dev, reg, &val, 1); + if (set) + { + val |= value; + } + else + { + val &= ~value; + } + + nrf24l01_writereg(dev, reg, &val, 1); + return val; +} + +#ifdef CONFIG_WL_NRF24L01_RXSUPPORT + +/* RX fifo mgt */ + +void fifoput(struct nrf24l01_dev_s *dev, uint8_t pipeno, uint8_t *buffer, uint8_t buflen) +{ + sem_wait(&dev->sem_fifo); + while (dev->fifo_len + buflen + 1 > CONFIG_WL_NRF24L01_RXFIFO_LEN) + { + /* TODO: Set fifo overrun flag ! */ + + int skiplen = FIFO_PKTLEN(dev) + 1; + + dev->nxt_read = (dev->nxt_read + skiplen) % CONFIG_WL_NRF24L01_RXFIFO_LEN; + dev->fifo_len -= skiplen; + } + + dev->rx_fifo[dev->nxt_write] = FIFO_HEADER(buflen, pipeno); + dev->nxt_write = (dev->nxt_write + 1) % CONFIG_WL_NRF24L01_RXFIFO_LEN; + + /* Adjust fifo bytes count */ + + dev->fifo_len += (buflen + 1); + while (buflen--) + { + dev->rx_fifo[dev->nxt_write] = *(buffer++); + dev->nxt_write = (dev->nxt_write + 1) % CONFIG_WL_NRF24L01_RXFIFO_LEN; + } + + sem_post(&dev->sem_fifo); +} + +uint8_t fifoget(struct nrf24l01_dev_s *dev, uint8_t *buffer, uint8_t buflen, uint8_t *pipeno) +{ + uint8_t pktlen; + uint8_t i; + + sem_wait(&dev->sem_fifo); + + ASSERT(dev->fifo_len > 0); + + pktlen = FIFO_PKTLEN(dev); + if (NULL != pipeno) + { + *pipeno = FIFO_PIPENO(dev); + } + + dev->nxt_read = (dev->nxt_read + 1) % CONFIG_WL_NRF24L01_RXFIFO_LEN; + + for (i = 0; i < pktlen && i < buflen; i++) + { + *(buffer++) = dev->rx_fifo[dev->nxt_read]; + dev->nxt_read = (dev->nxt_read + 1) % CONFIG_WL_NRF24L01_RXFIFO_LEN; + } + + if (i < pktlen) + { + dev->nxt_read = (dev->nxt_read + pktlen - i) % CONFIG_WL_NRF24L01_RXFIFO_LEN; + } + + /* Adjust fifo bytes count */ + + dev->fifo_len -= (pktlen + 1); + + sem_post(&dev->sem_fifo); + return pktlen; +} + +#endif + +static int nrf24l01_irqhandler(int irq, FAR void *context) +{ + FAR struct nrf24l01_dev_s *dev = g_nrf24l01dev; + + wllvdbg("*IRQ*"); + +#ifdef CONFIG_WL_NRF24L01_RXSUPPORT + + /* If RX is enabled we delegate the actual work to bottom-half handler */ + + work_queue(HPWORK, &g_nrf24l01dev->irq_work, nrf24l01_worker, dev, 0); +#else + + /* Otherwise we simply wake up the send function */ + + sem_post(&dev->sem_tx); /* Wake up the send function */ +#endif + + return OK; +} + +/* Configure IRQ pin (falling edge) */ + +static inline int nrf24l01_attachirq(FAR struct nrf24l01_dev_s *dev, xcpt_t isr) +{ + return dev->config->irqattach(isr); +} + +static inline bool nrf24l01_chipenable(FAR struct nrf24l01_dev_s *dev, bool enable) +{ + if (dev->ce_enabled != enable) + { + dev->config->chipenable(enable); + dev->ce_enabled = enable; + return !enable; + } + else + { + return enable; + } +} + +#ifdef CONFIG_WL_NRF24L01_RXSUPPORT + +static void nrf24l01_worker(FAR void *arg) +{ + FAR struct nrf24l01_dev_s *dev = (FAR struct nrf24l01_dev_s *) arg; + uint8_t status; + uint8_t fifo_status; + + nrf24l01_lock(dev->spi); + + status = nrf24l01_readregbyte(dev, NRF24L01_STATUS); + + if (status & NRF24L01_RX_DR) + { + /* put CE low */ + + bool ce = nrf24l01_chipenable(dev, false); + + wdbg("RX_DR is set!\n"); + + /* Read and store all received payloads */ + + do + { + uint8_t pipeno; + uint8_t pktlen; + uint8_t buf[NRF24L01_MAX_PAYLOAD_LEN]; + + /* For each packet: + * - Get pipe # + * - Get payload length (either static or dynamic) + * - Read payload content + */ + + pipeno = (status & NRF24L01_RX_P_NO_MASK) >> NRF24L01_RX_P_NO_SHIFT; + + pktlen = dev->pipedatalen[pipeno]; + if (NRF24L01_DYN_LENGTH == pktlen) + { + /* If dynamic length payload need to use R_RX_PL_WID command to get actual length */ + + nrf24l01_access(dev, MODE_READ, NRF24L01_R_RX_PL_WID, &pktlen, 1); + } + + /* Get payload content */ + + nrf24l01_access(dev, MODE_READ, NRF24L01_R_RX_PAYLOAD, buf, pktlen); + + fifoput(dev, pipeno, buf, pktlen); + sem_post(&dev->sem_rx); /* Wake-up any thread waiting in recv */ + + status = nrf24l01_readreg(dev, NRF24L01_FIFO_STATUS, &fifo_status, 1); + + wdbg("FIFO_STATUS=%02x\n", fifo_status); + wdbg("STATUS=%02x\n", status); + } + while (!(fifo_status | NRF24L01_RX_EMPTY)); + + /* Clear interrupt sources */ + + nrf24l01_writeregbyte(dev, NRF24L01_STATUS, NRF24L01_RX_DR); + + /* Restore CE */ + + nrf24l01_chipenable(dev, ce); + +#ifndef CONFIG_DISABLE_POLL + if (dev->pfd) + { + dev->pfd->revents |= POLLIN; /* Data available for input */ + + wvdbg("Wake up polled fd"); + sem_post(dev->pfd->sem); + } +#endif + } + + if (status & (NRF24L01_TX_DS | NRF24L01_MAX_RT)) + { + /* The actual work is done in the send function */ + + sem_post(&dev->sem_tx); + } + + if (dev->state == ST_RX) + { + /* re-enable CE (to go back to RX mode state) */ + + nrf24l01_chipenable(dev, true); + } + nrf24l01_unlock(dev->spi); +} + +#endif + +static void nrf24l01_tostate(struct nrf24l01_dev_s *dev, nrf24l01_state_t state) +{ + nrf24l01_state_t oldstate = dev->state; + + if (oldstate == state) + { + return; + } + + if (oldstate == ST_POWER_DOWN) + { + /* Leaving power down (note: new state cannot be power down here) */ + + nrf24l01_setregbit(dev, NRF24L01_CONFIG, NRF24L01_PWR_UP, true); + usleep(NRF24L01_TPD2STBY_DELAY); + } + + /* Entering new state */ + + switch(state) + { + case ST_UNKNOWN: + /* Power down the module here... */ + case ST_POWER_DOWN: + nrf24l01_chipenable(dev, false); + nrf24l01_setregbit(dev, NRF24L01_CONFIG, NRF24L01_PWR_UP, false); + break; + + case ST_STANDBY: + nrf24l01_chipenable(dev, false); + nrf24l01_setregbit(dev, NRF24L01_CONFIG, NRF24L01_PRIM_RX, false); + break; + +#ifdef CONFIG_WL_NRF24L01_RXSUPPORT + case ST_RX: + nrf24l01_setregbit(dev, NRF24L01_CONFIG, NRF24L01_PRIM_RX, true); + nrf24l01_chipenable(dev, true); + break; +#endif + } + + dev->state = state; +} + +static int dosend(FAR struct nrf24l01_dev_s *dev, FAR const uint8_t *data, size_t datalen) +{ + uint8_t status; + uint8_t obsvalue; + int result; + + /* Store the current lifecycle state in order to restore it after transmit done */ + + nrf24l01_state_t prevstate = dev->state; + + nrf24l01_tostate(dev, ST_STANDBY); + + /* Write payload */ + + nrf24l01_access(dev, MODE_WRITE, NRF24L01_W_TX_PAYLOAD, (FAR uint8_t *)data, datalen); + + /* Enable CE to start transmission */ + + nrf24l01_chipenable(dev, true); + + /* Free the SPI bus during the IRQ wait */ + + nrf24l01_unlock(dev->spi); + + /* Wait for IRQ (TX_DS or MAX_RT) */ + + while (sem_wait(&dev->sem_tx) != 0) + { + /* Note that we really need to wait here, as the interrupt source + * (either TX_DS in case of success, or MAX_RT for failure) needs to be cleared. + */ + + DEBUGASSERT(errno == EINTR); + } + + /* Re-acquire the SPI bus */ + + nrf24l01_lock(dev->spi); + + status = nrf24l01_readreg(dev, NRF24L01_OBSERVE_TX, &obsvalue, 1); + if (status & NRF24L01_TX_DS) + { + /* transmit OK */ + + result = OK; + dev->lastxmitcount = (obsvalue & NRF24L01_ARC_CNT_MASK) + >> NRF24L01_ARC_CNT_SHIFT; + + wvdbg("Transmission OK (lastxmitcount=%d)\n", dev->lastxmitcount); + } + else if (status & NRF24L01_MAX_RT) + { + wvdbg("MAX_RT!\n", dev->lastxmitcount); + result = -ECOMM; + dev->lastxmitcount = NRF24L01_XMIT_MAXRT; + + /* If no ACK packet is received the payload remains in TX fifo. We need to flush it. */ + + nrf24l01_flush_tx(dev); + } + else + { + /* Unexpected... */ + + wdbg("No TX_DS nor MAX_RT bit set in STATUS reg!\n"); + result = -EIO; + } + + /* Clear interrupt sources */ + + nrf24l01_writeregbyte(dev, NRF24L01_STATUS, NRF24L01_TX_DS | NRF24L01_MAX_RT); + + /* Restore state */ + + nrf24l01_tostate(dev, prevstate); + return result; +} + +/* POSIX API */ + +static int nrf24l01_open(FAR struct file *filep) +{ + FAR struct inode *inode; + FAR struct nrf24l01_dev_s *dev; + int result; + + wvdbg("Opening nRF24L01 dev\n"); + + DEBUGASSERT(filep); + inode = filep->f_inode; + + DEBUGASSERT(inode && inode->i_private); + dev = (FAR struct nrf24l01_dev_s *)inode->i_private; + + /* Get exclusive access to the driver data structure */ + + if (sem_wait(&dev->devsem) < 0) + { + /* This should only happen if the wait was canceled by an signal */ + + DEBUGASSERT(errno == EINTR); + return -EINTR; + } + + /* Check if device is not already used */ + + if (dev->nopens > 0) + { + result = -EBUSY; + goto errout; + } + + result = nrf24l01_init(dev); + if (!result) + { + dev->nopens++; + } + +errout: + sem_post(&dev->devsem); + return result; +} + +static int nrf24l01_close(FAR struct file *filep) +{ + FAR struct inode *inode; + FAR struct nrf24l01_dev_s *dev; + + wvdbg("Closing nRF24L01 dev\n"); + DEBUGASSERT(filep); + inode = filep->f_inode; + + DEBUGASSERT(inode && inode->i_private); + dev = (FAR struct nrf24l01_dev_s *)inode->i_private; + + /* Get exclusive access to the driver data structure */ + + if (sem_wait(&dev->devsem) < 0) + { + /* This should only happen if the wait was canceled by an signal */ + + DEBUGASSERT(errno == EINTR); + return -EINTR; + } + + nrf24l01_changestate(dev, ST_POWER_DOWN); + dev->nopens--; + + sem_post(&dev->devsem); + return OK; +} + +static ssize_t nrf24l01_read(FAR struct file *filep, FAR char *buffer, size_t buflen) +{ +#ifndef CONFIG_WL_NRF24L01_RXSUPPORT + return -ENOSYS; +#else + FAR struct nrf24l01_dev_s *dev; + FAR struct inode *inode; + int result; + + DEBUGASSERT(filep); + inode = filep->f_inode; + + DEBUGASSERT(inode && inode->i_private); + dev = (FAR struct nrf24l01_dev_s *)inode->i_private; + + if (sem_wait(&dev->devsem) < 0) + { + /* This should only happen if the wait was canceled by an signal */ + + DEBUGASSERT(errno == EINTR); + return -EINTR; + } + result = nrf24l01_recv(dev, (uint8_t *)buffer, buflen, &dev->last_recvpipeno); + + sem_post(&dev->devsem); + return result; +#endif +} + +static ssize_t nrf24l01_write(FAR struct file *filep, FAR const char *buffer, size_t buflen) +{ + FAR struct nrf24l01_dev_s *dev; + FAR struct inode *inode; + int result; + + DEBUGASSERT(filep); + inode = filep->f_inode; + + DEBUGASSERT(inode && inode->i_private); + dev = (FAR struct nrf24l01_dev_s *)inode->i_private; + + if (sem_wait(&dev->devsem) < 0) + { + /* This should only happen if the wait was canceled by an signal */ + + DEBUGASSERT(errno == EINTR); + return -EINTR; + } + + result = nrf24l01_send(dev, (const uint8_t *)buffer, buflen); + + sem_post(&dev->devsem); + return result; +} + +static int nrf24l01_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + FAR struct inode *inode; + FAR struct nrf24l01_dev_s *dev; + int result = OK; + + wvdbg("cmd: %d arg: %ld\n", cmd, arg); + DEBUGASSERT(filep); + inode = filep->f_inode; + + DEBUGASSERT(inode && inode->i_private); + dev = (FAR struct nrf24l01_dev_s *)inode->i_private; + + /* Get exclusive access to the driver data structure */ + + if (sem_wait(&dev->devsem) < 0) + { + /* This should only happen if the wait was canceled by an signal */ + + DEBUGASSERT(errno == EINTR); + return -EINTR; + } + + /* Process the IOCTL by command */ + + switch (cmd) + { + case WLIOC_SETRADIOFREQ: /* Set radio frequency. Arg: Pointer to uint32_t frequency value */ + { + FAR uint32_t *ptr = (FAR uint32_t *)((uintptr_t)arg); + DEBUGASSERT(ptr != NULL); + + nrf24l01_setradiofreq(dev, *ptr); + } + break; + + case WLIOC_GETRADIOFREQ: /* Get current radio frequency. arg: Pointer to uint32_t frequency value */ + { + FAR uint32_t *ptr = (FAR uint32_t *)((uintptr_t)arg); + DEBUGASSERT(ptr != NULL); + *ptr = nrf24l01_getradiofreq(dev); + } + break; + + case NRF24L01IOC_SETTXADDR: /* Set current TX addr. arg: Pointer to uint8_t array defining the address */ + { + FAR const uint8_t *addr = (FAR const uint8_t *)(arg); + DEBUGASSERT(addr != NULL); + nrf24l01_settxaddr(dev, addr); + } + break; + + case NRF24L01IOC_GETTXADDR: /* Get current TX addr. arg: Pointer to uint8_t array defining the address */ + { + FAR uint8_t *addr = (FAR uint8_t *)(arg); + DEBUGASSERT(addr != NULL); + nrf24l01_gettxaddr(dev, addr); + } + break; + + case WLIOC_SETTXPOWER: /* Set current radio frequency. arg: Pointer to int32_t, output power */ + { + FAR int32_t *ptr = (FAR int32_t *)(arg); + DEBUGASSERT(ptr != NULL); + nrf24l01_settxpower(dev, *ptr); + } + break; + + case WLIOC_GETTXPOWER: /* Get current radio frequency. arg: Pointer to int32_t, output power */ + { + FAR int32_t *ptr = (FAR int32_t *)(arg); + DEBUGASSERT(ptr != NULL); + *ptr = nrf24l01_gettxpower(dev); + } + break; + + case NRF24L01IOC_SETRETRCFG: /* Set retransmit params. arg: Pointer to nrf24l01_retrcfg_t */ + { + FAR nrf24l01_retrcfg_t *ptr = (FAR nrf24l01_retrcfg_t *)(arg); + DEBUGASSERT(ptr != NULL); + nrf24l01_setretransmit(dev, ptr->delay, ptr->count); + } + break; + + case NRF24L01IOC_GETRETRCFG: /* Get retransmit params. arg: Pointer to nrf24l01_retrcfg_t */ + result = -ENOSYS; /* TODO !*/ + break; + + case NRF24L01IOC_SETPIPESCFG: + { + int i; + FAR nrf24l01_pipecfg_t **cfg_array = (FAR nrf24l01_pipecfg_t **)(arg); + + DEBUGASSERT(cfg_array != NULL); + for (i = 0; i < NRF24L01_PIPE_COUNT; i++) + { + if (cfg_array[i]) + { + nrf24l01_setpipeconfig(dev, i, cfg_array[i]); + } + } + } + break; + + case NRF24L01IOC_GETPIPESCFG: + { + int i; + FAR nrf24l01_pipecfg_t **cfg_array = (FAR nrf24l01_pipecfg_t **)(arg); + + DEBUGASSERT(cfg_array != NULL); + for (i = 0; i < NRF24L01_PIPE_COUNT; i++) + { + if (cfg_array[i]) + { + nrf24l01_getpipeconfig(dev, i, cfg_array[i]); + } + } + } + break; + + case NRF24L01IOC_SETPIPESENABLED: + { + int i; + uint8_t en_pipes; + + FAR uint8_t *en_pipesp = (FAR uint8_t *)(arg); + + DEBUGASSERT(en_pipesp != NULL); + en_pipes = *en_pipesp; + for (i = 0; i < NRF24L01_PIPE_COUNT; i++) + { + if ((dev->en_pipes & (1 << i)) != (en_pipes & (1 << i))) + { + nrf24l01_enablepipe(dev, i, en_pipes & (1 << i)); + } + } + } + break; + + case NRF24L01IOC_GETPIPESENABLED: + { + FAR uint8_t *en_pipesp = (FAR uint8_t *)(arg); + + DEBUGASSERT(en_pipesp != NULL); + *en_pipesp = dev->en_pipes; + break; + } + + case NRF24L01IOC_SETDATARATE: + { + FAR nrf24l01_datarate_t *drp = (FAR nrf24l01_datarate_t *)(arg); + DEBUGASSERT(drp != NULL); + + nrf24l01_setdatarate(dev, *drp); + break; + } + + case NRF24L01IOC_GETDATARATE: + result = -ENOSYS; /* TODO !*/ + break; + + case NRF24L01IOC_SETADDRWIDTH: + { + FAR uint32_t *widthp = (FAR uint32_t *)(arg); + DEBUGASSERT(widthp != NULL); + + nrf24l01_setaddrwidth(dev, *widthp); + break; + } + + case NRF24L01IOC_GETADDRWIDTH: + { + FAR int *widthp = (FAR int *)(arg); + DEBUGASSERT(widthp != NULL); + + *widthp = (int)dev->addrlen; + break; + } + + case NRF24L01IOC_SETSTATE: + { + FAR nrf24l01_state_t *statep = (FAR nrf24l01_state_t *)(arg); + DEBUGASSERT(statep != NULL); + + nrf24l01_changestate(dev, *statep); + break; + } + + case NRF24L01IOC_GETSTATE: + { + FAR nrf24l01_state_t *statep = (FAR nrf24l01_state_t *)(arg); + DEBUGASSERT(statep != NULL); + + *statep = dev->state; + break; + } + + case NRF24L01IOC_GETLASTXMITCOUNT: + { + FAR uint32_t *xmitcntp = (FAR uint32_t *)(arg); + DEBUGASSERT(xmitcntp != NULL); + + *xmitcntp = dev->lastxmitcount; + break; + } + + case NRF24L01IOC_GETLASTPIPENO: + { + FAR uint32_t *lastpipep = (FAR uint32_t *)(arg); + DEBUGASSERT(lastpipep != NULL); + + *lastpipep = dev->last_recvpipeno; + break; + } + + default: + result = -ENOTTY; + break; + } + + sem_post(&dev->devsem); + return result; +} + +#ifndef CONFIG_DISABLE_POLL + +static int nrf24l01_poll(FAR struct file *filep, FAR struct pollfd *fds, + bool setup) +{ +#ifndef CONFIG_WL_NRF24L01_RXSUPPORT + /* Polling is currently implemented for data input only */ + return -ENOSYS; +#else + + FAR struct inode *inode; + FAR struct nrf24l01_dev_s *dev; + int result = OK; + + wvdbg("setup: %d\n", (int)setup); + DEBUGASSERT(filep && fds); + inode = filep->f_inode; + + DEBUGASSERT(inode && inode->i_private); + dev = (FAR struct nrf24l01_dev_s *)inode->i_private; + + /* Exclusive access */ + + if (sem_wait(&dev->devsem) < 0) + { + /* This should only happen if the wait was canceled by an signal */ + + DEBUGASSERT(errno == EINTR); + return -EINTR; + } + + /* Are we setting up the poll? Or tearing it down? */ + + if (setup) + { + /* Ignore waits that do not include POLLIN */ + + if ((fds->events & POLLIN) == 0) + { + result = -EDEADLK; + goto errout; + } + + /* Check if we can accept this poll. + * For now, only one thread can poll the device at any time (shorter / simpler code) + */ + + if (dev->pfd) + { + result = -EBUSY; + goto errout; + } + + dev->pfd = fds; + } + else /* Tear it down */ + { + dev->pfd = NULL; + } + +errout: + sem_post(&dev->devsem); + return result; +#endif +} + +#endif + +static int nrf24l01_unregister(FAR struct nrf24l01_dev_s *dev) +{ + CHECK_ARGS(dev); + + /* Release IRQ */ + + nrf24l01_attachirq(dev, NULL); + + g_nrf24l01dev = NULL; + + /* Free memory */ +#ifdef CONFIG_WL_NRF24L01_RXSUPPORT + kfree(dev->rx_fifo); +#endif + kfree(dev); + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int nrf24l01_register(FAR struct spi_dev_s *spi, FAR struct nrf24l01_config_s *cfg) +{ + FAR struct nrf24l01_dev_s *dev; + int result = OK; + +#ifdef CONFIG_WL_NRF24L01_RXSUPPORT + uint8_t *rx_fifo; +#endif + + ASSERT((spi != NULL) & (cfg != NULL)); + + if ((dev = kmalloc(sizeof(struct nrf24l01_dev_s))) == NULL) + { + return -ENOMEM; + } + + dev->spi = spi; + dev->config = cfg; + + dev->state = ST_UNKNOWN; + dev->en_aa = 0; + dev->ce_enabled = false; + + sem_init(&(dev->devsem), 0, 1); + dev->nopens = 0; + +#ifndef CONFIG_DISABLE_POLL + dev->pfd = NULL; +#endif + + sem_init(&(dev->sem_tx), 0, 0); + +#ifdef CONFIG_WL_NRF24L01_RXSUPPORT + if ((rx_fifo = kmalloc(CONFIG_WL_NRF24L01_RXFIFO_LEN)) == NULL) + { + kfree(dev); + return -ENOMEM; + } + + dev->rx_fifo = rx_fifo; + dev->nxt_read = 0; + dev->nxt_write = 0; + dev->fifo_len = 0; + + sem_init(&(dev->sem_fifo), 0, 1); + sem_init(&(dev->sem_rx), 0, 0); +#endif + + /* Set the global reference */ + + g_nrf24l01dev = dev; + + /* Configure IRQ pin (falling edge) */ + + nrf24l01_attachirq(dev, nrf24l01_irqhandler); + + /* Register the device as an input device */ + + ivdbg("Registering " DEV_NAME "\n"); + + result = register_driver(DEV_NAME, &nrf24l01_fops, 0666, dev); + if (result < 0) + { + wdbg("register_driver() failed: %d\n", result); + nrf24l01_unregister(dev); + } + + return result; +} + +FAR struct nrf24l01_dev_s * nrf24l01_getinstance(void) +{ + return g_nrf24l01dev; +} + +/* (re)set the device in a default initial state */ + +int nrf24l01_init(FAR struct nrf24l01_dev_s *dev) +{ + int result = OK; + uint8_t features; + + CHECK_ARGS(dev); + nrf24l01_lock(dev->spi); + + /* Configure the SPI parameters now (if we own the bus) */ + + nrf24l01_configspi(dev->spi); + + /* Enable features. */ + + nrf24l01_writeregbyte(dev, NRF24L01_FEATURE, NRF24L01_EN_DPL); + features = nrf24l01_readregbyte(dev, NRF24L01_FEATURE); + if (0 == features) + { + /* The ACTIVATE instruction is not documented in the nRF24L01+ docs. + * However it is referenced / described by many sources on Internet, + * + * Is it for nRF24L01 (not +) hardware ? + */ + + uint8_t v = 0x73; + nrf24l01_access(dev, MODE_WRITE, NRF24L01_ACTIVATE, &v, 1); + + features = nrf24l01_readregbyte(dev, NRF24L01_FEATURE); + if (0 == features) + { + /* If FEATURES reg is still unset here, consider there is no actual hardware */ + + result = -ENODEV; + goto out; + } + } + + /* Set initial state */ + + nrf24l01_tostate(dev, ST_POWER_DOWN); + + /* Disable all pipes */ + + dev->en_pipes = 0; + nrf24l01_writeregbyte(dev, NRF24L01_EN_RXADDR, 0); + + /* Set addr width to default */ + + dev->addrlen = CONFIG_WL_NRF24L01_DFLT_ADDR_WIDTH; + nrf24l01_writeregbyte(dev, NRF24L01_SETUP_AW, CONFIG_WL_NRF24L01_DFLT_ADDR_WIDTH - 2); + + /* Get pipe #0 addr */ + + nrf24l01_readreg(dev, NRF24L01_RX_ADDR_P0, dev->pipe0addr, dev->addrlen); + + dev->en_aa = nrf24l01_readregbyte(dev, NRF24L01_EN_AA); + + /* Flush HW fifo */ + + nrf24l01_flush_rx(dev); + nrf24l01_flush_tx(dev); + + /* Clear interrupt sources (useful ?) */ + + nrf24l01_writeregbyte(dev, NRF24L01_STATUS, NRF24L01_RX_DR|NRF24L01_TX_DS|NRF24L01_MAX_RT); + +out: + nrf24l01_unlock(dev->spi); + return result; +} + +int nrf24l01_setpipeconfig(FAR struct nrf24l01_dev_s *dev, unsigned int pipeno, + FAR const nrf24l01_pipecfg_t *pipecfg) +{ + bool dynlength; + bool en_aa; + + CHECK_ARGS(dev && pipecfg && pipeno < NRF24L01_PIPE_COUNT); + + dynlength = (pipecfg->payload_length == NRF24L01_DYN_LENGTH); + + /* Need to enable AA to enable dynamic length payload */ + + en_aa = dynlength || pipecfg->en_aa; + + nrf24l01_lock(dev->spi); + + /* Set addr */ + + int addrlen = (pipeno <= 1) ? dev->addrlen : 1; /* Pipe 0 & 1 are the only ones to have a full length address */ + nrf24l01_writereg(dev, NRF24L01_RX_ADDR_P0 + pipeno, pipecfg->rx_addr, addrlen); + + /* Auto ack */ + + if (en_aa) + { + dev->en_aa |= 1 << pipeno; + } + else + { + dev->en_aa &= ~(1 << pipeno); + } + + nrf24l01_setregbit(dev, NRF24L01_EN_AA, 1 << pipeno, en_aa); + + /* Payload config */ + + nrf24l01_setregbit(dev, NRF24L01_DYNPD, 1 << pipeno, dynlength); + if (!dynlength) + { + nrf24l01_writeregbyte(dev, NRF24L01_RX_PW_P0 + pipeno, pipecfg->payload_length); + } + nrf24l01_unlock(dev->spi); + + dev->pipedatalen[pipeno] = pipecfg->payload_length; + return OK; +} + +int nrf24l01_getpipeconfig(FAR struct nrf24l01_dev_s *dev, unsigned int pipeno, + FAR nrf24l01_pipecfg_t *pipecfg) +{ + bool dynlength; + + CHECK_ARGS(dev && pipecfg && pipeno < NRF24L01_PIPE_COUNT); + + nrf24l01_lock(dev->spi); + + /* Get pipe address */ + + int addrlen = (pipeno <= 1) ? dev->addrlen : 1; /* Pipe 0 & 1 are the only ones to have a full length address */ + nrf24l01_readreg(dev, NRF24L01_RX_ADDR_P0 + pipeno, pipecfg->rx_addr, addrlen); + + /* Auto ack */ + + pipecfg->en_aa = ((nrf24l01_readregbyte(dev, NRF24L01_EN_AA) & (1 << pipeno)) != 0); + + /* Payload config */ + + dynlength = ((nrf24l01_readregbyte(dev, NRF24L01_DYNPD) & (1 << pipeno)) != 0); + + if (dynlength) + { + pipecfg->payload_length = NRF24L01_DYN_LENGTH; + } + else + { + pipecfg->payload_length = nrf24l01_readregbyte(dev, NRF24L01_RX_PW_P0 + pipeno); + } + + nrf24l01_unlock(dev->spi); + + return OK; +} + +int nrf24l01_enablepipe(FAR struct nrf24l01_dev_s *dev, unsigned int pipeno, bool enable) +{ + CHECK_ARGS(dev && pipeno < NRF24L01_PIPE_COUNT); + + uint8_t rxaddrval; + uint8_t pipemask = 1 << pipeno; + + nrf24l01_lock(dev->spi); + + /* Enable pipe on nRF24L01 */ + + rxaddrval = nrf24l01_readregbyte(dev, NRF24L01_EN_RXADDR); + + if (enable) + { + rxaddrval |= pipemask; + } + else + { + rxaddrval &= ~pipemask; + } + + nrf24l01_writeregbyte(dev, NRF24L01_EN_RXADDR, rxaddrval); + nrf24l01_unlock(dev->spi); + + /* Update cached value */ + + dev->en_pipes = rxaddrval; + + return OK; +} + +int nrf24l01_settxaddr(FAR struct nrf24l01_dev_s *dev, FAR const uint8_t *txaddr) +{ + CHECK_ARGS(dev && txaddr); + + nrf24l01_lock(dev->spi); + + nrf24l01_writereg(dev, NRF24L01_TX_ADDR, txaddr, dev->addrlen); + nrf24l01_unlock(dev->spi); + return OK; +} + +int nrf24l01_gettxaddr(FAR struct nrf24l01_dev_s *dev, FAR uint8_t *txaddr) +{ + CHECK_ARGS(dev && txaddr); + + nrf24l01_lock(dev->spi); + + nrf24l01_readreg(dev, NRF24L01_TX_ADDR, txaddr, dev->addrlen); + nrf24l01_unlock(dev->spi); + return OK; +} + +int nrf24l01_setretransmit(FAR struct nrf24l01_dev_s *dev, nrf24l01_retransmit_delay_t retrdelay, uint8_t retrcount) +{ + uint8_t val; + + CHECK_ARGS(dev && retrcount <= NRF24L01_MAX_XMIT_RETR); + + val = (retrdelay << NRF24L01_ARD_SHIFT) | (retrcount << NRF24L01_ARC_SHIFT); + + nrf24l01_lock(dev->spi); + + nrf24l01_writeregbyte(dev, NRF24L01_SETUP_RETR, val); + nrf24l01_unlock(dev->spi); + return OK; +} + +int nrf24l01_settxpower(FAR struct nrf24l01_dev_s *dev, int outpower) +{ + uint8_t value; + uint8_t hwpow; + + /** RF_PWR value <-> Output power in dBm + * + * '00' – -18dBm + * '01' – -12dBm + * '10' – -6dBm + * '11' – 0dBm + */ + + switch(outpower) + { + case 0: + hwpow = 3 << NRF24L01_RF_PWR_SHIFT; + break; + + case -6: + hwpow = 2 << NRF24L01_RF_PWR_SHIFT; + break; + + case -12: + hwpow = 1 << NRF24L01_RF_PWR_SHIFT; + break; + + case -18: + hwpow = 0; + break; + + default: + return -EINVAL; + } + + nrf24l01_lock(dev->spi); + + value = nrf24l01_readregbyte(dev, NRF24L01_RF_SETUP); + + value &= ~(NRF24L01_RF_PWR_MASK); + value |= hwpow; + + nrf24l01_writeregbyte(dev, NRF24L01_RF_SETUP, value); + nrf24l01_unlock(dev->spi); + return OK; +} + +int nrf24l01_gettxpower(FAR struct nrf24l01_dev_s *dev) +{ + uint8_t value; + int powers[] = { -18, -12, -6, 0}; + + nrf24l01_lock(dev->spi); + + value = nrf24l01_readregbyte(dev, NRF24L01_RF_SETUP); + nrf24l01_unlock(dev->spi); + + value = (value & NRF24L01_RF_PWR_MASK) >> NRF24L01_RF_PWR_SHIFT; + return powers[value]; +} + +int nrf24l01_setdatarate(FAR struct nrf24l01_dev_s *dev, nrf24l01_datarate_t datarate) +{ + uint8_t value; + + nrf24l01_lock(dev->spi); + + value = nrf24l01_readregbyte(dev, NRF24L01_RF_SETUP); + value &= ~(NRF24L01_RF_DR_HIGH | NRF24L01_RF_DR_LOW); + + switch (datarate) + { + case RATE_1Mbps: + break; + + case RATE_2Mbps: + value |= NRF24L01_RF_DR_HIGH; + break; + + case RATE_250kbps: + value |= NRF24L01_RF_DR_LOW; + break; + } + + nrf24l01_writeregbyte(dev, NRF24L01_RF_SETUP, value); + nrf24l01_unlock(dev->spi); + return OK; +} + +int nrf24l01_setradiofreq(FAR struct nrf24l01_dev_s *dev, uint32_t freq) +{ + uint8_t value; + + CHECK_ARGS(dev && freq >= NRF24L01_MIN_FREQ && freq <= NRF24L01_MAX_FREQ); + + value = NRF24L01_MIN_FREQ - freq; + nrf24l01_lock(dev->spi); + nrf24l01_writeregbyte(dev, NRF24L01_RF_CH, value); + nrf24l01_unlock(dev->spi); + return OK; +} + +uint32_t nrf24l01_getradiofreq(FAR struct nrf24l01_dev_s *dev) +{ + int rffreq; + + CHECK_ARGS(dev); + + nrf24l01_lock(dev->spi); + rffreq = (int)nrf24l01_readregbyte(dev, NRF24L01_RF_CH); + nrf24l01_unlock(dev->spi); + + return rffreq + NRF24L01_MIN_FREQ; +} + +int nrf24l01_setaddrwidth(FAR struct nrf24l01_dev_s *dev, uint32_t width) +{ + CHECK_ARGS(dev && width <= NRF24L01_MAX_ADDR_LEN && width >= NRF24L01_MIN_ADDR_LEN); + + nrf24l01_lock(dev->spi); + nrf24l01_writeregbyte(dev, NRF24L01_SETUP_AW, width-2); + nrf24l01_unlock(dev->spi); + dev->addrlen = width; + return OK; +} + +int nrf24l01_changestate(FAR struct nrf24l01_dev_s *dev, nrf24l01_state_t state) +{ + nrf24l01_lock(dev->spi); + nrf24l01_tostate(dev, state); + nrf24l01_unlock(dev->spi); + return OK; +} + +int nrf24l01_send(FAR struct nrf24l01_dev_s *dev, FAR const uint8_t *data, size_t datalen) +{ + int result; + + CHECK_ARGS(dev && data && datalen <= NRF24L01_MAX_PAYLOAD_LEN); + + nrf24l01_lock(dev->spi); + + result = dosend(dev, data, datalen); + + nrf24l01_unlock(dev->spi); + return result; +} + +int nrf24l01_sendto(FAR struct nrf24l01_dev_s *dev, FAR const uint8_t *data, + size_t datalen, FAR const uint8_t *destaddr) +{ + bool pipeaddrchg = false; + int result; + + nrf24l01_lock(dev->spi); + + /* If AA is enabled (pipe 0 is active and its AA flag is set) and the dest + * addr is not the current pipe 0 addr we need to change pipe 0 addr in + * order to receive the ACK packet. + */ + + if ((dev->en_aa & 1) && (memcmp(destaddr, dev->pipe0addr, dev->addrlen))) + { + wdbg("Change pipe #0 addr to dest addr\n"); + nrf24l01_writereg(dev, NRF24L01_RX_ADDR_P0, destaddr, NRF24L01_MAX_ADDR_LEN); + pipeaddrchg = true; + } + + result = dosend(dev, data, datalen); + + if (pipeaddrchg) + { + /* Restore pipe #0 addr */ + + nrf24l01_writereg(dev, NRF24L01_RX_ADDR_P0, dev->pipe0addr, NRF24L01_MAX_ADDR_LEN); + wdbg("Pipe #0 default addr restored\n"); + } + + nrf24l01_unlock(dev->spi); + return result; +} + +int nrf24l01_lastxmitcount(FAR struct nrf24l01_dev_s *dev) +{ + return dev->lastxmitcount; +} + +#ifdef CONFIG_WL_NRF24L01_RXSUPPORT + +ssize_t nrf24l01_recv(struct nrf24l01_dev_s *dev, uint8_t *buffer, + size_t buflen, uint8_t *recvpipe) +{ + if (sem_wait(&dev->sem_rx) != 0) + { + /* This should only happen if the wait was canceled by an signal */ + + DEBUGASSERT(errno == EINTR); + return -EINTR; + } + + return fifoget(dev, buffer, buflen, recvpipe); +} + +#endif + +#ifdef NRF24L01_DEBUG + +static void binarycvt(char *deststr, const uint8_t *srcbin, size_t srclen) +{ + int i = 0; + while(i < srclen) + { + sprintf(deststr + i*2, "%02x", srcbin[i]); + ++i; + } + + *(deststr + i*2) = '\0'; +} + +void nrf24l01_dumpregs(struct nrf24l01_dev_s *dev) +{ + uint8_t addr[NRF24L01_MAX_ADDR_LEN]; + char addrstr[NRF24L01_MAX_ADDR_LEN * 2 +1]; + + syslog("CONFIG: %02x\n", nrf24l01_readregbyte(dev, NRF24L01_CONFIG)); + syslog("EN_AA: %02x\n", nrf24l01_readregbyte(dev, NRF24L01_EN_AA)); + syslog("EN_RXADDR: %02x\n", nrf24l01_readregbyte(dev, NRF24L01_EN_RXADDR)); + syslog("SETUP_AW: %02x\n", nrf24l01_readregbyte(dev, NRF24L01_SETUP_AW)); + + syslog("SETUP_RETR:%02x\n", nrf24l01_readregbyte(dev, NRF24L01_SETUP_RETR)); + syslog("RF_CH: %02x\n", nrf24l01_readregbyte(dev, NRF24L01_RF_CH)); + syslog("RF_SETUP: %02x\n", nrf24l01_readregbyte(dev, NRF24L01_RF_SETUP)); + syslog("STATUS: %02x\n", nrf24l01_readregbyte(dev, NRF24L01_STATUS)); + syslog("OBS_TX: %02x\n", nrf24l01_readregbyte(dev, NRF24L01_OBSERVE_TX)); + + nrf24l01_readreg(dev, NRF24L01_TX_ADDR, addr, dev->addrlen); + binarycvt(addrstr, addr, dev->addrlen); + syslog("TX_ADDR: %s\n", addrstr); + + syslog("CD: %02x\n", nrf24l01_readregbyte(dev, NRF24L01_CD)); + syslog("RX_PW_P0: %02x\n", nrf24l01_readregbyte(dev, NRF24L01_RX_PW_P0)); + syslog("RX_PW_P1: %02x\n", nrf24l01_readregbyte(dev, NRF24L01_RX_PW_P1)); + syslog("RX_PW_P2: %02x\n", nrf24l01_readregbyte(dev, NRF24L01_RX_PW_P2)); + syslog("RX_PW_P3: %02x\n", nrf24l01_readregbyte(dev, NRF24L01_RX_PW_P3)); + syslog("RX_PW_P4: %02x\n", nrf24l01_readregbyte(dev, NRF24L01_RX_PW_P4)); + syslog("RX_PW_P5: %02x\n", nrf24l01_readregbyte(dev, NRF24L01_RX_PW_P5)); + + syslog("FIFO_STAT: %02x\n", nrf24l01_readregbyte(dev, NRF24L01_FIFO_STATUS)); + syslog("DYNPD: %02x\n", nrf24l01_readregbyte(dev, NRF24L01_DYNPD)); + syslog("FEATURE: %02x\n", nrf24l01_readregbyte(dev, NRF24L01_FEATURE)); +} + +#ifdef CONFIG_WL_NRF24L01_RXSUPPORT +void nrf24l01_dumprxfifo(struct nrf24l01_dev_s *dev) +{ + syslog("bytes count: %d\n", dev->fifo_len); + syslog("next read: %d, next write: %d\n", dev->nxt_read, dev-> nxt_write); +} +#endif + +#endif diff --git a/nuttx/drivers/wireless/nrf24l01.h b/nuttx/drivers/wireless/nrf24l01.h new file mode 100644 index 000000000..c5bddf0b8 --- /dev/null +++ b/nuttx/drivers/wireless/nrf24l01.h @@ -0,0 +1,183 @@ +/**************************************************************************** + * include/nuttx/drivers/wireless/nrf24l01.h + * + * Copyright (C) 2013 Laurent Latil + * Author: Laurent Latil + * + * 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. + * + ****************************************************************************/ + +#ifndef __DRIVERS_WIRELESS_NRF24L01_H +#define __DRIVERS_WIRELESS_NRF24L01_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +#include +#include + +/**************************************************************************** + * Pre-Processor Declarations + ****************************************************************************/ + +/* nRF24L01 hardware definitions */ + +/* Commands */ + +#define NRF24L01_R_REGISTER 0x00 +#define NRF24L01_W_REGISTER 0x20 +#define NRF24L01_R_RX_PAYLOAD 0x61 +#define NRF24L01_W_TX_PAYLOAD 0xA0 +#define NRF24L01_FLUSH_TX 0xE1 +#define NRF24L01_FLUSH_RX 0xE2 +#define NRF24L01_REUSE_TX_PL 0xE3 + +#define NRF24L01_ACTIVATE 0x50 +#define NRF24L01_R_RX_PL_WID 0x60 +#define NRF24L01_W_TX_PAYLOAD_NOACK 0xB0 +#define NRF24L01_W_ACK_PAYLOAD 0xA8 +#define NRF24L01_NOP 0xFF + +/* Registers */ + +#define NRF24L01_CONFIG 0x00 +#define NRF24L01_EN_AA 0x01 +#define NRF24L01_EN_RXADDR 0x02 +#define NRF24L01_SETUP_AW 0x03 +#define NRF24L01_SETUP_RETR 0x04 +#define NRF24L01_RF_CH 0x05 +#define NRF24L01_RF_SETUP 0x06 +#define NRF24L01_STATUS 0x07 +#define NRF24L01_OBSERVE_TX 0x08 +#define NRF24L01_CD 0x09 +#define NRF24L01_RX_ADDR_P0 0x0A +#define NRF24L01_RX_ADDR_P1 0x0B +#define NRF24L01_RX_ADDR_P2 0x0C +#define NRF24L01_RX_ADDR_P3 0x0D +#define NRF24L01_RX_ADDR_P4 0x0E +#define NRF24L01_RX_ADDR_P5 0x0F +#define NRF24L01_TX_ADDR 0x10 +#define NRF24L01_RX_PW_P0 0x11 +#define NRF24L01_RX_PW_P1 0x12 +#define NRF24L01_RX_PW_P2 0x13 +#define NRF24L01_RX_PW_P3 0x14 +#define NRF24L01_RX_PW_P4 0x15 +#define NRF24L01_RX_PW_P5 0x16 +#define NRF24L01_FIFO_STATUS 0x17 +#define NRF24L01_DYNPD 0x1C +#define NRF24L01_FEATURE 0x1D + +/* STATUS register definitions */ + +#define NRF24L01_RX_DR (1 << 6) +#define NRF24L01_TX_DS (1 << 5) +#define NRF24L01_MAX_RT (1 << 4) +#define NRF24L01_RX_P_NO_SHIFT 1 +#define NRF24L01_RX_P_NO_MASK (7 << NRF24L01_RX_P_NO_SHIFT) +#define NRF24L01_STAT_TX_FULL (1 << 0) + +/* CONFIG register definitions */ + +#define NRF24L01_MASK_RX_DR (1 << 6) +#define NRF24L01_MASK_TX_DS (1 << 5) +#define NRF24L01_MASK_MAX_RT (1 << 4) +#define NRF24L01_EN_CRC (1 << 3) +#define NRF24L01_CRCO (1 << 2) +#define NRF24L01_PWR_UP (1 << 1) +#define NRF24L01_PRIM_RX (1 << 0) + +/* RF_SETUP register definition */ + +#define NRF24L01_CONT_WAVE (1 << 7) +#define NRF24L01_RF_DR_LOW (1 << 5) +#define NRF24L01_PLL_LOCK (1 << 4) +#define NRF24L01_RF_DR_HIGH (1 << 3) + +#define NRF24L01_RF_PWR_SHIFT 1 +#define NRF24L01_RF_PWR_MASK (3 << NRF24L01_RF_PWR_SHIFT) + +/* FIFO STATUS register definitions */ + +#define NRF24L01_TX_REUSE (1 << 6) +#define NRF24L01_TX_FULL (1 << 5) +#define NRF24L01_TX_EMPTY (1 << 4) +#define NRF24L01_RX_FULL (1 << 1) +#define NRF24L01_RX_EMPTY (1 << 0) + +/* SETUP_RETR */ + +#define NRF24L01_ARC_SHIFT 0 +#define NRF24L01_ARC_MASK (0xF << NRF24L01_ARC_SHIFT) + +#define NRF24L01_ARD_SHIFT 4 +#define NRF24L01_ARD_MASK (0xF << NRF24L01_ARD_SHIFT) + +/* OBSERVE_TX register definitions */ +#define NRF24L01_PLOS_CNT_SHIFT 4 +#define NRF24L01_PLOS_CNT_MASK (0xF << NRF24L01_PLOS_CNT_SHIFT) +#define NRF24L01_ARC_CNT_SHIFT 0 +#define NRF24L01_ARC_CNT_MASK (0xF << NRF24L01_ARC_CNT_SHIFT) +#define NRF24L01_RX_P_NO_SHIFT 1 +#define NRF24L01_RX_P_NO_MASK (7 << NRF24L01_RX_P_NO_SHIFT) + +/* FEATURE register definitions */ + +#define NRF24L01_EN_DPL (1 << 2) +#define NRF24L01_EN_ACK_PAY (1 << 1) +#define NRF24L01_EN_DYN_ACK (1 << 0) + +/**************************************************************************** + * Public Data Types + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +# define EXTERN extern "C" +extern "C" + { +#else +# define EXTERN extern +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __DRIVERS_WIRELESS_NRF24L01_H */ -- cgit v1.2.3