summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/app/lora32u4ii/Kconfig6
-rw-r--r--src/app/lora32u4ii/Makefile.inc9
-rw-r--r--src/app/lora32u4ii/main.cc135
-rw-r--r--src/app/lora32u4ii/oslmic.h42
-rw-r--r--src/app/lora32u4ii/radio.h369
5 files changed, 561 insertions, 0 deletions
diff --git a/src/app/lora32u4ii/Kconfig b/src/app/lora32u4ii/Kconfig
new file mode 100644
index 0000000..0b75206
--- /dev/null
+++ b/src/app/lora32u4ii/Kconfig
@@ -0,0 +1,6 @@
+# Copyright 2021 Daniel Friesel
+#
+# SPDX-License-Identifier: CC0-1.0
+
+prompt "LoRa32u4 II v1.3 Test App"
+depends on loop && !wakeup
diff --git a/src/app/lora32u4ii/Makefile.inc b/src/app/lora32u4ii/Makefile.inc
new file mode 100644
index 0000000..c201be2
--- /dev/null
+++ b/src/app/lora32u4ii/Makefile.inc
@@ -0,0 +1,9 @@
+# vim:ft=make
+#
+# Copyright 2021 Daniel Friesel
+#
+# SPDX-License-Identifier: CC0-1.0
+
+ifdef app
+ loop = 1
+endif
diff --git a/src/app/lora32u4ii/main.cc b/src/app/lora32u4ii/main.cc
new file mode 100644
index 0000000..b44652b
--- /dev/null
+++ b/src/app/lora32u4ii/main.cc
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2021 Daniel Friesel
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+#include "arch.h"
+#include "driver/gpio.h"
+#include "driver/stdout.h"
+#include "driver/uptime.h"
+#include "driver/adc.h"
+#include "driver/spi.h"
+
+#define CFG_eu868 1
+#define CFG_sx1276_radio 1
+
+#include "radio.h"
+#include "oslmic.h"
+
+unsigned char txbuf[4];
+unsigned char rxbuf[4];
+
+// DIYMall BSFrance LoRa32u4 II v1.3
+// See also: arduino packages/adafruit/hardware/avr/1.4.13/variants/feather32u4/pins_arduino.h
+// PB0 -> Charger enable and Vbat/2 measurement voltage divider enable
+// PB0 is also the !SS pin, so it must be configured as output in order to use SPI.
+// PB5 "D9" <- Vbat/2 via voltage divider. Appears to also have a connection to the user LED
+// PC7 "D13" -> User LED
+const GPIO::Pin rstpin = GPIO::pd4; // "D4" -> RST
+const GPIO::Pin cspin = GPIO::pb4; // "D8" -> NSS
+const GPIO::Pin dio0pin = GPIO::pe6; // "D7" <- DIO0 / IRQ
+const GPIO::Pin dio1pin = GPIO::pc6; // "D5" <- DIO1
+
+static void writeReg (u1_t addr, u1_t data) {
+ txbuf[0] = addr | 0x80;
+ txbuf[1] = data;
+ gpio.write(cspin, 0);
+ spi.xmit(2, txbuf, 0, rxbuf);
+ gpio.write(cspin, 1);
+}
+
+static u1_t readReg (u1_t addr) {
+ txbuf[0] = addr & 0x7f;
+ gpio.write(cspin, 0);
+ spi.xmit(1, txbuf, 2, rxbuf);
+ gpio.write(cspin, 1);
+ return rxbuf[1];
+}
+/*
+static void writeBuf (u1_t addr, xref2u1_t buf, u1_t len) {
+ txbuf[0] = addr | 0x80;
+ for (uint8_t i = 0; i < len; i++) {
+ txbuf[i+1] = buf[i];
+ }
+ spi.xmit(len+1, txbuf, 0, rxbuf);
+}
+
+static void readBuf (u1_t addr, xref2u1_t buf, u1_t len) {
+ txbuf[0] = addr & 0x7f;
+ spi.xmit(1, txbuf, len, buf);
+}
+*/
+
+static void writeOpmode(u1_t mode) {
+ u1_t const maskedMode = mode & OPMODE_MASK;
+ writeReg(RegOpMode, mode);
+}
+
+static void opmode (u1_t mode) {
+ writeOpmode((readReg(RegOpMode) & ~OPMODE_MASK) | mode);
+}
+
+
+
+bool radio_init()
+{
+ // requestModuleActive(1); not required for sx yadayada
+ gpio.output(cspin, 1);
+#ifdef CFG_sx1276_radio
+ gpio.output(rstpin, 0);
+#else
+ gpio.output(rstpin, 1);
+#endif
+ arch.delay_ms(1);
+ gpio.input(rstpin);
+ gpio.write(rstpin, 0); // disable pull-up
+ arch.delay_ms(5);
+ opmode(OPMODE_SLEEP);
+
+ u1_t v = readReg(RegVersion);
+#ifdef CFG_sx1276_radio
+ if(v != 0x12 ) {
+ kout << "Radio version mismatch: expected " << hex << 0x12 << ", got " << v << endl;
+ return false;
+ }
+#elif CFG_sx1272_radio
+ if(v != 0x22) {
+ kout << "Radio version mismatch: expected " << hex << 0x22 << ", got " << v << endl;
+ return false;
+ }
+#else
+#error Missing CFG_sx1272_radio/CFG_sx1276_radio
+#endif
+ return true;
+}
+
+void loop(void)
+{
+ //gpio.led_toggle(1);
+#ifdef TIMER_S
+ kout << dec << uptime.get_s() << endl;
+#else
+ kout << "beep boop" << endl;
+#endif
+ kout << "VCC = " << adc.getVCC_mV() << " mV" << endl;
+ kout << "Vbat = " << adc.getVBat_mV(false) << " mV" << endl;
+ gpio.led_toggle(0);
+}
+
+int main(void)
+{
+ arch.setup();
+ gpio.setup();
+ kout.setup();
+ spi.setup();
+ gpio.input(GPIO::pb5);
+
+ radio_init();
+
+ kout << "Hello, World!" << endl;
+ kout << "Test, World!" << endl;
+
+ arch.idle_loop();
+
+ return 0;
+}
diff --git a/src/app/lora32u4ii/oslmic.h b/src/app/lora32u4ii/oslmic.h
new file mode 100644
index 0000000..8cdb91b
--- /dev/null
+++ b/src/app/lora32u4ii/oslmic.h
@@ -0,0 +1,42 @@
+#pragma once
+/*
+ * Copyright (c) 2014-2016 IBM Corporation.
+ * Copyright (c) 2018, 2019 MCCI Corporation
+ * Copyright (c) 2021 Daniel Friesel
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the <organization> nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+typedef uint8_t bit_t;
+typedef uint8_t u1_t;
+typedef int8_t s1_t;
+typedef uint16_t u2_t;
+typedef int16_t s2_t;
+typedef uint32_t u4_t;
+typedef int32_t s4_t;
+typedef unsigned int uint;
+typedef const char* str_t;
+
+
diff --git a/src/app/lora32u4ii/radio.h b/src/app/lora32u4ii/radio.h
new file mode 100644
index 0000000..bc65405
--- /dev/null
+++ b/src/app/lora32u4ii/radio.h
@@ -0,0 +1,369 @@
+#pragma once
+/*
+ * Copyright (c) 2014-2016 IBM Corporation.
+ * Copyright (c) 2016-2019 MCCI Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the <organization> nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// ----------------------------------------
+// Registers Mapping
+// // -type- 1272 vs 1276
+#define RegFifo 0x00 // common
+#define RegOpMode 0x01 // common see below
+#define FSKRegBitrateMsb 0x02 // -
+#define FSKRegBitrateLsb 0x03 // -
+#define FSKRegFdevMsb 0x04 // -
+#define FSKRegFdevLsb 0x05 // -
+#define RegFrfMsb 0x06 // common FSK: 1272: 915; 1276: 434 MHz
+#define RegFrfMid 0x07 // common ditto
+#define RegFrfLsb 0x08 // common ditto
+#define RegPaConfig 0x09 // common see below, many diffs
+#define RegPaRamp 0x0A // common see below: bits 6..4 are diff
+#define RegOcp 0x0B // common -
+#define RegLna 0x0C // common bits 4..0 are diff.
+#define FSKRegRxConfig 0x0D // -
+#define LORARegFifoAddrPtr 0x0D
+#define FSKRegRssiConfig 0x0E // -
+#define LORARegFifoTxBaseAddr 0x0E
+#define FSKRegRssiCollision 0x0F // -
+#define LORARegFifoRxBaseAddr 0x0F
+#define FSKRegRssiThresh 0x10 // -
+#define LORARegFifoRxCurrentAddr 0x10
+#define FSKRegRssiValue 0x11 // -
+#define LORARegIrqFlagsMask 0x11
+#define FSKRegRxBw 0x12 // -
+#define LORARegIrqFlags 0x12
+#define FSKRegAfcBw 0x13 // -
+#define LORARegRxNbBytes 0x13
+#define FSKRegOokPeak 0x14 // -
+#define LORARegRxHeaderCntValueMsb 0x14
+#define FSKRegOokFix 0x15 // -
+#define LORARegRxHeaderCntValueLsb 0x15
+#define FSKRegOokAvg 0x16 // -
+#define LORARegRxPacketCntValueMsb 0x16
+#define LORARegRxpacketCntValueLsb 0x17
+#define LORARegModemStat 0x18
+#define LORARegPktSnrValue 0x19
+#define FSKRegAfcFei 0x1A // -
+#define LORARegPktRssiValue 0x1A
+#define FSKRegAfcMsb 0x1B // -
+#define LORARegRssiValue 0x1B
+#define FSKRegAfcLsb 0x1C // -
+#define LORARegHopChannel 0x1C
+#define FSKRegFeiMsb 0x1D // -
+#define LORARegModemConfig1 0x1D
+#define FSKRegFeiLsb 0x1E // -
+#define LORARegModemConfig2 0x1E
+#define FSKRegPreambleDetect 0x1F // -
+#define LORARegSymbTimeoutLsb 0x1F
+#define FSKRegRxTimeout1 0x20 // -
+#define LORARegPreambleMsb 0x20
+#define FSKRegRxTimeout2 0x21 // -
+#define LORARegPreambleLsb 0x21
+#define FSKRegRxTimeout3 0x22 // -
+#define LORARegPayloadLength 0x22
+#define FSKRegRxDelay 0x23 // -
+#define LORARegPayloadMaxLength 0x23
+#define FSKRegOsc 0x24 // -
+#define LORARegHopPeriod 0x24
+#define FSKRegPreambleMsb 0x25 // -
+#define LORARegFifoRxByteAddr 0x25
+#define FSKRegPreambleLsb 0x26 // -
+#define LORARegModemConfig3 0x26
+#define FSKRegSyncConfig 0x27 // -
+#define LORARegFeiMsb 0x28
+#define FSKRegSyncValue1 0x28 // -
+#define LORAFeiMib 0x29
+#define FSKRegSyncValue2 0x29 // -
+#define LORARegFeiLsb 0x2A
+#define FSKRegSyncValue3 0x2A // -
+#define FSKRegSyncValue4 0x2B // -
+#define LORARegRssiWideband 0x2C
+#define FSKRegSyncValue5 0x2C // -
+#define FSKRegSyncValue6 0x2D // -
+#define FSKRegSyncValue7 0x2E // -
+#define FSKRegSyncValue8 0x2F // -
+#define LORARegIffReq1 0x2F
+#define FSKRegPacketConfig1 0x30 // -
+#define LORARegIffReq2 0x30
+#define FSKRegPacketConfig2 0x31 // -
+#define LORARegDetectOptimize 0x31
+#define FSKRegPayloadLength 0x32 // -
+#define FSKRegNodeAdrs 0x33 // -
+#define LORARegInvertIQ 0x33
+#define FSKRegBroadcastAdrs 0x34 // -
+#define FSKRegFifoThresh 0x35 // -
+#define FSKRegSeqConfig1 0x36 // -
+#define LORARegHighBwOptimize1 0x36
+#define FSKRegSeqConfig2 0x37 // -
+#define LORARegDetectionThreshold 0x37
+#define FSKRegTimerResol 0x38 // -
+#define FSKRegTimer1Coef 0x39 // -
+#define LORARegSyncWord 0x39
+#define FSKRegTimer2Coef 0x3A // -
+#define LORARegHighBwOptimize2 0x3A
+#define FSKRegImageCal 0x3B // -
+#define FSKRegTemp 0x3C // -
+#define FSKRegLowBat 0x3D // -
+#define FSKRegIrqFlags1 0x3E // -
+#define FSKRegIrqFlags2 0x3F // -
+#define RegDioMapping1 0x40 // common
+#define RegDioMapping2 0x41 // common
+#define RegVersion 0x42 // common
+// #define RegAgcRef 0x43 // common
+// #define RegAgcThresh1 0x44 // common
+// #define RegAgcThresh2 0x45 // common
+// #define RegAgcThresh3 0x46 // common
+// #define RegPllHop 0x4B // common
+// #define RegTcxo 0x58 // common
+// #define RegPll 0x5C // common
+// #define RegPllLowPn 0x5E // common
+// #define RegFormerTemp 0x6C // common
+// #define RegBitRateFrac 0x70 // common
+
+#if defined(CFG_sx1276_radio)
+#define RegTcxo 0x4B // common different addresses, same bits
+#define RegPaDac 0x4D // common differnet addresses, same bits
+#elif defined(CFG_sx1272_radio)
+#define RegTcxo 0x58 // common
+#define RegPaDac 0x5A // common
+#endif
+
+#define RegTcxo_TcxoInputOn (1u << 4)
+
+// ----------------------------------------
+// spread factors and mode for RegModemConfig2
+#define SX1272_MC2_FSK 0x00
+#define SX1272_MC2_SF7 0x70
+#define SX1272_MC2_SF8 0x80
+#define SX1272_MC2_SF9 0x90
+#define SX1272_MC2_SF10 0xA0
+#define SX1272_MC2_SF11 0xB0
+#define SX1272_MC2_SF12 0xC0
+// bandwidth for RegModemConfig1
+#define SX1272_MC1_BW_125 0x00
+#define SX1272_MC1_BW_250 0x40
+#define SX1272_MC1_BW_500 0x80
+// coding rate for RegModemConfig1
+#define SX1272_MC1_CR_4_5 0x08
+#define SX1272_MC1_CR_4_6 0x10
+#define SX1272_MC1_CR_4_7 0x18
+#define SX1272_MC1_CR_4_8 0x20
+#define SX1272_MC1_IMPLICIT_HEADER_MODE_ON 0x04 // required for receive
+#define SX1272_MC1_RX_PAYLOAD_CRCON 0x02
+#define SX1272_MC1_LOW_DATA_RATE_OPTIMIZE 0x01 // mandated for SF11 and SF12
+// transmit power configuration for RegPaConfig
+#define SX1272_PAC_PA_SELECT_PA_BOOST 0x80
+#define SX1272_PAC_PA_SELECT_RFIO_PIN 0x00
+
+
+// sx1276 RegModemConfig1
+#define SX1276_MC1_BW_125 0x70
+#define SX1276_MC1_BW_250 0x80
+#define SX1276_MC1_BW_500 0x90
+#define SX1276_MC1_CR_4_5 0x02
+#define SX1276_MC1_CR_4_6 0x04
+#define SX1276_MC1_CR_4_7 0x06
+#define SX1276_MC1_CR_4_8 0x08
+
+#define SX1276_MC1_IMPLICIT_HEADER_MODE_ON 0x01
+
+#ifdef CFG_sx1276_radio
+# define SX127X_MC1_IMPLICIT_HEADER_MODE_ON SX1276_MC1_IMPLICIT_HEADER_MODE_ON
+#else
+# define SX127X_MC1_IMPLICIT_HEADER_MODE_ON SX1272_MC1_IMPLICIT_HEADER_MODE_ON
+#endif
+
+// transmit power configuration for RegPaConfig
+#define SX1276_PAC_PA_SELECT_PA_BOOST 0x80
+#define SX1276_PAC_PA_SELECT_RFIO_PIN 0x00
+#define SX1276_PAC_MAX_POWER_MASK 0x70
+
+// the bits to change for max power.
+#define SX127X_PADAC_POWER_MASK 0x07
+#define SX127X_PADAC_POWER_NORMAL 0x04
+#define SX127X_PADAC_POWER_20dBm 0x07
+
+// convert milliamperes to equivalent value for
+// RegOcp; delivers conservative value.
+#define SX127X_OCP_MAtoBITS(mA) \
+ ((mA) < 45 ? 0 : \
+ (mA) <= 120 ? ((mA) - 45) / 5 : \
+ (mA) < 130 ? 0xF : \
+ (mA) < 240 ? ((mA) - 130) / 10 + 0x10 : \
+ 27)
+
+// bit in RegOcp that enables overcurrent protect.
+#define SX127X_OCP_ENA 0x20
+
+// sx1276 RegModemConfig2
+#define SX1276_MC2_RX_PAYLOAD_CRCON 0x04
+
+// sx1276 RegModemConfig3
+#define SX1276_MC3_LOW_DATA_RATE_OPTIMIZE 0x08
+#define SX1276_MC3_AGCAUTO 0x04
+
+// preamble for lora networks (nibbles swapped)
+#define LORA_MAC_PREAMBLE 0x34
+
+#define RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG1 0x0A
+#ifdef CFG_sx1276_radio
+#define RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG2 0x70
+#elif CFG_sx1272_radio
+#define RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG2 0x74
+#endif
+
+//-----------------------------------------
+// Parameters for RSSI monitoring
+#define SX127X_FREQ_LF_MAX 525000000 // per datasheet 6.3
+
+// per datasheet 5.5.3 and 5.5.5:
+#define SX1272_RSSI_ADJUST -139 // add to rssi value to get dB (LF)
+
+// per datasheet 5.5.3 and 5.5.5:
+#define SX1276_RSSI_ADJUST_LF -164 // add to rssi value to get dB (LF)
+#define SX1276_RSSI_ADJUST_HF -157 // add to rssi value to get dB (HF)
+
+#ifdef CFG_sx1276_radio
+# define SX127X_RSSI_ADJUST_LF SX1276_RSSI_ADJUST_LF
+# define SX127X_RSSI_ADJUST_HF SX1276_RSSI_ADJUST_HF
+#else
+# define SX127X_RSSI_ADJUST_LF SX1272_RSSI_ADJUST
+# define SX127X_RSSI_ADJUST_HF SX1272_RSSI_ADJUST
+#endif
+
+// per datasheet 2.5.2 (but note that we ought to ask Semtech to confirm, because
+// datasheet is unclear).
+#define SX127X_RX_POWER_UP us2osticks(500) // delay this long to let the receiver power up.
+
+// ----------------------------------------
+// Constants for radio registers
+#define OPMODE_LORA 0x80
+#define OPMODE_MASK 0x07
+#define OPMODE_SLEEP 0x00
+#define OPMODE_STANDBY 0x01
+#define OPMODE_FSTX 0x02
+#define OPMODE_TX 0x03
+#define OPMODE_FSRX 0x04
+#define OPMODE_RX 0x05
+#define OPMODE_RX_SINGLE 0x06
+#define OPMODE_CAD 0x07
+
+// ----------------------------------------
+// FSK opmode bits
+// bits 6:5 are the same for 1272 and 1276
+#define OPMODE_FSK_SX127x_ModulationType_FSK (0u << 5)
+#define OPMODE_FSK_SX127x_ModulationType_OOK (1u << 5)
+#define OPMODE_FSK_SX127x_ModulationType_MASK (3u << 5)
+
+// bits 4:3 are different for 1272
+#define OPMODE_FSK_SX1272_ModulationShaping_FSK_None (0u << 3)
+#define OPMODE_FSK_SX1272_ModulationShaping_FSK_BT1_0 (1u << 3)
+#define OPMODE_FSK_SX1272_ModulationShaping_FSK_BT0_5 (2u << 3)
+#define OPMODE_FSK_SX1272_ModulationShaping_FSK_BT0_3 (3u << 3)
+#define OPMODE_FSK_SX1272_ModulationShaping_OOK_None (0u << 3)
+#define OPMODE_FSK_SX1272_ModulationShaping_OOK_BR (1u << 3)
+#define OPMODE_FSK_SX1272_ModulationShaping_OOK_2BR (2u << 3)
+
+#define OPMODE_FSK_SX1272_ModulationShaping_MASK (3u << 3)
+
+// SX1276
+#define OPMODE_FSK_SX1276_LowFrequencyModeOn (1u << 3)
+
+// define the opmode bits apporpriate for the 127x in use.
+#if defined(CFG_sx1272_radio)
+# define OPMODE_FSK_SX127X_SETUP (OPMODE_FSK_SX127x_ModulationType_FSK | \
+ OPMODE_FSK_SX1272_ModulationShaping_FSK_BT0_5)
+#elif defined(CFG_sx1276_radio)
+# define OPMODE_FSK_SX127X_SETUP (OPMODE_FSK_SX127x_ModulationType_FSK)
+#endif
+
+// ----------------------------------------
+// LoRa opmode bits
+#define OPMODE_LORA_SX127x_AccessSharedReg (1u << 6)
+#define OPMODE_LORA_SX1276_LowFrequencyModeOn (1u << 3)
+
+// ----------------------------------------
+// Bits masking the corresponding IRQs from the radio
+#define IRQ_LORA_RXTOUT_MASK 0x80
+#define IRQ_LORA_RXDONE_MASK 0x40
+#define IRQ_LORA_CRCERR_MASK 0x20
+#define IRQ_LORA_HEADER_MASK 0x10
+#define IRQ_LORA_TXDONE_MASK 0x08
+#define IRQ_LORA_CDDONE_MASK 0x04
+#define IRQ_LORA_FHSSCH_MASK 0x02
+#define IRQ_LORA_CDDETD_MASK 0x01
+
+#define IRQ_FSK1_MODEREADY_MASK 0x80
+#define IRQ_FSK1_RXREADY_MASK 0x40
+#define IRQ_FSK1_TXREADY_MASK 0x20
+#define IRQ_FSK1_PLLLOCK_MASK 0x10
+#define IRQ_FSK1_RSSI_MASK 0x08
+#define IRQ_FSK1_TIMEOUT_MASK 0x04
+#define IRQ_FSK1_PREAMBLEDETECT_MASK 0x02
+#define IRQ_FSK1_SYNCADDRESSMATCH_MASK 0x01
+#define IRQ_FSK2_FIFOFULL_MASK 0x80
+#define IRQ_FSK2_FIFOEMPTY_MASK 0x40
+#define IRQ_FSK2_FIFOLEVEL_MASK 0x20
+#define IRQ_FSK2_FIFOOVERRUN_MASK 0x10
+#define IRQ_FSK2_PACKETSENT_MASK 0x08
+#define IRQ_FSK2_PAYLOADREADY_MASK 0x04
+#define IRQ_FSK2_CRCOK_MASK 0x02
+#define IRQ_FSK2_LOWBAT_MASK 0x01
+
+// ----------------------------------------
+// DIO function mappings D0D1D2D3
+#define MAP_DIO0_LORA_RXDONE 0x00 // 00------
+#define MAP_DIO0_LORA_TXDONE 0x40 // 01------
+#define MAP_DIO1_LORA_RXTOUT 0x00 // --00----
+#define MAP_DIO1_LORA_NOP 0x30 // --11----
+#define MAP_DIO2_LORA_NOP 0x0C // ----11--
+
+#define MAP_DIO0_FSK_READY 0x00 // 00------ (packet sent / payload ready)
+#define MAP_DIO1_FSK_NOP 0x30 // --11----
+#define MAP_DIO2_FSK_TXNOP 0x04 // ----01--
+#define MAP_DIO2_FSK_TIMEOUT 0x08 // ----10--
+
+
+// FSK IMAGECAL defines
+#define RF_IMAGECAL_AUTOIMAGECAL_MASK 0x7F
+#define RF_IMAGECAL_AUTOIMAGECAL_ON 0x80
+#define RF_IMAGECAL_AUTOIMAGECAL_OFF 0x00 // Default
+
+#define RF_IMAGECAL_IMAGECAL_MASK 0xBF
+#define RF_IMAGECAL_IMAGECAL_START 0x40
+
+#define RF_IMAGECAL_IMAGECAL_RUNNING 0x20
+#define RF_IMAGECAL_IMAGECAL_DONE 0x00 // Default
+
+// LNA gain constant. Bits 4..0 have different meaning for 1272 and 1276, but
+// by chance, the bit patterns we use are the same.
+#ifdef CFG_sx1276_radio
+#define LNA_RX_GAIN (0x20|0x3)
+#elif CFG_sx1272_radio
+#define LNA_RX_GAIN (0x20|0x03)
+#else
+#error Missing CFG_sx1272_radio/CFG_sx1276_radio
+#endif