From 8111bc058fe5818082c347370a7af00bf1ff286f Mon Sep 17 00:00:00 2001
From: jgromes <jan.gromes@gmail.com>
Date: Sun, 14 Nov 2021 11:33:35 +0100
Subject: [PATCH] Added HAL

---
 src/BuildOpt.h | 636 +++++++++++++++++++++++++++++++++++++++----------
 src/Module.cpp | 389 +++++++++++++++---------------
 src/Module.h   | 290 ++++++++--------------
 3 files changed, 812 insertions(+), 503 deletions(-)

diff --git a/src/BuildOpt.h b/src/BuildOpt.h
index c5a015f8..0d8b628c 100644
--- a/src/BuildOpt.h
+++ b/src/BuildOpt.h
@@ -2,11 +2,16 @@
 #define _RADIOLIB_BUILD_OPTIONS_H
 
 #if ARDUINO >= 100
+  // Arduino build
   #include "Arduino.h"
+  #define RADIOLIB_BUILD_ARDUINO
 #else
-  #error "Unsupported Arduino version (< 1.0.0)"
+  // generic build
+  #define RADIOLIB_BUILD_GENERIC
 #endif
 
+#if defined(RADIOLIB_BUILD_ARDUINO)
+
 /*
  * Platform-specific configuration.
  *
@@ -18,24 +23,22 @@
  * RADIOLIB_DIGITAL_PIN_TO_INTERRUPT - function/macro to be used to convert digital pin number to interrupt pin number.
  * RADIOLIB_NC - alias for unused pin, usually the largest possible value of RADIOLIB_PIN_TYPE.
  * RADIOLIB_DEFAULT_SPI - default SPIClass instance to use.
- * RADIOLIB_PROGMEM - macro to place variable into program storage (usually Flash).
- * RADIOLIB_PROGMEM_READ_BYTE - function/macro to read variables saved in program storage (usually Flash).
+ * RADIOLIB_NONVOLATILE - macro to place variable into program storage (usually Flash).
+ * RADIOLIB_NONVOLATILE_READ_BYTE - function/macro to read variables saved in program storage (usually Flash).
  * RADIOLIB_TYPE_ALIAS - construct to create an alias for a type, usually vai the `using` keyword.
- * RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - defined if the specific platform does not support SoftwareSerial.
- * RADIOLIB_HARDWARE_SERIAL_PORT - which hardware serial port should be used on platform that do not have SoftwareSerial support.
  * RADIOLIB_TONE_UNSUPPORTED - some platforms do not have tone()/noTone(), which is required for AFSK.
  *
  * In addition, some platforms may require RadioLib to disable specific drivers (such as ESP8266).
  *
- * Users may also specify their own configuration by uncommenting the RADIOLIB_CUSTOM_PLATFORM,
+ * Users may also specify their own configuration by uncommenting the RADIOLIB_CUSTOM_ARDUINO,
  * and then specifying all platform parameters in the section below. This will override automatic
  * platform detection.
  */
 
 // uncomment to enable custom platform definition
-//#define RADIOLIB_CUSTOM_PLATFORM
+//#define RADIOLIB_CUSTOM_ARDUINO
 
-#if defined(RADIOLIB_CUSTOM_PLATFORM)
+#if defined(RADIOLIB_CUSTOM_ARDUINO)
   // name for your platform
   #define RADIOLIB_PLATFORM                           "Custom"
 
@@ -47,14 +50,11 @@
   #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p)        digitalPinToInterrupt(p)
   #define RADIOLIB_NC                                 (0xFF)
   #define RADIOLIB_DEFAULT_SPI                        SPI
-  #define RADIOLIB_PROGMEM                            PROGMEM
-  #define RADIOLIB_PROGMEM_READ_BYTE(addr)            pgm_read_byte(addr)
+  #define RADIOLIB_DEFAULT_SPI_SETTINGS               SPISettings(2000000, MSBFIRST, SPI_MODE0)
+  #define RADIOLIB_NONVOLATILE                        PROGMEM
+  #define RADIOLIB_NONVOLATILE_READ_BYTE(addr)        pgm_read_byte(addr)
   #define RADIOLIB_TYPE_ALIAS(type, alias)            using alias = type;
 
-  // the following must be defined if the Arduino core does not support SoftwareSerial library
-  //#define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
-  //#define RADIOLIB_HARDWARE_SERIAL_PORT               Serial1
-
   // the following must be defined if the Arduino core does not support tone function
   //#define RADIOLIB_TONE_UNSUPPORTED
 
@@ -69,9 +69,6 @@
   //       while keeping SX1231 (because RF69 is the base class for SX1231). The dependency is always uni-directional,
   //       so excluding SX1231 and keeping RF69 is valid.
   //#define RADIOLIB_EXCLUDE_CC1101
-  //#define RADIOLIB_EXCLUDE_ESP8266
-  //#define RADIOLIB_EXCLUDE_HC05
-  //#define RADIOLIB_EXCLUDE_JDY08
   //#define RADIOLIB_EXCLUDE_NRF24
   //#define RADIOLIB_EXCLUDE_RF69
   //#define RADIOLIB_EXCLUDE_SX1231     // dependent on RADIOLIB_EXCLUDE_RF69
@@ -81,13 +78,10 @@
   //#define RADIOLIB_EXCLUDE_RFM9X      // dependent on RADIOLIB_EXCLUDE_SX127X
   //#define RADIOLIB_EXCLUDE_SX126X
   //#define RADIOLIB_EXCLUDE_SX128X
-  //#define RADIOLIB_EXCLUDE_XBEE
   //#define RADIOLIB_EXCLUDE_AFSK
   //#define RADIOLIB_EXCLUDE_AX25
   //#define RADIOLIB_EXCLUDE_HELLSCHREIBER
-  //#define RADIOLIB_EXCLUDE_HTTP
   //#define RADIOLIB_EXCLUDE_MORSE
-  //#define RADIOLIB_EXCLUDE_MQTT
   //#define RADIOLIB_EXCLUDE_RTTY
   //#define RADIOLIB_EXCLUDE_SSTV
 
@@ -102,10 +96,30 @@
     #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p)        digitalPinToInterrupt(p)
     #define RADIOLIB_NC                                 (0xFF)
     #define RADIOLIB_DEFAULT_SPI                        SPI
-    #define RADIOLIB_PROGMEM                            PROGMEM
-    #define RADIOLIB_PROGMEM_READ_BYTE(addr)            pgm_read_byte(addr)
+    #define RADIOLIB_DEFAULT_SPI_SETTINGS               SPISettings(2000000, MSBFIRST, SPI_MODE0)
+    #define RADIOLIB_NONVOLATILE                        PROGMEM
+    #define RADIOLIB_NONVOLATILE_READ_BYTE(addr)        pgm_read_byte(addr)
     #define RADIOLIB_TYPE_ALIAS(type, alias)            using alias = type;
 
+    // Arduino API callbacks
+    #define RADIOLIB_CB_ARGS_PIN_MODE                   (void, pinMode, uint8_t pin, uint8_t mode)
+    #define RADIOLIB_CB_ARGS_DIGITAL_WRITE              (void, digitalWrite, uint8_t pin, uint8_t value)
+    #define RADIOLIB_CB_ARGS_DIGITAL_READ               (int, digitalRead, uint8_t pin)
+    #define RADIOLIB_CB_ARGS_TONE                       (void, tone, uint8_t _pin, unsigned int frequency, unsigned long duration)
+    #define RADIOLIB_CB_ARGS_NO_TONE                    (void, noTone, uint8_t _pin)
+    #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT           (void, attachInterrupt, uint8_t interruptNum, void (*userFunc)(void), int mode)
+    #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT           (void, detachInterrupt, uint8_t interruptNum)
+    #define RADIOLIB_CB_ARGS_YIELD                      (void, yield, void)
+    #define RADIOLIB_CB_ARGS_DELAY                      (void, delay, unsigned long ms)
+    #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS         (void, delayMicroseconds, unsigned int us)
+    #define RADIOLIB_CB_ARGS_MILLIS                     (unsigned long, millis, void)
+    #define RADIOLIB_CB_ARGS_MICROS                     (unsigned long, micros, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN                  (void, SPIbegin, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION      (void, SPIbeginTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_TRANSFER               (uint8_t, SPItransfer, uint8_t b)
+    #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION        (void, SPIendTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_END                    (void, SPIend, void)
+
   #elif defined(ESP8266)
     // ESP8266 boards
     #define RADIOLIB_PLATFORM                           "ESP8266"
@@ -116,13 +130,29 @@
     #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p)        digitalPinToInterrupt(p)
     #define RADIOLIB_NC                                 (0xFF)
     #define RADIOLIB_DEFAULT_SPI                        SPI
-    #define RADIOLIB_PROGMEM                            PROGMEM
-    #define RADIOLIB_PROGMEM_READ_BYTE(addr)            pgm_read_byte(addr)
+    #define RADIOLIB_DEFAULT_SPI_SETTINGS               SPISettings(2000000, MSBFIRST, SPI_MODE0)
+    #define RADIOLIB_NONVOLATILE                        PROGMEM
+    #define RADIOLIB_NONVOLATILE_READ_BYTE(addr)        pgm_read_byte(addr)
     #define RADIOLIB_TYPE_ALIAS(type, alias)            using alias = type;
 
-    // RadioLib has ESP8266 driver, this must be disabled to use ESP8266 as platform
-    #define RADIOLIB_EXCLUDE_ESP8266
-    #define RADIOLIB_EXCLUDE_HTTP
+    // Arduino API callbacks
+    #define RADIOLIB_CB_ARGS_PIN_MODE                   (void, pinMode, uint8_t pin, uint8_t mode)
+    #define RADIOLIB_CB_ARGS_DIGITAL_WRITE              (void, digitalWrite, uint8_t pin, uint8_t value)
+    #define RADIOLIB_CB_ARGS_DIGITAL_READ               (int, digitalRead, uint8_t pin)
+    #define RADIOLIB_CB_ARGS_TONE                       (void, tone, uint8_t _pin, unsigned int frequency, unsigned long duration)
+    #define RADIOLIB_CB_ARGS_NO_TONE                    (void, noTone, uint8_t _pin)
+    #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT           (void, attachInterrupt, uint8_t pin, void (*)(void), int mode)
+    #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT           (void, detachInterrupt, uint8_t interruptNum)
+    #define RADIOLIB_CB_ARGS_YIELD                      (void, yield, void)
+    #define RADIOLIB_CB_ARGS_DELAY                      (void, delay, unsigned long)
+    #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS         (void, delayMicroseconds, unsigned int us)
+    #define RADIOLIB_CB_ARGS_MILLIS                     (unsigned long, millis, void)
+    #define RADIOLIB_CB_ARGS_MICROS                     (unsigned long, micros, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN                  (void, SPIbegin, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION      (void, SPIbeginTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_TRANSFER               (uint8_t, SPItransfer, uint8_t b)
+    #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION        (void, SPIendTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_END                    (void, SPIend, void)
 
   #elif defined(ESP32)
     // ESP32 boards
@@ -134,16 +164,34 @@
     #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p)        digitalPinToInterrupt(p)
     #define RADIOLIB_NC                                 (0xFF)
     #define RADIOLIB_DEFAULT_SPI                        SPI
-    #define RADIOLIB_PROGMEM                            PROGMEM
-    #define RADIOLIB_PROGMEM_READ_BYTE(addr)            pgm_read_byte(addr)
+    #define RADIOLIB_DEFAULT_SPI_SETTINGS               SPISettings(2000000, MSBFIRST, SPI_MODE0)
+    #define RADIOLIB_NONVOLATILE                        PROGMEM
+    #define RADIOLIB_NONVOLATILE_READ_BYTE(addr)        pgm_read_byte(addr)
     #define RADIOLIB_TYPE_ALIAS(type, alias)            using alias = type;
-    #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
-    #define RADIOLIB_HARDWARE_SERIAL_PORT               Serial1
 
     // ESP32 doesn't support tone(), but it can be emulated via LED control peripheral
     #define RADIOLIB_TONE_UNSUPPORTED
     #define RADIOLIB_TONE_ESP32_CHANNEL                 (1)
 
