diff --git a/connectivity/drivers/802.15.4_RF/atmel-rf-driver/LICENSE b/connectivity/drivers/802.15.4_RF/atmel-rf-driver/LICENSE new file mode 100644 index 0000000000..97df0e645d --- /dev/null +++ b/connectivity/drivers/802.15.4_RF/atmel-rf-driver/LICENSE @@ -0,0 +1,2 @@ +Unless specifically indicated otherwise in a file, files are licensed +under the Apache 2.0 license, as can be found in: apache-2.0.txt \ No newline at end of file diff --git a/connectivity/drivers/802.15.4_RF/atmel-rf-driver/README.md b/connectivity/drivers/802.15.4_RF/atmel-rf-driver/README.md new file mode 100644 index 0000000000..f5710629b8 --- /dev/null +++ b/connectivity/drivers/802.15.4_RF/atmel-rf-driver/README.md @@ -0,0 +1,7 @@ +# Example RF driver for Atmel 802.15.4 transceivers # + +Support for: + * AT86RF233 + * AT86RF212B + +This driver is used with 6LoWPAN stack. \ No newline at end of file diff --git a/connectivity/drivers/802.15.4_RF/atmel-rf-driver/apache-2.0.txt b/connectivity/drivers/802.15.4_RF/atmel-rf-driver/apache-2.0.txt new file mode 100644 index 0000000000..0e4cf3ee99 --- /dev/null +++ b/connectivity/drivers/802.15.4_RF/atmel-rf-driver/apache-2.0.txt @@ -0,0 +1,56 @@ + + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + You must give any other recipients of the Work or Derivative Works a copy of this License; and + You must cause any modified files to carry prominent notices stating that You changed the files; and + You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/connectivity/drivers/802.15.4_RF/atmel-rf-driver/atmel-rf-driver/NanostackRfPhyAtmel.h b/connectivity/drivers/802.15.4_RF/atmel-rf-driver/atmel-rf-driver/NanostackRfPhyAtmel.h new file mode 100644 index 0000000000..d6fab5cf5d --- /dev/null +++ b/connectivity/drivers/802.15.4_RF/atmel-rf-driver/atmel-rf-driver/NanostackRfPhyAtmel.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef NANOSTACK_RF_PHY_ATMEL_H_ +#define NANOSTACK_RF_PHY_ATMEL_H_ + +#include "at24mac.h" +#include "PinNames.h" + +#if defined(MBED_CONF_NANOSTACK_CONFIGURATION) && DEVICE_SPI && DEVICE_I2C && defined(MBED_CONF_RTOS_PRESENT) + +#include "NanostackRfPhy.h" + +// Uncomment to use testing gpios attached to TX/RX processes +// #define TEST_GPIOS_ENABLED + +// Arduino pin defaults for convenience +#if !defined(ATMEL_SPI_MOSI) +#define ATMEL_SPI_MOSI D11 +#endif +#if !defined(ATMEL_SPI_MISO) +#define ATMEL_SPI_MISO D12 +#endif +#if !defined(ATMEL_SPI_SCLK) +#define ATMEL_SPI_SCLK D13 +#endif +#if !defined(ATMEL_SPI_CS) +#define ATMEL_SPI_CS D10 +#endif +#if !defined(ATMEL_SPI_RST) +#define ATMEL_SPI_RST D5 +#endif +#if !defined(ATMEL_SPI_SLP) +#define ATMEL_SPI_SLP D7 +#endif +#if !defined(ATMEL_SPI_IRQ) +#define ATMEL_SPI_IRQ D9 +#endif +#if !defined(ATMEL_I2C_SDA) +#define ATMEL_I2C_SDA D14 +#endif +#if !defined(ATMEL_I2C_SCL) +#define ATMEL_I2C_SCL D15 +#endif +#if !defined(TEST_PIN_TX) +#define TEST_PIN_TX D6 +#endif +#if !defined(TEST_PIN_RX) +#define TEST_PIN_RX D3 +#endif +#if !defined(TEST_PIN_CSMA) +#define TEST_PIN_CSMA D4 +#endif +#if !defined(TEST_PIN_SPARE_1) +#define TEST_PIN_SPARE_1 D2 +#endif +#if !defined(TEST_PIN_SPARE_2) +#define TEST_PIN_SPARE_2 D8 +#endif +#if !defined(SE2435L_CSD) +#define SE2435L_CSD D2 +#endif +#if !defined(SE2435L_ANT_SEL) +#define SE2435L_ANT_SEL D8 +#endif + +class RFBits; +class TestPins; +class Se2435Pins; + +class NanostackRfPhyAtmel : public NanostackRfPhy { +public: + NanostackRfPhyAtmel(PinName spi_mosi, PinName spi_miso, + PinName spi_sclk, PinName spi_cs, PinName spi_rst, PinName spi_slp, PinName spi_irq, + PinName i2c_sda, PinName i2c_scl); + virtual ~NanostackRfPhyAtmel(); + virtual int8_t rf_register(); + virtual void rf_unregister(); + virtual void get_mac_address(uint8_t *mac); + virtual void set_mac_address(uint8_t *mac); + +private: +#if !defined(DISABLE_AT24MAC) + AT24Mac _mac; +#endif + uint8_t _mac_addr[8]; + RFBits *_rf; + TestPins *_test_pins; + Se2435Pins *_se2435_pa_pins; + bool _mac_set; + + const PinName _spi_mosi; + const PinName _spi_miso; + const PinName _spi_sclk; + const PinName _spi_cs; + const PinName _spi_rst; + const PinName _spi_slp; + const PinName _spi_irq; +}; + +#ifdef TEST_GPIOS_ENABLED +#define TEST_TX_STARTED test_pins->TEST1 = 1; +#define TEST_TX_DONE test_pins->TEST1 = 0; +#define TEST_RX_STARTED test_pins->TEST2 = 1; +#define TEST_RX_DONE test_pins->TEST2 = 0; +#define TEST_CSMA_STARTED test_pins->TEST3 = 1; +#define TEST_CSMA_DONE test_pins->TEST3 = 0; +#define TEST_SPARE_1_ON test_pins->TEST4 = 1; +#define TEST_SPARE_1_OFF test_pins->TEST4 = 0; +#define TEST_SPARE_2_ON test_pins->TEST5 = 1; +#define TEST_SPARE_2_OFF test_pins->TEST5 = 0; +extern void (*fhss_uc_switch)(void); +extern void (*fhss_bc_switch)(void); +#else +#define TEST_TX_STARTED +#define TEST_TX_DONE +#define TEST_RX_STARTED +#define TEST_RX_DONE +#define TEST_CSMA_STARTED +#define TEST_CSMA_DONE +#define TEST_SPARE_1_ON +#define TEST_SPARE_1_OFF +#define TEST_SPARE_2_ON +#define TEST_SPARE_2_OFF +#endif //TEST_GPIOS_ENABLED + +#endif /* MBED_CONF_NANOSTACK_CONFIGURATION */ +#endif /* NANOSTACK_RF_PHY_ATMEL_H_ */ diff --git a/connectivity/drivers/802.15.4_RF/atmel-rf-driver/mbed_lib.json b/connectivity/drivers/802.15.4_RF/atmel-rf-driver/mbed_lib.json new file mode 100644 index 0000000000..e44a0dc527 --- /dev/null +++ b/connectivity/drivers/802.15.4_RF/atmel-rf-driver/mbed_lib.json @@ -0,0 +1,38 @@ +{ + "name": "atmel-rf", + "config": { + "full-spi-speed": { + "help": "Maximum SPI clock speed (Hz), as long as sufficient inter-byte spacing", + "value": 7500000 + }, + "full-spi-speed-byte-spacing": { + "help": "Required byte spacing in nanoseconds if full SPI speed is in use", + "value": 250 + }, + "low-spi-speed": { + "help": "Maximum SPI clock speed (Hz) if no inter-byte spacing", + "value": 3750000 + }, + "use-spi-spacing-api": { + "help": "Use SPI spacing API proposed in https://github.com/ARMmbed/mbed-os/pull/5353 to ensure spacing between bytes - either run at full speed with spacing, or low with no spacing", + "value": false + }, + "assume-spaced-spi": { + "help": "If not using SPI spacing API, assume platform has widely-spaced bytes in bursts, so use full clock speed rather than low.", + "value": false + }, + "provide-default": { + "help": "Provide default NanostackRfpy. [true/false]", + "value": false + }, + "irq-thread-stack-size": { + "help": "The stack size of the Thread serving the Atmel RF interrupts", + "value": 1024 + } + }, + "target_overrides": { + "STM": { + "assume-spaced-spi": true + } + } +} diff --git a/connectivity/drivers/802.15.4_RF/atmel-rf-driver/source/AT86RF215Reg.h b/connectivity/drivers/802.15.4_RF/atmel-rf-driver/source/AT86RF215Reg.h new file mode 100644 index 0000000000..6836b0cb3f --- /dev/null +++ b/connectivity/drivers/802.15.4_RF/atmel-rf-driver/source/AT86RF215Reg.h @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2020 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AT86RF215REG_H_ +#define AT86RF215REG_H_ +#ifdef __cplusplus +extern "C" { +#endif + + +/*Register addresses*/ +#define RF09_IRQS 0x00 +#define RF24_IRQS 0x01 +#define BBC0_IRQS 0x02 +#define BBC1_IRQS 0x03 +#define RF_AUXS 0x01 +#define RF_CFG 0x06 +#define RF_IQIFC1 0x0B +#define RF_PN 0x0D +#define RF_VN 0x0E +#define RF_IRQM 0x00 +#define RF_STATE 0x02 +#define RF_CMD 0x03 +#define RF_CS 0x04 +#define RF_CCF0L 0x05 +#define RF_CCF0H 0x06 +#define RF_CNL 0x07 +#define RF_CNM 0x08 +#define RF_RXBWC 0x09 +#define RF_RXDFE 0x0A +#define RF_AGCC 0x0B +#define RF_AGCS 0x0C +#define RF_RSSI 0x0D +#define RF_EDC 0x0E +#define RF_EDV 0x10 +#define RF_TXCUTC 0x12 +#define RF_TXDFE 0x13 +#define RF_PAC 0x14 +#define RF_PADFE 0x16 +#define BBC_IRQM 0x00 +#define BBC_PC 0x01 +#define BBC_RXFLL 0x04 +#define BBC_RXFLH 0x05 +#define BBC_TXFLL 0x06 +#define BBC_TXFLH 0x07 +#define BBC_FBLL 0x08 +#define BBC_FBLH 0x09 +#define BBC_OFDMPHRTX 0x0C +#define BBC_OFDMC 0x0E +#define BBC_OFDMSW 0x0F +#define BBC_OQPSKC0 0x10 +#define BBC_OQPSKC1 0x11 +#define BBC_OQPSKC2 0x12 +#define BBC_OQPSKC3 0x13 +#define BBC_OQPSKPHRTX 0x14 +#define BBC_OQPSKPHRRX 0x15 +#define BBC_AFC0 0x20 +#define BBC_AFFTM 0x22 +#define BBC_MACEA0 0x25 +#define BBC_MACPID0F0 0x2D +#define BBC_MACSHA0F0 0x2F +#define BBC_AMCS 0x40 +#define BBC_AMEDT 0x41 +#define BBC_AMAACKTL 0x43 +#define BBC_AMAACKTH 0x44 +#define BBC_FSKC0 0x60 +#define BBC_FSKC1 0x61 +#define BBC_FSKC2 0x62 +#define BBC_FSKC3 0x63 +#define BBC_FSKPLL 0x65 +#define BBC_FSKPHRTX 0x6A +#define BBC_FSKPHRRX 0x6B +#define BBC0_FBRXS 0x2000 +#define BBC0_FBTXS 0x2800 +#define BBC1_FBRXS 0x3000 +#define BBC1_FBTXS 0x3800 + +// RF_AUXS +#define EXTLNABYP (1 << 7) +#define AGCMAP 0x60 +#define AGCMAP_2 (2 << 5) +#define AVEN (1 << 3) + +// RF_PAC +#define TXPWR 0x1F +#define TXPWR_11 (11 << 0) + +// RF_PADFE +#define PADFE 0xC0 +#define RF_FEMODE3 (3 << 6) + +// RF_AGCC +#define AGCI (1 << 6) +#define AVGS 0x30 +#define AVGS_8_SAMPLES (0 << 4) + +// RF_AGCS +#define TGT 0xE0 +#define TGT_1 (1 << 5) +#define TGT_3 (3 << 5) + +// RF_RXBWC +#define BW 0x0F +#define RF_BW2000KHZ_IF2000KHZ (11 << 0) +#define RF_BW1600KHZ_IF2000KHZ (10 << 0) +#define RF_BW1250KHZ_IF2000KHZ (9 << 0) +#define RF_BW1000KHZ_IF1000KHZ (8 << 0) +#define RF_BW800KHZ_IF1000KHZ (7 << 0) +#define RF_BW630KHZ_IF1000KHZ (6 << 0) +#define RF_BW500KHZ_IF500KHZ (5 << 0) +#define RF_BW400KHZ_IF500KHZ (4 << 0) +#define RF_BW320KHZ_IF500KHZ (3 << 0) +#define RF_BW250KHZ_IF250KHZ (2 << 0) +#define RF_BW200KHZ_IF250KHZ (1 << 0) +#define RF_BW160KHZ_IF250KHZ (0 << 0) +#define IFS (1 << 4) + +// RF_TXCUTC +#define PARAMP 0xC0 +#define RF_PARAMP32U (3 << 6) +#define RF_PARAMP16U (2 << 6) +#define RF_PARAMP8U (1 << 6) +#define RF_PARAMP4U (0 << 6) +#define LPFCUT 0x0F +#define RF_FLC80KHZ (0 << 0) +#define RF_FLC100KHZ (1 << 0) +#define RF_FLC125KHZ (2 << 0) +#define RF_FLC160KHZ (3 << 0) +#define RF_FLC200KHZ (4 << 0) +#define RF_FLC250KHZ (5 << 0) +#define RF_FLC315KHZ (6 << 0) +#define RF_FLC400KHZ (7 << 0) +#define RF_FLC500KHZ (8 << 0) +#define RF_FLC625KHZ (9 << 0) +#define RF_FLC800KHZ (10 << 0) +#define RF_FLC1000KHZ (11 << 0) + +// RF_TXDFE, RF_RXDFE +#define RCUT 0xE0 +#define RCUT_4 (4 << 5) +#define RCUT_3 (3 << 5) +#define RCUT_2 (2 << 5) +#define RCUT_1 (1 << 5) +#define RCUT_0 (0 << 5) +#define SR 0x0F +#define SR_10 (10 << 0) +#define SR_8 (8 << 0) +#define SR_6 (6 << 0) +#define SR_5 (5 << 0) +#define SR_4 (4 << 0) +#define SR_3 (3 << 0) +#define SR_2 (2 << 0) +#define SR_1 (1 << 0) + +// BBC_OFDMPHRTX +#define MCS 0x07 +#define MCS_0 (0 << 0) +#define MCS_1 (1 << 0) +#define MCS_2 (2 << 0) +#define MCS_3 (3 << 0) +#define MCS_4 (4 << 0) +#define MCS_5 (5 << 0) +#define MCS_6 (6 << 0) + +// BBC_OFDMC +#define SSRX 0xC0 +#define SSRX_0 (0 << 6) +#define SSRX_1 (1 << 6) +#define SSRX_2 (2 << 6) +#define SSRX_3 (3 << 6) +#define SSTX 0x30 +#define SSTX_0 (0 << 4) +#define SSTX_1 (1 << 4) +#define SSTX_2 (2 << 4) +#define SSTX_3 (3 << 4) +#define LFO (1 << 3) +#define POI (1 << 2) +#define OPT 0x03 +#define OPT_1 (0 << 0) +#define OPT_2 (1 << 0) +#define OPT_3 (2 << 0) +#define OPT_4 (3 << 0) + +// BBC_OFDMSW +#define OFDM_PDT 0xE0 +#define OFDM_PDT_5 (5 << 5) +#define OFDM_PDT_4 (4 << 5) +#define OFDM_PDT_3 (3 << 5) + +// BBC_FSKC0 +#define BT 0xC0 +#define BT_20 (3 << 6) +#define BT_10 (1 << 6) +#define MIDXS 0x30 +#define MIDXS_0 (0 << 4) +#define MIDX 0x0E +#define MIDX_10 (3 << 1) +#define MIDX_075 (2 << 1) +#define MIDX_05 (1 << 1) +#define MIDX_0375 (0 << 1) + +// BBC_FSKC1 +#define SRATE 0x0F +#define SRATE_400KHZ (5 << 0) +#define SRATE_300KHZ (4 << 0) +#define SRATE_200KHZ (3 << 0) +#define SRATE_150KHZ (2 << 0) +#define SRATE_100KHZ (1 << 0) +#define SRATE_50KHZ (0 << 0) + +// BBC_FSKC2 +#define RXO 0x60 +#define RXO_DIS (0 << 5) +#define FECIE (1 << 0) + +// BBC_FSKC3 +#define SFDT 0xF0 +#define PDT 0x0F +#define PDT_6 (6 << 0) + +// BBC_AFFTM +#define TYPE_2 (1 << 2) + +// BBC_AFC0 +#define PM (1 << 4) +#define AFEN3 (1 << 3) +#define AFEN2 (1 << 2) +#define AFEN1 (1 << 1) +#define AFEN0 (1 << 0) + +// BBC_OQPSKPHRTX +#define LEG (1 << 0) + +// BBC_OQPSKC0 +#define FCHIP 0x03 +#define BB_FCHIP100 (0 << 0) +#define BB_FCHIP200 (1 << 0) +#define BB_FCHIP1000 (2 << 0) +#define BB_FCHIP2000 (3 << 0) + +// BBC_OQPSKC2 +#define FCSTLEG 0x04 +#define RXM 0x03 +#define FCS_16 (1 << 2) +#define RXM_2 (2 << 0) + +// BBC_IRQS, BBC_IRQM +#define FBLI (1 << 7) +#define AGCR (1 << 6) +#define AGCH (1 << 5) +#define TXFE (1 << 4) +#define RXEM (1 << 3) +#define RXAM (1 << 2) +#define RXFE (1 << 1) +#define RXFS (1 << 0) + +//BBC_PC +#define BBEN (1 << 2) +#define PT 0x03 +#define BB_PHYOFF (0 << 0) +#define BB_MRFSK (1 << 0) +#define BB_MROFDM (2 << 0) +#define BB_MROQPSK (3 << 0) +#define FCSOK (1 << 5) +#define TXAFCS (1 << 4) +#define FCST (1 << 3) +#define FCSFE (1 << 6) + +//BBC_AMCS +#define AACKFT (1 << 7) +#define AACK (1 << 3) +#define CCAED (1 << 2) + +// RF_IQIFC1 +#define CHPM 0x70 +#define RF_MODE_BBRF (0 << 4) +#define RF_MODE_RF (1 << 4) +#define RF_MODE_BBRF09 (4 << 4) +#define RF_MODE_BBRF24 (5 << 4) + +/*RF_CFG bits*/ +#define IRQMM 0x08 +#define IRQP 0x04 + +/*RFn_IRQM bits*/ +#define TRXRDY (1 << 1) +#define EDC (1 << 2) + +/*RFn_EDC bits*/ +#define EDM 0x03 +#define RF_EDAUTO (0 << 0) +#define RF_EDSINGLE (1 << 0) +#define RF_EDCONT (2 << 0) +#define RF_EDOFF (3 << 0) + +/*Masks*/ +#define CNH 0x01 +#define EDM 0x03 +#define CHPM 0x70 + +#ifdef __cplusplus +} +#endif + +#endif /* AT86RF215REG_H_ */ diff --git a/connectivity/drivers/802.15.4_RF/atmel-rf-driver/source/AT86RFReg.h b/connectivity/drivers/802.15.4_RF/atmel-rf-driver/source/AT86RFReg.h new file mode 100644 index 0000000000..fb86b7119b --- /dev/null +++ b/connectivity/drivers/802.15.4_RF/atmel-rf-driver/source/AT86RFReg.h @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AT86RFREG_H_ +#define AT86RFREG_H_ +#ifdef __cplusplus +extern "C" { +#endif + +/*AT86RF212 PHY Modes*/ +#define BPSK_20 0x00 +#define BPSK_40 0x04 +#define BPSK_40_ALT 0x14 +#define OQPSK_SIN_RC_100 0x08 +#define OQPSK_SIN_RC_200 0x09 +#define OQPSK_RC_100 0x18 +#define OQPSK_RC_200 0x19 +#define OQPSK_SIN_250 0x0c +#define OQPSK_SIN_500 0x0d +#define OQPSK_SIN_500_ALT 0x0f +#define OQPSK_RC_250 0x1c +#define OQPSK_RC_500 0x1d +#define OQPSK_RC_500_ALT 0x1f +#define OQPSK_SIN_RC_400_SCR_ON 0x2A +#define OQPSK_SIN_RC_400_SCR_OFF 0x0A +#define OQPSK_RC_400_SCR_ON 0x3A +#define OQPSK_RC_400_SCR_OFF 0x1A +#define OQPSK_SIN_1000_SCR_ON 0x2E +#define OQPSK_SIN_1000_SCR_OFF 0x0E +#define OQPSK_RC_1000_SCR_ON 0x3E +#define OQPSK_RC_1000_SCR_OFF 0x1E + +/*Supported transceivers*/ +#define PART_AT86RF231 0x03 +#define PART_AT86RF212 0x07 +#define PART_AT86RF233 0x0B +#define PART_AT86RF215 0x34 +#define PART_AT86RF215M 0x36 +#define VERSION_AT86RF212 0x01 +#define VERSION_AT86RF212B 0x03 + +/*RF Configuration Registers*/ +#define TRX_STATUS 0x01 +#define TRX_STATE 0x02 +#define TRX_CTRL_0 0x03 +#define TRX_CTRL_1 0x04 +#define PHY_TX_PWR 0x05 +#define PHY_RSSI 0x06 +#define PHY_ED_LEVEL 0x07 +#define PHY_CC_CCA 0x08 +#define RX_CTRL 0x0A +#define SFD_VALUE 0x0B +#define TRX_CTRL_2 0x0C +#define ANT_DIV 0x0D +#define IRQ_MASK 0x0E +#define IRQ_STATUS 0x0F +#define VREG_CTRL 0x10 +#define BATMON 0x11 +#define XOSC_CTRL 0x12 +#define CC_CTRL_0 0x13 +#define CC_CTRL_1 0x14 +#define RX_SYN 0x15 +#define TRX_RPC 0x16 +#define RF_CTRL_0 0x16 +#define XAH_CTRL_1 0x17 +#define FTN_CTRL 0x18 +#define PLL_CF 0x1A +#define PLL_DCU 0x1B +#define PART_NUM 0x1C +#define VERSION_NUM 0x1D +#define MAN_ID_0 0x1E +#define MAN_ID_1 0x1F +#define SHORT_ADDR_0 0x20 +#define SHORT_ADDR_1 0x21 +#define PAN_ID_0 0x22 +#define PAN_ID_1 0x23 +#define IEEE_ADDR_0 0x24 +#define IEEE_ADDR_1 0x25 +#define IEEE_ADDR_2 0x26 +#define IEEE_ADDR_3 0x27 +#define IEEE_ADDR_4 0x28 +#define IEEE_ADDR_5 0x29 +#define IEEE_ADDR_6 0x2A +#define IEEE_ADDR_7 0x2B +#define XAH_CTRL_0 0x2C +#define CSMA_SEED_0 0x2D +#define CSMA_SEED_1 0x2E +#define CSMA_BE 0x2F + +/* CSMA_SEED_1*/ +#define AACK_FVN_MODE1 7 +#define AACK_FVN_MODE0 6 +#define AACK_SET_PD 5 +#define AACK_DIS_ACK 4 +#define AACK_I_AM_COORD 3 +#define CSMA_SEED_12 2 +#define CSMA_SEED_11 1 +#define CSMA_SEED_10 0 + +/*TRX_STATUS bits*/ +#define CCA_STATUS 0x40 +#define CCA_DONE 0x80 + +/*PHY_CC_CCA bits*/ +#define CCA_REQUEST 0x80 +#define CCA_MODE_3A 0x00 +#define CCA_MODE_1 0x20 +#define CCA_MODE_2 0x40 +#define CCA_MODE_3B 0x60 +#define CCA_MODE_MASK 0x60 +#define CCA_CHANNEL_MASK 0x1F + +/*IRQ_MASK bits*/ +#define RX_START 0x04 +#define TRX_END 0x08 +#define CCA_ED_DONE 0x10 +#define AMI 0x20 +#define TRX_UR 0x40 + +/*ANT_DIV bits*/ +#define ANT_DIV_EN 0x08 +#define ANT_EXT_SW_EN 0x04 +#define ANT_CTRL_DEFAULT 0x03 + +/*TRX_CTRL_1 bits*/ +#define PA_EXT_EN 0x80 +#define TX_AUTO_CRC_ON 0x20 +#define SPI_CMD_MODE_TRX_STATUS 0x04 +#define SPI_CMD_MODE_PHY_RSSI 0x08 +#define SPI_CMD_MODE_IRQ_STATUS 0x0C + +/*TRX_CTRL_2 bits*/ +#define RX_SAFE_MODE 0x80 + +/*FTN_CTRL bits*/ +#define FTN_START 0x80 + +/*PHY_RSSI bits*/ +#define CRC_VALID 0x80 + +/*RX_SYN bits*/ +#define RX_PDT_DIS 0x80 + +/*TRX_RPC bits */ +#define RX_RPC_CTRL 0xC0 +#define RX_RPC_EN 0x20 +#define PDT_RPC_EN 0x10 +#define PLL_RPC_EN 0x08 +#define XAH_TX_RPC_EN 0x04 +#define IPAN_RPC_EN 0x02 +#define TRX_RPC_RSVD_1 0x01 + +/*XAH_CTRL_1 bits*/ +#define AACK_PROM_MODE 0x02 + + +#ifdef __cplusplus +} +#endif + +#endif /* AT86RFREG_H_ */ diff --git a/connectivity/drivers/802.15.4_RF/atmel-rf-driver/source/NanostackRfPhyAT86RF215.cpp b/connectivity/drivers/802.15.4_RF/atmel-rf-driver/source/NanostackRfPhyAT86RF215.cpp new file mode 100644 index 0000000000..488b337527 --- /dev/null +++ b/connectivity/drivers/802.15.4_RF/atmel-rf-driver/source/NanostackRfPhyAT86RF215.cpp @@ -0,0 +1,1230 @@ +/* + * Copyright (c) 2020 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#if defined(MBED_CONF_NANOSTACK_CONFIGURATION) && DEVICE_SPI && DEVICE_INTERRUPTIN && defined(MBED_CONF_RTOS_PRESENT) + +#include "ns_types.h" +#include "platform/arm_hal_interrupt.h" +#include "platform/mbed_wait_api.h" +#include "nanostack/platform/arm_hal_phy.h" +#include "NanostackRfPhyAtmel.h" +#include "AT86RFReg.h" +#include "AT86RF215Reg.h" +#include "mbed_trace.h" +#include "common_functions.h" +#include +#include "Timeout.h" +#include "SPI.h" + +#define TRACE_GROUP "AtRF" + +#define RF_MTU_15_4_2011 127 +#define RF_MTU_15_4G_2012 2047 + +namespace { + +typedef enum { + RF_NOP = 0x00, + RF_SLEEP = 0x01, + RF_TRX_OFF = 0x02, + RF_TXPREP = 0x03, + RF_TX = 0x04, + RF_RX = 0x05, + RF_TRANSITION = 0x06, + RF_RESET = 0x07 +} rf_command_e; + +typedef enum { + COMMON = 0x00, + RF_09 = 0x01, + RF_24 = 0x02, + BBC0 = 0x03, + BBC1 = 0x04 +} rf_modules_e; + +typedef enum { + RF_IDLE, + RF_CSMA_STARTED, + RF_CSMA_WHILE_RX, + RF_TX_STARTED, + RF_RX_STARTED +} rf_states_e; + +} // anonymous namespace + +static void rf_init(void); +static int8_t rf_address_write(phy_address_type_e address_type, uint8_t *address_ptr); +static int8_t rf_extension(phy_extension_type_e extension_type, uint8_t *data_ptr); +static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel); +static int8_t rf_start_csma_ca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol); +static void rf_init_registers(rf_modules_e module); +static void rf_spi_exchange(const void *tx, size_t tx_len, void *rx, size_t rx_len); +static uint8_t rf_read_rf_register(uint8_t addr, rf_modules_e module); +static void rf_write_rf_register(uint8_t addr, rf_modules_e module, uint8_t data); +static void rf_write_rf_register_field(uint8_t addr, rf_modules_e module, uint8_t field, uint8_t value); +static void rf_write_tx_packet_length(uint16_t packet_length, rf_modules_e module); +static uint16_t rf_read_rx_frame_length(rf_modules_e module); +static void rf_write_tx_buffer(uint8_t *data, uint16_t len, rf_modules_e module); +static int rf_read_rx_buffer(uint16_t length, rf_modules_e module); +static void rf_irq_rf_enable(uint8_t irq, rf_modules_e module); +static void rf_irq_rf_disable(uint8_t irq, rf_modules_e module); +static void rf_irq_bbc_enable(uint8_t irq, rf_modules_e module); +static void rf_irq_bbc_disable(uint8_t irq, rf_modules_e module); +static rf_command_e rf_read_state(rf_modules_e module); +static void rf_poll_state_change(rf_command_e state, rf_modules_e module); +static void rf_change_state(rf_command_e state, rf_modules_e module); +static void rf_receive(uint16_t rx_channel, rf_modules_e module); +static void rf_interrupt_handler(void); +static void rf_irq_task_process_irq(void); +static void rf_handle_cca_ed_done(void); +static void rf_start_tx(void); +static void rf_backup_timer_interrupt(void); +static void rf_backup_timer_stop(void); +static uint32_t rf_backup_timer_start(uint16_t bytes, uint32_t time_us); +static int rf_set_channel(uint16_t channel, rf_modules_e module); +static int rf_set_ch0_frequency(uint32_t frequency, rf_modules_e module); +static int rf_set_channel_spacing(uint32_t channel_spacing, rf_modules_e module); +static int rf_set_fsk_symbol_rate_configuration(uint32_t symbol_rate, rf_modules_e module); +static int rf_configure_by_ofdm_bandwidth_option(uint8_t option, uint32_t data_rate, rf_modules_e module); +static void rf_calculate_symbol_rate(uint32_t baudrate, phy_modulation_e modulation); +static void rf_conf_set_cca_threshold(uint8_t percent); +// Defined register read/write functions +#define rf_read_bbc_register(x, y) rf_read_rf_register(x, (rf_modules_e)(y + 2)) +#define rf_read_common_register(x) rf_read_rf_register(x, COMMON) +#define rf_write_bbc_register(x, y, z) rf_write_rf_register(x, (rf_modules_e)(y + 2), z) +#define rf_write_common_register(x, z) rf_write_rf_register(x, COMMON, z) +#define rf_write_bbc_register_field(v, x, y, z) rf_write_rf_register_field(v, (rf_modules_e)(x + 2), y, z) +#define rf_write_common_register_field(v, y, z) rf_write_rf_register_field(v, COMMON, y, z) + +static int8_t rf_radio_driver_id = -1; +static phy_device_driver_s device_driver; +static uint8_t rf_version_num = 0; +static rf_modules_e rf_module = RF_24; +static phy_802_15_4_mode_t mac_mode = IEEE_802_15_4_2011; +static uint8_t mac_tx_handle = 0; +static rf_states_e rf_state = RF_IDLE; +static bool receiver_enabled = false; +static int8_t cca_prepare_status = PHY_TX_NOT_ALLOWED; +static uint8_t rx_buffer[RF_MTU_15_4G_2012]; +static uint8_t rf_rx_channel; +static uint16_t tx_sequence = 0xffff; +static uint16_t cur_tx_packet_len = 0xffff; +static uint16_t cur_rx_packet_len = 0xffff; +static uint32_t cur_rx_stop_time = 0; +static uint32_t tx_time = 0; +static uint32_t rx_time = 0; +static uint8_t rf09_irq_mask = 0; +static uint8_t rf24_irq_mask = 0; +static uint8_t bbc0_irq_mask = 0; +static uint8_t bbc1_irq_mask = 0; + +static bool rf_update_config = false; +static int8_t cca_threshold = -80; +static bool cca_enabled = true; +static uint32_t rf_symbol_rate; + +/* Channel configurations for 2.4 and sub-GHz */ +static const phy_rf_channel_configuration_s phy_24ghz = {.channel_0_center_frequency = 2350000000U, + .channel_spacing = 5000000U, + .datarate = 250000U, + .number_of_channels = 16U, + .modulation = M_OQPSK + }; +static const phy_rf_channel_configuration_s phy_subghz = {.channel_0_center_frequency = 868300000U, + .channel_spacing = 2000000U, + .datarate = 250000U, + .number_of_channels = 11U, + .modulation = M_OQPSK + }; + +static phy_rf_channel_configuration_s phy_current_config; + +static const phy_device_channel_page_s phy_channel_pages[] = { + { CHANNEL_PAGE_0, &phy_24ghz}, + { CHANNEL_PAGE_2, &phy_subghz}, + { CHANNEL_PAGE_0, NULL} +}; + +using namespace mbed; +using namespace rtos; + +#include "rfbits.h" +static RFBits *rf; +static TestPins *test_pins; +static Se2435Pins *se2435_pa_pins = NULL; + +#define MAC_FRAME_TYPE_MASK 0x07 +#define MAC_TYPE_ACK (2) +#define MAC_DATA_PENDING 0x10 +#define FC_AR 0x20 +#define VERSION_FIELD_MASK 0x30 +#define SHIFT_VERSION_FIELD (4) + +#define SIG_RADIO 1 +#define SIG_TIMER_BACKUP 2 +#define SIG_TIMER_CCA 4 +#define SIG_TIMERS (SIG_TIMER_BACKUP|SIG_TIMER_CCA) +#define SIG_ALL (SIG_RADIO|SIG_TIMERS) + +#define ACK_FRAME_LENGTH 3 +#define PACKET_PROCESSING_TIME 5000 +#define MAX_STATE_TRANSITION_TIME_US 1000 +#define CCA_BACKUP_TIMEOUT 1000 +#define MAX_TRANSMISSION_TIME 1000000 + +#define MIN_CCA_THRESHOLD -117 +#define MAX_CCA_THRESHOLD -5 + +static uint32_t rf_get_timestamp(void) +{ + return (uint32_t)rf->tx_timer.read_us(); +} + +static void rf_lock(void) +{ + platform_enter_critical(); +} + +static void rf_unlock(void) +{ + platform_exit_critical(); +} + +static int8_t rf_device_register(const uint8_t *mac_addr) +{ + rf_init(); + device_driver.PHY_MAC = (uint8_t *)mac_addr; + device_driver.driver_description = (char *)"ATMEL_MAC"; + device_driver.link_type = PHY_LINK_15_4_2_4GHZ_TYPE; + device_driver.phy_channel_pages = phy_channel_pages; + device_driver.phy_MTU = RF_MTU_15_4G_2012; + device_driver.phy_header_length = 0; + device_driver.phy_tail_length = 0; + device_driver.address_write = &rf_address_write; + device_driver.extension = &rf_extension; + device_driver.state_control = &rf_interface_state_control; + device_driver.tx = &rf_start_csma_ca; + device_driver.phy_rx_cb = NULL; + device_driver.phy_tx_done_cb = NULL; + rf_radio_driver_id = arm_net_phy_register(&device_driver); + rf_update_config = true; + return rf_radio_driver_id; +} + +static int8_t rf_address_write(phy_address_type_e address_type, uint8_t *address_ptr) +{ + uint8_t rf_address = 0, addr_size = 0; + switch (address_type) { + case PHY_MAC_48BIT: + break; + case PHY_MAC_64BIT: + rf_address = BBC_MACEA0; + addr_size = 8; + break; + case PHY_MAC_16BIT: + rf_address = BBC_MACSHA0F0; + addr_size = 2; + break; + case PHY_MAC_PANID: + rf_address = BBC_MACPID0F0; + addr_size = 2; + break; + } + for (uint8_t i = 0; i < addr_size; i++) { + rf_write_bbc_register(rf_address++, rf_module, address_ptr[(addr_size - 1) - i]); + } + return 0; +} + +static int8_t rf_extension(phy_extension_type_e extension_type, uint8_t *data_ptr) +{ + phy_csma_params_t *csma_params; + uint32_t *timer_value; + switch (extension_type) { + case PHY_EXTENSION_SET_CHANNEL: + if (rf_state == RF_IDLE || (rf_state == RF_CSMA_STARTED && !(rf_read_rf_register(RF_EDC, rf_module) & RF_EDSINGLE))) { + rf_receive(*data_ptr, rf_module); + } else { + return -1; + } + break; + case PHY_EXTENSION_READ_RX_TIME: + common_write_32_bit(rx_time, data_ptr); + break; + case PHY_EXTENSION_GET_TIMESTAMP: + timer_value = (uint32_t *)data_ptr; + *timer_value = rf_get_timestamp(); + break; + case PHY_EXTENSION_SET_CSMA_PARAMETERS: + csma_params = (phy_csma_params_t *)data_ptr; + if (csma_params->backoff_time == 0) { + TEST_CSMA_DONE + rf->cca_timer.detach(); + if (rf_state == RF_TX_STARTED) { + rf_state = RF_IDLE; + rf_receive(rf_rx_channel, rf_module); + } + tx_time = 0; + } else { + tx_time = csma_params->backoff_time; + cca_enabled = csma_params->cca_enabled; + } + break; + case PHY_EXTENSION_GET_SYMBOLS_PER_SECOND: + timer_value = (uint32_t *)data_ptr; + *timer_value = rf_symbol_rate; + break; + case PHY_EXTENSION_DYNAMIC_RF_SUPPORTED: + *data_ptr = true; + break; + case PHY_EXTENSION_SET_RF_CONFIGURATION: + memcpy(&phy_current_config, data_ptr, sizeof(phy_rf_channel_configuration_s)); + rf_calculate_symbol_rate(phy_current_config.datarate, phy_current_config.modulation); + rf_update_config = true; + if (rf_state == RF_IDLE) { + rf_receive(rf_rx_channel, rf_module); + } + break; + case PHY_EXTENSION_SET_CCA_THRESHOLD: + rf_conf_set_cca_threshold(*data_ptr); + break; + case PHY_EXTENSION_SET_CHANNEL_CCA_THRESHOLD: + cca_threshold = (int8_t) *data_ptr; // *NOPAD* + break; + case PHY_EXTENSION_SET_802_15_4_MODE: + mac_mode = (phy_802_15_4_mode_t) *data_ptr; // *NOPAD* + if (mac_mode == IEEE_802_15_4_2011) { + rf_module = RF_24; + } else if (mac_mode == IEEE_802_15_4G_2012) { + rf_module = RF_09; + } + break; + default: + break; + } + return 0; +} + +static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel) +{ + int8_t ret_val = 0; + switch (new_state) { + case PHY_INTERFACE_RESET: + break; + case PHY_INTERFACE_DOWN: + break; + case PHY_INTERFACE_UP: + rf_receive(rf_channel, rf_module); + break; + case PHY_INTERFACE_RX_ENERGY_STATE: + break; + case PHY_INTERFACE_SNIFFER_STATE: + break; + } + return ret_val; +} + +#ifdef TEST_GPIOS_ENABLED +static void test1_toggle(void) +{ + if (test_pins->TEST4) { + test_pins->TEST4 = 0; + } else { + test_pins->TEST4 = 1; + } +} +static void test2_toggle(void) +{ + if (test_pins->TEST5) { + test_pins->TEST5 = 0; + } else { + test_pins->TEST5 = 1; + } +} +#endif //TEST_GPIOS_ENABLED + +static void rf_init(void) +{ +#ifdef TEST_GPIOS_ENABLED + fhss_bc_switch = test1_toggle; + fhss_uc_switch = test2_toggle; +#endif //TEST_GPIOS_ENABLED + rf_lock(); + // Disable interrupts + rf_write_rf_register(RF_IRQM, RF_09, 0); + rf_write_rf_register(RF_IRQM, RF_24, 0); + // Ensure basebands enabled, I/Q IF's disabled + rf_write_rf_register_field(RF_IQIFC1, COMMON, CHPM, RF_MODE_BBRF); + rf_change_state(RF_TRX_OFF, RF_09); + rf_change_state(RF_TRX_OFF, RF_24); + memcpy(&phy_current_config, &phy_24ghz, sizeof(phy_rf_channel_configuration_s)); + rf_calculate_symbol_rate(phy_current_config.datarate, phy_current_config.modulation); + rf_init_registers(RF_24); + rf->IRQ.rise(&rf_interrupt_handler); + rf->IRQ.enable_irq(); + rf->tx_timer.start(); + rf_unlock(); +} + +static void rf_init_registers(rf_modules_e module) +{ + // O-QPSK configuration using IEEE Std 802.15.4-2011 + // FSK/OFDM configuration using IEEE Std 802.15.4g-2012 + // OFDM configuration is experimental only + if (mac_mode == IEEE_802_15_4_2011) { + device_driver.link_type = PHY_LINK_15_4_2_4GHZ_TYPE; + // 16-bit FCS + rf_write_bbc_register_field(BBC_PC, module, FCST, FCST); + // Enable O-QPSK + rf_write_bbc_register_field(BBC_PC, module, PT, BB_MROQPSK); + // Chip frequency 2000kchip/s + rf_write_bbc_register_field(BBC_OQPSKC0, module, FCHIP, BB_FCHIP2000); + // FCS type legacy O-QPSK is 16-bit + rf_write_bbc_register_field(BBC_OQPSKC2, module, FCSTLEG, FCS_16); + // Listen for both MR-O-QPSK and legacy O-QPSK PHY + rf_write_bbc_register_field(BBC_OQPSKC2, module, RXM, RXM_2); + // PHY type Legacy O-QPSK + rf_write_bbc_register_field(BBC_OQPSKPHRTX, module, LEG, LEG); + // Low pass filter cut-off frequency to 1000 kHz + rf_write_rf_register_field(RF_TXCUTC, module, LPFCUT, RF_FLC1000KHZ); + // Set TX filter to sample frequency / 2 + rf_write_rf_register_field(RF_TXDFE, module, RCUT, RCUT_4); + // Enable auto ack + rf_write_bbc_register_field(BBC_AMCS, module, AACK, AACK); + // Enable address filter unit 0 + rf_write_bbc_register_field(BBC_AFC0, module, AFEN0, AFEN0); + // Allow Ack frame type with address filter + rf_write_bbc_register_field(BBC_AFFTM, module, TYPE_2, TYPE_2); + } else if (mac_mode == IEEE_802_15_4G_2012) { + device_driver.link_type = PHY_LINK_15_4_SUBGHZ_TYPE; + // Disable auto ack + rf_write_bbc_register_field(BBC_AMCS, module, AACK, 0); + // Disable address filter unit 0 + rf_write_bbc_register_field(BBC_AFC0, module, AFEN0, 0); + // Enable FSK + if (phy_current_config.modulation == M_2FSK) { + rf_write_bbc_register_field(BBC_PC, module, PT, BB_MRFSK); + // Set bandwidth time product + rf_write_bbc_register_field(BBC_FSKC0, module, BT, BT_20); + // Disable interleaving + rf_write_bbc_register_field(BBC_FSKC2, module, FECIE, 0); + // Disable receiver override + rf_write_bbc_register_field(BBC_FSKC2, module, RXO, RXO_DIS); + // Set modulation index + if (phy_current_config.modulation_index == MODULATION_INDEX_0_5) { + rf_write_bbc_register_field(BBC_FSKC0, module, MIDX, MIDX_05); + rf_write_rf_register_field(RF_TXDFE, module, RCUT, RCUT_0); + } else { + rf_write_bbc_register_field(BBC_FSKC0, module, MIDX, MIDX_10); + rf_write_rf_register_field(RF_TXDFE, module, RCUT, RCUT_4); + } + // Set Gain control settings + rf_write_rf_register_field(RF_AGCC, module, AVGS, AVGS_8_SAMPLES); + rf_write_rf_register_field(RF_AGCS, module, TGT, TGT_1); + // Set symbol rate and related configurations + rf_set_fsk_symbol_rate_configuration(phy_current_config.datarate, module); + // Set preamble length + uint8_t preamble_len = 24; + if (phy_current_config.datarate < 150000) { + preamble_len = 8; + } else if (phy_current_config.datarate < 300000) { + preamble_len = 12; + } + rf_write_bbc_register(BBC_FSKPLL, module, preamble_len); + // Set preamble detector threshold + rf_write_bbc_register_field(BBC_FSKC3, module, PDT, PDT_6); + } else if (phy_current_config.modulation == M_OFDM) { + rf_write_bbc_register_field(BBC_PC, module, PT, BB_MROFDM); + // Set TX scrambler seed + rf_write_bbc_register_field(BBC_OFDMC, module, SSTX, SSTX_0); + // Set RX scrambler seed + rf_write_bbc_register_field(BBC_OFDMC, module, SSRX, SSRX_0); + // Set phyOFDMInterleaving + rf_write_bbc_register_field(BBC_OFDMC, module, POI, 0); + // Set low frequency offset bit + rf_write_bbc_register_field(BBC_OFDMC, module, LFO, 0); + // Configure using bandwidth option + rf_configure_by_ofdm_bandwidth_option(4, 300000, module); + // Set Gain control settings + rf_write_rf_register_field(RF_AGCC, module, AVGS, AVGS_8_SAMPLES); + rf_write_rf_register_field(RF_AGCC, module, AGCI, 0); + rf_write_rf_register_field(RF_AGCS, module, TGT, TGT_3); + } + } + if (se2435_pa_pins) { + // Wakeup SE2435L + se2435_pa_pins->CSD = 1; + // Antenna port selection: (0 - port 1, 1 - port 2) + se2435_pa_pins->ANT_SEL = 0; + // Enable external front end with configuration 3 + rf_write_rf_register_field(RF_PADFE, module, PADFE, RF_FEMODE3); + // Output power at 900MHz: 0 dBm with FSK/QPSK, less than -5 dBm with OFDM + rf_write_rf_register_field(RF_PAC, module, TXPWR, TXPWR_11); + } + // Enable analog voltage regulator + rf_write_rf_register_field(RF_AUXS, module, AVEN, AVEN); + // Disable filtering FCS + rf_write_bbc_register_field(BBC_PC, module, FCSFE, 0); + // Set channel spacing + rf_set_channel_spacing(phy_current_config.channel_spacing, module); + // Set channel 0 center frequency + rf_set_ch0_frequency(phy_current_config.channel_0_center_frequency, module); + // Set channel (must be called after frequency change) + rf_set_channel(rf_rx_channel, module); +} + +static void rf_csma_ca_timer_interrupt(void) +{ + cca_prepare_status = device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_PREPARE, 0, 0); + if (cca_prepare_status == PHY_TX_NOT_ALLOWED) { + if (rf_state == RF_CSMA_STARTED) { + rf_state = RF_IDLE; + } else if (rf_state == RF_CSMA_WHILE_RX) { + rf_state = RF_RX_STARTED; + } + TEST_CSMA_DONE + return; + } + rf_irq_rf_enable(EDC, RF_09); + rf_irq_rf_enable(EDC, rf_module); + rf_write_rf_register_field(RF_EDC, rf_module, EDM, RF_EDSINGLE); + rf_backup_timer_start(0, CCA_BACKUP_TIMEOUT); +} + +static void rf_csma_ca_timer_signal(void) +{ + rf->irq_thread_215.flags_set(SIG_TIMER_CCA); +} + +static int8_t rf_start_csma_ca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol) +{ + rf_lock(); + if (rf_state != RF_IDLE) { + rf_unlock(); + return -1; + } + rf_state = RF_CSMA_STARTED; + + // If Ack is requested, store the MAC sequence. This will be compared with received Ack. + uint8_t version = ((*(data_ptr + 1) & VERSION_FIELD_MASK) >> SHIFT_VERSION_FIELD); + if ((version != MAC_FRAME_VERSION_2) && (*data_ptr & FC_AR)) { + tx_sequence = *(data_ptr + 2); + } + rf_write_tx_buffer(data_ptr, data_length, rf_module); + // Add CRC bytes + if (mac_mode == IEEE_802_15_4_2011) { + data_length += 2; + } else { + data_length += 4; + } + rf_write_tx_packet_length(data_length, rf_module); + mac_tx_handle = tx_handle; + + if (tx_time) { + uint32_t backoff_time = tx_time - rf_get_timestamp(); + // Max. time to TX can be 65ms, otherwise time has passed already -> send immediately + if (backoff_time <= 65000) { + rf->cca_timer.attach_us(rf_csma_ca_timer_signal, backoff_time); + TEST_CSMA_STARTED + rf_unlock(); + return 0; + } + } + // Short timeout to start CCA immediately. + rf->cca_timer.attach_us(rf_csma_ca_timer_signal, 1); + TEST_CSMA_STARTED + rf_unlock(); + return 0; +} + +static void rf_handle_cca_ed_done(void) +{ + TEST_CSMA_DONE + rf_backup_timer_stop(); + rf_irq_rf_disable(EDC, RF_09); + rf_irq_rf_disable(EDC, rf_module); + if (rf_state == RF_CSMA_WHILE_RX) { + rf_state = RF_RX_STARTED; + } + + if ((cca_enabled == true) && (rf_state == RF_RX_STARTED)) { + uint32_t backup_time = cur_rx_stop_time - rf_get_timestamp(); + if (backup_time > MAX_TRANSMISSION_TIME) { + backup_time = 0; + } + rf_backup_timer_start(0, backup_time + PACKET_PROCESSING_TIME); + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 0, 0); + return; + } + if ((cca_enabled == true) && (((int8_t) rf_read_rf_register(RF_EDV, rf_module) > cca_threshold))) { + rf_state = RF_IDLE; + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 0, 0); + return; + } + if (cca_prepare_status == PHY_RESTART_CSMA) { + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_OK, 0, 0); + if (tx_time) { + uint32_t backoff_time = tx_time - rf_get_timestamp(); + // Max. time to TX can be 65ms, otherwise time has passed already -> send immediately + if (backoff_time > 65000) { + backoff_time = 1; + } + rf->cca_timer.attach_us(rf_csma_ca_timer_signal, backoff_time); + TEST_CSMA_STARTED + } + return; + } + rf_irq_bbc_disable(RXFE, rf_module); + rf_start_tx(); +} + +static void rf_handle_tx_done(void) +{ + rf_backup_timer_stop(); + TEST_TX_DONE + rf_irq_bbc_disable(TXFE, rf_module); + rf_state = RF_IDLE; + rf_receive(rf_rx_channel, rf_module); + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_SUCCESS, 0, 0); +} + +static void rf_start_tx(void) +{ + receiver_enabled = false; + rf_change_state(RF_TXPREP, rf_module); + rf_irq_bbc_enable(TXFE, rf_module); + rf_change_state(RF_TX, rf_module); + rf_state = RF_TX_STARTED; + TEST_TX_STARTED + rf_backup_timer_start(cur_tx_packet_len, 0); +} + +static void rf_handle_ack(uint8_t seq_number, uint8_t pending) +{ + phy_link_tx_status_e phy_status; + if (tx_sequence == (uint16_t)seq_number) { + if (pending) { + phy_status = PHY_LINK_TX_DONE_PENDING; + } else { + phy_status = PHY_LINK_TX_DONE; + } + // No CCA attempts done, just waited Ack + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, phy_status, 0, 0); + // Clear TX sequence when Ack is received to avoid duplicate Acks + tx_sequence = 0xffff; + } +} + +static void rf_handle_rx_done(void) +{ + receiver_enabled = false; + TEST_RX_DONE + rf_backup_timer_stop(); + if (rf_state == RF_CSMA_WHILE_RX) { + rf_state = RF_CSMA_STARTED; + uint32_t backup_time = tx_time - rf_get_timestamp(); + // Next TX start event must occur in less than 65ms + if (backup_time > 65000) { + backup_time = 0; + } + rf_backup_timer_start(0, backup_time + CCA_BACKUP_TIMEOUT); + } else if (rf_state == RF_RX_STARTED) { + rf_state = RF_IDLE; + } + if (rf_read_bbc_register(BBC_PC, rf_module) & FCSOK) { + if (!rf_read_rx_buffer(cur_rx_packet_len, rf_module)) { + uint8_t version = ((rx_buffer[1] & VERSION_FIELD_MASK) >> SHIFT_VERSION_FIELD); + if (((rx_buffer[0] & MAC_FRAME_TYPE_MASK) == MAC_TYPE_ACK) && (version < MAC_FRAME_VERSION_2)) { + rf_handle_ack(rx_buffer[2], rx_buffer[0] & MAC_DATA_PENDING); + } else { + int8_t rssi = (int8_t) rf_read_rf_register(RF_EDV, rf_module); + // Cut CRC bytes + if (mac_mode == IEEE_802_15_4_2011) { + cur_rx_packet_len -= 2; + } else { + cur_rx_packet_len -= 4; + } + device_driver.phy_rx_cb(rx_buffer, cur_rx_packet_len, 0xf0, rssi, rf_radio_driver_id); + // If auto ack used, must wait until RF returns to RF_TXPREP state + if ((version != MAC_FRAME_VERSION_2) && (rx_buffer[0] & FC_AR)) { + wait_us(100); + rf_poll_state_change(RF_TXPREP, rf_module); + } + } + } + } else { + if (device_driver.phy_rf_statistics) { + device_driver.phy_rf_statistics->crc_fails++; + } + device_driver.phy_rx_cb(NULL, 0, 0, 0, rf_radio_driver_id); + } + rf_receive(rf_rx_channel, rf_module); +} + +static void rf_handle_rx_start(void) +{ + rx_time = rf_get_timestamp(); + cur_rx_packet_len = rf_read_rx_frame_length(rf_module); + if (!cur_rx_packet_len || cur_rx_packet_len > device_driver.phy_MTU) { + return; + } + if (rf_state == RF_CSMA_STARTED) { + rf_backup_timer_stop(); + rf_state = RF_CSMA_WHILE_RX; + } else { + rf_state = RF_RX_STARTED; + } + TEST_RX_STARTED + cur_rx_stop_time = rf_backup_timer_start(cur_rx_packet_len, 0); +} + +static void rf_receive(uint16_t rx_channel, rf_modules_e module) +{ + if ((receiver_enabled == true) && (rf_update_config == false) && (rx_channel == rf_rx_channel)) { + return; + } + TEST_RX_DONE + rf_lock(); + if (rf_update_config == true) { + rf_update_config = false; + rf_change_state(RF_TRX_OFF, module); + rf_init_registers(module); + rf_change_state(RF_TXPREP, module); + } + if (rx_channel != rf_rx_channel) { + rf_change_state(RF_TXPREP, module); + rf_set_channel(rx_channel, module); + rf_rx_channel = rx_channel; + } + rf_change_state(RF_RX, module); + rf_irq_bbc_enable(RXFS, module); + rf_irq_bbc_enable(RXFE, module); + receiver_enabled = true; + rf_unlock(); + +} + +static void rf_interrupt_handler(void) +{ + rf->irq_thread_215.flags_set(SIG_RADIO); +} + +static void rf_irq_task_process_irq(void) +{ + uint8_t irq_rf09_status = 0, irq_bbc0_status = 0, irq_rf24_status = 0, irq_bbc1_status = 0; + if (rf09_irq_mask) { + irq_rf09_status = rf_read_common_register(RF09_IRQS); + irq_rf09_status &= rf09_irq_mask; + } + if (bbc0_irq_mask) { + irq_bbc0_status = rf_read_common_register(BBC0_IRQS); + irq_bbc0_status &= bbc0_irq_mask; + } + if (rf24_irq_mask) { + irq_rf24_status = rf_read_common_register(RF24_IRQS); + irq_rf24_status &= rf24_irq_mask; + } + if (bbc1_irq_mask) { + irq_bbc1_status = rf_read_common_register(BBC1_IRQS); + irq_bbc1_status &= bbc1_irq_mask; + } + if ((rf_state == RF_CSMA_STARTED) || (rf_state == RF_CSMA_WHILE_RX) || (rf_state == RF_RX_STARTED)) { + if ((irq_rf09_status & EDC) || (irq_rf24_status & EDC)) { + rf_handle_cca_ed_done(); + } + } + if (rf_state == RF_TX_STARTED) { + if ((irq_bbc0_status & TXFE) || (irq_bbc1_status & TXFE)) { + rf_handle_tx_done(); + } + } + if ((rf_state == RF_IDLE) || (rf_state == RF_CSMA_STARTED)) { + if ((irq_bbc0_status & RXFS) || (irq_bbc1_status & RXFS)) { + rf_handle_rx_start(); + } + } + if ((rf_state == RF_RX_STARTED) || (rf_state == RF_CSMA_WHILE_RX)) { + if ((irq_bbc0_status & RXFE) || (irq_bbc1_status & RXFE)) { + rf_handle_rx_done(); + } + } +} + +static void rf_write_tx_packet_length(uint16_t packet_length, rf_modules_e module) +{ + if (packet_length > device_driver.phy_MTU) { + return; + } + if ((uint8_t)(cur_tx_packet_len >> 8) != (packet_length / 256)) { + rf_write_bbc_register(BBC_TXFLH, module, packet_length / 256); + } + if ((uint8_t)cur_tx_packet_len != (packet_length % 256)) { + rf_write_bbc_register(BBC_TXFLL, module, packet_length % 256); + } + cur_tx_packet_len = packet_length; +} + +static uint16_t rf_read_rx_frame_length(rf_modules_e module) +{ + const uint8_t tx[2] = { static_cast(module + 2), static_cast(BBC_RXFLL) }; + uint8_t rx[2]; + rf->CS = 0; + rf_spi_exchange(tx, 2, NULL, 0); + rf_spi_exchange(NULL, 0, rx, 2); + rf->CS = 1; + return (uint16_t)((rx[1] << 8) | rx[0]); +} + +static void rf_write_tx_buffer(uint8_t *data, uint16_t len, rf_modules_e module) +{ + uint16_t buffer_addr = BBC0_FBTXS + (0x1000 * (module - 1)); + const uint8_t tx[2] = { static_cast(0x80 | (buffer_addr >> 8)), static_cast(buffer_addr) }; + rf->CS = 0; + rf_spi_exchange(tx, 2, NULL, 0); + rf_spi_exchange(data, len, NULL, 0); + rf->CS = 1; +} + +static int rf_read_rx_buffer(uint16_t length, rf_modules_e module) +{ + if (length > device_driver.phy_MTU) { + return -1; + } + uint8_t *ptr = rx_buffer; + uint16_t buffer_addr = BBC0_FBRXS + (0x1000 * (module - 1)); + const uint8_t tx[2] = { static_cast(buffer_addr >> 8), static_cast(buffer_addr) }; + rf->CS = 0; + rf_spi_exchange(tx, 2, NULL, 0); + rf_spi_exchange(NULL, 0, ptr, length); + rf->CS = 1; + return 0; +} + +static void rf_irq_rf_enable(uint8_t irq, rf_modules_e module) +{ + if ((module == RF_09) && !(rf09_irq_mask & irq)) { + rf_write_rf_register_field(RF_IRQM, module, irq, irq); + rf09_irq_mask |= irq; + } else if ((module == RF_24) && !(rf24_irq_mask & irq)) { + rf_write_rf_register_field(RF_IRQM, module, irq, irq); + rf24_irq_mask |= irq; + } +} + +static void rf_irq_rf_disable(uint8_t irq, rf_modules_e module) +{ + if ((module == RF_09) && (rf09_irq_mask & irq)) { + rf_write_rf_register_field(RF_IRQM, module, irq, 0); + rf09_irq_mask &= ~irq; + } else if ((module == RF_24) && (rf24_irq_mask & irq)) { + rf_write_rf_register_field(RF_IRQM, module, irq, 0); + rf24_irq_mask &= ~irq; + } +} + +static void rf_irq_bbc_enable(uint8_t irq, rf_modules_e module) +{ + if ((module == RF_09) && !(bbc0_irq_mask & irq)) { + rf_write_bbc_register_field(BBC_IRQM, module, irq, irq); + bbc0_irq_mask |= irq; + } else if ((module == RF_24) && !(bbc1_irq_mask & irq)) { + rf_write_bbc_register_field(BBC_IRQM, module, irq, irq); + bbc1_irq_mask |= irq; + } +} + +static void rf_irq_bbc_disable(uint8_t irq, rf_modules_e module) +{ + if ((module == RF_09) && (bbc0_irq_mask & irq)) { + rf_write_bbc_register_field(BBC_IRQM, module, irq, 0); + bbc0_irq_mask &= ~irq; + } else if ((module == RF_24) && (bbc1_irq_mask & irq)) { + rf_write_bbc_register_field(BBC_IRQM, module, irq, 0); + bbc1_irq_mask &= ~irq; + } +} + +static rf_command_e rf_read_state(rf_modules_e module) +{ + return (rf_command_e) rf_read_rf_register(RF_STATE, module); +} + +static void rf_poll_state_change(rf_command_e state, rf_modules_e module) +{ + uint32_t transition_start_time = rf_get_timestamp(); + while (rf_read_state(module) != state) { + if (rf_get_timestamp() > (transition_start_time + MAX_STATE_TRANSITION_TIME_US)) { + tr_err("Failed to change module %u state from %x to: %x", module, rf_read_state(module), state); + break; + } + } +} + +static void rf_change_state(rf_command_e state, rf_modules_e module) +{ + rf_write_rf_register(RF_CMD, module, state); + return rf_poll_state_change(state, module); +} + +static void rf_spi_exchange(const void *tx, size_t tx_len, void *rx, size_t rx_len) +{ + rf->spi.write(static_cast(tx), tx_len, static_cast(rx), rx_len); +} + +static uint8_t rf_read_rf_register(uint8_t addr, rf_modules_e module) +{ + const uint8_t tx[2] = { static_cast(module), static_cast(addr) }; + uint8_t rx[3]; + rf->CS = 0; + rf_spi_exchange(tx, 2, rx, 3); + rf->CS = 1; + return rx[2]; +} + +static void rf_write_rf_register(uint8_t addr, rf_modules_e module, uint8_t data) +{ + const uint8_t tx[3] = { static_cast(0x80 | module), static_cast(addr), static_cast(data) }; + uint8_t rx[2]; + rf->CS = 0; + rf_spi_exchange(tx, 3, rx, 2); + rf->CS = 1; +} + +static void rf_write_rf_register_field(uint8_t addr, rf_modules_e module, uint8_t field, uint8_t value) +{ + uint8_t reg_tmp = rf_read_rf_register(addr, module); + reg_tmp &= ~field; + reg_tmp |= value; + rf_write_rf_register(addr, module, reg_tmp); +} + +static void rf_backup_timer_interrupt(void) +{ + receiver_enabled = false; + rf_read_common_register(RF09_IRQS); + rf_read_common_register(RF24_IRQS); + rf_read_common_register(BBC0_IRQS); + rf_read_common_register(BBC1_IRQS); + rf_irq_rf_disable(EDC, RF_09); + rf_irq_rf_disable(EDC, RF_24); + if (rf_state == RF_RX_STARTED) { + if (device_driver.phy_rf_statistics) { + device_driver.phy_rf_statistics->rx_timeouts++; + } + } else { + if (device_driver.phy_rf_statistics) { + device_driver.phy_rf_statistics->tx_timeouts++; + } + } + if (rf_state == RF_TX_STARTED) { + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_SUCCESS, 0, 0); + } + if ((rf_state == RF_CSMA_STARTED) || (rf_state == RF_CSMA_WHILE_RX)) { + TEST_CSMA_DONE + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 0, 0); + } + TEST_TX_DONE + TEST_RX_DONE + rf_state = RF_IDLE; + rf_receive(rf_rx_channel, rf_module); +} + +static void rf_backup_timer_signal(void) +{ + rf->irq_thread_215.flags_set(SIG_TIMER_BACKUP); +} + +static void rf_backup_timer_stop(void) +{ + rf->cal_timer.detach(); +} + +static uint32_t rf_backup_timer_start(uint16_t bytes, uint32_t time_us) +{ + if (!time_us) { + time_us = (uint32_t)(8000000 / phy_current_config.datarate) * bytes + PACKET_PROCESSING_TIME; + } + // Using cal_timer as backup timer + rf->cal_timer.attach_us(rf_backup_timer_signal, time_us); + + return (rf_get_timestamp() + time_us); +} + +static int rf_set_channel(uint16_t channel, rf_modules_e module) +{ + rf_write_rf_register(RF_CNL, module, (uint8_t) channel); + rf_write_rf_register_field(RF_CNM, module, CNH, (uint8_t)(channel >> 8)); + return 0; +} + +static int rf_set_ch0_frequency(uint32_t frequency, rf_modules_e module) +{ + if (module == RF_24) { + frequency -= 1500000000; + } + frequency /= 25000; + rf_write_rf_register(RF_CCF0L, module, (uint8_t)frequency); + rf_write_rf_register(RF_CCF0H, module, (uint8_t)(frequency >> 8)); + return 0; +} + +static int rf_set_channel_spacing(uint32_t channel_spacing, rf_modules_e module) +{ + channel_spacing /= 25000; + rf_write_rf_register(RF_CS, module, channel_spacing); + return 0; +} + +static int rf_set_fsk_symbol_rate_configuration(uint32_t symbol_rate, rf_modules_e module) +{ + if (symbol_rate == 50000) { + rf_write_bbc_register_field(BBC_FSKC1, module, SRATE, SRATE_50KHZ); + if (rf_version_num == 1) { + rf_write_rf_register_field(RF_TXDFE, module, SR, SR_10); + } else { + rf_write_rf_register_field(RF_TXDFE, module, SR, SR_8); + } + rf_write_rf_register_field(RF_RXDFE, module, SR, SR_10); + if (phy_current_config.modulation_index == MODULATION_INDEX_0_5) { + rf_write_rf_register_field(RF_RXDFE, module, RCUT, RCUT_0); + } else { + rf_write_rf_register_field(RF_RXDFE, module, RCUT, RCUT_1); + } + rf_write_rf_register_field(RF_TXCUTC, module, PARAMP, RF_PARAMP32U); + rf_write_rf_register_field(RF_TXCUTC, module, LPFCUT, RF_FLC80KHZ); + rf_write_rf_register_field(RF_RXBWC, module, BW, RF_BW160KHZ_IF250KHZ); + rf_write_rf_register_field(RF_RXBWC, module, IFS, 0); + } else if (symbol_rate == 100000) { + rf_write_bbc_register_field(BBC_FSKC1, module, SRATE, SRATE_100KHZ); + if (rf_version_num == 1) { + rf_write_rf_register_field(RF_TXDFE, module, SR, SR_5); + } else { + rf_write_rf_register_field(RF_TXDFE, module, SR, SR_4); + } + rf_write_rf_register_field(RF_RXDFE, module, SR, SR_5); + rf_write_rf_register_field(RF_TXCUTC, module, PARAMP, RF_PARAMP16U); + if (phy_current_config.modulation_index == MODULATION_INDEX_0_5) { + rf_write_rf_register_field(RF_RXDFE, module, RCUT, RCUT_0); + rf_write_rf_register_field(RF_TXCUTC, module, LPFCUT, RF_FLC100KHZ); + rf_write_rf_register_field(RF_RXBWC, module, BW, RF_BW200KHZ_IF250KHZ); + } else { + rf_write_rf_register_field(RF_RXDFE, module, RCUT, RCUT_1); + rf_write_rf_register_field(RF_TXCUTC, module, LPFCUT, RF_FLC160KHZ); + rf_write_rf_register_field(RF_RXBWC, module, BW, RF_BW320KHZ_IF500KHZ); + } + rf_write_rf_register_field(RF_RXBWC, module, IFS, 0); + } else if (symbol_rate == 150000) { + rf_write_bbc_register_field(BBC_FSKC1, module, SRATE, SRATE_150KHZ); + rf_write_rf_register_field(RF_TXDFE, module, SR, SR_2); + rf_write_rf_register_field(RF_RXDFE, module, SR, SR_4); + rf_write_rf_register_field(RF_TXCUTC, module, PARAMP, RF_PARAMP16U); + if (phy_current_config.modulation_index == MODULATION_INDEX_0_5) { + rf_write_rf_register_field(RF_RXDFE, module, RCUT, RCUT_0); + rf_write_rf_register_field(RF_TXCUTC, module, LPFCUT, RF_FLC160KHZ); + rf_write_rf_register_field(RF_RXBWC, module, BW, RF_BW320KHZ_IF500KHZ); + } else { + rf_write_rf_register_field(RF_RXDFE, module, RCUT, RCUT_1); + rf_write_rf_register_field(RF_TXCUTC, module, LPFCUT, RF_FLC250KHZ); + rf_write_rf_register_field(RF_RXBWC, module, BW, RF_BW400KHZ_IF500KHZ); + } + rf_write_rf_register_field(RF_RXBWC, module, IFS, 0); + } else if (symbol_rate == 200000) { + rf_write_bbc_register_field(BBC_FSKC1, module, SRATE, SRATE_200KHZ); + rf_write_rf_register_field(RF_TXDFE, module, SR, SR_2); + rf_write_rf_register_field(RF_RXDFE, module, SR, SR_4); + rf_write_rf_register_field(RF_TXCUTC, module, PARAMP, RF_PARAMP16U); + if (phy_current_config.modulation_index == MODULATION_INDEX_0_5) { + rf_write_rf_register_field(RF_RXDFE, module, RCUT, RCUT_1); + rf_write_rf_register_field(RF_TXCUTC, module, LPFCUT, RF_FLC200KHZ); + rf_write_rf_register_field(RF_RXBWC, module, BW, RF_BW320KHZ_IF500KHZ); + rf_write_rf_register_field(RF_RXBWC, module, IFS, 0); + } else { + rf_write_rf_register_field(RF_RXDFE, module, RCUT, RCUT_2); + rf_write_rf_register_field(RF_TXCUTC, module, LPFCUT, RF_FLC315KHZ); + rf_write_rf_register_field(RF_RXBWC, module, BW, RF_BW500KHZ_IF500KHZ); + rf_write_rf_register_field(RF_RXBWC, module, IFS, IFS); + } + } else if (symbol_rate == 300000) { + rf_write_bbc_register_field(BBC_FSKC1, module, SRATE, SRATE_300KHZ); + rf_write_rf_register_field(RF_TXDFE, module, SR, SR_1); + rf_write_rf_register_field(RF_RXDFE, module, SR, SR_2); + rf_write_rf_register_field(RF_TXCUTC, module, PARAMP, RF_PARAMP8U); + if (phy_current_config.modulation_index == MODULATION_INDEX_0_5) { + rf_write_rf_register_field(RF_RXDFE, module, RCUT, RCUT_0); + rf_write_rf_register_field(RF_TXCUTC, module, LPFCUT, RF_FLC315KHZ); + rf_write_rf_register_field(RF_RXBWC, module, BW, RF_BW500KHZ_IF500KHZ); + rf_write_rf_register_field(RF_RXBWC, module, IFS, IFS); + } else { + rf_write_rf_register_field(RF_RXDFE, module, RCUT, RCUT_1); + rf_write_rf_register_field(RF_TXCUTC, module, LPFCUT, RF_FLC500KHZ); + rf_write_rf_register_field(RF_RXBWC, module, BW, RF_BW630KHZ_IF1000KHZ); + rf_write_rf_register_field(RF_RXBWC, module, IFS, 0); + } + } else if (symbol_rate == 400000) { + rf_write_bbc_register_field(BBC_FSKC1, module, SRATE, SRATE_400KHZ); + rf_write_rf_register_field(RF_TXDFE, module, SR, SR_1); + rf_write_rf_register_field(RF_RXDFE, module, SR, SR_2); + rf_write_rf_register_field(RF_TXCUTC, module, PARAMP, RF_PARAMP8U); + if (phy_current_config.modulation_index == MODULATION_INDEX_0_5) { + rf_write_rf_register_field(RF_RXDFE, module, RCUT, RCUT_0); + rf_write_rf_register_field(RF_TXCUTC, module, LPFCUT, RF_FLC400KHZ); + rf_write_rf_register_field(RF_RXBWC, module, BW, RF_BW630KHZ_IF1000KHZ); + rf_write_rf_register_field(RF_RXBWC, module, IFS, 0); + } else { + rf_write_rf_register_field(RF_RXDFE, module, RCUT, RCUT_1); + rf_write_rf_register_field(RF_TXCUTC, module, LPFCUT, RF_FLC625KHZ); + rf_write_rf_register_field(RF_RXBWC, module, BW, RF_BW1000KHZ_IF1000KHZ); + rf_write_rf_register_field(RF_RXBWC, module, IFS, IFS); + } + } + return 0; +} + +static int rf_configure_by_ofdm_bandwidth_option(uint8_t option, uint32_t data_rate, rf_modules_e module) +{ + if (!option || option > 4) { + return -1; + } + uint32_t datarate_tmp = 100000 >> (option - 1); + + // Set modulation and coding scheme + if (data_rate == datarate_tmp) { + rf_write_bbc_register_field(BBC_OFDMPHRTX, module, MCS, MCS_0); + } else if (data_rate == datarate_tmp * 2) { + rf_write_bbc_register_field(BBC_OFDMPHRTX, module, MCS, MCS_1); + } else if (data_rate == datarate_tmp * 4) { + rf_write_bbc_register_field(BBC_OFDMPHRTX, module, MCS, MCS_2); + } else if (data_rate == datarate_tmp * 8) { + rf_write_bbc_register_field(BBC_OFDMPHRTX, module, MCS, MCS_3); + } else if (data_rate == datarate_tmp * 12) { + rf_write_bbc_register_field(BBC_OFDMPHRTX, module, MCS, MCS_4); + } else if (data_rate == datarate_tmp * 16) { + rf_write_bbc_register_field(BBC_OFDMPHRTX, module, MCS, MCS_5); + } else if (data_rate == datarate_tmp * 24) { + rf_write_bbc_register_field(BBC_OFDMPHRTX, module, MCS, MCS_6); + } else { + return -1; + } + if (option == 1) { + rf_write_bbc_register_field(BBC_OFDMC, module, OPT, OPT_1); + rf_write_rf_register_field(RF_TXDFE, module, SR, SR_3); + rf_write_rf_register_field(RF_RXDFE, module, SR, SR_3); + rf_write_rf_register_field(RF_TXDFE, module, RCUT, RCUT_4); + rf_write_rf_register_field(RF_RXDFE, module, RCUT, RCUT_4); + rf_write_rf_register_field(RF_TXCUTC, module, LPFCUT, RF_FLC800KHZ); + rf_write_rf_register_field(RF_RXBWC, module, BW, RF_BW1250KHZ_IF2000KHZ); + rf_write_rf_register_field(RF_RXBWC, module, IFS, IFS); + rf_write_bbc_register_field(BBC_OFDMSW, module, OFDM_PDT, OFDM_PDT_5); + } else if (option == 2) { + rf_write_bbc_register_field(BBC_OFDMC, module, OPT, OPT_2); + rf_write_rf_register_field(RF_TXDFE, module, SR, SR_3); + rf_write_rf_register_field(RF_RXDFE, module, SR, SR_3); + rf_write_rf_register_field(RF_TXDFE, module, RCUT, RCUT_3); + rf_write_rf_register_field(RF_RXDFE, module, RCUT, RCUT_2); + rf_write_rf_register_field(RF_TXCUTC, module, LPFCUT, RF_FLC500KHZ); + rf_write_rf_register_field(RF_RXBWC, module, BW, RF_BW800KHZ_IF1000KHZ); + rf_write_rf_register_field(RF_RXBWC, module, IFS, IFS); + rf_write_bbc_register_field(BBC_OFDMSW, module, OFDM_PDT, OFDM_PDT_5); + } else if (option == 3) { + rf_write_bbc_register_field(BBC_OFDMC, module, OPT, OPT_3); + rf_write_rf_register_field(RF_TXDFE, module, SR, SR_6); + rf_write_rf_register_field(RF_RXDFE, module, SR, SR_6); + rf_write_rf_register_field(RF_TXDFE, module, RCUT, RCUT_3); + rf_write_rf_register_field(RF_RXDFE, module, RCUT, RCUT_2); + rf_write_rf_register_field(RF_TXCUTC, module, LPFCUT, RF_FLC250KHZ); + rf_write_rf_register_field(RF_RXBWC, module, BW, RF_BW400KHZ_IF500KHZ); + rf_write_rf_register_field(RF_RXBWC, module, IFS, 0); + rf_write_bbc_register_field(BBC_OFDMSW, module, OFDM_PDT, OFDM_PDT_4); + } else if (option == 4) { + rf_write_bbc_register_field(BBC_OFDMC, module, OPT, OPT_4); + rf_write_rf_register_field(RF_TXDFE, module, SR, SR_6); + rf_write_rf_register_field(RF_RXDFE, module, SR, SR_6); + rf_write_rf_register_field(RF_TXDFE, module, RCUT, RCUT_2); + rf_write_rf_register_field(RF_RXDFE, module, RCUT, RCUT_1); + rf_write_rf_register_field(RF_TXCUTC, module, LPFCUT, RF_FLC160KHZ); + rf_write_rf_register_field(RF_RXBWC, module, BW, RF_BW250KHZ_IF250KHZ); + rf_write_rf_register_field(RF_RXBWC, module, IFS, 1); + rf_write_bbc_register_field(BBC_OFDMSW, module, OFDM_PDT, OFDM_PDT_3); + } + return 0; +} + +static void rf_conf_set_cca_threshold(uint8_t percent) +{ + uint8_t step = (MAX_CCA_THRESHOLD - MIN_CCA_THRESHOLD); + cca_threshold = MIN_CCA_THRESHOLD + (step * percent) / 100; +} + +static void rf_calculate_symbol_rate(uint32_t baudrate, phy_modulation_e modulation) +{ + uint8_t bits_in_symbols = 4; + if (modulation == M_2FSK) { + bits_in_symbols = 1; + } + rf_symbol_rate = baudrate / bits_in_symbols; +} + +void RFBits::rf_irq_task(void) +{ + for (;;) { + uint32_t flags = ThisThread::flags_wait_any(SIG_ALL); + rf_lock(); + if (flags & SIG_RADIO) { + rf_irq_task_process_irq(); + } + if (flags & SIG_TIMER_CCA) { + rf_csma_ca_timer_interrupt(); + } + if (flags & SIG_TIMER_BACKUP) { + rf_backup_timer_interrupt(); + } + rf_unlock(); + } +} + +int RFBits::init_215_driver(RFBits *_rf, TestPins *_test_pins, const uint8_t mac[8], uint8_t *rf_part_num) +{ + rf = _rf; + test_pins = _test_pins; + irq_thread_215.start(mbed::callback(this, &RFBits::rf_irq_task)); + rf->spi.frequency(25000000); + /* Atmel AT86RF215 Device Family datasheet: + * Errata #9: RF215M device has a wrong part number + * Description: + * The RF215M device part number is 0x34 instead of 0x36 (register RF_PN.PN). + */ +#if !defined(HAVE_AT86RF215M) + *rf_part_num = rf_read_common_register(RF_PN); +#else + *rf_part_num = PART_AT86RF215M; + // AT86RF215M is Sub-GHz only transceiver. Change default settings. + rf_module = RF_09; + mac_mode = IEEE_802_15_4G_2012; +#endif + rf_version_num = rf_read_common_register(RF_VN); + tr_info("RF version number: %x", rf_version_num); + return rf_device_register(mac); +} + +int RFBits::init_se2435_pa(Se2435Pins *_se2435_pa_pins) +{ + se2435_pa_pins = _se2435_pa_pins; + return 0; +} + +#endif // MBED_CONF_NANOSTACK_CONFIGURATION && DEVICE_SPI && DEVICE_INTERRUPTIN && defined(MBED_CONF_RTOS_PRESENT) diff --git a/connectivity/drivers/802.15.4_RF/atmel-rf-driver/source/NanostackRfPhyAtmel.cpp b/connectivity/drivers/802.15.4_RF/atmel-rf-driver/source/NanostackRfPhyAtmel.cpp new file mode 100644 index 0000000000..ef3ce7f447 --- /dev/null +++ b/connectivity/drivers/802.15.4_RF/atmel-rf-driver/source/NanostackRfPhyAtmel.cpp @@ -0,0 +1,2311 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include + +#if defined(MBED_CONF_NANOSTACK_CONFIGURATION) && DEVICE_SPI && DEVICE_INTERRUPTIN && DEVICE_I2C && defined(MBED_CONF_RTOS_PRESENT) + +#include "platform/arm_hal_interrupt.h" +#include "nanostack/platform/arm_hal_phy.h" +#include "ns_types.h" +#include "NanostackRfPhyAtmel.h" +#include "randLIB.h" +#include "AT86RFReg.h" +#include "AT86RF215Reg.h" +#include "nanostack/platform/arm_hal_phy.h" +#include "mbed_trace.h" +#include "mbed_toolchain.h" +#include "DigitalIn.h" +#include "DigitalOut.h" +#include "InterruptIn.h" +#include "SPI.h" +#include "inttypes.h" +#include "Timeout.h" +#include "platform/mbed_error.h" + +#define TRACE_GROUP "AtRF" + +/*Worst case sensitivity*/ +#define RF_DEFAULT_SENSITIVITY -88 +/*Run calibration every 5 minutes*/ +#define RF_CALIBRATION_INTERVAL 6000000 +/*Wait ACK for 2.5ms*/ +#define RF_ACK_WAIT_DEFAULT_TIMEOUT 50 +/*Base CCA backoff (50us units) - substitutes for Inter-Frame Spacing*/ +#define RF_CCA_BASE_BACKOFF 13 /* 650us */ +/*CCA random backoff (50us units)*/ +#define RF_CCA_RANDOM_BACKOFF 51 /* 2550us */ + +#define RF_MTU 127 + +#define RF_PHY_MODE OQPSK_SIN_250 + +/*Radio RX and TX state definitions*/ +#define RFF_ON 0x01 +#define RFF_RX 0x02 +#define RFF_TX 0x04 +#define RFF_CCA 0x08 + +namespace { + +typedef enum { + RF_MODE_NORMAL = 0, + RF_MODE_SNIFFER = 1, + RF_MODE_ED = 2 +} rf_mode_t; + +/*Atmel RF Part Type*/ +typedef enum { + ATMEL_UNKNOW_DEV = 0, + ATMEL_AT86RF212, + ATMEL_AT86RF231, // No longer supported (doesn't give ED+status on frame read) + ATMEL_AT86RF233 +} rf_trx_part_e; + +/*Atmel RF states*/ +typedef enum { + NOP = 0x00, + BUSY_RX = 0x01, + BUSY_TX = 0x02, + RF_TX_START = 0x02, + FORCE_TRX_OFF = 0x03, + FORCE_PLL_ON = 0x04, + RX_ON = 0x06, + TRX_OFF = 0x08, + PLL_ON = 0x09, + BUSY_RX_AACK = 0x11, + SLEEP = 0x0F, + RX_AACK_ON = 0x16, + TX_ARET_ON = 0x19, + STATE_TRANSITION_IN_PROGRESS = 0x1F +} rf_trx_states_t; + +} // anonymous namespace + +static const uint8_t *rf_tx_data; // Points to Nanostack's buffer +static uint8_t rf_tx_length; +/*ACK wait duration changes depending on data rate*/ +static uint16_t rf_ack_wait_duration = RF_ACK_WAIT_DEFAULT_TIMEOUT; + +static int8_t rf_sensitivity = RF_DEFAULT_SENSITIVITY; +static rf_mode_t rf_mode = RF_MODE_NORMAL; +static uint8_t radio_tx_power = 0x00; // Default to +4dBm +static uint8_t rf_phy_channel = 12; +static uint8_t rf_tuned = 1; +static uint8_t rf_use_antenna_diversity = 0; +static int16_t expected_ack_sequence = -1; +static uint8_t rf_rx_mode = 0; +static uint8_t rf_flags = 0; +static int8_t rf_radio_driver_id = -1; +static phy_device_driver_s device_driver; +static uint8_t mac_tx_handle = 0; +static uint8_t xah_ctrl_1; + +/* Channel configurations for 2.4 and sub-GHz */ +static const phy_rf_channel_configuration_s phy_24ghz = {.channel_0_center_frequency = 2405000000U, .channel_spacing = 5000000U, .datarate = 250000U, .number_of_channels = 16U, .modulation = M_OQPSK}; +static const phy_rf_channel_configuration_s phy_subghz = {.channel_0_center_frequency = 868300000U, .channel_spacing = 2000000U, .datarate = 250000U, .number_of_channels = 11U, .modulation = M_OQPSK}; + +static const phy_device_channel_page_s phy_channel_pages[] = { + { CHANNEL_PAGE_0, &phy_24ghz}, + { CHANNEL_PAGE_2, &phy_subghz}, + { CHANNEL_PAGE_0, NULL} +}; + +/** + * RF output power write + * + * \brief TX power has to be set before network start. + * + * \param power + * AT86RF233 + * 0 = 4 dBm + * 1 = 3.7 dBm + * 2 = 3.4 dBm + * 3 = 3 dBm + * 4 = 2.5 dBm + * 5 = 2 dBm + * 6 = 1 dBm + * 7 = 0 dBm + * 8 = -1 dBm + * 9 = -2 dBm + * 10 = -3 dBm + * 11 = -4 dBm + * 12 = -6 dBm + * 13 = -8 dBm + * 14 = -12 dBm + * 15 = -17 dBm + * + * AT86RF212B + * See datasheet for TX power settings + * + * \return 0, Supported Value + * \return -1, Not Supported Value + */ +static rf_trx_part_e rf_radio_type_read(void); +static void rf_ack_wait_timer_start(uint16_t slots); +static void rf_handle_cca_ed_done(uint8_t full_trx_status); +static void rf_handle_tx_end(rf_trx_states_t trx_status); +static void rf_handle_rx_end(rf_trx_states_t trx_status); +static void rf_on(void); +static void rf_give_up_on_ack(void); +static void rf_receive(rf_trx_states_t trx_status = STATE_TRANSITION_IN_PROGRESS); +static rf_trx_states_t rf_poll_trx_state_change(rf_trx_states_t trx_state); +static void rf_init(void); +static int8_t rf_device_register(const uint8_t *mac_addr); +static void rf_device_unregister(void); +static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol); +static void rf_cca_abort(void); +static void rf_calibration_cb(void); +static void rf_init_phy_mode(void); +static void rf_ack_wait_timer_interrupt(void); +static void rf_calibration_timer_interrupt(void); +static void rf_calibration_timer_start(uint32_t slots); +static void rf_cca_timer_interrupt(void); +static void rf_cca_timer_start(uint32_t slots); +static uint8_t rf_scale_lqi(int8_t rssi); + +static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel); +static int8_t rf_extension(phy_extension_type_e extension_type, uint8_t *data_ptr); +static int8_t rf_address_write(phy_address_type_e address_type, uint8_t *address_ptr); + +static void rf_if_cca_timer_start(uint32_t slots); +static void rf_if_enable_promiscuous_mode(void); +static void rf_if_lock(void); +static void rf_if_unlock(void); +static uint8_t rf_if_read_rnd(void); +static void rf_if_calibration_timer_start(uint32_t slots); +static void rf_if_interrupt_handler(void); +static void rf_if_ack_wait_timer_start(uint16_t slots); +static void rf_if_ack_wait_timer_stop(void); +static void rf_if_ack_pending_ctrl(uint8_t state); +static void rf_if_calibration(void); +static uint8_t rf_if_read_register(uint8_t addr); +static void rf_if_set_bit(uint8_t addr, uint8_t bit, uint8_t bit_mask); +static void rf_if_clear_bit(uint8_t addr, uint8_t bit); +static void rf_if_write_register(uint8_t addr, uint8_t data); +static void rf_if_reset_radio(void); +static void rf_if_enable_ant_div(void); +static void rf_if_disable_ant_div(void); +static void rf_if_enable_slptr(void); +static void rf_if_disable_slptr(void); +static void rf_if_write_antenna_diversity_settings(void); +static void rf_if_write_set_tx_power_register(uint8_t value); +static void rf_if_write_rf_settings(void); +static rf_trx_states_t rf_if_read_trx_state(void); +static uint16_t rf_if_read_packet(uint8_t data[RF_MTU], uint8_t *lqi_out, uint8_t *ed_out, bool *crc_good); +static void rf_if_write_short_addr_registers(uint8_t *short_address); +static uint8_t rf_if_last_acked_pending(void); +static void rf_if_write_pan_id_registers(uint8_t *pan_id); +static void rf_if_write_ieee_addr_registers(uint8_t *address); +static void rf_if_write_frame_buffer(const uint8_t *ptr, uint8_t length); +static rf_trx_states_t rf_if_change_trx_state(rf_trx_states_t trx_state); +static void rf_if_start_cca_process(void); +static int8_t rf_if_scale_rssi(uint8_t ed_level); +static void rf_if_set_channel_register(uint8_t channel); +static void rf_if_enable_promiscuous_mode(void); +static void rf_if_disable_promiscuous_mode(void); +static uint8_t rf_if_read_part_num(void); +static void rf_if_enable_irq(void); +static void rf_if_disable_irq(void); +static void rf_if_spi_exchange_n(const void *tx, size_t tx_len, void *rx, size_t rx_len); + +static inline rf_trx_states_t rf_if_trx_status_from_full(uint8_t full_trx_status) +{ + return (rf_trx_states_t)(full_trx_status & 0x1F); +} + +#ifdef MBED_CONF_RTOS_PRESENT + +#include "rtos.h" + +using namespace mbed; +using namespace rtos; + +static void rf_if_irq_task_process_irq(); + +#define SIG_RADIO 1 +#define SIG_TIMER_ACK 2 +#define SIG_TIMER_CAL 4 +#define SIG_TIMER_CCA 8 + +#define SIG_TIMERS (SIG_TIMER_ACK|SIG_TIMER_CAL|SIG_TIMER_CCA) +#define SIG_ALL (SIG_RADIO|SIG_TIMERS) +#endif + +// HW pins to RF chip +#include "rfbits.h" + + +RFBits::RFBits(PinName spi_mosi, PinName spi_miso, + PinName spi_sclk, PinName spi_cs, + PinName spi_rst, PinName spi_slp, PinName spi_irq) + : spi(spi_mosi, spi_miso, spi_sclk), + CS(spi_cs), + RST(spi_rst), + SLP_TR(spi_slp), + IRQ(spi_irq) +#ifdef MBED_CONF_RTOS_PRESENT + , irq_thread(osPriorityRealtime, MBED_CONF_ATMEL_RF_IRQ_THREAD_STACK_SIZE, NULL, "atmel_irq_thread"), + irq_thread_215(osPriorityRealtime, MBED_CONF_ATMEL_RF_IRQ_THREAD_STACK_SIZE, NULL, "atmel_215_irq_thread") +#endif +{ +#ifdef MBED_CONF_RTOS_PRESENT + irq_thread.start(mbed::callback(this, &RFBits::rf_if_irq_task)); +#endif +} + +TestPins::TestPins(PinName test_pin_1, PinName test_pin_2, PinName test_pin_3, PinName test_pin_4, PinName test_pin_5) + : TEST1(test_pin_1), + TEST2(test_pin_2), + TEST3(test_pin_3), + TEST4(test_pin_4), + TEST5(test_pin_5) +{ +} + +Se2435Pins::Se2435Pins(PinName csd_pin, PinName ant_sel_pin) + : CSD(csd_pin), + ANT_SEL(ant_sel_pin) +{ +} + +static RFBits *rf; +static TestPins *test_pins; +static Se2435Pins *se2435_pa_pins; +static uint8_t rf_part_num = 0; +/*TODO: RSSI Base value setting*/ +static int8_t rf_rssi_base_val = -91; + +static void rf_if_lock(void) +{ + platform_enter_critical(); +} + +static void rf_if_unlock(void) +{ + platform_exit_critical(); +} + +#ifdef MBED_CONF_RTOS_PRESENT +static void rf_if_cca_timer_signal(void) +{ + rf->irq_thread.flags_set(SIG_TIMER_CCA); +} + +static void rf_if_cal_timer_signal(void) +{ + rf->irq_thread.flags_set(SIG_TIMER_CAL); +} + +static void rf_if_ack_timer_signal(void) +{ + rf->irq_thread.flags_set(SIG_TIMER_ACK); +} +#endif + +// t1 = 180ns, SEL falling edge to MISO active [SPI setup assumed slow enough to not need manual delay] +#define CS_SELECT() {rf->CS = 0; /* delay_ns(180); */} +// t9 = 250ns, last clock to SEL rising edge, t8 = 250ns, SPI idle time between consecutive access +#define CS_RELEASE() {wait_ns(250); rf->CS = 1; wait_ns(250);} + +/* + * \brief Read connected radio part. + * + * This function only return valid information when rf_init() is called + * + * \return + */ +static rf_trx_part_e rf_radio_type_read(void) +{ + rf_trx_part_e ret_val = ATMEL_UNKNOW_DEV; + + switch (rf_part_num) { + case PART_AT86RF212: + ret_val = ATMEL_AT86RF212; + break; + case PART_AT86RF233: + ret_val = ATMEL_AT86RF233; + break; + default: + break; + } + + return ret_val; +} + + +/* + * \brief Function starts the ACK wait timeout. + * + * \param slots Given slots, resolution 50us + * + * \return none + */ +static void rf_if_ack_wait_timer_start(uint16_t slots) +{ +#ifdef MBED_CONF_RTOS_PRESENT + rf->ack_timer.attach_us(rf_if_ack_timer_signal, slots * 50); +#else + rf->ack_timer.attach_us(rf_ack_wait_timer_interrupt, slots * 50); +#endif +} + +/* + * \brief Function starts the calibration interval. + * + * \param slots Given slots, resolution 50us + * + * \return none + */ +static void rf_if_calibration_timer_start(uint32_t slots) +{ +#ifdef MBED_CONF_RTOS_PRESENT + rf->cal_timer.attach_us(rf_if_cal_timer_signal, slots * 50); +#else + rf->cal_timer.attach_us(rf_calibration_timer_interrupt, slots * 50); +#endif +} + +/* + * \brief Function starts the CCA interval. + * + * \param slots Given slots, resolution 50us + * + * \return none + */ +static void rf_if_cca_timer_start(uint32_t slots) +{ +#ifdef MBED_CONF_RTOS_PRESENT + rf->cca_timer.attach_us(rf_if_cca_timer_signal, slots * 50); +#else + rf->cca_timer.attach_us(rf_cca_timer_interrupt, slots * 50); +#endif +} + +/* + * \brief Function stops the CCA interval. + * + * \return none + */ +static void rf_if_cca_timer_stop(void) +{ + rf->cca_timer.detach(); +} + +/* + * \brief Function stops the ACK wait timeout. + * + * \param none + * + * \return none + */ +static void rf_if_ack_wait_timer_stop(void) +{ + rf->ack_timer.detach(); +} + +/* + * \brief Function sets bit(s) in given RF register. + * + * \param addr Address of the register to set + * \param bit Bit(s) to set + * \param bit_mask Masks the field inside the register + * + * \return none + */ +static void rf_if_set_bit(uint8_t addr, uint8_t bit, uint8_t bit_mask) +{ + uint8_t reg = rf_if_read_register(addr); + reg &= ~bit_mask; + reg |= bit; + rf_if_write_register(addr, reg); +} + +/* + * \brief Function clears bit(s) in given RF register. + * + * \param addr Address of the register to clear + * \param bit Bit(s) to clear + * + * \return none + */ +static void rf_if_clear_bit(uint8_t addr, uint8_t bit) +{ + rf_if_set_bit(addr, 0, bit); +} + +/* + * \brief Function writes register in RF. + * + * \param addr Address on the RF + * \param data Written data + * + * \return none + */ +static void rf_if_write_register(uint8_t addr, uint8_t data) +{ + const uint8_t tx[2] = { static_cast(0xC0 | addr), data }; + uint8_t rx[2]; + CS_SELECT(); + rf_if_spi_exchange_n(tx, 2, rx, 2); + CS_RELEASE(); +} + +/* + * \brief Function reads RF register, and also outputs PHY_STATUS + * + * \param addr Address on the RF + * \param[out] status_out Pointer to store PHY_STATUS + * + * \return Read register data + */ +static uint8_t rf_if_read_register_with_status(uint8_t addr, uint8_t *status_out) +{ + const uint8_t tx[1] = { static_cast(0x80 | addr) }; + uint8_t rx[2]; + CS_SELECT(); + rf_if_spi_exchange_n(tx, 1, rx, 2); + CS_RELEASE(); + if (status_out) { + *status_out = rx[0]; + } + return rx[1]; +} + +/* + * \brief Function reads RF register. + * + * \param addr Address on the RF + * + * \return Read register data + */ +static uint8_t rf_if_read_register(uint8_t addr) +{ + return rf_if_read_register_with_status(addr, NULL); +} + +/* + * \brief Function resets the RF. + * + * \param none + * + * \return none + */ +static void rf_if_reset_radio(void) +{ +#if MBED_CONF_ATMEL_RF_USE_SPI_SPACING_API + rf->spi.frequency(MBED_CONF_ATMEL_RF_FULL_SPI_SPEED); + int spacing = rf->spi.write_spacing(MBED_CONF_ATMEL_RF_FULL_SPI_SPEED_BYTE_SPACING); + if (spacing < MBED_CONF_ATMEL_RF_FULL_SPI_SPEED_BYTE_SPACING) { + rf->spi.frequency(MBED_CONF_ATMEL_RF_LOW_SPI_SPEED); + rf->spi.write_spacing(0); + } +#elif MBED_CONF_ATMEL_RF_ASSUME_SPACED_SPI + rf->spi.frequency(MBED_CONF_ATMEL_RF_FULL_SPI_SPEED); +#else + rf->spi.frequency(MBED_CONF_ATMEL_RF_LOW_SPI_SPEED); +#endif + rf->IRQ.rise(nullptr); + rf->RST = 1; + ThisThread::sleep_for(2); + rf->RST = 0; + ThisThread::sleep_for(10); + CS_RELEASE(); + rf->SLP_TR = 0; + ThisThread::sleep_for(10); + rf->RST = 1; + ThisThread::sleep_for(10); + + rf->IRQ.rise(&rf_if_interrupt_handler); +} + +/* + * \brief Function enables the promiscuous mode. + * + * \param none + * + * \return none + */ +static void rf_if_enable_promiscuous_mode(void) +{ + if (!(xah_ctrl_1 & AACK_PROM_MODE)) { + /*Set AACK_PROM_MODE to enable the promiscuous mode*/ + rf_if_write_register(XAH_CTRL_1, xah_ctrl_1 |= AACK_PROM_MODE); + } +} + +/* + * \brief Function disable the promiscuous mode. + * + * \param none + * + * \return none + */ +static void rf_if_disable_promiscuous_mode(void) +{ + if (xah_ctrl_1 & AACK_PROM_MODE) { + /*Clear AACK_PROM_MODE to disable the promiscuous mode*/ + rf_if_write_register(XAH_CTRL_1, xah_ctrl_1 &= ~AACK_PROM_MODE); + } +} + +/* + * \brief Function enables the Antenna diversity usage. + * + * \param none + * + * \return none + */ +static void rf_if_enable_ant_div(void) +{ + /*Set ANT_EXT_SW_EN to enable controlling of antenna diversity*/ + rf_if_set_bit(ANT_DIV, ANT_EXT_SW_EN, ANT_EXT_SW_EN); +} + +/* + * \brief Function disables the Antenna diversity usage. + * + * \param none + * + * \return none + */ +static void rf_if_disable_ant_div(void) +{ + rf_if_clear_bit(ANT_DIV, ANT_EXT_SW_EN); +} + +/* + * \brief Function sets the SLP TR pin. + * + * \param none + * + * \return none + */ +static void rf_if_enable_slptr(void) +{ + rf->SLP_TR = 1; +} + +/* + * \brief Function clears the SLP TR pin. + * + * \param none + * + * \return none + */ +static void rf_if_disable_slptr(void) +{ + rf->SLP_TR = 0; +} + +/* + * \brief Function writes the antenna diversity settings. + * + * \param none + * + * \return none + */ +static void rf_if_write_antenna_diversity_settings(void) +{ + /*Recommended setting of PDT_THRES is 3 when antenna diversity is used*/ + rf_if_set_bit(RX_CTRL, 0x03, 0x0f); + rf_if_write_register(ANT_DIV, ANT_DIV_EN | ANT_EXT_SW_EN | ANT_CTRL_DEFAULT); +} + +/* + * \brief Function writes the TX output power register. + * + * \param value Given register value + * + * \return none + */ +static void rf_if_write_set_tx_power_register(uint8_t value) +{ + rf_if_write_register(PHY_TX_PWR, value); +} + +/* + * \brief Function returns the RF part number. + * + * \param none + * + * \return part number + */ +static uint8_t rf_if_read_part_num(void) +{ + // Part number is already set + if (rf_part_num) { + return rf_part_num; + } + return rf_if_read_register(PART_NUM); +} + +/* + * \brief Function writes the RF settings and initialises SPI interface. + * + * \param none + * + * \return none + */ +static void rf_if_write_rf_settings(void) +{ + rf_part_num = rf_if_read_part_num(); + + rf_if_write_register(XAH_CTRL_0, 0); + + /* Auto CRC on, IRQ status shows unmasked only, TRX_STATUS output on all accesses */ + rf_if_write_register(TRX_CTRL_1, TX_AUTO_CRC_ON | SPI_CMD_MODE_TRX_STATUS); + + rf_if_write_register(IRQ_MASK, CCA_ED_DONE | TRX_END | TRX_UR); +#ifdef TEST_GPIOS_ENABLED + rf_if_set_bit(IRQ_MASK, RX_START, RX_START); +#endif + xah_ctrl_1 = rf_if_read_register(XAH_CTRL_1); + + /*Read transceiver PART_NUM*/ + rf_part_num = rf_if_read_register(PART_NUM); + + /*Sub-GHz RF settings*/ + if (rf_part_num == PART_AT86RF212) { + /*GC_TX_OFFS mode-dependent setting - OQPSK*/ + rf_if_write_register(RF_CTRL_0, 0x32); + + if (rf_if_read_register(VERSION_NUM) == VERSION_AT86RF212B) { + /*TX Output Power setting - 0 dBm North American Band*/ + rf_if_write_register(PHY_TX_PWR, 0x03); + } else { + /*TX Output Power setting - 0 dBm North American Band*/ + rf_if_write_register(PHY_TX_PWR, 0x24); + } + + /*PHY Mode: IEEE 802.15.4-2006/2011 - OQPSK-SIN-250*/ + rf_if_write_register(TRX_CTRL_2, RX_SAFE_MODE | RF_PHY_MODE); + /*Based on receiver Characteristics. See AT86RF212B Datasheet where RSSI BASE VALUE in range -97 - -100 dBm*/ + rf_rssi_base_val = -98; + } + /*2.4GHz RF settings*/ + else { +#if 0 + /* Disable power saving functions for now - can only impact reliability, + * and don't have any users demanding it. */ + /*Set RPC register*/ + rf_if_write_register(TRX_RPC, RX_RPC_CTRL | RX_RPC_EN | PLL_RPC_EN | XAH_TX_RPC_EN | IPAN_RPC_EN | TRX_RPC_RSVD_1); +#endif + /*PHY Mode: IEEE 802.15.4 - Data Rate 250 kb/s*/ + rf_if_write_register(TRX_CTRL_2, RX_SAFE_MODE); + rf_rssi_base_val = -91; + } +} + +/* + * \brief Function returns the RF state + * + * \param none + * + * \return RF state + */ +static rf_trx_states_t rf_if_read_trx_state(void) +{ + return rf_if_trx_status_from_full(rf_if_read_register(TRX_STATUS)); +} + +/* + * \brief Function reads packet buffer. + * + * \param data_out Output buffer + * \param lqi_out LQI output + * \param ed_out ED output + * \param crc_good CRC good indication + * + * \return PSDU length [0..RF_MTU] + */ +static uint16_t rf_if_read_packet(uint8_t data_out[RF_MTU], uint8_t *lqi_out, uint8_t *ed_out, bool *crc_good) +{ + CS_SELECT(); + const uint8_t tx[1] = { 0x20 }; + uint8_t rx[3]; + rf_if_spi_exchange_n(tx, 1, rx, 2); + uint8_t len = rx[1] & 0x7F; + rf_if_spi_exchange_n(NULL, 0, data_out, len); + rf_if_spi_exchange_n(NULL, 0, rx, 3); + *lqi_out = rx[0]; + *ed_out = rx[1]; + *crc_good = rx[2] & 0x80; + CS_RELEASE(); + + return len; +} + +/* + * \brief Function writes RF short address registers + * + * \param short_address Given short address + * + * \return none + */ +static void rf_if_write_short_addr_registers(uint8_t *short_address) +{ + rf_if_write_register(SHORT_ADDR_1, *short_address++); + rf_if_write_register(SHORT_ADDR_0, *short_address); +} + +/* + * \brief Function sets the frame pending in ACK message + * + * \param state Given frame pending state + * + * \return none + */ +static void rf_if_ack_pending_ctrl(uint8_t state) +{ + rf_if_lock(); + if (state) { + rf_if_set_bit(CSMA_SEED_1, (1 << AACK_SET_PD), (1 << AACK_SET_PD)); + } else { + rf_if_clear_bit(CSMA_SEED_1, (1 << AACK_SET_PD)); + } + rf_if_unlock(); +} + +/* + * \brief Function returns the state of frame pending control + * + * \param none + * + * \return Frame pending state + */ +static uint8_t rf_if_last_acked_pending(void) +{ + uint8_t last_acked_data_pending; + + rf_if_lock(); + if (rf_if_read_register(CSMA_SEED_1) & (1 << AACK_SET_PD)) { + last_acked_data_pending = 1; + } else { + last_acked_data_pending = 0; + } + rf_if_unlock(); + + return last_acked_data_pending; +} + +/* + * \brief Function calibrates the RF part. + * + * \param none + * + * \return none + */ +static void rf_if_calibration(void) +{ + rf_if_set_bit(FTN_CTRL, FTN_START, FTN_START); + /*Wait while calibration is running*/ + while (rf_if_read_register(FTN_CTRL) & FTN_START); +} + +/* + * \brief Function writes RF PAN Id registers + * + * \param pan_id Given PAN Id + * + * \return none + */ +static void rf_if_write_pan_id_registers(uint8_t *pan_id) +{ + rf_if_write_register(PAN_ID_1, *pan_id++); + rf_if_write_register(PAN_ID_0, *pan_id); +} + +/* + * \brief Function writes RF IEEE Address registers + * + * \param address Given IEEE Address + * + * \return none + */ +static void rf_if_write_ieee_addr_registers(uint8_t *address) +{ + uint8_t i; + uint8_t temp = IEEE_ADDR_0; + + for (i = 0; i < 8; i++) { + rf_if_write_register(temp++, address[7 - i]); + } +} + +/* + * \brief Function writes data in RF frame buffer. + * + * \param ptr Pointer to data (PSDU, except FCS) + * \param length Pointer to length (PSDU length, minus 2 for FCS) + * + * \return none + */ +static void rf_if_write_frame_buffer(const uint8_t *ptr, uint8_t length) +{ + const uint8_t cmd[2] = { 0x60, static_cast(length + 2) }; + + CS_SELECT(); + rf_if_spi_exchange_n(cmd, 2, NULL, 0); + rf_if_spi_exchange_n(ptr, length, NULL, 0); + CS_RELEASE(); +} + +/* + * \brief Function returns 8-bit random value. + * + * \param none + * + * \return random value + */ +static uint8_t rf_if_read_rnd(void) +{ + uint8_t temp; + uint8_t tmp_rpc_val = 0; + /*RPC must be disabled while reading the random number*/ + if (rf_part_num == PART_AT86RF233) { + tmp_rpc_val = rf_if_read_register(TRX_RPC); + rf_if_write_register(TRX_RPC, RX_RPC_CTRL | TRX_RPC_RSVD_1); + } + + + wait_ns(1000); + temp = ((rf_if_read_register(PHY_RSSI) >> 5) << 6); + wait_ns(1000); + temp |= ((rf_if_read_register(PHY_RSSI) >> 5) << 4); + wait_ns(1000); + temp |= ((rf_if_read_register(PHY_RSSI) >> 5) << 2); + wait_ns(1000); + temp |= ((rf_if_read_register(PHY_RSSI) >> 5)); + wait_ns(1000); + if (rf_part_num == PART_AT86RF233) { + rf_if_write_register(TRX_RPC, tmp_rpc_val); + } + return temp; +} + +/* + * \brief Function changes the state of the RF. + * + * \param trx_state Given RF state + * + * \return none + */ +static rf_trx_states_t rf_if_change_trx_state(rf_trx_states_t trx_state) +{ + rf_if_write_register(TRX_STATE, trx_state); + /*Wait while not in desired state*/ + return rf_poll_trx_state_change(trx_state); +} + +/* + * \brief Function starts the CCA process + * + * \param none + * + * \return none + */ +static void rf_if_start_cca_process(void) +{ + rf_if_write_register(PHY_CC_CCA, CCA_REQUEST | CCA_MODE_3A | rf_phy_channel); +} + +/* + * \brief Function scales RSSI + * + * \param ed_level ED level read from chip + * + * \return appropriately scaled RSSI dBm + */ +static int8_t rf_if_scale_rssi(uint8_t ed_level) +{ + if (rf_part_num == PART_AT86RF212) { + /* Data sheet says to multiply by 1.03 - this is 1.03125, rounding down */ + ed_level += ed_level >> 5; + } + return rf_rssi_base_val + ed_level; +} + +/* + * \brief Function sets the RF channel field + * + * \param Given channel + * + * \return none + */ +static void rf_if_set_channel_register(uint8_t channel) +{ + rf_if_set_bit(PHY_CC_CCA, channel, CCA_CHANNEL_MASK); +} + +/* + * \brief Function enables RF irq pin interrupts in RF interface. + * + * \param none + * + * \return none + */ +static void rf_if_enable_irq(void) +{ + rf->IRQ.enable_irq(); +} + +/* + * \brief Function disables RF irq pin interrupts in RF interface. + * + * \param none + * + * \return none + */ +static void rf_if_disable_irq(void) +{ + rf->IRQ.disable_irq(); +} + +#ifdef MBED_CONF_RTOS_PRESENT +static void rf_if_interrupt_handler(void) +{ + rf->irq_thread.flags_set(SIG_RADIO); +} + +// Started during construction of rf, so variable +// rf isn't set at the start. Uses 'this' instead. +void RFBits::rf_if_irq_task(void) +{ + for (;;) { + uint32_t flags = ThisThread::flags_wait_any(SIG_ALL); + rf_if_lock(); + if (flags & SIG_RADIO) { + rf_if_irq_task_process_irq(); + } + if (flags & SIG_TIMER_ACK) { + rf_ack_wait_timer_interrupt(); + } + if (flags & SIG_TIMER_CCA) { + rf_cca_timer_interrupt(); + } + if (flags & SIG_TIMER_CAL) { + rf_calibration_timer_interrupt(); + } + rf_if_unlock(); + } +} + +static void rf_if_irq_task_process_irq(void) +#else +/* + * \brief Function is a RF interrupt vector. End of frame in RX and TX are handled here as well as CCA process interrupt. + * + * \param none + * + * \return none + */ +static void rf_if_interrupt_handler(void) +#endif +{ + uint8_t irq_status, full_trx_status; + + /*Read and clear interrupt flag, and pick up trx_status*/ + irq_status = rf_if_read_register_with_status(IRQ_STATUS, &full_trx_status); + +#ifdef TEST_GPIOS_ENABLED + if (irq_status & RX_START) { + TEST_RX_STARTED + } +#endif + /*Frame end interrupt (RX and TX)*/ + if (irq_status & TRX_END) { + rf_trx_states_t trx_status = rf_if_trx_status_from_full(full_trx_status); + if (rf_flags & RFF_TX) { + rf_handle_tx_end(trx_status); + } else if (rf_flags & RFF_RX) { + rf_handle_rx_end(trx_status); + } else { + //something went really wrong + } + } + if (irq_status & CCA_ED_DONE) { + rf_handle_cca_ed_done(full_trx_status); + } + if (irq_status & TRX_UR) { + // Here some counter could be used to monitor the under run occurrence count. + // Do not print anything here! + } +} + +/* + * \brief Function writes/read data in SPI interface + */ +static void rf_if_spi_exchange_n(const void *tx, size_t tx_len, void *rx, size_t rx_len) +{ +#if 1 + rf->spi.write(static_cast(tx), tx_len, + static_cast(rx), rx_len); +#else + const uint8_t *txb = static_cast(tx); + uint8_t *rxb = static_cast(rx); + while (tx_len > 0 || rx_len > 0) { + uint8_t b; + if (tx_len) { + tx_len--; + b = *txb++; + } else { + b = 0xFF; + } + b = rf->spi.write(b); + if (rx_len) { + rx_len--; + *rxb++ = b; + } + } +#endif +} + +/* + * \brief Function sets given RF flag on. + * + * \param x Given RF flag + * + * \return none + */ +static void rf_flags_set(uint8_t x) +{ + rf_flags |= x; +} + +/* + * \brief Function clears given RF flag on. + * + * \param x Given RF flag + * + * \return none + */ +static void rf_flags_clear(uint8_t x) +{ + rf_flags &= ~x; +} + +/* + * \brief Function checks if given RF flag is on. + * + * \param x Given RF flag + * + * \return states of the given flags + */ +static uint8_t rf_flags_check(uint8_t x) +{ + return (rf_flags & x); +} + +/* + * \brief Function clears all RF flags. + * + * \param none + * + * \return none + */ +static void rf_flags_reset(void) +{ + rf_flags = 0; +} + +/* + * \brief Function initialises and registers the RF driver. + * + * \param none + * + * \return rf_radio_driver_id Driver ID given by NET library + */ +static int8_t rf_device_register(const uint8_t *mac_addr) +{ + rf_trx_part_e radio_type; + + rf_init(); + + radio_type = rf_radio_type_read(); + if (radio_type != ATMEL_UNKNOW_DEV) { + /*Set pointer to MAC address*/ + device_driver.PHY_MAC = (uint8_t *)mac_addr; + device_driver.driver_description = (char *)"ATMEL_MAC"; + //Create setup Used Radio chips + if (radio_type == ATMEL_AT86RF212) { + device_driver.link_type = PHY_LINK_15_4_SUBGHZ_TYPE; + } else { + device_driver.link_type = PHY_LINK_15_4_2_4GHZ_TYPE; + } + device_driver.phy_channel_pages = phy_channel_pages; + /*Maximum size of payload is 127*/ + device_driver.phy_MTU = 127; + /*No header in PHY*/ + device_driver.phy_header_length = 0; + /*No tail in PHY*/ + device_driver.phy_tail_length = 0; + /*Set address write function*/ + device_driver.address_write = &rf_address_write; + /*Set RF extension function*/ + device_driver.extension = &rf_extension; + /*Set RF state control function*/ + device_driver.state_control = &rf_interface_state_control; + /*Set transmit function*/ + device_driver.tx = &rf_start_cca; + /*NULLIFY rx and tx_done callbacks*/ + device_driver.phy_rx_cb = NULL; + device_driver.phy_tx_done_cb = NULL; + /*Register device driver*/ + rf_radio_driver_id = arm_net_phy_register(&device_driver); + } else { + rf_if_disable_irq(); + } + return rf_radio_driver_id; +} + +/* + * \brief Function unregisters the RF driver. + * + * \param none + * + * \return none + */ +static void rf_device_unregister() +{ + if (rf_radio_driver_id >= 0) { + arm_net_phy_unregister(rf_radio_driver_id); + rf_radio_driver_id = -1; + } +} + + +/* + * \brief Function is a call back for ACK wait timeout. + * + * \param none + * + * \return none + */ +static void rf_ack_wait_timer_interrupt(void) +{ + rf_if_lock(); + rf_give_up_on_ack(); + rf_if_unlock(); +} + +/* + * \brief Function is a call back for calibration interval timer. + * + * \param none + * + * \return none + */ +static void rf_calibration_timer_interrupt(void) +{ + /*Calibrate RF*/ + rf_calibration_cb(); + /*Start new calibration timeout*/ + rf_calibration_timer_start(RF_CALIBRATION_INTERVAL); +} + +/* + * \brief Function is a call back for cca interval timer. + * + * \param none + * + * \return none + */ +static void rf_cca_timer_interrupt(void) +{ + rf_flags_set(RFF_CCA); + /*Start CCA process*/ + rf_if_start_cca_process(); +} + +/* + * \brief Function starts the ACK wait timeout. + * + * \param slots Given slots, resolution 50us + * + * \return none + */ +static void rf_ack_wait_timer_start(uint16_t slots) +{ + rf_if_ack_wait_timer_start(slots); +} + +/* + * \brief Function starts the calibration interval. + * + * \param slots Given slots, resolution 50us + * + * \return none + */ +static void rf_calibration_timer_start(uint32_t slots) +{ + rf_if_calibration_timer_start(slots); +} + +/* + * \brief Function starts the CCA backoff. + * + * \param slots Given slots, resolution 50us + * + * \return none + */ +static void rf_cca_timer_start(uint32_t slots) +{ + rf_if_cca_timer_start(slots); +} + +/* + * \brief Function stops the CCA backoff. + * + * \return none + */ +static void rf_cca_timer_stop(void) +{ + rf_if_cca_timer_stop(); +} + +/* + * \brief Function writes various RF settings in startup. + * + * \param none + * + * \return none + */ +static void rf_write_settings(void) +{ + rf_if_lock(); + rf_if_write_rf_settings(); + /*Set output power*/ + rf_if_write_set_tx_power_register(radio_tx_power); + /*Initialise Antenna Diversity*/ + if (rf_use_antenna_diversity) { + rf_if_write_antenna_diversity_settings(); + } + rf_if_unlock(); +} + +/* + * \brief Function writes 16-bit address in RF address filter. + * + * \param short_address Given short address + * + * \return none + */ +static void rf_set_short_adr(uint8_t *short_address) +{ + rf_if_lock(); + /*Wake up RF if sleeping*/ + if (rf_flags_check(RFF_ON) == 0) { + rf_if_disable_slptr(); + rf_poll_trx_state_change(TRX_OFF); + } + /*Write address filter registers*/ + rf_if_write_short_addr_registers(short_address); + /*RF back to sleep*/ + if (rf_flags_check(RFF_ON) == 0) { + rf_if_enable_slptr(); + } + rf_if_unlock(); +} + +/* + * \brief Function writes PAN Id in RF PAN Id filter. + * + * \param pan_id Given PAN Id + * + * \return none + */ +static void rf_set_pan_id(uint8_t *pan_id) +{ + rf_if_lock(); + /*Wake up RF if sleeping*/ + if (rf_flags_check(RFF_ON) == 0) { + rf_if_disable_slptr(); + rf_poll_trx_state_change(TRX_OFF); + } + /*Write address filter registers*/ + rf_if_write_pan_id_registers(pan_id); + /*RF back to sleep*/ + if (rf_flags_check(RFF_ON) == 0) { + rf_if_enable_slptr(); + } + rf_if_unlock(); +} + +/* + * \brief Function writes 64-bit address in RF address filter. + * + * \param address Given 64-bit address + * + * \return none + */ +static void rf_set_address(uint8_t *address) +{ + rf_if_lock(); + /*Wake up RF if sleeping*/ + if (rf_flags_check(RFF_ON) == 0) { + rf_if_disable_slptr(); + rf_poll_trx_state_change(TRX_OFF); + } + /*Write address filter registers*/ + rf_if_write_ieee_addr_registers(address); + /*RF back to sleep*/ + if (rf_flags_check(RFF_ON) == 0) { + rf_if_enable_slptr(); + } + rf_if_unlock(); +} + +/* + * \brief Function sets the RF channel. + * + * \param ch New channel + * + * \return none + */ +static void rf_channel_set(uint8_t ch) +{ + rf_if_lock(); + rf_phy_channel = ch; + if (ch < 0x1f) { + rf_if_set_channel_register(ch); + } + rf_if_unlock(); +} + +/* + * \brief Function initialises the radio driver and resets the radio. + * + * \param none + * + * \return none + */ +static void rf_init(void) +{ + rf_if_lock(); + + /*Write RF settings*/ + rf_write_settings(); + /*Initialise PHY mode*/ + rf_init_phy_mode(); + /*Clear RF flags*/ + rf_flags_reset(); + /*Set RF in TRX OFF state*/ + rf_if_change_trx_state(TRX_OFF); + /*Set RF in PLL_ON state*/ + rf_trx_states_t trx_status = rf_if_change_trx_state(PLL_ON); + /*Start receiver*/ + rf_receive(trx_status); + /*Read randomness, and add to seed*/ + randLIB_add_seed(rf_if_read_rnd()); + /*Start RF calibration timer*/ + rf_calibration_timer_start(RF_CALIBRATION_INTERVAL); + + rf_if_unlock(); +} + +/** + * \brief Function gets called when MAC is setting radio off. + * + * \param none + * + * \return none + */ +static void rf_off(void) +{ + if (rf_flags_check(RFF_ON)) { + rf_if_lock(); + rf_cca_abort(); + uint16_t while_counter = 0; + /*Wait while receiving*/ + while (rf_if_read_trx_state() == BUSY_RX_AACK) { + while_counter++; + if (while_counter == 0xffff) { + break; + } + } + /*RF state change: RX_AACK_ON->PLL_ON->TRX_OFF->SLEEP*/ + if (rf_if_read_trx_state() == RX_AACK_ON) { + rf_if_change_trx_state(PLL_ON); + } + rf_if_change_trx_state(TRX_OFF); + rf_if_enable_slptr(); + + /*Disable Antenna Diversity*/ + if (rf_use_antenna_diversity) { + rf_if_disable_ant_div(); + } + rf_if_unlock(); + } + + /*Clears all flags*/ + rf_flags_reset(); +} + +/* + * \brief Function polls the RF state until it has changed to desired state. + * + * \param trx_state RF state + * + * \return none + */ +static rf_trx_states_t rf_poll_trx_state_change(rf_trx_states_t trx_state) +{ + uint16_t while_counter = 0; + + if (trx_state == FORCE_PLL_ON) { + trx_state = PLL_ON; + } else if (trx_state == FORCE_TRX_OFF) { + trx_state = TRX_OFF; + } + + rf_trx_states_t state_out; + while ((state_out = rf_if_read_trx_state()) != trx_state) { + while_counter++; + if (while_counter == 0x1ff) { + break; + } + } + + return state_out; +} + +/* + * \brief Function polls the RF state until it is no longer transitioning. + * + * \param trx_state RF state + * + * \return none + */ +static rf_trx_states_t rf_poll_for_state(void) +{ + rf_trx_states_t state_out; + while ((state_out = rf_if_read_trx_state()) == STATE_TRANSITION_IN_PROGRESS) { + } + + return state_out; +} + +/* + * \brief Function starts the CCA process before starting data transmission and copies the data to RF TX FIFO. + * + * \param data_ptr Pointer to TX data (excluding FCS) + * \param data_length Length of the TX data (excluding FCS) + * \param tx_handle Handle to transmission + * \return 0 Success + * \return -1 Busy + */ +static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol) +{ + (void)data_protocol; + rf_if_lock(); + /*Check if transmitter is busy*/ + rf_trx_states_t trx_state = rf_if_read_trx_state(); + if (trx_state == BUSY_RX || trx_state == BUSY_RX_AACK || data_length > RF_MTU - 2) { + rf_if_unlock(); + /*Return busy*/ + return -1; + } else { + rf_give_up_on_ack(); + + /*Nanostack has a static TX buffer, which will remain valid until we*/ + /*generate a callback, so we just note the pointer for reading later.*/ + rf_tx_data = data_ptr; + rf_tx_length = data_length; + /*Start CCA timeout*/ + rf_cca_timer_start(RF_CCA_BASE_BACKOFF + randLIB_get_random_in_range(0, RF_CCA_RANDOM_BACKOFF)); + TEST_CSMA_STARTED + /*Store TX handle*/ + mac_tx_handle = tx_handle; + rf_if_unlock(); + } + + /*Return success*/ + return 0; +} + +/* + * \brief Function aborts CCA process. + * + * \param none + * + * \return none + */ +static void rf_cca_abort(void) +{ + TEST_CSMA_DONE + rf_cca_timer_stop(); + rf_flags_clear(RFF_CCA); +} + +/* + * \brief Function starts the transmission of the frame. + * + * \param none + * + * \return none + */ +static bool rf_start_tx() +{ + /* Attempt change to PLL_ON */ + rf_if_write_register(TRX_STATE, PLL_ON); + + // It appears that if radio is busy, rather than ignoring the state change, + // the state change happens when it stops being busy - eg + // after address match fail or finishing reception. If this happens, we do + // not want to transmit - our channel clear check is stale (either someone is + // still transmitting, or it's a long time since we checked). So wait for the + // PLL_ON change and then go to receive mode without trying to transmit. + rf_trx_states_t state = rf_poll_for_state(); + int poll_count = 0; + while (state != PLL_ON) { + /* Change didn't work (yet) - must be busy - assume it will eventually change */ + state = rf_poll_for_state(); + poll_count++; + } + + rf_flags_clear(RFF_RX); + // Check whether we saw any delay in the PLL_ON transition. + if (poll_count > 0) { + // let's get back to the receiving state. + rf_receive(state); + return false; + } + + rf_flags_set(RFF_TX); + /*RF state change: SLP_TR pulse triggers PLL_ON->BUSY_TX*/ + rf_if_enable_slptr(); + TEST_TX_STARTED + /*Chip permits us to write frame buffer while it is transmitting*/ + /*As long as first byte of data is in within 176us of TX start, we're good */ + rf_if_write_frame_buffer(rf_tx_data, rf_tx_length); + rf_if_disable_slptr(); + return true; +} + +/* + * \brief Function sets the RF in RX state. + * + * \param none + * + * \return none + */ +static void rf_receive(rf_trx_states_t trx_status) +{ + TEST_RX_DONE + uint16_t while_counter = 0; + if (rf_flags_check(RFF_ON) == 0) { + rf_on(); + rf_channel_set(rf_phy_channel); + trx_status = TRX_OFF; + } + /*If not yet in RX state set it*/ + if (rf_flags_check(RFF_RX) == 0) { + /*Wait while receiving data. Just making sure, usually this shouldn't happen. */ + while (trx_status == BUSY_RX || trx_status == BUSY_RX_AACK || trx_status == STATE_TRANSITION_IN_PROGRESS) { + while_counter++; + if (while_counter == 0xffff) { + break; + } + trx_status = rf_if_read_trx_state(); + } + + if ((rf_mode == RF_MODE_SNIFFER) || (rf_mode == RF_MODE_ED)) { + if (trx_status != RX_ON) { + trx_status = rf_if_change_trx_state(RX_ON); + } + } else { + /*ACK is always received in promiscuous mode to bypass address filters*/ + if (rf_rx_mode) { + rf_rx_mode = 0; + rf_if_enable_promiscuous_mode(); + } else { + rf_if_disable_promiscuous_mode(); + } + if (trx_status != RX_AACK_ON) { + trx_status = rf_if_change_trx_state(RX_AACK_ON); + } + } + /*If calibration timer was unable to calibrate the RF, run calibration now*/ + if (!rf_tuned) { + /*Start calibration. This can be done in states TRX_OFF, PLL_ON or in any receive state*/ + rf_if_calibration(); + /*RF is tuned now*/ + rf_tuned = 1; + } + + rf_flags_set(RFF_RX); + } +} + +/* + * \brief Function calibrates the radio. + * + * \param none + * + * \return none + */ +static void rf_calibration_cb(void) +{ + /*clear tuned flag to start tuning in rf_receive*/ + rf_tuned = 0; + /*If RF is in default receive state, start calibration*/ + if (rf_if_read_trx_state() == RX_AACK_ON) { + rf_if_lock(); + /*Set RF in PLL_ON state*/ + rf_if_change_trx_state(PLL_ON); + /*Set RF in TRX_OFF state to start PLL tuning*/ + rf_if_change_trx_state(TRX_OFF); + /*Set RF in RX_ON state to calibrate*/ + rf_trx_states_t trx_status = rf_if_change_trx_state(RX_ON); + /*Calibrate FTN*/ + rf_if_calibration(); + /*RF is tuned now*/ + rf_tuned = 1; + /*Back to default receive state*/ + rf_flags_clear(RFF_RX); + rf_receive(trx_status); + rf_if_unlock(); + } +} + +/* + * \brief Function sets RF_ON flag when radio is powered. + * + * \param none + * + * \return none + */ +static void rf_on(void) +{ + /*Set RFF_ON flag*/ + if (rf_flags_check(RFF_ON) == 0) { + rf_if_lock(); + rf_flags_set(RFF_ON); + /*Enable Antenna diversity*/ + if (rf_use_antenna_diversity) + /*Set ANT_EXT_SW_EN to enable controlling of antenna diversity*/ + { + rf_if_enable_ant_div(); + } + + /*Wake up from sleep state*/ + rf_if_disable_slptr(); + rf_poll_trx_state_change(TRX_OFF); + rf_if_unlock(); + } +} + +/* + * \brief Abandon waiting for an ack frame + + * \return none + */ +static void rf_give_up_on_ack(void) +{ + if (expected_ack_sequence == -1) { + return; + } + + rf_if_disable_promiscuous_mode(); + rf_if_ack_wait_timer_stop(); + expected_ack_sequence = -1; + + if (device_driver.phy_tx_done_cb) { + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_FAIL, 0, 0); + } +} + +/* + * \brief Function handles the received ACK frame. + * + * \param seq_number Sequence number of received ACK + * \param data_pending Pending bit state in received ACK + * + * \return none + */ +static void rf_handle_ack(uint8_t seq_number, uint8_t data_pending) +{ + phy_link_tx_status_e phy_status; + /*Received ACK sequence must be equal with transmitted packet sequence*/ + if (expected_ack_sequence == seq_number) { + rf_if_disable_promiscuous_mode(); + rf_if_ack_wait_timer_stop(); + expected_ack_sequence = -1; + + /*When data pending bit in ACK frame is set, inform NET library*/ + if (data_pending) { + phy_status = PHY_LINK_TX_DONE_PENDING; + } else { + phy_status = PHY_LINK_TX_DONE; + } + /*Call PHY TX Done API*/ + if (device_driver.phy_tx_done_cb) { + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, phy_status, 0, 0); + } + } else { + rf_give_up_on_ack(); + } +} + +/* + * \brief Function is a call back for RX end interrupt. + * + * \param none + * + * \return none + */ +static void rf_handle_rx_end(rf_trx_states_t trx_status) +{ + TEST_RX_DONE + /*Frame received interrupt*/ + if (!rf_flags_check(RFF_RX)) { + return; + } + + static uint8_t rf_buffer[RF_MTU]; + uint8_t rf_lqi, rf_ed; + int8_t rf_rssi; + bool crc_good; + + /*Read received packet*/ + uint8_t len = rf_if_read_packet(rf_buffer, &rf_lqi, &rf_ed, &crc_good); + + if (len < 5 || !crc_good) { + rf_give_up_on_ack(); + return; + } + + /* Convert raw ED to dBm value (chip-dependent) */ + rf_rssi = rf_if_scale_rssi(rf_ed); + + /* Create a virtual LQI using received RSSI, forgetting actual HW LQI */ + /* (should be done through PHY_EXTENSION_CONVERT_SIGNAL_INFO) */ + rf_lqi = rf_scale_lqi(rf_rssi); + + /*Handle received ACK*/ + if ((rf_buffer[0] & 0x07) == 0x02 && rf_mode != RF_MODE_SNIFFER) { + /*Check if data is pending*/ + bool pending = (rf_buffer[0] & 0x10); + + /*Send sequence number in ACK handler*/ + rf_handle_ack(rf_buffer[2], pending); + } else { + rf_give_up_on_ack(); + if (device_driver.phy_rx_cb) { + device_driver.phy_rx_cb(rf_buffer, len - 2, rf_lqi, rf_rssi, rf_radio_driver_id); + } + } +} + +/* + * \brief Function is called when MAC is shutting down the radio. + * + * \param none + * + * \return none + */ +static void rf_shutdown(void) +{ + /*Call RF OFF*/ + rf_off(); +} + +/* + * \brief Function is a call back for TX end interrupt. + * + * \param none + * + * \return none + */ +static void rf_handle_tx_end(rf_trx_states_t trx_status) +{ + TEST_TX_DONE + rf_rx_mode = 0; + /*If ACK is needed for this transmission*/ + if ((rf_tx_data[0] & 0x20) && rf_flags_check(RFF_TX)) { + expected_ack_sequence = rf_tx_data[2]; + rf_ack_wait_timer_start(rf_ack_wait_duration); + rf_rx_mode = 1; + } + rf_flags_clear(RFF_TX); + /*Start receiver*/ + rf_receive(trx_status); + + /*Call PHY TX Done API*/ + if (device_driver.phy_tx_done_cb) { + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_SUCCESS, 0, 0); + } +} + +/* + * \brief Function is a call back for CCA ED done interrupt. + * + * \param none + * + * \return none + */ +static void rf_handle_cca_ed_done(uint8_t full_trx_status) +{ + TEST_CSMA_DONE + if (!rf_flags_check(RFF_CCA)) { + return; + } + rf_flags_clear(RFF_CCA); + + bool success = false; + + /*Check the result of CCA process*/ + if ((full_trx_status & CCA_STATUS) && rf_if_trx_status_from_full(full_trx_status) == RX_AACK_ON) { + success = rf_start_tx(); + } + + if (!success) { + /*Send CCA fail notification*/ + if (device_driver.phy_tx_done_cb) { + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 0, 0); + } + } +} + +/* + * \brief Function gives the control of RF states to MAC. + * + * \param new_state RF state + * \param rf_channel RF channel + * + * \return 0 Success + */ +static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel) +{ + int8_t ret_val = 0; + switch (new_state) { + /*Reset PHY driver and set to idle*/ + case PHY_INTERFACE_RESET: + break; + /*Disable PHY Interface driver*/ + case PHY_INTERFACE_DOWN: + rf_shutdown(); + break; + /*Enable PHY Interface driver*/ + case PHY_INTERFACE_UP: + rf_if_lock(); + rf_mode = RF_MODE_NORMAL; + rf_channel_set(rf_channel); + rf_receive(); + rf_if_enable_irq(); + rf_if_unlock(); + break; + /*Enable wireless interface ED scan mode*/ + case PHY_INTERFACE_RX_ENERGY_STATE: + rf_mode = RF_MODE_ED; + rf_channel_set(rf_channel); + rf_receive(); + rf_if_disable_irq(); + // Read status to clear pending flags. + rf_if_read_register(IRQ_STATUS); + // ED can be initiated by writing arbitrary value to PHY_ED_LEVEL + rf_if_write_register(PHY_ED_LEVEL, 0xff); + break; + case PHY_INTERFACE_SNIFFER_STATE: /**< Enable Sniffer state */ + rf_mode = RF_MODE_SNIFFER; + rf_channel_set(rf_channel); + rf_flags_clear(RFF_RX); + rf_receive(); + rf_if_enable_irq(); + break; + } + return ret_val; +} + +/* + * \brief Function controls the ACK pending, channel setting and energy detection. + * + * \param extension_type Type of control + * \param data_ptr Data from NET library + * + * \return 0 Success + */ +static int8_t rf_extension(phy_extension_type_e extension_type, uint8_t *data_ptr) +{ + switch (extension_type) { + /*Control MAC pending bit for Indirect data transmission*/ + case PHY_EXTENSION_CTRL_PENDING_BIT: + if (*data_ptr) { + rf_if_ack_pending_ctrl(1); + } else { + rf_if_ack_pending_ctrl(0); + } + break; + /*Return frame pending status*/ + case PHY_EXTENSION_READ_LAST_ACK_PENDING_STATUS: + *data_ptr = rf_if_last_acked_pending(); + break; + /*Set channel*/ + case PHY_EXTENSION_SET_CHANNEL: + break; + /*Read energy on the channel*/ + case PHY_EXTENSION_READ_CHANNEL_ENERGY: + // End of the ED measurement is indicated by CCA_ED_DONE + while (!(rf_if_read_register(IRQ_STATUS) & CCA_ED_DONE)); + // RF input power: RSSI base level + 1[db] * PHY_ED_LEVEL + *data_ptr = rf_sensitivity + rf_if_read_register(PHY_ED_LEVEL); + // Read status to clear pending flags. + rf_if_read_register(IRQ_STATUS); + // Next ED measurement is started, next PHY_EXTENSION_READ_CHANNEL_ENERGY call will return the result. + rf_if_write_register(PHY_ED_LEVEL, 0xff); + break; + /*Read status of the link*/ + case PHY_EXTENSION_READ_LINK_STATUS: + break; + default: + break; + } + return 0; +} + +/* + * \brief Function sets the addresses to RF address filters. + * + * \param address_type Type of address + * \param address_ptr Pointer to given address + * + * \return 0 Success + */ +static int8_t rf_address_write(phy_address_type_e address_type, uint8_t *address_ptr) +{ + int8_t ret_val = 0; + switch (address_type) { + /*Set 48-bit address*/ + case PHY_MAC_48BIT: + break; + /*Set 64-bit address*/ + case PHY_MAC_64BIT: + rf_set_address(address_ptr); + break; + /*Set 16-bit address*/ + case PHY_MAC_16BIT: + rf_set_short_adr(address_ptr); + break; + /*Set PAN Id*/ + case PHY_MAC_PANID: + rf_set_pan_id(address_ptr); + break; + } + return ret_val; +} + +/* + * \brief Function initialises the ACK wait time and returns the used PHY mode. + * + * \param none + * + * \return tmp Used PHY mode + */ +static void rf_init_phy_mode(void) +{ + uint8_t tmp = 0; + uint8_t part = rf_if_read_part_num(); + /*Read used PHY Mode*/ + tmp = rf_if_read_register(TRX_CTRL_2); + /*Set ACK wait time for used data rate*/ + if (part == PART_AT86RF212) { + if ((tmp & 0x1f) == 0x00) { + rf_sensitivity = -110; + rf_ack_wait_duration = 938; + tmp = BPSK_20; + } else if ((tmp & 0x1f) == 0x04) { + rf_sensitivity = -108; + rf_ack_wait_duration = 469; + tmp = BPSK_40; + } else if ((tmp & 0x1f) == 0x14) { + rf_sensitivity = -108; + rf_ack_wait_duration = 469; + tmp = BPSK_40_ALT; + } else if ((tmp & 0x1f) == 0x08) { + rf_sensitivity = -101; + rf_ack_wait_duration = 50; + tmp = OQPSK_SIN_RC_100; + } else if ((tmp & 0x1f) == 0x09) { + rf_sensitivity = -99; + rf_ack_wait_duration = 30; + tmp = OQPSK_SIN_RC_200; + } else if ((tmp & 0x1f) == 0x18) { + rf_sensitivity = -102; + rf_ack_wait_duration = 50; + tmp = OQPSK_RC_100; + } else if ((tmp & 0x1f) == 0x19) { + rf_sensitivity = -100; + rf_ack_wait_duration = 30; + tmp = OQPSK_RC_200; + } else if ((tmp & 0x1f) == 0x0c) { + rf_sensitivity = -100; + rf_ack_wait_duration = 20; + tmp = OQPSK_SIN_250; + } else if ((tmp & 0x1f) == 0x0d) { + rf_sensitivity = -98; + rf_ack_wait_duration = 25; + tmp = OQPSK_SIN_500; + } else if ((tmp & 0x1f) == 0x0f) { + rf_sensitivity = -98; + rf_ack_wait_duration = 25; + tmp = OQPSK_SIN_500_ALT; + } else if ((tmp & 0x1f) == 0x1c) { + rf_sensitivity = -101; + rf_ack_wait_duration = 20; + tmp = OQPSK_RC_250; + } else if ((tmp & 0x1f) == 0x1d) { + rf_sensitivity = -99; + rf_ack_wait_duration = 25; + tmp = OQPSK_RC_500; + } else if ((tmp & 0x1f) == 0x1f) { + rf_sensitivity = -99; + rf_ack_wait_duration = 25; + tmp = OQPSK_RC_500_ALT; + } else if ((tmp & 0x3f) == 0x2A) { + rf_sensitivity = -91; + rf_ack_wait_duration = 25; + tmp = OQPSK_SIN_RC_400_SCR_ON; + } else if ((tmp & 0x3f) == 0x0A) { + rf_sensitivity = -91; + rf_ack_wait_duration = 25; + tmp = OQPSK_SIN_RC_400_SCR_OFF; + } else if ((tmp & 0x3f) == 0x3A) { + rf_sensitivity = -97; + rf_ack_wait_duration = 25; + tmp = OQPSK_RC_400_SCR_ON; + } else if ((tmp & 0x3f) == 0x1A) { + rf_sensitivity = -97; + rf_ack_wait_duration = 25; + tmp = OQPSK_RC_400_SCR_OFF; + } else if ((tmp & 0x3f) == 0x2E) { + rf_sensitivity = -93; + rf_ack_wait_duration = 13; + tmp = OQPSK_SIN_1000_SCR_ON; + } else if ((tmp & 0x3f) == 0x0E) { + rf_sensitivity = -93; + rf_ack_wait_duration = 13; + tmp = OQPSK_SIN_1000_SCR_OFF; + } else if ((tmp & 0x3f) == 0x3E) { + rf_sensitivity = -95; + rf_ack_wait_duration = 13; + tmp = OQPSK_RC_1000_SCR_ON; + } else if ((tmp & 0x3f) == 0x1E) { + rf_sensitivity = -95; + rf_ack_wait_duration = 13; + tmp = OQPSK_RC_1000_SCR_OFF; + } + } else { + rf_sensitivity = -101; + rf_ack_wait_duration = 20; + } + /*Board design might reduces the sensitivity*/ + //rf_sensitivity += RF_SENSITIVITY_CALIBRATION; +} + + +static uint8_t rf_scale_lqi(int8_t rssi) +{ + uint8_t scaled_lqi; + + /*rssi < RF sensitivity*/ + if (rssi < rf_sensitivity) { + scaled_lqi = 0; + } + /*-91 dBm < rssi < -81 dBm (AT86RF233 XPro)*/ + /*-90 dBm < rssi < -80 dBm (AT86RF212B XPro)*/ + else if (rssi < (rf_sensitivity + 10)) { + scaled_lqi = 31; + } + /*-81 dBm < rssi < -71 dBm (AT86RF233 XPro)*/ + /*-80 dBm < rssi < -70 dBm (AT86RF212B XPro)*/ + else if (rssi < (rf_sensitivity + 20)) { + scaled_lqi = 207; + } + /*-71 dBm < rssi < -61 dBm (AT86RF233 XPro)*/ + /*-70 dBm < rssi < -60 dBm (AT86RF212B XPro)*/ + else if (rssi < (rf_sensitivity + 30)) { + scaled_lqi = 255; + } + /*-61 dBm < rssi < -51 dBm (AT86RF233 XPro)*/ + /*-60 dBm < rssi < -50 dBm (AT86RF212B XPro)*/ + else if (rssi < (rf_sensitivity + 40)) { + scaled_lqi = 255; + } + /*-51 dBm < rssi < -41 dBm (AT86RF233 XPro)*/ + /*-50 dBm < rssi < -40 dBm (AT86RF212B XPro)*/ + else if (rssi < (rf_sensitivity + 50)) { + scaled_lqi = 255; + } + /*-41 dBm < rssi < -31 dBm (AT86RF233 XPro)*/ + /*-40 dBm < rssi < -30 dBm (AT86RF212B XPro)*/ + else if (rssi < (rf_sensitivity + 60)) { + scaled_lqi = 255; + } + /*-31 dBm < rssi < -21 dBm (AT86RF233 XPro)*/ + /*-30 dBm < rssi < -20 dBm (AT86RF212B XPro)*/ + else if (rssi < (rf_sensitivity + 70)) { + scaled_lqi = 255; + } + /*rssi > RF saturation*/ + else if (rssi > (rf_sensitivity + 80)) { + scaled_lqi = 111; + } + /*-21 dBm < rssi < -11 dBm (AT86RF233 XPro)*/ + /*-20 dBm < rssi < -10 dBm (AT86RF212B XPro)*/ + else { + scaled_lqi = 255; + } + + return scaled_lqi; +} + +NanostackRfPhyAtmel::NanostackRfPhyAtmel(PinName spi_mosi, PinName spi_miso, + PinName spi_sclk, PinName spi_cs, PinName spi_rst, PinName spi_slp, PinName spi_irq, + PinName i2c_sda, PinName i2c_scl) + : +#if !defined(DISABLE_AT24MAC) + _mac(i2c_sda, i2c_scl), +#endif + _mac_addr(), _rf(NULL), _test_pins(NULL), _se2435_pa_pins(NULL), _mac_set(false), + _spi_mosi(spi_mosi), _spi_miso(spi_miso), _spi_sclk(spi_sclk), + _spi_cs(spi_cs), _spi_rst(spi_rst), _spi_slp(spi_slp), _spi_irq(spi_irq) +{ + _rf = new RFBits(_spi_mosi, _spi_miso, _spi_sclk, _spi_cs, _spi_rst, _spi_slp, _spi_irq); +#ifdef TEST_GPIOS_ENABLED + _test_pins = new TestPins(TEST_PIN_TX, TEST_PIN_RX, TEST_PIN_CSMA, TEST_PIN_SPARE_1, TEST_PIN_SPARE_2); +#endif +#ifdef SE2435L_PA + _se2435_pa_pins = new Se2435Pins(SE2435L_CSD, SE2435L_ANT_SEL); +#endif +} + +NanostackRfPhyAtmel::~NanostackRfPhyAtmel() +{ + delete _rf; +} + +int8_t NanostackRfPhyAtmel::rf_register() +{ + if (NULL == _rf) { + return -1; + } + + rf_if_lock(); + + if (rf != NULL) { + rf_if_unlock(); + error("Multiple registrations of NanostackRfPhyAtmel not supported"); + return -1; + } + + // Read the mac address if it hasn't been set by a user + rf = _rf; + test_pins = _test_pins; + se2435_pa_pins = _se2435_pa_pins; + if (!_mac_set) { +// Unless AT24MAC is available, using randomly generated MAC address +#if !defined(DISABLE_AT24MAC) + int ret = _mac.read_eui64((void *)_mac_addr); + if (ret < 0) { + rf = NULL; + rf_if_unlock(); + return -1; + } +#else + randLIB_seed_random(); + randLIB_get_n_bytes_random(_mac_addr, 8); + _mac_addr[0] |= 2; //Set Local Bit + _mac_addr[0] &= ~1; //Clear multicast bit +#endif + } + /*Reset RF module*/ + rf_if_reset_radio(); + rf_part_num = rf_if_read_part_num(); + int8_t radio_id = -1; + if (rf_part_num != PART_AT86RF231 && rf_part_num != PART_AT86RF233 && rf_part_num != PART_AT86RF212) { + rf->init_se2435_pa(_se2435_pa_pins); + // Register RF type 215. Jumps to AT86RF215 driver. + radio_id = rf->init_215_driver(_rf, _test_pins, _mac_addr, &rf_part_num); + } else { + // Register other RF types. + radio_id = rf_device_register(_mac_addr); + } + tr_info("RF part number: %x", rf_part_num); + if (radio_id < 0) { + tr_err("RF registration failed"); + rf = NULL; + } + + rf_if_unlock(); + return radio_id; +} + +void NanostackRfPhyAtmel::rf_unregister() +{ + rf_if_lock(); + + if (NULL == rf) { + rf_if_unlock(); + return; + } + + rf_device_unregister(); + rf = NULL; + + rf_if_unlock(); +} + +void NanostackRfPhyAtmel::get_mac_address(uint8_t *mac) +{ + rf_if_lock(); + + if (NULL == rf) { + error("NanostackRfPhyAtmel Must be registered to read mac address"); + rf_if_unlock(); + return; + } + memcpy((void *)mac, (void *)_mac_addr, sizeof(_mac_addr)); + + rf_if_unlock(); +} + +void NanostackRfPhyAtmel::set_mac_address(uint8_t *mac) +{ + rf_if_lock(); + + if (NULL != rf) { + error("NanostackRfPhyAtmel cannot change mac address when running"); + rf_if_unlock(); + return; + } + memcpy((void *)_mac_addr, (void *)mac, sizeof(_mac_addr)); + _mac_set = true; + + rf_if_unlock(); +} + +#if MBED_CONF_ATMEL_RF_PROVIDE_DEFAULT + +NanostackRfPhy &NanostackRfPhy::get_default_instance() +{ + static NanostackRfPhyAtmel rf_phy(ATMEL_SPI_MOSI, ATMEL_SPI_MISO, ATMEL_SPI_SCLK, ATMEL_SPI_CS, + ATMEL_SPI_RST, ATMEL_SPI_SLP, ATMEL_SPI_IRQ, ATMEL_I2C_SDA, ATMEL_I2C_SCL); + return rf_phy; +} + +#endif // MBED_CONF_ATMEL_RF_PROVIDE_DEFAULT + +#endif // MBED_CONF_NANOSTACK_CONFIGURATION diff --git a/connectivity/drivers/802.15.4_RF/atmel-rf-driver/source/at24mac.cpp b/connectivity/drivers/802.15.4_RF/atmel-rf-driver/source/at24mac.cpp new file mode 100644 index 0000000000..cdb18a0cb7 --- /dev/null +++ b/connectivity/drivers/802.15.4_RF/atmel-rf-driver/source/at24mac.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2016-2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "at24mac.h" + +#if DEVICE_I2C + +/* Device addressing */ +#define AT24MAC_EEPROM_ADDRESS (0x0A<<4) +#define AT24MAC_RW_PROTECT_ADDRESS (0x06<<4) +#define AT24MAC_SERIAL_ADDRESS (0x0B<<4) + +/* Known memory blocks */ +#define AT24MAC_SERIAL_OFFSET (0x80) +#define AT24MAC_EUI64_OFFSET (0x98) +#define AT24MAC_EUI48_OFFSET (0x9A) + +#define SERIAL_LEN 16 +#define EUI64_LEN 8 +#define EUI48_LEN 6 + +using namespace mbed; + +AT24Mac::AT24Mac(PinName sda, PinName scl) : _i2c(sda, scl) +{ + // Do nothing +} + +int AT24Mac::read_serial(void *buf) +{ + char offset = AT24MAC_SERIAL_OFFSET; + if (_i2c.write(AT24MAC_SERIAL_ADDRESS, &offset, 1, true)) { + return -1; //No ACK + } + return _i2c.read(AT24MAC_SERIAL_ADDRESS, (char *)buf, SERIAL_LEN); +} + +int AT24Mac::read_eui64(void *buf) +{ + char offset = AT24MAC_EUI64_OFFSET; + if (_i2c.write(AT24MAC_SERIAL_ADDRESS, &offset, 1, true)) { + return -1; //No ACK + } + return _i2c.read(AT24MAC_SERIAL_ADDRESS, (char *)buf, EUI64_LEN); +} + +int AT24Mac::read_eui48(void *buf) +{ + char offset = AT24MAC_EUI48_OFFSET; + if (_i2c.write(AT24MAC_SERIAL_ADDRESS, &offset, 1, true)) { + return -1; //No ACK + } + return _i2c.read(AT24MAC_SERIAL_ADDRESS, (char *)buf, EUI48_LEN); +} + +#endif /* DEVICE_I2C */ diff --git a/connectivity/drivers/802.15.4_RF/atmel-rf-driver/source/at24mac.h b/connectivity/drivers/802.15.4_RF/atmel-rf-driver/source/at24mac.h new file mode 100644 index 0000000000..d89d24400f --- /dev/null +++ b/connectivity/drivers/802.15.4_RF/atmel-rf-driver/source/at24mac.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef AT24MAC_H +#define AT24MAC_H + +#include "PinNames.h" + +#if DEVICE_I2C + +#include "I2C.h" +#include "drivers/DigitalInOut.h" +#include "platform/mbed_wait_api.h" + +/* + * AT24MAC drivers. + * + * This is a EEPROM chip designed to contain factory programmed read-only EUI-64 or EUI-48, + * a 128bit serial number and some user programmable EEPROM. + * + * AT24MAC602 contains EUI-64, use read_eui64() + * AT24MAC402 contains EUI-64, use read_eui48() + * + * NOTE: You cannot use both EUI-64 and EUI-48. Chip contains only one of those. + */ + +class AT24Mac { +public: + AT24Mac(PinName sda, PinName scl); + + /** + * Read unique serial number from chip. + * \param buf pointer to write serial number to. Must have space for 16 bytes. + * \return zero on success, negative number on failure + */ + int read_serial(void *buf); + + /** + * Read EUI-64 from chip. + * \param buf pointer to write EUI-64 to. Must have space for 8 bytes. + * \return zero on success, negative number on failure + */ + int read_eui64(void *buf); + + /** + * Read EUI-48 from chip. + * \param buf pointer to write EUI-48 to. Must have space for 6 bytes. + * \return zero on success, negative number on failure + */ + int read_eui48(void *buf); + +private: + mbed::I2C _i2c; +}; + +#endif /* DEVICE_I2C */ +#endif /* AT24MAC_H */ diff --git a/connectivity/drivers/802.15.4_RF/atmel-rf-driver/source/rfbits.h b/connectivity/drivers/802.15.4_RF/atmel-rf-driver/source/rfbits.h new file mode 100644 index 0000000000..e9b17b2ea8 --- /dev/null +++ b/connectivity/drivers/802.15.4_RF/atmel-rf-driver/source/rfbits.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RFBITS_H_ +#define RFBITS_H_ + +#include "DigitalIn.h" +#include "DigitalOut.h" +#include "InterruptIn.h" +#include "SPI.h" +#include +#include "Timeout.h" +#include "rtos.h" + +using namespace mbed; +using namespace rtos; + +class UnlockedSPI : public SPI { +public: + UnlockedSPI(PinName mosi, PinName miso, PinName sclk) : + SPI(mosi, miso, sclk) { } + virtual void lock() { } + virtual void unlock() { } +}; + +class RFBits { +public: + RFBits(PinName spi_mosi, PinName spi_miso, + PinName spi_sclk, PinName spi_cs, + PinName spi_rst, PinName spi_slp, PinName spi_irq); + UnlockedSPI spi; + DigitalOut CS; + DigitalOut RST; + DigitalOut SLP_TR; + InterruptIn IRQ; + Timeout ack_timer; + Timeout cal_timer; + Timeout cca_timer; + Timer tx_timer; + int init_215_driver(RFBits *_rf, TestPins *_test_pins, const uint8_t mac[8], uint8_t *rf_part_num); + int init_se2435_pa(Se2435Pins *_se2435_pa_pins); +#ifdef MBED_CONF_RTOS_PRESENT + Thread irq_thread; + Thread irq_thread_215; + Mutex mutex; + void rf_if_irq_task(); + void rf_irq_task(); +#endif +}; + +class TestPins { +public: + TestPins(PinName test_pin_1, PinName test_pin_2, PinName test_pin_3, PinName test_pin_4, PinName test_pin_5); + DigitalOut TEST1; + DigitalOut TEST2; + DigitalOut TEST3; + DigitalOut TEST4; + DigitalOut TEST5; +}; + +class Se2435Pins { +public: + Se2435Pins(PinName csd_pin, PinName ant_sel_pin); + DigitalOut CSD; + DigitalOut ANT_SEL; +}; + +#endif /* RFBITS_H_ */