+    // Arduino API callbacks
+    #define RADIOLIB_CB_ARGS_PIN_MODE                   (void, pinMode, uint8_t pin, uint8_t mode)
+    #define RADIOLIB_CB_ARGS_DIGITAL_WRITE              (void, digitalWrite, uint8_t pin, uint8_t value)
+    #define RADIOLIB_CB_ARGS_DIGITAL_READ               (int, digitalRead, uint8_t pin)
+    #define RADIOLIB_CB_ARGS_TONE                       (void, tone, void)
+    #define RADIOLIB_CB_ARGS_NO_TONE                    (void, noTone, void)
+    #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT           (void, attachInterrupt, uint8_t pin, void (*)(void), int mode)
+    #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT           (void, detachInterrupt, uint8_t pin)
+    #define RADIOLIB_CB_ARGS_YIELD                      (void, yield, void)
+    #define RADIOLIB_CB_ARGS_DELAY                      (void, delay, uint32_t)
+    #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS         (void, delayMicroseconds, uint32_t us)
+    #define RADIOLIB_CB_ARGS_MILLIS                     (unsigned long, millis, void)
+    #define RADIOLIB_CB_ARGS_MICROS                     (unsigned long, micros, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN                  (void, SPIbegin, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION      (void, SPIbeginTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_TRANSFER               (uint8_t, SPItransfer, uint8_t b)
+    #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION        (void, SPIendTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_END                    (void, SPIend, void)
+
   #elif defined(ARDUINO_ARCH_STM32)
     // official STM32 Arduino core (https://github.com/stm32duino/Arduino_Core_STM32)
     #define RADIOLIB_PLATFORM                           "Arduino STM32 (official)"
@@ -151,18 +199,36 @@
     #define RADIOLIB_PIN_MODE                           uint32_t
     #define RADIOLIB_PIN_STATUS                         uint32_t
     #define RADIOLIB_INTERRUPT_STATUS                   RADIOLIB_PIN_STATUS
-    #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p)        digitalPinToInterrupt(p)
+    #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p)        digitalPinToInterrupt((PinName)p)
     #define RADIOLIB_NC                                 (0xFFFFFFFF)
     #define RADIOLIB_DEFAULT_SPI                        SPI
-    #define RADIOLIB_PROGMEM                            PROGMEM
-    #define RADIOLIB_PROGMEM_READ_BYTE(addr)            pgm_read_byte(addr)
+    #define RADIOLIB_DEFAULT_SPI_SETTINGS               SPISettings(2000000, MSBFIRST, SPI_MODE0)
+    #define RADIOLIB_NONVOLATILE                        PROGMEM
+    #define RADIOLIB_NONVOLATILE_READ_BYTE(addr)        pgm_read_byte(addr)
     #define RADIOLIB_TYPE_ALIAS(type, alias)            using alias = type;
-    #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
-    #define RADIOLIB_HARDWARE_SERIAL_PORT               Serial1
 
     // slow down SX126x/8x SPI on this platform
     #define RADIOLIB_SPI_SLOWDOWN
 
+    // Arduino API callbacks
+    #define RADIOLIB_CB_ARGS_PIN_MODE                   (void, pinMode, uint32_t dwPin, uint32_t dwMode)
+    #define RADIOLIB_CB_ARGS_DIGITAL_WRITE              (void, digitalWrite, uint32_t dwPin, uint32_t dwVal)
+    #define RADIOLIB_CB_ARGS_DIGITAL_READ               (int, digitalRead, uint32_t ulPin)
+    #define RADIOLIB_CB_ARGS_TONE                       (void, tone, uint8_t _pin, unsigned int frequency, unsigned long duration)
+    #define RADIOLIB_CB_ARGS_NO_TONE                    (void, noTone, uint8_t _pin, bool destruct)
+    #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT           (void, attachInterrupt, uint32_t pin, void (*callback)(void), uint32_t mode)
+    #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT           (void, detachInterrupt, uint32_t pin)
+    #define RADIOLIB_CB_ARGS_YIELD                      (void, yield, void)
+    #define RADIOLIB_CB_ARGS_DELAY                      (void, delay, uint32_t ms)
+    #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS         (void, delayMicroseconds, uint32_t us)
+    #define RADIOLIB_CB_ARGS_MILLIS                     (uint32_t, millis, void)
+    #define RADIOLIB_CB_ARGS_MICROS                     (uint32_t, micros, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN                  (void, SPIbegin, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION      (void, SPIbeginTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_TRANSFER               (uint8_t, SPItransfer, uint8_t b)
+    #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION        (void, SPIendTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_END                    (void, SPIend, void)
+
   #elif defined(SAMD_SERIES)
     // Adafruit SAMD boards (M0 and M4)
     #define RADIOLIB_PLATFORM                           "Adafruit SAMD"
@@ -173,15 +239,33 @@
     #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p)        digitalPinToInterrupt(p)
     #define RADIOLIB_NC                                 (0xFFFFFFFF)
     #define RADIOLIB_DEFAULT_SPI                        SPI
-    #define RADIOLIB_PROGMEM                            PROGMEM
-    #define RADIOLIB_PROGMEM_READ_BYTE(addr)            pgm_read_byte(addr)
+    #define RADIOLIB_DEFAULT_SPI_SETTINGS               SPISettings(2000000, MSBFIRST, SPI_MODE0)
+    #define RADIOLIB_NONVOLATILE                        PROGMEM
+    #define RADIOLIB_NONVOLATILE_READ_BYTE(addr)        pgm_read_byte(addr)
     #define RADIOLIB_TYPE_ALIAS(type, alias)            using alias = type;
-    #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
-    #define RADIOLIB_HARDWARE_SERIAL_PORT               Serial1
 
     // slow down SX126x/8x SPI on this platform
     #define RADIOLIB_SPI_SLOWDOWN
 
+    // Arduino API callbacks
+    #define RADIOLIB_CB_ARGS_PIN_MODE                   (void, pinMode, uint32_t dwPin, uint32_t dwMode)
+    #define RADIOLIB_CB_ARGS_DIGITAL_WRITE              (void, digitalWrite, uint32_t dwPin, uint32_t dwVal)
+    #define RADIOLIB_CB_ARGS_DIGITAL_READ               (int, digitalRead, uint32_t ulPin)
+    #define RADIOLIB_CB_ARGS_TONE                       (void, tone, uint32_t _pin, uint32_t frequency, uint32_t duration)
+    #define RADIOLIB_CB_ARGS_NO_TONE                    (void, noTone, uint32_t _pin)
+    #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT           (void, attachInterrupt, uint32_t pin, voidFuncPtr callback, uint32_t mode)
+    #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT           (void, detachInterrupt, uint32_t pin)
+    #define RADIOLIB_CB_ARGS_YIELD                      (void, yield, void)
+    #define RADIOLIB_CB_ARGS_DELAY                      (void, delay, unsigned long dwMs)
+    #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS         (void, delayMicroseconds, unsigned int)
+    #define RADIOLIB_CB_ARGS_MILLIS                     (unsigned long, millis, void)
+    #define RADIOLIB_CB_ARGS_MICROS                     (unsigned long, micros, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN                  (void, SPIbegin, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION      (void, SPIbeginTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_TRANSFER               (uint8_t, SPItransfer, uint8_t b)
+    #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION        (void, SPIendTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_END                    (void, SPIend, void)
+
   #elif defined(ARDUINO_ARCH_SAMD)
     // Arduino SAMD (Zero, MKR, etc.)
     #define RADIOLIB_PLATFORM                           "Arduino SAMD"
@@ -192,11 +276,29 @@
     #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p)        digitalPinToInterrupt(p)
     #define RADIOLIB_NC                                 (0xFF)
     #define RADIOLIB_DEFAULT_SPI                        SPI
-    #define RADIOLIB_PROGMEM                            PROGMEM
-    #define RADIOLIB_PROGMEM_READ_BYTE(addr)            pgm_read_byte(addr)
+    #define RADIOLIB_DEFAULT_SPI_SETTINGS               SPISettings(2000000, MSBFIRST, SPI_MODE0)
+    #define RADIOLIB_NONVOLATILE                        PROGMEM
+    #define RADIOLIB_NONVOLATILE_READ_BYTE(addr)        pgm_read_byte(addr)
     #define RADIOLIB_TYPE_ALIAS(type, alias)            using alias = type;
-    #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
-    #define RADIOLIB_HARDWARE_SERIAL_PORT               Serial1
+
+    // Arduino API callbacks
+    #define RADIOLIB_CB_ARGS_PIN_MODE                   (void, pinMode, pin_size_t pinNumber, PinMode pinMode)
+    #define RADIOLIB_CB_ARGS_DIGITAL_WRITE              (void, digitalWrite, pin_size_t pinNumber, PinStatus status)
+    #define RADIOLIB_CB_ARGS_DIGITAL_READ               (int, digitalRead, pin_size_t pinNumber)
+    #define RADIOLIB_CB_ARGS_TONE                       (void, tone, unsigned char outputPin, unsigned int frequency, unsigned long duration)
+    #define RADIOLIB_CB_ARGS_NO_TONE                    (void, noTone, uint8_t outputPin)
+    #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT           (void, attachInterrupt, pin_size_t pin, voidFuncPtr callback, PinStatus mode)
+    #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT           (void, detachInterrupt, pin_size_t pin)
+    #define RADIOLIB_CB_ARGS_YIELD                      (void, yield, void)
+    #define RADIOLIB_CB_ARGS_DELAY                      (void, delay, unsigned long)
+    #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS         (void, delayMicroseconds, unsigned int us)
+    #define RADIOLIB_CB_ARGS_MILLIS                     (unsigned long, millis, void)
+    #define RADIOLIB_CB_ARGS_MICROS                     (unsigned long, micros, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN                  (void, SPIbegin, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION      (void, SPIbeginTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_TRANSFER               (uint8_t, SPItransfer, uint8_t b)
+    #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION        (void, SPIendTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_END                    (void, SPIend, void)
 
   #elif defined(__SAM3X8E__)
     // Arduino Due
@@ -208,13 +310,31 @@
     #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p)        digitalPinToInterrupt(p)
     #define RADIOLIB_NC                                 (0xFFFFFFFF)
     #define RADIOLIB_DEFAULT_SPI                        SPI
-    #define RADIOLIB_PROGMEM                            PROGMEM
-    #define RADIOLIB_PROGMEM_READ_BYTE(addr)            pgm_read_byte(addr)
+    #define RADIOLIB_DEFAULT_SPI_SETTINGS               SPISettings(2000000, MSBFIRST, SPI_MODE0)
+    #define RADIOLIB_NONVOLATILE                        PROGMEM
+    #define RADIOLIB_NONVOLATILE_READ_BYTE(addr)        pgm_read_byte(addr)
     #define RADIOLIB_TYPE_ALIAS(type, alias)            using alias = type;
-    #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
-    #define RADIOLIB_HARDWARE_SERIAL_PORT               Serial1
     #define RADIOLIB_TONE_UNSUPPORTED
 
+    // Arduino API callbacks
+    #define RADIOLIB_CB_ARGS_PIN_MODE                   (void, pinMode, uint32_t dwPin, uint32_t dwMode)
+    #define RADIOLIB_CB_ARGS_DIGITAL_WRITE              (void, digitalWrite, uint32_t dwPin, uint32_t dwVal)
+    #define RADIOLIB_CB_ARGS_DIGITAL_READ               (int, digitalRead, uint32_t ulPin)
+    #define RADIOLIB_CB_ARGS_TONE                       (void, tone, void)
+    #define RADIOLIB_CB_ARGS_NO_TONE                    (void, noTone, void)
+    #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT           (void, attachInterrupt, uint32_t pin, void (*callback)(void), uint32_t mode)
+    #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT           (void, detachInterrupt, uint32_t pin)
+    #define RADIOLIB_CB_ARGS_YIELD                      (void, yield, void)
+    #define RADIOLIB_CB_ARGS_DELAY                      (void, delay, uint32_t dwMs)
+    #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS         (void, delayMicroseconds, uint32_t usec)
+    #define RADIOLIB_CB_ARGS_MILLIS                     (uint32_t, millis, void)
+    #define RADIOLIB_CB_ARGS_MICROS                     (uint32_t, micros, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN                  (void, SPIbegin, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION      (void, SPIbeginTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_TRANSFER               (uint8_t, SPItransfer, uint8_t b)
+    #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION        (void, SPIendTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_END                    (void, SPIend, void)
+
   #elif (defined(NRF52832_XXAA) || defined(NRF52840_XXAA)) && !defined(ARDUINO_ARDUINO_NANO33BLE)
     // Adafruit nRF52 boards
     #define RADIOLIB_PLATFORM                           "Adafruit nRF52"
@@ -225,10 +345,30 @@
     #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p)        digitalPinToInterrupt(p)
     #define RADIOLIB_NC                                 (0xFFFFFFFF)
     #define RADIOLIB_DEFAULT_SPI                        SPI
-    #define RADIOLIB_PROGMEM                            PROGMEM
-    #define RADIOLIB_PROGMEM_READ_BYTE(addr)            pgm_read_byte(addr)
+    #define RADIOLIB_DEFAULT_SPI_SETTINGS               SPISettings(2000000, MSBFIRST, SPI_MODE0)
+    #define RADIOLIB_NONVOLATILE                        PROGMEM
+    #define RADIOLIB_NONVOLATILE_READ_BYTE(addr)        pgm_read_byte(addr)
     #define RADIOLIB_TYPE_ALIAS(type, alias)            using alias = type;
 
+    // Arduino API callbacks
+    #define RADIOLIB_CB_ARGS_PIN_MODE                   (void, pinMode, uint32_t dwPin, uint32_t dwMode)
+    #define RADIOLIB_CB_ARGS_DIGITAL_WRITE              (void, digitalWrite, uint32_t dwPin, uint32_t dwVal)
+    #define RADIOLIB_CB_ARGS_DIGITAL_READ               (int, digitalRead, uint32_t ulPin)
+    #define RADIOLIB_CB_ARGS_TONE                       (void, tone, uint8_t pin, unsigned int frequency, unsigned long duration)
+    #define RADIOLIB_CB_ARGS_NO_TONE                    (void, noTone, uint8_t pin)
+    #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT           (int, attachInterrupt, uint32_t pin, voidFuncPtr callback, uint32_t mode)
+    #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT           (void, detachInterrupt, uint32_t pin)
+    #define RADIOLIB_CB_ARGS_YIELD                      (void, yield, void)
+    #define RADIOLIB_CB_ARGS_DELAY                      (void, delay, uint32_t dwMs)
+    #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS         (void, delayMicroseconds, uint32_t usec)
+    #define RADIOLIB_CB_ARGS_MILLIS                     (uint32_t, millis, void)
+    #define RADIOLIB_CB_ARGS_MICROS                     (uint32_t, micros, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN                  (void, SPIbegin, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION      (void, SPIbeginTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_TRANSFER               (uint8_t, SPItransfer, uint8_t b)
+    #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION        (void, SPIendTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_END                    (void, SPIend, void)
+
   #elif defined(ARDUINO_ARC32_TOOLS)
     // Intel Curie
     #define RADIOLIB_PLATFORM                           "Intel Curie"
@@ -239,10 +379,30 @@
     #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p)        digitalPinToInterrupt(p)
     #define RADIOLIB_NC                                 (0xFF)
     #define RADIOLIB_DEFAULT_SPI                        SPI
-    #define RADIOLIB_PROGMEM                            PROGMEM
-    #define RADIOLIB_PROGMEM_READ_BYTE(addr)            pgm_read_byte(addr)
+    #define RADIOLIB_DEFAULT_SPI_SETTINGS               SPISettings(2000000, MSBFIRST, SPI_MODE0)
+    #define RADIOLIB_NONVOLATILE                        PROGMEM
+    #define RADIOLIB_NONVOLATILE_READ_BYTE(addr)        pgm_read_byte(addr)
     #define RADIOLIB_TYPE_ALIAS(type, alias)            using alias = type;
 
+    // Arduino API callbacks
+    #define RADIOLIB_CB_ARGS_PIN_MODE                   (void, pinMode, uint8_t pin, uint8_t mode)
+    #define RADIOLIB_CB_ARGS_DIGITAL_WRITE              (void, digitalWrite, uint8_t pin, uint8_t val)
+    #define RADIOLIB_CB_ARGS_DIGITAL_READ               (int, digitalRead, uint8_t pin)
+    #define RADIOLIB_CB_ARGS_TONE                       (void, tone, uint32_t _pin, unsigned int frequency, unsigned long duration)
+    #define RADIOLIB_CB_ARGS_NO_TONE                    (void, noTone, uint32_t _pin)
+    #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT           (void, attachInterrupt, uint32_t pin, void (*callback)(void), uint32_t mode)
+    #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT           (void, detachInterrupt, uint32_t pin)
+    #define RADIOLIB_CB_ARGS_YIELD                      (void, yield, void)
+    #define RADIOLIB_CB_ARGS_DELAY                      (void, delay, uint32_t dwMs)
+    #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS         (void, delayMicroseconds, uint32_t dwUs)
+    #define RADIOLIB_CB_ARGS_MILLIS                     (uint64_t, millis, void)
+    #define RADIOLIB_CB_ARGS_MICROS                     (uint64_t, micros, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN                  (void, SPIbegin, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION      (void, SPIbeginTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_TRANSFER               (uint8_t, SPItransfer, uint8_t b)
+    #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION        (void, SPIendTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_END                    (void, SPIend, void)
+
   #elif defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY)
     // Arduino megaAVR boards - Uno Wifi Rev.2, Nano Every
     #define RADIOLIB_PLATFORM                           "Arduino megaAVR"
@@ -253,10 +413,30 @@
     #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p)        digitalPinToInterrupt(p)
     #define RADIOLIB_NC                                 (0xFF)
     #define RADIOLIB_DEFAULT_SPI                        SPI
-    #define RADIOLIB_PROGMEM                            PROGMEM
-    #define RADIOLIB_PROGMEM_READ_BYTE(addr)            pgm_read_byte(addr)
+    #define RADIOLIB_DEFAULT_SPI_SETTINGS               SPISettings(2000000, MSBFIRST, SPI_MODE0)
+    #define RADIOLIB_NONVOLATILE                        PROGMEM
+    #define RADIOLIB_NONVOLATILE_READ_BYTE(addr)        pgm_read_byte(addr)
     #define RADIOLIB_TYPE_ALIAS(type, alias)            using alias = type;
 
+    // Arduino API callbacks
+    #define RADIOLIB_CB_ARGS_PIN_MODE                   (void, pinMode, uint8_t pin, PinMode mode)
+    #define RADIOLIB_CB_ARGS_DIGITAL_WRITE              (void, digitalWrite, uint8_t pin, PinStatus val)
+    #define RADIOLIB_CB_ARGS_DIGITAL_READ               (PinStatus, digitalRead, uint8_t pin)
+    #define RADIOLIB_CB_ARGS_TONE                       (void, tone, uint8_t pin, unsigned int frequency, unsigned long duration)
+    #define RADIOLIB_CB_ARGS_NO_TONE                    (void, noTone, uint8_t pin)
+    #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT           (void, attachInterrupt, uint8_t pin, void (*userFunc)(void), PinStatus mode)
+    #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT           (void, detachInterrupt, uint8_t pin)
+    #define RADIOLIB_CB_ARGS_YIELD                      (void, yield, void)
+    #define RADIOLIB_CB_ARGS_DELAY                      (void, delay, unsigned long ms)
+    #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS         (void, delayMicroseconds, unsigned int us)
+    #define RADIOLIB_CB_ARGS_MILLIS                     (unsigned long, millis, void)
+    #define RADIOLIB_CB_ARGS_MICROS                     (unsigned long, micros, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN                  (void, SPIbegin, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION      (void, SPIbeginTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_TRANSFER               (uint8_t, SPItransfer, uint8_t b)
+    #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION        (void, SPIendTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_END                    (void, SPIend, void)
+
   #elif defined(ARDUINO_ARCH_APOLLO3)
     // Sparkfun Apollo3 boards
     #define RADIOLIB_PLATFORM                           "Sparkfun Apollo3"
@@ -267,18 +447,33 @@
     #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p)        digitalPinToInterrupt(p)
     #define RADIOLIB_NC                                 (0xFF)
     #define RADIOLIB_DEFAULT_SPI                        SPI
-    #define RADIOLIB_PROGMEM                            PROGMEM
-    #define RADIOLIB_PROGMEM_READ_BYTE(addr)            pgm_read_byte(addr)
+    #define RADIOLIB_DEFAULT_SPI_SETTINGS               SPISettings(2000000, MSBFIRST, SPI_MODE0)
+    #define RADIOLIB_NONVOLATILE                        PROGMEM
+    #define RADIOLIB_NONVOLATILE_READ_BYTE(addr)        pgm_read_byte(addr)
     #define RADIOLIB_TYPE_ALIAS(type, alias)            using alias = type;
-    #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
-    #define RADIOLIB_HARDWARE_SERIAL_PORT               Serial1
-
-    // Apollo3 uses mbed libraries, which already contain ESP8266 driver
-    #define RADIOLIB_EXCLUDE_ESP8266
 
     // slow down SX126x/8x SPI on this platform
     #define RADIOLIB_SPI_SLOWDOWN
 
+    // Arduino API callbacks
+    #define RADIOLIB_CB_ARGS_PIN_MODE                   (void, pinMode, pin_size_t pinName, Arduino_PinMode pinMode)
+    #define RADIOLIB_CB_ARGS_DIGITAL_WRITE              (void, digitalWrite, pin_size_t pinName, PinStatus val)
+    #define RADIOLIB_CB_ARGS_DIGITAL_READ               (PinStatus, digitalRead, pin_size_t pinName)
+    #define RADIOLIB_CB_ARGS_TONE                       (void, tone, uint8_t _pin, unsigned int frequency, unsigned long duration)
+    #define RADIOLIB_CB_ARGS_NO_TONE                    (void, noTone, uint8_t _pin)
+    #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT           (void, attachInterrupt, pin_size_t interruptNumber, voidFuncPtr callback, PinStatus mode)
+    #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT           (void, detachInterrupt, pin_size_t interruptNumber)
+    #define RADIOLIB_CB_ARGS_YIELD                      (void, yield, void)
+    #define RADIOLIB_CB_ARGS_DELAY                      (void, delay, unsigned long ms)
+    #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS         (void, delayMicroseconds, unsigned int us)
+    #define RADIOLIB_CB_ARGS_MILLIS                     (unsigned long, millis, void)
+    #define RADIOLIB_CB_ARGS_MICROS                     (unsigned long, micros, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN                  (void, SPIbegin, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION      (void, SPIbeginTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_TRANSFER               (uint8_t, SPItransfer, uint8_t b)
+    #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION        (void, SPIendTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_END                    (void, SPIend, void)
+
   #elif defined(ARDUINO_ARDUINO_NANO33BLE)
     // Arduino Nano 33 BLE
     #define RADIOLIB_PLATFORM                           "Arduino Nano 33 BLE"
@@ -289,14 +484,29 @@
     #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p)        digitalPinToInterrupt(p)
     #define RADIOLIB_NC                                 (0xFF)
     #define RADIOLIB_DEFAULT_SPI                        SPI
-    #define RADIOLIB_PROGMEM                            PROGMEM
-    #define RADIOLIB_PROGMEM_READ_BYTE(addr)            pgm_read_byte(addr)
+    #define RADIOLIB_DEFAULT_SPI_SETTINGS               SPISettings(2000000, MSBFIRST, SPI_MODE0)
+    #define RADIOLIB_NONVOLATILE                        PROGMEM
+    #define RADIOLIB_NONVOLATILE_READ_BYTE(addr)        pgm_read_byte(addr)
     #define RADIOLIB_TYPE_ALIAS(type, alias)            using alias = type;
-    #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
-    #define RADIOLIB_HARDWARE_SERIAL_PORT               Serial1
 
-    // Nano 33 BLE uses mbed libraries, which already contain ESP8266 driver
-    #define RADIOLIB_EXCLUDE_ESP8266
+    // Arduino API callbacks
+    #define RADIOLIB_CB_ARGS_PIN_MODE                   (void, pinMode, pin_size_t pin, PinMode mode)
+    #define RADIOLIB_CB_ARGS_DIGITAL_WRITE              (void, digitalWrite, pin_size_t pin, PinStatus val)
+    #define RADIOLIB_CB_ARGS_DIGITAL_READ               (PinStatus, digitalRead, pin_size_t pin)
+    #define RADIOLIB_CB_ARGS_TONE                       (void, tone, uint8_t pin, unsigned int frequency, unsigned long duration)
+    #define RADIOLIB_CB_ARGS_NO_TONE                    (void, noTone, uint8_t pin)
+    #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT           (void, attachInterrupt, pin_size_t interruptNum, voidFuncPtr func, PinStatus mode)
+    #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT           (void, detachInterrupt, pin_size_t interruptNum)
+    #define RADIOLIB_CB_ARGS_YIELD                      (void, yield, void)
+    #define RADIOLIB_CB_ARGS_DELAY                      (void, delay, unsigned long ms)
+    #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS         (void, delayMicroseconds, unsigned int us)
+    #define RADIOLIB_CB_ARGS_MILLIS                     (unsigned long, millis, void)
+    #define RADIOLIB_CB_ARGS_MICROS                     (unsigned long, micros, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN                  (void, SPIbegin, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION      (void, SPIbeginTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_TRANSFER               (uint8_t, SPItransfer, uint8_t b)
+    #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION        (void, SPIendTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_END                    (void, SPIend, void)
 
   #elif defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4)
     // Arduino Portenta H7
@@ -308,14 +518,29 @@
     #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p)        digitalPinToInterrupt(p)
     #define RADIOLIB_NC                                 (0xFF)
     #define RADIOLIB_DEFAULT_SPI                        SPI
-    #define RADIOLIB_PROGMEM                            PROGMEM
-    #define RADIOLIB_PROGMEM_READ_BYTE(addr)            pgm_read_byte(addr)
+    #define RADIOLIB_DEFAULT_SPI_SETTINGS               SPISettings(2000000, MSBFIRST, SPI_MODE0)
+    #define RADIOLIB_NONVOLATILE                        PROGMEM
+    #define RADIOLIB_NONVOLATILE_READ_BYTE(addr)        pgm_read_byte(addr)
     #define RADIOLIB_TYPE_ALIAS(type, alias)            using alias = type;
-    #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
-    #define RADIOLIB_HARDWARE_SERIAL_PORT               Serial1
 
-    // Arduino Portenta H7 uses mbed libraries, which already contain ESP8266 driver
-    #define RADIOLIB_EXCLUDE_ESP8266
+    // Arduino API callbacks
+    #define RADIOLIB_CB_ARGS_PIN_MODE                   (void, pinMode, pin_size_t pin, PinMode mode)
+    #define RADIOLIB_CB_ARGS_DIGITAL_WRITE              (void, digitalWrite, pin_size_t pin, PinStatus val)
+    #define RADIOLIB_CB_ARGS_DIGITAL_READ               (PinStatus, digitalRead, pin_size_t pin)
+    #define RADIOLIB_CB_ARGS_TONE                       (void, tone, uint8_t pin, unsigned int frequency, unsigned long duration)
+    #define RADIOLIB_CB_ARGS_NO_TONE                    (void, noTone, uint8_t pin)
+    #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT           (void, attachInterrupt, pin_size_t interruptNum, voidFuncPtr func, PinStatus mode)
+    #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT           (void, detachInterrupt, pin_size_t interruptNum)
+    #define RADIOLIB_CB_ARGS_YIELD                      (void, yield, void)
+    #define RADIOLIB_CB_ARGS_DELAY                      (void, delay, unsigned long ms)
+    #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS         (void, delayMicroseconds, unsigned int us)
+    #define RADIOLIB_CB_ARGS_MILLIS                     (unsigned long, millis, void)
+    #define RADIOLIB_CB_ARGS_MICROS                     (unsigned long, micros, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN                  (void, SPIbegin, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION      (void, SPIbeginTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_TRANSFER               (uint8_t, SPItransfer, uint8_t b)
+    #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION        (void, SPIendTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_END                    (void, SPIend, void)
 
   #elif defined(__STM32F4__) || defined(__STM32F1__)
     // Arduino STM32 core by Roger Clark (https://github.com/rogerclarkmelbourne/Arduino_STM32)
@@ -327,11 +552,29 @@
     #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p)        digitalPinToInterrupt(p)
     #define RADIOLIB_NC                                 (0xFF)
     #define RADIOLIB_DEFAULT_SPI                        SPI
-    #define RADIOLIB_PROGMEM                            PROGMEM
-    #define RADIOLIB_PROGMEM_READ_BYTE(addr)            pgm_read_byte(addr)
+    #define RADIOLIB_DEFAULT_SPI_SETTINGS               SPISettings(2000000, MSBFIRST, SPI_MODE0)
+    #define RADIOLIB_NONVOLATILE                        PROGMEM
+    #define RADIOLIB_NONVOLATILE_READ_BYTE(addr)        pgm_read_byte(addr)
     #define RADIOLIB_TYPE_ALIAS(type, alias)            using alias = type;
-    #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
-    #define RADIOLIB_HARDWARE_SERIAL_PORT               Serial1
+
+    // Arduino API callbacks
+    #define RADIOLIB_CB_ARGS_PIN_MODE                   (void, pinMode, uint8 pin, WiringPinMode mode)
+    #define RADIOLIB_CB_ARGS_DIGITAL_WRITE              (void, digitalWrite, uint8 pin, uint8 val)
+    #define RADIOLIB_CB_ARGS_DIGITAL_READ               (uint32_t, digitalRead, uint8 pin)
+    #define RADIOLIB_CB_ARGS_TONE                       (void, tone, uint32_t _pin, uint32_t frequency, uint32_t duration)
+    #define RADIOLIB_CB_ARGS_NO_TONE                    (void, noTone, uint32_t _pin)
+    #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT           (void, attachInterrupt, uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode)
+    #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT           (void, detachInterrupt, uint8 pin)
+    #define RADIOLIB_CB_ARGS_YIELD                      (void, yield, void)
+    #define RADIOLIB_CB_ARGS_DELAY                      (void, delay, unsigned long ms)
+    #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS         (void, delayMicroseconds, uint32 us)
+    #define RADIOLIB_CB_ARGS_MILLIS                     (uint32_t, millis, void)
+    #define RADIOLIB_CB_ARGS_MICROS                     (uint32_t, micros, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN                  (void, SPIbegin, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION      (void, SPIbeginTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_TRANSFER               (uint8_t, SPItransfer, uint8_t b)
+    #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION        (void, SPIendTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_END                    (void, SPIend, void)
 
   #elif defined(ARDUINO_ARCH_MEGAAVR)
     // MegaCoreX by MCUdude (https://github.com/MCUdude/MegaCoreX)
@@ -343,10 +586,30 @@
     #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p)        digitalPinToInterrupt(p)
     #define RADIOLIB_NC                                 (0xFF)
     #define RADIOLIB_DEFAULT_SPI                        SPI
-    #define RADIOLIB_PROGMEM                            PROGMEM
-    #define RADIOLIB_PROGMEM_READ_BYTE(addr)            pgm_read_byte(addr)
+    #define RADIOLIB_DEFAULT_SPI_SETTINGS               SPISettings(2000000, MSBFIRST, SPI_MODE0)
+    #define RADIOLIB_NONVOLATILE                        PROGMEM
+    #define RADIOLIB_NONVOLATILE_READ_BYTE(addr)        pgm_read_byte(addr)
     #define RADIOLIB_TYPE_ALIAS(type, alias)            using alias = type;
 
+    // Arduino API callbacks
+    #define RADIOLIB_CB_ARGS_PIN_MODE                   (void, pinMode, uint8_t pin, uint8_t mode)
+    #define RADIOLIB_CB_ARGS_DIGITAL_WRITE              (void, digitalWrite, uint8_t pin, uint8_t value)
+    #define RADIOLIB_CB_ARGS_DIGITAL_READ               (uint8_t, digitalRead, uint8_t pin)
+    #define RADIOLIB_CB_ARGS_TONE                       (void, tone, uint8_t _pin, unsigned int frequency, unsigned long duration)
+    #define RADIOLIB_CB_ARGS_NO_TONE                    (void, noTone, uint8_t _pin)
+    #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT           (void, attachInterrupt, uint8_t pin, void (*userFunc)(void), uint8_t mode)
+    #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT           (void, detachInterrupt, uint8_t interruptNum)
+    #define RADIOLIB_CB_ARGS_YIELD                      (void, yield, void)
+    #define RADIOLIB_CB_ARGS_DELAY                      (void, delay, unsigned long ms)
+    #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS         (void, delayMicroseconds, unsigned int us)
+    #define RADIOLIB_CB_ARGS_MILLIS                     (unsigned long, millis, void)
+    #define RADIOLIB_CB_ARGS_MICROS                     (unsigned long, micros, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN                  (void, SPIbegin, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION      (void, SPIbeginTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_TRANSFER               (uint8_t, SPItransfer, uint8_t b)
+    #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION        (void, SPIendTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_END                    (void, SPIend, void)
+
   #elif defined(ARDUINO_ARCH_RP2040)
     // Raspberry Pi Pico
     #define RADIOLIB_PLATFORM                           "Raspberry Pi Pico"
@@ -357,12 +620,29 @@
     #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p)        digitalPinToInterrupt(p)
     #define RADIOLIB_NC                                 (0xFF)
     #define RADIOLIB_DEFAULT_SPI                        SPI
-    #define RADIOLIB_PROGMEM                            PROGMEM
-    #define RADIOLIB_PROGMEM_READ_BYTE(addr)            pgm_read_byte(addr)
+    #define RADIOLIB_DEFAULT_SPI_SETTINGS               SPISettings(2000000, MSBFIRST, SPI_MODE0)
+    #define RADIOLIB_NONVOLATILE                        PROGMEM
+    #define RADIOLIB_NONVOLATILE_READ_BYTE(addr)        pgm_read_byte(addr)
     #define RADIOLIB_TYPE_ALIAS(type, alias)            using alias = type;
-    #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
-    #define RADIOLIB_HARDWARE_SERIAL_PORT               Serial1
-    #define RADIOLIB_EXCLUDE_ESP8266
+
+    // Arduino API callbacks
+    #define RADIOLIB_CB_ARGS_PIN_MODE                   (void, pinMode, pin_size_t pin, PinMode mode)
+    #define RADIOLIB_CB_ARGS_DIGITAL_WRITE              (void, digitalWrite, pin_size_t pin, PinStatus val)
+    #define RADIOLIB_CB_ARGS_DIGITAL_READ               (PinStatus, digitalRead, pin_size_t pin)
+    #define RADIOLIB_CB_ARGS_TONE                       (void, tone, uint8_t pin, unsigned int frequency, unsigned long duration)
+    #define RADIOLIB_CB_ARGS_NO_TONE                    (void, noTone, uint8_t pin)
+    #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT           (void, attachInterrupt, pin_size_t interruptNum, voidFuncPtr func, PinStatus mode)
+    #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT           (void, detachInterrupt, pin_size_t interruptNum)
+    #define RADIOLIB_CB_ARGS_YIELD                      (void, yield, void)
+    #define RADIOLIB_CB_ARGS_DELAY                      (void, delay, unsigned long ms)
+    #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS         (void, delayMicroseconds, unsigned int us)
+    #define RADIOLIB_CB_ARGS_MILLIS                     (unsigned long, millis, void)
+    #define RADIOLIB_CB_ARGS_MICROS                     (unsigned long, micros, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN                  (void, SPIbegin, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION      (void, SPIbeginTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_TRANSFER               (uint8_t, SPItransfer, uint8_t b)
+    #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION        (void, SPIendTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_END                    (void, SPIend, void)
 
   #elif defined(__ASR6501__) || defined(ARDUINO_ARCH_ASR650X) || defined(DARDUINO_ARCH_ASR6601)
     // CubeCell
@@ -374,10 +654,28 @@
     #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p)        digitalPinToInterrupt(p)
     #define RADIOLIB_NC                                 (0xFF)
     #define RADIOLIB_DEFAULT_SPI                        SPI
-    #define RADIOLIB_PROGMEM                            PROGMEM
-    #define RADIOLIB_PROGMEM_READ_BYTE(addr)            pgm_read_byte(addr)
-    #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
-    #define RADIOLIB_HARDWARE_SERIAL_PORT               Serial1
+    #define RADIOLIB_DEFAULT_SPI_SETTINGS               SPISettings(2000000, MSBFIRST, SPI_MODE0)
+    #define RADIOLIB_NONVOLATILE                        PROGMEM
+    #define RADIOLIB_NONVOLATILE_READ_BYTE(addr)        pgm_read_byte(addr)
+
+    // Arduino API callbacks
+    #define RADIOLIB_CB_ARGS_PIN_MODE                   (void, pinMode, uint8_t pin, PINMODE mode)
+    #define RADIOLIB_CB_ARGS_DIGITAL_WRITE              (void, digitalWrite, uint8_t pin_name, uint8_t level)
+    #define RADIOLIB_CB_ARGS_DIGITAL_READ               (uint8_t, digitalRead, uint8_t pin_name)
+    #define RADIOLIB_CB_ARGS_TONE                       (void, tone, void)
+    #define RADIOLIB_CB_ARGS_NO_TONE                    (void, noTone, void)
+    #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT           (void, attachInterrupt, uint8_t pin_name, GpioIrqHandler GpioIrqHandlerCallback, IrqModes interrupt_mode)
+    #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT           (void, detachInterrupt, uint8_t pin_name)
+    #define RADIOLIB_CB_ARGS_YIELD                      (void, yield, void)
+    #define RADIOLIB_CB_ARGS_DELAY                      (void, delay, uint32_t milliseconds)
+    #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS         (void, delayMicroseconds, uint16 microseconds)
+    #define RADIOLIB_CB_ARGS_MILLIS                     (uint32_t, millis, void)
+    #define RADIOLIB_CB_ARGS_MICROS                     (uint32_t, micros, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN                  (void, SPIbegin, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION      (void, SPIbeginTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_TRANSFER               (uint8_t, SPItransfer, uint8_t b)
+    #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION        (void, SPIendTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_END                    (void, SPIend, void)
 
     // CubeCell doesn't seem to define nullptr, let's do something like that now
     #define nullptr                                     NULL
@@ -398,8 +696,8 @@
     #endif
 
   #else
-    // other platforms not covered by the above list - this may or may not work
-    #define RADIOLIB_PLATFORM                           "Unknown"
+    // other Arduino platforms not covered by the above list - this may or may not work
+    #define RADIOLIB_PLATFORM                           "Unknown Arduino"
     #define RADIOLIB_UNKNOWN_PLATFORM
     #define RADIOLIB_PIN_TYPE                           uint8_t
     #define RADIOLIB_PIN_MODE                           uint8_t
@@ -408,13 +706,49 @@
     #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p)        digitalPinToInterrupt(p)
     #define RADIOLIB_NC                                 (0xFF)
     #define RADIOLIB_DEFAULT_SPI                        SPI
-    #define RADIOLIB_PROGMEM                            PROGMEM
-    #define RADIOLIB_PROGMEM_READ_BYTE(addr)            pgm_read_byte(addr)
+    #define RADIOLIB_DEFAULT_SPI_SETTINGS               SPISettings(2000000, MSBFIRST, SPI_MODE0)
+    #define RADIOLIB_NONVOLATILE                        PROGMEM
+    #define RADIOLIB_NONVOLATILE_READ_BYTE(addr)        pgm_read_byte(addr)
     #define RADIOLIB_TYPE_ALIAS(type, alias)            using alias = type;
 
+    // Arduino API callbacks
+    #define RADIOLIB_CB_ARGS_PIN_MODE                   (void, pinMode, uint8_t pin, uint8_t mode)
+    #define RADIOLIB_CB_ARGS_DIGITAL_WRITE              (void, digitalWrite, uint8_t pin, uint8_t value)
+    #define RADIOLIB_CB_ARGS_DIGITAL_READ               (int, digitalRead, uint8_t pin)
+    #define RADIOLIB_CB_ARGS_TONE                       (void, tone, uint8_t _pin, unsigned int frequency, unsigned long duration)
+    #define RADIOLIB_CB_ARGS_NO_TONE                    (void, noTone, uint8_t _pin)
+    #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT           (void, attachInterrupt, uint8_t interruptNum, void (*userFunc)(void), int mode)
+    #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT           (void, detachInterrupt, uint8_t interruptNum)
+    #define RADIOLIB_CB_ARGS_YIELD                      (void, yield, void)
+    #define RADIOLIB_CB_ARGS_DELAY                      (void, delay, unsigned long ms)
+    #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS         (void, delayMicroseconds, unsigned int us)
+    #define RADIOLIB_CB_ARGS_MILLIS                     (unsigned long, millis, void)
+    #define RADIOLIB_CB_ARGS_MICROS                     (unsigned long, micros, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN                  (void, SPIbegin, void)
+    #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION      (void, SPIbeginTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_TRANSFER               (uint8_t, SPItransfer, uint8_t b)
+    #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION        (void, SPIendTransaction, void)
+    #define RADIOLIB_CB_ARGS_SPI_END                    (void, SPIend, void)
+
   #endif
 #endif
 
+#else
+  // generic non-Arduino platform
+  #define RADIOLIB_PLATFORM                           "Generic"
+  #define RADIOLIB_PIN_TYPE                           int
+  #define RADIOLIB_PIN_MODE                           int
+  #define RADIOLIB_PIN_STATUS                         int
+  #define RADIOLIB_INTERRUPT_STATUS                   RADIOLIB_PIN_STATUS
+  #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p)        (p)
+  #define RADIOLIB_NC                                 (-1)
+  #define RADIOLIB_DEFAULT_SPI                        SPI
+  #define RADIOLIB_NONVOLATILE                        PROGMEM
+  #define RADIOLIB_NONVOLATILE_READ_BYTE(addr)        pgm_read_byte(addr)
+  #define RADIOLIB_TYPE_ALIAS(type, alias)            using alias = type;
+
+#endif
+
 /*
  * Uncomment to enable debug output.
  * Warning: Debug output will slow down the whole system significantly.
@@ -422,27 +756,17 @@
  * Levels: debug - only main info
  *         verbose - full transcript of all SPI/UART communication
  */
-
-//#define RADIOLIB_DEBUG
-//#define RADIOLIB_VERBOSE
-
-// set which Serial port should be used for debug output
-#define RADIOLIB_DEBUG_PORT   Serial
-
-#if defined(RADIOLIB_DEBUG)
-  #define RADIOLIB_DEBUG_PRINT(...) { RADIOLIB_DEBUG_PORT.print(__VA_ARGS__); }
-  #define RADIOLIB_DEBUG_PRINTLN(...) { RADIOLIB_DEBUG_PORT.println(__VA_ARGS__); }
-#else
-  #define RADIOLIB_DEBUG_PRINT(...) {}
-  #define RADIOLIB_DEBUG_PRINTLN(...) {}
+#if !defined(RADIOLIB_DEBUG)
+  //#define RADIOLIB_DEBUG
+#endif
+#if !defined(RADIOLIB_VERBOSE)
+  //#define RADIOLIB_VERBOSE
 #endif
 
-#if defined(RADIOLIB_VERBOSE)
-  #define RADIOLIB_VERBOSE_PRINT(...) { RADIOLIB_DEBUG_PORT.print(__VA_ARGS__); }
-  #define RADIOLIB_VERBOSE_PRINTLN(...) { RADIOLIB_DEBUG_PORT.println(__VA_ARGS__); }
-#else
-  #define RADIOLIB_VERBOSE_PRINT(...) {}
-  #define RADIOLIB_VERBOSE_PRINTLN(...) {}
+// set which output port should be used for debug output
+// may be Serial port (on Arduino) or file like stdout or stderr (on generic platforms)
+#if !defined(RADIOLIB_DEBUG_PORT)
+  #define RADIOLIB_DEBUG_PORT   Serial
 #endif
 
 /*
@@ -451,7 +775,9 @@
  * This improves reliablility, but slightly slows down communication.
  * Note: Enabled by default.
  */
-#define RADIOLIB_SPI_PARANOID
+#if !defined(RADIOLIB_SPI_PARANOID)
+  #define RADIOLIB_SPI_PARANOID
+#endif
 
 /*
  * Uncomment to enable parameter range checking
@@ -460,7 +786,9 @@
  * possibly leading to bricked module and/or program crashing.
  * Note: Enabled by default.
  */
-#define RADIOLIB_CHECK_PARAMS
+#if !defined(RADIOLIB_CHECK_PARAMS)
+  #define RADIOLIB_CHECK_PARAMS
+#endif
 
 /*
  * Uncomment to enable SX127x errata fix
@@ -468,12 +796,8 @@
  *          It should only be enabled if you really are observing some errata-related issue.
  * Note: Disabled by default.
  */
-//#define RADIOLIB_FIX_ERRATA_SX127X
-
-#if defined(RADIOLIB_FIX_ERRATA_SX127X)
-  #define RADIOLIB_ERRATA_SX127X(...) { errataFix(__VA_ARGS__); }
-#else
-  #define RADIOLIB_ERRATA_SX127X(...) {}
+#if !defined(RADIOLIB_FIX_ERRATA_SX127X)
+  //#define RADIOLIB_FIX_ERRATA_SX127X
 #endif
 
 /*
@@ -481,43 +805,101 @@
  * Warning: Come on, it's called GOD mode - obviously only use this if you know what you're doing.
  *          Failure to heed the above warning may result in bricked module.
  */
-//#define RADIOLIB_GODMODE
+#if !defined(RADIOLIB_FIX_ERRATA_SX127X)
+  //#define RADIOLIB_GODMODE
+#endif
 
 /*
  * Uncomment to enable low-level hardware access
  * This will make some hardware methods like SPI get/set accessible from the user sketch - think of it as "god mode lite"
  * Warning: RadioLib won't stop you from writing invalid stuff into your device, so it's quite easy to brick your module with this.
  */
-//#define RADIOLIB_LOW_LEVEL
+#if !defined(RADIOLIB_FIX_ERRATA_SX127X)
+  //#define RADIOLIB_LOW_LEVEL
+#endif
 
 /*
  * Uncomment to enable pre-defined modules when using RadioShield.
  */
-//#define RADIOLIB_RADIOSHIELD
+#if !defined(RADIOLIB_FIX_ERRATA_SX127X)
+  //#define RADIOLIB_RADIOSHIELD
+#endif
 
 /*
  * Uncomment to enable static-only memory management: no dynamic allocation will be performed.
  * Warning: Large static arrays will be created in some methods. It is not advised to send large packets in this mode.
  */
-//#define RADIOLIB_STATIC_ONLY
+#if !defined(RADIOLIB_FIX_ERRATA_SX127X)
+  //#define RADIOLIB_STATIC_ONLY
+#endif
 
 // set the size of static arrays to use
 #if !defined(RADIOLIB_STATIC_ARRAY_SIZE)
-#define RADIOLIB_STATIC_ARRAY_SIZE   256
+  #define RADIOLIB_STATIC_ARRAY_SIZE   (256)
+#endif
+
+#if defined(RADIOLIB_DEBUG)
+  #if defined(RADIOLIB_BUILD_ARDUINO)
+    #define RADIOLIB_DEBUG_PRINT(...) { RADIOLIB_DEBUG_PORT.print(__VA_ARGS__); }
+    #define RADIOLIB_DEBUG_PRINTLN(...) { RADIOLIB_DEBUG_PORT.println(__VA_ARGS__); }
+  #else
+    #if !defined(RADIOLIB_DEBUG_PRINT)
+      #define RADIOLIB_DEBUG_PRINT(...) { frintf(RADIOLIB_DEBUG_PORT, __VA_ARGS__); }
+    #endif
+    #if !defined(RADIOLIB_DEBUG_PRINTLN)
+      #define RADIOLIB_DEBUG_PRINTLN(...)  { printf(RADIOLIB_DEBUG_PORT, __VA_ARGS__ "\n"); }
+    #endif
+  #endif
+#else
+  #define RADIOLIB_DEBUG_PRINT(...) {}
+  #define RADIOLIB_DEBUG_PRINTLN(...) {}
+#endif
+
+#if defined(RADIOLIB_VERBOSE)
+  #define RADIOLIB_VERBOSE_PRINT(...) RADIOLIB_DEBUG_PRINT(__VA_ARGS__)
+  #define RADIOLIB_VERBOSE_PRINTLN(...) RADIOLIB_DEBUG_PRINT(__VA_ARGS__)
+#else
+  #define RADIOLIB_VERBOSE_PRINT(...) {}
+  #define RADIOLIB_VERBOSE_PRINTLN(...) {}
 #endif
 
 /*!
   \brief A simple assert macro, will return on error.
 */
-#define RADIOLIB_ASSERT(STATEVAR) { if((STATEVAR) != ERR_NONE) { return(STATEVAR); } }
+#define RADIOLIB_ASSERT(STATEVAR) { if((STATEVAR) != RADIOLIB_ERR_NONE) { return(STATEVAR); } }
+
+/*
+ * Macros that create callback for the hardware abstraction layer.
+ *
+ * This is the most evil thing I have ever created. I am deeply sorry to anyone currently reading this text.
+ * Come one, come all and witness the horror:
+ * Variadics, forced expansions, inlined function, string concatenation, and it even messes up access specifiers.
+ */
+#define FIRST(arg, ...) arg
+#define REST(arg, ...) __VA_ARGS__
+#define EXP(...) __VA_ARGS__
+
+#define RADIOLIB_GENERATE_CALLBACK_RET_FUNC(RET, FUNC, ...) public: typedef RET (*FUNC##_cb_t)(__VA_ARGS__); void setCb_##FUNC(FUNC##_cb_t cb) { cb_##FUNC = cb; }; private: FUNC##_cb_t cb_##FUNC;
+#define RADIOLIB_GENERATE_CALLBACK_RET(RET, ...) RADIOLIB_GENERATE_CALLBACK_RET_FUNC(RET, __VA_ARGS__)
+#define RADIOLIB_GENERATE_CALLBACK(CB) RADIOLIB_GENERATE_CALLBACK_RET(EXP(FIRST CB), EXP(REST CB))
+
+#define RADIOLIB_GENERATE_CALLBACK_SPI_RET_FUNC(RET, FUNC, ...) public: typedef RET (Module::*FUNC##_cb_t)(__VA_ARGS__); void setCb_##FUNC(FUNC##_cb_t cb) { cb_##FUNC = cb; }; private: FUNC##_cb_t cb_##FUNC;
+#define RADIOLIB_GENERATE_CALLBACK_SPI_RET(RET, ...) RADIOLIB_GENERATE_CALLBACK_SPI_RET_FUNC(RET, __VA_ARGS__)
+#define RADIOLIB_GENERATE_CALLBACK_SPI(CB) RADIOLIB_GENERATE_CALLBACK_SPI_RET(EXP(FIRST CB), EXP(REST CB))
 
 /*!
   \brief Macro to check variable is within constraints - this is commonly used to check parameter ranges. Requires RADIOLIB_CHECK_RANGE to be enabled
 */
 #if defined(RADIOLIB_CHECK_PARAMS)
-#define RADIOLIB_CHECK_RANGE(VAR, MIN, MAX, ERR) { if(!(((VAR) >= (MIN)) && ((VAR) <= (MAX)))) { return(ERR); } }
+  #define RADIOLIB_CHECK_RANGE(VAR, MIN, MAX, ERR) { if(!(((VAR) >= (MIN)) && ((VAR) <= (MAX)))) { return(ERR); } }
 #else
-#define RADIOLIB_CHECK_RANGE(VAR, MIN, MAX, ERR) {}
+  #define RADIOLIB_CHECK_RANGE(VAR, MIN, MAX, ERR) {}
+#endif
+
+#if defined(RADIOLIB_FIX_ERRATA_SX127X)
+  #define RADIOLIB_ERRATA_SX127X(...) { errataFix(__VA_ARGS__); }
+#else
+  #define RADIOLIB_ERRATA_SX127X(...) {}
 #endif
 
 // version definitions
diff --git a/src/Module.cpp b/src/Module.cpp
index 98e6af34..9ff29213 100644
--- a/src/Module.cpp
+++ b/src/Module.cpp
@@ -1,199 +1,122 @@
 #include "Module.h"
 
-SerialModule::SerialModule(RADIOLIB_PIN_TYPE rx, RADIOLIB_PIN_TYPE tx, RADIOLIB_PIN_TYPE rst, HardwareSerial* serial):
-  Module(RADIOLIB_NC, RADIOLIB_NC, (RADIOLIB_PIN_TYPE)rst, (RADIOLIB_PIN_TYPE)rx, (RADIOLIB_PIN_TYPE)tx, RADIOLIB_DEFAULT_SPI, SPISettings(2000000, MSBFIRST, SPI_MODE0), NULL)
-{
-  _initInterface = true;
-
-#ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
-  ModuleSerial = serial;
-#else
-  ModuleSerial = new SoftwareSerial(rx, tx);
-  (void)serial;
-#endif
-}
-
-Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst):
-  _cs(cs),
-  _irq(irq),
-  _rst(rst),
-  _rx(RADIOLIB_NC),
-  _tx(RADIOLIB_NC),
-  _spiSettings(SPISettings(2000000, MSBFIRST, SPI_MODE0))
-{
-  _spi = &RADIOLIB_DEFAULT_SPI;
-  _initInterface = true;
-  ModuleSerial = NULL;
-}
-
+#if defined(RADIOLIB_BUILD_ARDUINO)
 Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio):
   _cs(cs),
   _irq(irq),
   _rst(rst),
-  _rx(gpio),
-  _tx(RADIOLIB_NC),
-  _spiSettings(SPISettings(2000000, MSBFIRST, SPI_MODE0))
+  _gpio(gpio)
 {
   _spi = &RADIOLIB_DEFAULT_SPI;
   _initInterface = true;
-  ModuleSerial = NULL;
-}
 
-Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, SPIClass& spi, SPISettings spiSettings):
-  _cs(cs),
-  _irq(irq),
-  _rst(rst),
-  _rx(RADIOLIB_NC),
-  _tx(RADIOLIB_NC),
-  _spiSettings(spiSettings)
-{
-  _spi = &spi;
-  _initInterface = false;
-  ModuleSerial = NULL;
+  // this is Arduino build, pre-set callbacks
+  setCb_pinMode(::pinMode);
+  setCb_digitalRead(::digitalRead);
+  setCb_digitalWrite(::digitalWrite);
+  #if !defined(RADIOLIB_TONE_UNSUPPORTED)
+  setCb_tone(::tone);
+  setCb_noTone(::noTone);
+  #endif
+  setCb_attachInterrupt(::attachInterrupt);
+  setCb_detachInterrupt(::detachInterrupt);
+  #if !defined(RADIOLIB_YIELD_UNSUPPORTED)
+  setCb_yield(::yield);
+  #endif
+  setCb_delay(::delay);
+  setCb_delayMicroseconds(::delayMicroseconds);
+  setCb_millis(::millis);
+  setCb_micros(::micros);
+  setCb_SPIbegin(&Module::SPIbegin);
+  setCb_SPIbeginTransaction(&Module::beginTransaction);
+  setCb_SPItransfer(&Module::transfer);
+  setCb_SPIendTransaction(&Module::endTransaction);
+  setCb_SPIend(&Module::end);
 }
 
 Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio, SPIClass& spi, SPISettings spiSettings):
   _cs(cs),
   _irq(irq),
   _rst(rst),
-  _rx(gpio),
-  _tx(RADIOLIB_NC),
+  _gpio(gpio),
   _spiSettings(spiSettings)
 {
   _spi = &spi;
   _initInterface = false;
-  ModuleSerial = NULL;
-}
 
-Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE rx, RADIOLIB_PIN_TYPE tx, SPIClass& spi, SPISettings spiSettings, HardwareSerial* serial):
+  // this is Arduino build, pre-set callbacks
+  setCb_pinMode(::pinMode);
+  setCb_digitalRead(::digitalRead);
+  setCb_digitalWrite(::digitalWrite);
+  #if !defined(RADIOLIB_TONE_UNSUPPORTED)
+  setCb_tone(::tone);
+  setCb_noTone(::noTone);
+  #endif
+  setCb_attachInterrupt(::attachInterrupt);
+  setCb_detachInterrupt(::detachInterrupt);
+  #if !defined(RADIOLIB_YIELD_UNSUPPORTED)
+  setCb_yield(::yield);
+  #endif
+  setCb_delay(::delay);
+  setCb_delayMicroseconds(::delayMicroseconds);
+  setCb_millis(::millis);
+  setCb_micros(::micros);
+  setCb_SPIbegin(&Module::SPIbegin);
+  setCb_SPIbeginTransaction(&Module::beginTransaction);
+  setCb_SPItransfer(&Module::transfer);
+  setCb_SPIendTransaction(&Module::endTransaction);
+  setCb_SPIend(&Module::end);
+}
+#else
+
+Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio):
   _cs(cs),
   _irq(irq),
   _rst(rst),
-  _rx(rx),
-  _tx(tx),
-  _spiSettings(spiSettings)
+  _gpio(gpio)
 {
-  _spi = &spi;
-  _initInterface = false;
-
-#ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
-  ModuleSerial = serial;
-#else
-  ModuleSerial = new SoftwareSerial(_rx, _tx);
-  (void)serial;
-#endif
+  // not an Arduino build, it's up to the user to set all callbacks
 }
 
+#endif
+
 Module::Module(const Module& mod) {
   *this = mod;
 }
 
 Module& Module::operator=(const Module& mod) {
-  this->ModuleSerial = mod.ModuleSerial;
-  this->baudrate = mod.baudrate;
-  memcpy(this->AtLineFeed, mod.AtLineFeed, strlen(mod.AtLineFeed));
   this->SPIreadCommand = mod.SPIreadCommand;
   this->SPIwriteCommand = mod.SPIwriteCommand;
   this->_cs = mod.getCs();
   this->_irq = mod.getIrq();
   this->_rst = mod.getRst();
-  this->_rx = mod.getRx();
-  this->_tx = mod.getTx();
-  this->_spiSettings = mod.getSpiSettings();
-  this->_spi = mod.getSpi();
+  this->_gpio = mod.getGpio();
 
   return(*this);
 }
 
-void Module::init(uint8_t interface) {
-  // select interface
-  switch(interface) {
-    case RADIOLIB_USE_SPI:
-      Module::pinMode(_cs, OUTPUT);
-      Module::digitalWrite(_cs, HIGH);
-      if(_initInterface) {
-        _spi->begin();
-      }
-      break;
-    case RADIOLIB_USE_UART:
-      if(_initInterface) {
-#if defined(ESP32)
-        ModuleSerial->begin(baudrate, SERIAL_8N1, _rx, _tx);
-#else
-        ModuleSerial->begin(baudrate);
-#endif
-      }
-      break;
+void Module::init() {
+  this->pinMode(_cs, OUTPUT);
+  this->digitalWrite(_cs, HIGH);
+  if(_initInterface) {
+    (this->*cb_SPIbegin)();
   }
 }
 
-void Module::term(uint8_t interface) {
+void Module::term() {
   // stop hardware interfaces (if they were initialized by the library)
   if(!_initInterface) {
     return;
   }
 
-  if((interface == RADIOLIB_USE_SPI) && (_spi != nullptr)) {
-    _spi->end();
+  if(_spi != nullptr) {
+    this->SPIend();
   }
-
-  #if !defined(__ASR6501__)
-  if(((interface == RADIOLIB_USE_UART) && ModuleSerial != nullptr)) {
-    ModuleSerial->end();
-  }
-  #endif
-}
-
-void Module::ATemptyBuffer() {
-  while(ModuleSerial->available() > 0) {
-    ModuleSerial->read();
-  }
-}
-
-bool Module::ATsendCommand(const char* cmd) {
-  ATemptyBuffer();
-  ModuleSerial->print(cmd);
-  ModuleSerial->print(AtLineFeed);
-  return(ATgetResponse());
-}
-
-bool Module::ATsendData(uint8_t* data, uint32_t len) {
-  ATemptyBuffer();
-  for(uint32_t i = 0; i < len; i++) {
-    ModuleSerial->write(data[i]);
-  }
-
-  ModuleSerial->print(AtLineFeed);
-  return(ATgetResponse());
-}
-
-bool Module::ATgetResponse() {
-  char data[128];
-  char* dataPtr = data;
-  uint32_t start = Module::millis();
-  while(Module::millis() - start < _ATtimeout) {
-    while(ModuleSerial->available() > 0) {
-      char c = ModuleSerial->read();
-      RADIOLIB_VERBOSE_PRINT(c);
-      *dataPtr++ = c;
-    }
-
-    if(strstr(data, "OK") == 0) {
-      RADIOLIB_VERBOSE_PRINTLN();
-      return(true);
-    } else if(strstr(data, "ERROR") == 0) {
-      RADIOLIB_VERBOSE_PRINTLN();
-      return(false);
-    }
-
-  }
-  RADIOLIB_VERBOSE_PRINTLN();
-  return(false);
 }
 
 int16_t Module::SPIgetRegValue(uint8_t reg, uint8_t msb, uint8_t lsb) {
   if((msb > 7) || (lsb > 7) || (lsb > msb)) {
-    return(ERR_INVALID_BIT_RANGE);
+    return(RADIOLIB_ERR_INVALID_BIT_RANGE);
   }
 
   uint8_t rawValue = SPIreadRegister(reg);
@@ -203,7 +126,7 @@ int16_t Module::SPIgetRegValue(uint8_t reg, uint8_t msb, uint8_t lsb) {
 
 int16_t Module::SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t lsb, uint8_t checkInterval, uint8_t checkMask) {
   if((msb > 7) || (lsb > 7) || (lsb > msb)) {
-    return(ERR_INVALID_BIT_RANGE);
+    return(RADIOLIB_ERR_INVALID_BIT_RANGE);
   }
 
   uint8_t currentValue = SPIreadRegister(reg);
@@ -214,13 +137,13 @@ int16_t Module::SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t
   #if defined(RADIOLIB_SPI_PARANOID)
     // check register value each millisecond until check interval is reached
     // some registers need a bit of time to process the change (e.g. SX127X_REG_OP_MODE)
-    uint32_t start = Module::micros();
+    uint32_t start = this->micros();
     uint8_t readValue = 0x00;
-    while(Module::micros() - start < (checkInterval * 1000)) {
+    while(this->micros() - start < (checkInterval * 1000)) {
       readValue = SPIreadRegister(reg);
       if((readValue & checkMask) == (newValue & checkMask)) {
         // check passed, we can stop the loop
-        return(ERR_NONE);
+        return(RADIOLIB_ERR_NONE);
       }
     }
 
@@ -244,9 +167,9 @@ int16_t Module::SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t
     RADIOLIB_DEBUG_PRINTLN(readValue, BIN);
     RADIOLIB_DEBUG_PRINTLN();
 
-    return(ERR_SPI_WRITE_FAILED);
+    return(RADIOLIB_ERR_SPI_WRITE_FAILED);
   #else
-    return(ERR_NONE);
+    return(RADIOLIB_ERR_NONE);
   #endif
 }
 
@@ -270,14 +193,14 @@ void Module::SPIwriteRegister(uint8_t reg, uint8_t data) {
 
 void Module::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes) {
   // start SPI transaction
-  _spi->beginTransaction(_spiSettings);
+  this->SPIbeginTransaction();
 
   // pull CS low
-  Module::digitalWrite(_cs, LOW);
+  this->digitalWrite(_cs, LOW);
 
   // send SPI register address with access command
-  _spi->transfer(reg | cmd);
-  #ifdef RADIOLIB_VERBOSE
+  this->SPItransfer(reg | cmd);
+  #if defined(RADIOLIB_VERBOSE)
     if(cmd == SPIwriteCommand) {
       RADIOLIB_VERBOSE_PRINT('W');
     } else if(cmd == SPIreadCommand) {
@@ -292,7 +215,7 @@ void Module::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* da
   if(cmd == SPIwriteCommand) {
     if(dataOut != NULL) {
       for(size_t n = 0; n < numBytes; n++) {
-        _spi->transfer(dataOut[n]);
+        this->SPItransfer(dataOut[n]);
         RADIOLIB_VERBOSE_PRINT(dataOut[n], HEX);
         RADIOLIB_VERBOSE_PRINT('\t');
       }
@@ -300,7 +223,7 @@ void Module::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* da
   } else if (cmd == SPIreadCommand) {
     if(dataIn != NULL) {
       for(size_t n = 0; n < numBytes; n++) {
-        dataIn[n] = _spi->transfer(0x00);
+        dataIn[n] = this->SPItransfer(0x00);
         RADIOLIB_VERBOSE_PRINT(dataIn[n], HEX);
         RADIOLIB_VERBOSE_PRINT('\t');
       }
@@ -309,92 +232,184 @@ void Module::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* da
   RADIOLIB_VERBOSE_PRINTLN();
 
   // release CS
-  Module::digitalWrite(_cs, HIGH);
+  this->digitalWrite(_cs, HIGH);
 
   // end SPI transaction
-  _spi->endTransaction();
+  this->SPIendTransaction();
 }
 
 void Module::pinMode(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_MODE mode) {
-  if(pin != RADIOLIB_NC) {
-    ::pinMode(pin, mode);
+  if((pin == RADIOLIB_NC) || (cb_pinMode == nullptr)) {
+    return;
   }
+  cb_pinMode(pin, mode);
 }
 
 void Module::digitalWrite(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_STATUS value) {
-  if(pin != RADIOLIB_NC) {
-    ::digitalWrite(pin, value);
+  if((pin == RADIOLIB_NC) || (cb_digitalWrite == nullptr)) {
+    return;
   }
+  cb_digitalWrite(pin, value);
 }
 
 RADIOLIB_PIN_STATUS Module::digitalRead(RADIOLIB_PIN_TYPE pin) {
-  if(pin != RADIOLIB_NC) {
-    return(::digitalRead(pin));
+  if((pin == RADIOLIB_NC) || (cb_digitalRead == nullptr)) {
+    return((RADIOLIB_PIN_STATUS)0);
   }
-  return(LOW);
+  return(cb_digitalRead(pin));
 }
 
-void Module::tone(RADIOLIB_PIN_TYPE pin, uint16_t value) {
+void Module::tone(RADIOLIB_PIN_TYPE pin, uint16_t value, uint32_t duration) {
+  #if !defined(RADIOLIB_TONE_UNSUPPORTED)
+  if((pin == RADIOLIB_NC) || (cb_tone == nullptr)) {
+    return;
+  }
+  cb_tone(pin, value, duration);
+  #else
   if(pin == RADIOLIB_NC) {
     return;
   }
-
-  #if !defined(RADIOLIB_TONE_UNSUPPORTED)
-    ::tone(pin, value);
-  #else
     #if defined(ESP32)
       // ESP32 tone() emulation
       ledcAttachPin(pin, RADIOLIB_TONE_ESP32_CHANNEL);
       ledcWriteTone(RADIOLIB_TONE_ESP32_CHANNEL, value);
+    #else
+      (void)value;
+      (void)duration;
     #endif
   #endif
 }
 
 void Module::noTone(RADIOLIB_PIN_TYPE pin) {
+  #if !defined(RADIOLIB_TONE_UNSUPPORTED)
+  if((pin == RADIOLIB_NC) || (cb_noTone == nullptr)) {
+    return;
+  }
+  #if defined(ARDUINO_ARCH_STM32)
+  cb_noTone(pin, false);
+  #else
+  cb_noTone(pin);
+  #endif
+  #else
   if(pin == RADIOLIB_NC) {
     return;
   }
-
-  #if !defined(RADIOLIB_TONE_UNSUPPORTED)
-    ::noTone(pin);
-  #else
-  #if defined(ESP32)
-    ledcDetachPin(pin);
-    ledcWrite(RADIOLIB_TONE_ESP32_CHANNEL, 0);
-  #endif
+    #if defined(ESP32)
+      // ESP32 tone() emulation
+      ledcDetachPin(pin);
+      ledcWrite(RADIOLIB_TONE_ESP32_CHANNEL, 0);
+    #endif
   #endif
 }
 
 void Module::attachInterrupt(RADIOLIB_PIN_TYPE interruptNum, void (*userFunc)(void), RADIOLIB_INTERRUPT_STATUS mode) {
-  ::attachInterrupt(interruptNum, userFunc, mode);
+  if((interruptNum == RADIOLIB_NC) || (cb_attachInterrupt == nullptr)) {
+    return;
+  }
+  cb_attachInterrupt(interruptNum, userFunc, mode);
 }
 
 void Module::detachInterrupt(RADIOLIB_PIN_TYPE interruptNum) {
-  ::detachInterrupt(interruptNum);
+  if((interruptNum == RADIOLIB_NC) || (cb_detachInterrupt == nullptr)) {
+    return;
+  }
+  cb_detachInterrupt(interruptNum);
 }
 
 void Module::yield() {
+  if(cb_yield == nullptr) {
+    return;
+  }
   #if !defined(RADIOLIB_YIELD_UNSUPPORTED)
-  ::yield();
+  cb_yield();
   #endif
 }
 
 void Module::delay(uint32_t ms) {
-  ::delay(ms);
+  if(cb_delay == nullptr) {
+    return;
+  }
+  cb_delay(ms);
 }
 
 void Module::delayMicroseconds(uint32_t us) {
-  ::delayMicroseconds(us);
+  if(cb_delayMicroseconds == nullptr) {
+    return;
+  }
+  cb_delayMicroseconds(us);
 }
 
 uint32_t Module::millis() {
-  return(::millis());
+  if(cb_millis == nullptr) {
+    return(0);
+  }
+  return(cb_millis());
 }
 
 uint32_t Module::micros() {
-  return(::micros());
+  if(cb_micros == nullptr) {
+    return(0);
+  }
+  return(cb_micros());
 }
 
+void Module::begin() {
+  if(cb_SPIbegin == nullptr) {
+    return;
+  }
+  (this->*cb_SPIbegin)();
+}
+
+void Module::beginTransaction() {
+  if(cb_SPIbeginTransaction == nullptr) {
+    return;
+  }
+  (this->*cb_SPIbeginTransaction)();
+}
+
+uint8_t Module::transfer(uint8_t b) {
+  if(cb_SPItransfer == nullptr) {
+    return(0xFF);
+  }
+  return((this->*cb_SPItransfer)(b));
+}
+
+void Module::endTransaction() {
+  if(cb_SPIendTransaction == nullptr) {
+    return;
+  }
+  (this->*cb_SPIendTransaction)();
+}
+
+void Module::end() {
+  if(cb_SPIend == nullptr) {
+    return;
+  }
+  (this->*cb_SPIend)();
+}
+
+#if defined(RADIOLIB_BUILD_ARDUINO)
+void Module::SPIbegin() {
+  _spi->begin();
+}
+
+void Module::SPIbeginTransaction() {
+  _spi->beginTransaction(_spiSettings);
+}
+
+uint8_t Module::SPItransfer(uint8_t b) {
+  return(_spi->transfer(b));
+}
+
+void Module::SPIendTransaction() {
+  _spi->endTransaction();
+}
+
+void Module::SPIend() {
+  _spi->end();
+}
+#endif
+
 uint8_t Module::flipBits(uint8_t b) {
   b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
   b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
@@ -414,8 +429,8 @@ void Module::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) {
   _useRfSwitch = true;
   _rxEn = rxEn;
   _txEn = txEn;
-  Module::pinMode(rxEn, OUTPUT);
-  Module::pinMode(txEn, OUTPUT);
+  this->pinMode(rxEn, OUTPUT);
+  this->pinMode(txEn, OUTPUT);
 }
 
 void Module::setRfSwitchState(RADIOLIB_PIN_STATUS rxPinState, RADIOLIB_PIN_STATUS txPinState) {
@@ -425,6 +440,6 @@ void Module::setRfSwitchState(RADIOLIB_PIN_STATUS rxPinState, RADIOLIB_PIN_STATU
   }
 
   // set pins
-  Module::digitalWrite(_rxEn, rxPinState);
-  Module::digitalWrite(_txEn, txPinState);
+  this->digitalWrite(_rxEn, rxPinState);
+  this->digitalWrite(_txEn, txPinState);
 }
diff --git a/src/Module.h b/src/Module.h
index 324c4e30..a824d173 100644
--- a/src/Module.h
+++ b/src/Module.h
@@ -1,12 +1,9 @@
-#ifndef _RADIOLIB_MODULE_H
+#if !defined(_RADIOLIB_MODULE_H)
 #define _RADIOLIB_MODULE_H
 
 #include "TypeDef.h"
 
 #include <SPI.h>
-#ifndef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
-#include <SoftwareSerial.h>
-#endif
 
 /*!
   \class Module
@@ -16,19 +13,11 @@
 */
 class Module {
   public:
-    /*!
-      \brief SPI-based module constructor. Will use the default SPI interface automatically initialize it.
 
-      \param cs Arduino pin to be used as chip select.
-
-      \param irq Arduino pin to be used as interrupt/GPIO.
-
-      \param rst Arduino pin to be used as hardware reset for the module.
-    */
-    Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst);
+    #if defined(RADIOLIB_BUILD_ARDUINO)
 
     /*!
-      \brief Extended SPI-based module constructor. Will use the default SPI interface automatically initialize it.
+      \brief Arduino Module constructor. Will use the default SPI interface and automatically initialize it
 
       \param cs Arduino pin to be used as chip select.
 
@@ -38,10 +27,10 @@ class Module {
 
       \param gpio Arduino pin to be used as additional interrupt/GPIO.
     */
-    Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio);
+    Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio = RADIOLIB_NC);
 
     /*!
-      \brief SPI-based module constructor.
+      \brief Arduino Module constructor. Will not attempt SPI interface initialization.
 
       \param cs Arduino pin to be used as chip select.
 
@@ -49,53 +38,30 @@ class Module {
 
       \param rst Arduino pin to be used as hardware reset for the module.
 
+      \param gpio Arduino pin to be used as additional interrupt/GPIO.
+
       \param spi SPI interface to be used, can also use software SPI implementations.
 
       \param spiSettings SPI interface settings.
     */
-    Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, SPIClass& spi, SPISettings spiSettings);
+    Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio, SPIClass& spi, SPISettings spiSettings);
+
+    #else
 
     /*!
-      \brief Extended SPI-based module constructor.
+      \brief Default constructor.
 
-      \param cs Arduino pin to be used as chip select.
+      \param cs Pin to be used as chip select.
 
-      \param irq Arduino pin to be used as interrupt/GPIO.
+      \param irq Pin to be used as interrupt/GPIO.
 
-      \param rst Arduino pin to be used as hardware reset for the module.
+      \param rst Pin to be used as hardware reset for the module.
 
-      \param gpio Arduino pin to be used as additional interrupt/GPIO.
-
-      \param spi SPI interface to be used, can also use software SPI implementations.
-
-      \param spiSettings SPI interface settings. Defaults to 2 MHz clock, MSB first, mode 0.
+      \param gpio Pin to be used as additional interrupt/GPIO.
     */
-    Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio, SPIClass& spi, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0));
+    Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio = RADIOLIB_NC);
 
-    /*!
-      \brief Generic module constructor.
-
-      \param cs Arduino pin to be used as chip select.
-
-      \param irq Arduino pin to be used as interrupt/GPIO.
-
-      \param rst Arduino pin to be used as hardware reset for the module.
-
-      \param tx Arduino pin to be used as Tx pin for SoftwareSerial communication.
-
-      \param rx Arduino pin to be used as Rx pin for SoftwareSerial communication.
-
-      \param spi SPI interface to be used. Defaults to Arduino hardware SPI interface, can also use software SPI implementations.
-
-      \param spiSettings SPI interface settings. Defaults to 2 MHz clock, MSB first, mode 0.
-
-      \param serial HardwareSerial to be used on ESP32 and SAMD. Defaults to 1
-    */
-#ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
-    Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE rx, RADIOLIB_PIN_TYPE tx, SPIClass& spi = RADIOLIB_DEFAULT_SPI, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0), HardwareSerial* serial = &RADIOLIB_HARDWARE_SERIAL_PORT);
-#else
-    Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE rx, RADIOLIB_PIN_TYPE tx, SPIClass& spi = RADIOLIB_DEFAULT_SPI, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0), HardwareSerial* serial = nullptr);
-#endif
+    #endif
 
     /*!
       \brief Copy constructor.
@@ -113,25 +79,6 @@ class Module {
 
     // public member variables
 
-    /*!
-      \brief Internal SoftwareSerial instance.
-    */
-#ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
-    HardwareSerial* ModuleSerial;
-#else
-    SoftwareSerial* ModuleSerial;
-#endif
-
-    /*!
-      \brief Baud rate of SoftwareSerial UART communication. Defaults to 9600 baud.
-    */
-    uint32_t baudrate = 9600;
-
-    /*!
-      \brief Line feed to be used when sending AT commands. Defaults to CR+LF.
-    */
-    char AtLineFeed[3] = {'\r', '\n'};
-
     /*!
       \brief Basic SPI read command. Defaults to 0x00.
     */
@@ -146,51 +93,13 @@ class Module {
 
     /*!
       \brief Initialize low-level module control.
-
-      \param interface Interface to be used on the module. See \ref shield_config for details.
     */
-    void init(uint8_t interface);
+    void init();
 
     /*!
       \brief Terminate low-level module control.
-
-      \param interface Interface to be terminated. See \ref shield_config for details.
     */
-    void term(uint8_t interface);
-
-    // AT methods
-
-    /*!
-      \brief Empty internal AT buffer.
-    */
-    void ATemptyBuffer();
-
-    /*!
-      \brief Get response after sending AT command.
-
-      \returns True if AT response contains the string "OK", false otherwise.
-    */
-    bool ATgetResponse();
-
-    /*!
-      \brief Send AT command. Will also call ATgetResponse.
-
-      \param cmd AT command to be sent. Line feed characters are added automatically.
-
-      \returns True if AT response contains the string "OK", false otherwise.
-    */
-    bool ATsendCommand(const char* cmd);
-
-    /*!
-      \brief Send raw AT data. Will also call ATgetResponse.
-
-      \param data Data to be sent.
-
-      \param len Number of bytes to send.
-
-      \returns True if AT response contains the string "OK", false otherwise.
-    */
-    bool ATsendData(uint8_t* data, uint32_t len);
+    void term();
 
     // SPI methods
 
@@ -309,35 +218,7 @@ class Module {
 
       \returns Pin number of second interrupt/GPIO configured in the constructor.
     */
-    RADIOLIB_PIN_TYPE getGpio() const { return(_rx); }
-
-    /*!
-      \brief Access method to get the pin number of UART Rx.
-
-      \returns Pin number of UART Rx configured in the constructor.
-    */
-    RADIOLIB_PIN_TYPE getRx() const { return(_rx); }
-
-    /*!
-      \brief Access method to get the pin number of UART Rx.
-
-      \returns Pin number of UART Rx configured in the constructor.
-    */
-    RADIOLIB_PIN_TYPE getTx() const { return(_tx); }
-
-    /*!
-      \brief Access method to get the SPI interface.
-
-      \returns SPI interface configured in the constructor.
-    */
-    SPIClass* getSpi() const { return(_spi); }
-
-    /*!
-      \brief Access method to get the SPI interface settings.
-
-      \returns SPI interface settings configured in the constructor.
-    */
-    SPISettings getSpiSettings() const { return(_spiSettings); }
+    RADIOLIB_PIN_TYPE getGpio() const { return(_gpio); }
 
     /*!
       \brief Some modules contain external RF switch controlled by two pins. This function gives RadioLib control over those two pins to automatically switch Rx and Tx state.
@@ -367,7 +248,7 @@ class Module {
 
       \param mode Which mode to set.
     */
-    static void pinMode(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_MODE mode);
+    void pinMode(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_MODE mode);
 
     /*!
       \brief Arduino core digitalWrite override that checks RADIOLIB_NC as alias for unused pin.
@@ -376,7 +257,7 @@ class Module {
 
       \param value Whether to set the pin high or low.
     */
-    static void digitalWrite(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_STATUS value);
+    void digitalWrite(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_STATUS value);
 
     /*!
       \brief Arduino core digitalWrite override that checks RADIOLIB_NC as alias for unused pin.
@@ -385,7 +266,7 @@ class Module {
 
       \returns Pin value.
     */
-    static RADIOLIB_PIN_STATUS digitalRead(RADIOLIB_PIN_TYPE pin);
+    RADIOLIB_PIN_STATUS digitalRead(RADIOLIB_PIN_TYPE pin);
 
     /*!
       \brief Arduino core tone override that checks RADIOLIB_NC as alias for unused pin and RADIOLIB_TONE_UNSUPPORTED to make sure the platform does support tone.
@@ -394,14 +275,14 @@ class Module {
 
       \param value Frequency to output.
     */
-    static void tone(RADIOLIB_PIN_TYPE pin, uint16_t value);
+    void tone(RADIOLIB_PIN_TYPE pin, uint16_t value, uint32_t duration = 0);
 
     /*!
       \brief Arduino core noTone override that checks RADIOLIB_NC as alias for unused pin and RADIOLIB_TONE_UNSUPPORTED to make sure the platform does support tone.
 
       \param pin Pin to write to.
     */
-    static void noTone(RADIOLIB_PIN_TYPE pin);
+    void noTone(RADIOLIB_PIN_TYPE pin);
 
     /*!
       \brief Arduino core attachInterrupt override.
@@ -412,43 +293,77 @@ class Module {
 
       \param mode Pin hcange direction.
     */
-    static void attachInterrupt(RADIOLIB_PIN_TYPE interruptNum, void (*userFunc)(void), RADIOLIB_INTERRUPT_STATUS mode);
+    void attachInterrupt(RADIOLIB_PIN_TYPE interruptNum, void (*userFunc)(void), RADIOLIB_INTERRUPT_STATUS mode);
 
     /*!
       \brief Arduino core detachInterrupt override.
 
       \param interruptNum Interrupt number.
     */
-    static void detachInterrupt(RADIOLIB_PIN_TYPE interruptNum);
+    void detachInterrupt(RADIOLIB_PIN_TYPE interruptNum);
 
     /*!
       \brief Arduino core yield override.
     */
-    static void yield();
+    void yield();
 
     /*!
       \brief Arduino core delay override.
 
       \param ms Delay length in milliseconds.
     */
-    static void delay(uint32_t ms);
+    void delay(uint32_t ms);
 
     /*!
       \brief Arduino core delayMicroseconds override.
 
       \param us Delay length in microseconds.
     */
-    static void delayMicroseconds(uint32_t us);
+    void delayMicroseconds(uint32_t us);
 
     /*!
       \brief Arduino core millis override.
     */
-    static uint32_t millis();
+    uint32_t millis();
 
     /*!
       \brief Arduino core micros override.
     */
-    static uint32_t micros();
+    uint32_t micros();
+
+    /*!
+      \brief Arduino core SPI begin override.
+    */
+    void begin();
+
+    /*!
+      \brief Arduino core SPI beginTransaction override.
+    */
+    void beginTransaction();
+
+    /*!
+      \brief Arduino core SPI transfer override.
+    */
+    uint8_t transfer(uint8_t b);
+
+    /*!
+      \brief Arduino core SPI endTransaction override.
+    */
+    void endTransaction();
+
+    /*!
+      \brief Arduino core SPI end override.
+    */
+    void end();
+
+    // helper functions to set up SPI overrides on Arduino
+    #if defined(RADIOLIB_BUILD_ARDUINO)
+    void SPIbegin();
+    void SPIbeginTransaction();
+    uint8_t SPItransfer(uint8_t b);
+    void SPIendTransaction();
+    void SPIend();
+    #endif
 
     /*!
       \brief Function to reflect bits within a byte.
@@ -460,58 +375,55 @@ class Module {
     */
     static uint16_t flipBits16(uint16_t i);
 
-#ifndef RADIOLIB_GODMODE
+    // hardware abstraction layer callbacks
+    RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_PIN_MODE);
+    RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_DIGITAL_WRITE);
+    RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_DIGITAL_READ);
+    RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_TONE);
+    RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_NO_TONE);
+    RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_ATTACH_INTERRUPT);
+    RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_DETACH_INTERRUPT);
+    RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_YIELD);
+    RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_DELAY);
+    RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_DELAY_MICROSECONDS);
+    RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_MILLIS);
+    RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_MICROS);
+
+    #if defined(RADIOLIB_BUILD_ARDUINO)
+    RADIOLIB_GENERATE_CALLBACK_SPI(RADIOLIB_CB_ARGS_SPI_BEGIN);
+    RADIOLIB_GENERATE_CALLBACK_SPI(RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION);
+    RADIOLIB_GENERATE_CALLBACK_SPI(RADIOLIB_CB_ARGS_SPI_TRANSFER);
+    RADIOLIB_GENERATE_CALLBACK_SPI(RADIOLIB_CB_ARGS_SPI_END_TRANSACTION);
+    RADIOLIB_GENERATE_CALLBACK_SPI(RADIOLIB_CB_ARGS_SPI_END);
+    #else
+    RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_SPI_BEGIN);
+    RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION);
+    RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_SPI_TRANSFER);
+    RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_SPI_END_TRANSACTION);
+    RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_SPI_END);
+    #endif
+
+#if !defined(RADIOLIB_GODMODE)
   private:
 #endif
-    // allow SerialModule class to access private members
-    friend class SerialModule;
-
-    // whether RadioLib should automatically initalize selected SPI or UART interface
-    bool _initInterface = false;
 
     // pins
     RADIOLIB_PIN_TYPE _cs = RADIOLIB_NC;
     RADIOLIB_PIN_TYPE _irq = RADIOLIB_NC;
     RADIOLIB_PIN_TYPE _rst = RADIOLIB_NC;
-    RADIOLIB_PIN_TYPE _rx = RADIOLIB_NC;
-    RADIOLIB_PIN_TYPE _tx = RADIOLIB_NC;
+    RADIOLIB_PIN_TYPE _gpio = RADIOLIB_NC;
 
-    // SPI settings
-    SPISettings _spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0);
+    // SPI interface (Arduino only)
+    #if defined(RADIOLIB_BUILD_ARDUINO)
     SPIClass* _spi = NULL;
+    SPISettings _spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS;
+    bool _initInterface = false;
+    #endif
 
     // RF switch presence and pins
     bool _useRfSwitch = false;
     RADIOLIB_PIN_TYPE _rxEn = RADIOLIB_NC;
     RADIOLIB_PIN_TYPE _txEn = RADIOLIB_NC;
-
-    // AT command timeout in milliseconds
-    uint32_t _ATtimeout = 15000;
-};
-
-/*!
-  \class SerialModule
-
-  \brief Extension of Module class for UART-based modules, only exists to distinguish the UART constructor.
-*/
-class SerialModule: public Module {
-  public:
-    /*!
-      \brief UART-based module constructor.
-
-      \param rx Arduino pin to be used as Rx pin for SoftwareSerial communication.
-
-      \param tx Arduino pin to be used as Tx pin for SoftwareSerial communication.
-
-      \param rst Arduino pin to be used as hardware reset for the module. Defaults to NC (unused).
-
-      \param serial HardwareSerial to be used on platforms that do not support SoftwareSerial. Defaults to Serial1.
-    */
-    #ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
-        SerialModule(RADIOLIB_PIN_TYPE rx, RADIOLIB_PIN_TYPE tx, RADIOLIB_PIN_TYPE rst = RADIOLIB_NC, HardwareSerial* serial = &RADIOLIB_HARDWARE_SERIAL_PORT);
-    #else
-        SerialModule(RADIOLIB_PIN_TYPE rx, RADIOLIB_PIN_TYPE tx, RADIOLIB_PIN_TYPE rst = RADIOLIB_NC, HardwareSerial* serial = nullptr);
-    #endif
 };
 
 #endif