blob: e23a39539bc86815f37febbdaad87f5f6922cb1b [file] [log] [blame]
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2015 Intel Corporation.
*
* Thanks to Semtech for their example code at:
* https://github.com/Lora-net/LoRaMac-node
* released under a modified BSD license, for many clues as to how to
* initialize and operate this radio properly.
* See src/sx1276/LICENSE.txt
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include <string>
#include <sys/time.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pthread.h>
#include <mraa/common.hpp>
#include <mraa/spi.hpp>
#include <mraa/gpio.hpp>
// Our crystal oscillator frequency (32Mhz)
#define FXOSC_FREQ 32000000.0
// Our freq stepping resolution (in Hz) if FXOSC_FREQ is 32Mhz
// (FXOSC_FREQ / 2^19) =
#define FXOSC_STEP 61.03515625
namespace upm {
/**
* @brief SX1276 LoRa/FSK modem
* @defgroup sx1276 libupm-sx1276
* @ingroup spi gpio wifi
*/
/**
* @library sx1276
* @sensor sx1276
* @comname SX1276 LoRa/FSK modem
* @altname SX1277 SX1278 SX1279
* @type wifi
* @man semtech
* @con spi gpio
* @web http://www.digikey.com/product-search/en?vendor=0&keywords=SX1276MB1LAS
*
* @brief API for the SX1276 LoRa/FSK modem
*
* The SX1276 is a FSK/OOK/LoRa modem capable of both Low Frequency
* and High Frequency communication.
*
* It requires a 3.3v power supply, do not use 5v.
*
* Frequency Hopping Spread Spectrum (FHSS) is not currently supported.
*
* While not all of the functionality of this device is supported
* initially, methods and register definitions are provided that
* should allow an end user to implement whatever features are
* required.
*
* FSK send/receive example
* @snippet sx1276-fsk.cxx Interesting
* LORA send/receive example
* @snippet sx1276-lora.cxx Interesting
*/
class SX1276 {
public:
// The default chip revision
static const uint8_t chipRevision = 0x12;
// total FIFO size
static const int FIFO_SIZE = 256;
// differentiator between high and low bands
static const int RF_MID_BAND_THRESH = 525000000;
// LoRa RSSI offsets depending on LF or HF bands
static const int LOR_RSSI_OFFSET_HF = -157;
static const int LOR_RSSI_OFFSET_LF = -164;
/**
* What modem we are configured for
*/
typedef enum {
MODEM_LORA = 0,
MODEM_FSK
} RADIO_MODEM_T;
/**
* Events that can occurr during a TX or RX operation.
*
* When sending or receiving a packet (calling setTx()/send() or
* setRx()), the state will be initialized to ESTATE_EXEC to
* indicate the operation is in progress. Once an event has
* occurred, this state will be updated accordingly.
*
* For receiving, if RX_DONE is set, then it is safe to retrieve
* the rx buffer (via getRxBuffer()/getRxBufferStr()) as well as
* query the RSSI and SNR. On RX_ERROR, these values will be the
* same as they were last set during the last RX_DONE event.
*/
typedef enum {
REVENT_DONE = 0, // operation completed successfully
REVENT_EXEC, // runninsg something
REVENT_ERROR, // failed, crc error, sync timeout
REVENT_TIMEOUT // timed out
} RADIO_EVENT_T;
/**
* SX1276 registers
*
* NOTE: reserved registers must not be written into or read from.
* Reserved bitfields must always be 0.
*
* This device has a set of "common" registers, as well as
* registers that represent different things depending on whether
* the device in in LoRa mode or FSK/OOK mode. So here, we will
* prefix the register names with COM (common), LOR (LoRa mode),
* and FSK (FSK/OOK mode) accordingly.
*/
typedef enum {
COM_RegFifo = 0x00, // FIFO r/w access
COM_RegOpMode = 0x01, // LoRa/FSK
FSK_RegBitrateMsb = 0x02,
LOR_Reserved02 = 0x02, // reserved
FSK_RegBitrateLsb = 0x03,
LOR_Reserved03 = 0x03, // reserved
FSK_RegFdevMsb = 0x04, // freq deviation
LOR_Reserved04 = 0x04, // reserved
FSK_RegFdevLsb = 0x05,
LOR_Reserved05 = 0x05, // reserved
COM_RegFrfMsb = 0x06, // carrier freq
COM_RegFrfMid = 0x07,
COM_RegFrfLsb = 0x08,
COM_RegPaConfig = 0x09,
COM_RegPaRamp = 0x0a,
COM_RegOcp = 0x0b, // overcurrent protection
COM_RegLna = 0x0c,
FSK_RegRxConfig = 0x0d,
LOR_RegFifoAddrPtr = 0x0d,
FSK_RegRssiConfg = 0x0e,
LOR_RegFifoTxBaseAddr = 0x0e,
FSK_RegRssiCollision = 0x0f,
LOR_RegFifoRxBaseAddr = 0x0f,
FSK_RegRssiThresh = 0x10,
LOR_RegFifoRxCurrentAddr = 0x10,
FSK_RegRssiValue = 0x11,
LOR_RegIrqFlagsMask = 0x11,
FSK_RegRxBw = 0x12,
LOR_RegIrqFlags = 0x12,
FSK_RegAfcBw = 0x13, // automatic freq cntrl
LOR_RegRxNbBytes = 0x13, // received pkt len
FSK_RegOokPeak = 0x14,
LOR_RegRxHeaderCntValueMsb = 0x14,
FSK_RegOokFix = 0x15,
LOR_RegRxHeaderCntValueLsb = 0x15,
FSK_RegOokAvg = 0x16,
LOR_RegRxPacketCntValueMsb = 0x16,
FSK_Reserved17 = 0x17, // reserved
LOR_RegRxPacketCntValueLsb = 0x17,
FSK_Reserved18 = 0x18, // reserved
LOR_RegModemStat = 0x18,
FSK_Reserved19 = 0x19, // reserved
LOR_RegPktSnrValue = 0x19,
FSK_RegAfcFei = 0x1a,
LOR_RegPktRssiValue = 0x1a,
FSK_RegAfcMsb = 0x1b,
LOR_RegRssiValue = 0x1b,
FSK_RegAfcLsb = 0x1c,
LOR_RegHopChannel = 0x1c, // fhss starting channel
FSK_RegFeiMsb = 0x1d,
LOR_RegModemConfig1 = 0x1d,
FSK_RegFeiLsb = 0x1e,
LOR_RegModemConfig2 = 0x1e,
FSK_RegPreambleDetect = 0x1f,
LOR_RegSymbTimeoutLsb = 0x1f,
FSK_RegRxTimeout1 = 0x20,
LOR_RegPreambleMsb = 0x20,
FSK_RegRxTimeout2 = 0x21,
LOR_RegPreambleLsb = 0x21,
FSK_RegRxTimeout3 = 0x22,
LOR_RegPayloadLength = 0x22,
FSK_RegRxDelay = 0x23,
LOR_RegMaxPayloadLength = 0x23,
FSK_RegOsc = 0x24,
LOR_RegHopPeriod = 0x24,
FSK_RegPreambleMsb = 0x25,
LOR_RegFifoRxByteAddr = 0x25,
FSK_RegPreambleLsb = 0x26,
LOR_RegModemConfig3 = 0x26,
FSK_RegSyncConfig = 0x27,
LOR_Reserved27 = 0x27, // reserved
FSK_RegSyncValue1 = 0x28,
LOR_RegFeiMsb = 0x28,
FSK_RegSyncValue2 = 0x29,
LOR_RegFeiMid = 0x29,
FSK_RegSyncValue3 = 0x2a,
LOR_RegFeiLsb = 0x2a,
FSK_RegSyncValue4 = 0x2b,
LOR_Reserved2b = 0x2b, // reserved
FSK_RegSyncValue5 = 0x2c,
LOR_RegRssiWideband = 0x2c,
FSK_RegSyncValue6 = 0x2d,
LOR_Reserved2d = 0x2d, // reserved
FSK_RegSyncValue7 = 0x2e,
LOR_Reserved2e = 0x2e, // reserved
FSK_RegSyncValue8 = 0x2f,
LOR_Reserved2f = 0x2f, // reserved
FSK_RegPacketConfig1 = 0x30,
LOR_Reserved30 = 0x30, // reserved
FSK_RegPacketConfig2 = 0x31,
LOR_RegDetectOptimize = 0x31,
FSK_RegPayloadLength = 0x32,
LOR_Reserved32 = 0x32, // reserved
FSK_RegNodeAddr = 0x33,
LOR_RegInvertIQ = 0x33,
FSK_RegBroadcastAddr = 0x34,
LOR_Reserved34 = 0x34, // reserved
FSK_RegFifoThresh = 0x35,
LOR_Reserved35 = 0x35, // reserved
FSK_RegSeqConfig1 = 0x36,
LOR_Reserved36 = 0x36, // reserved
FSK_RegSeqConfig2 = 0x37,
LOR_RegDetectionThreshold = 0x37,
FSK_RegTimerResol = 0x38,
LOR_Reserved38 = 0x38, // reserved
FSK_RegTimer1Coeff = 0x39,
LOR_RegSyncWord = 0x39,
FSK_RegTimer2Coeff = 0x3a,
LOR_Reserved3a = 0x3a, // reserved
FSK_RegImageCal = 0x3b,
LOR_Reserved3b = 0x3b, // reserved (in datasheet)?
LOR_RegInvertIQ2 = 0x3b, // does not exist in datasheet
// but used in Semtech code.
// UNDOCUMENTED
FSK_RegTemp = 0x3c,
LOR_Reserved3c = 0x3c, // reserved
FSK_RegLowBat = 0x3d,
LOR_Reserved3d = 0x3d, // reserved
FSK_RegIrqFlags1 = 0x3e,
LOR_Reserved3e = 0x3e, // reserved
FSK_RegIrqFlags2 = 0x3f,
LOR_Reserved3f = 0x3f, // reserved
COM_RegDioMapping1 = 0x40, // DIO0-DIO3
COM_RegDioMapping2 = 0x41, // DIO4-DIO5, clk out freq
COM_RegVersion = 0x42, // Semtech ID (silicon revision)
// 0x43 reserved
// The data sheet says this is FSK only, but the semtech code
// implies this is only valid for LoRa. So for now, assume the
// datasheet is wrong.
//
// FSK_RegPllHop = 0x44,
// LOR_Reserved44 = 0x44, // reserved
FSK_Reserved44 = 0x44,
LOR_RegPllHop = 0x44,
// 0x45-0x4a reserved
COM_RegTcxo = 0x4b,
// 0x4c reserved
COM_RegPaDac = 0x4d,
// 0x4e-0x5a reserved
COM_RegFormerTemp = 0x5b,
// 0x5c reserved
FSK_RegBitRateFrac = 0x5d,
LOR_Reserved5d = 0x5d, // reserved
// 0x5e-0x60 reserved
COM_RegAgcRef = 0x61,
COM_RegAgcThresh1 = 0x62,
COM_RegAgcThresh2 = 0x63,
COM_RegAgcThresh3 = 0x64,
// 0x65-0x6f reserved
COM_RegPll = 0x70
// 0x71-0xff reserved
} SX1276_REGS_T;
/**
* OpMode register (differing bitfields depending on mode)
*/
typedef enum {
OPMODE_Mode0 = 0x01, // operating modes (sleep, etc)
OPMODE_Mode1 = 0x02,
OPMODE_Mode2 = 0x04,
_OPMODE_Mode_MASK = 7,
_OPMODE_Mode_SHIFT = 0,
OPMODE_LowFrequencyModeOn = 0x08,
// 0x10 reserved
OPMODE_FSK_ModulationType0 = 0x20,
OPMODE_FSK_ModulationType1 = 0x40,
_OPMODE_FSK_ModulationType_MASK = 3,
_OPMODE_FSK_ModulationType_SHIFT = 5,
OPMODE_LOR_Reserved0x20 = 0x20,
OPMODE_LOR_AccessSharedReg = 0x40, // tmp sw to FSK regs
OPMODE_LongRangeMode = 0x80 // LoRa mode enable(1), else FSK
} OPMODE_BITS_T;
/**
* Mode values
*/
typedef enum {
MODE_Sleep = 0,
MODE_Standby = 1,
MODE_FSTX = 2, // freq synth
MODE_TxMode = 3,
MODE_FSRX = 4, // freq synth
MODE_FSK_RxMode = 5,
MODE_LOR_RxContinuous = 5, // continuous rx mode
MODE_FSK_Reserved6 = 6,
MODE_LOR_RxSingle = 6, // single packet rx mode
MODE_FSK_Reserved7 = 7,
MODE_LOR_CAD = 7 // channel activity detection
} MODE_T;
/**
* FSK_ModulationType values
*/
typedef enum {
MODULATION_FSK = 0, // freq shift keying
MODULATION_OOK = 1, // on/off keying
// 2-3 reserved
} FSK_MODULATION_TYPE_T;
/**
* RegPaConfig register
*/
typedef enum {
PACONFIG_OutputPower0 = 0x01,
PACONFIG_OutputPower1 = 0x02,
PACONFIG_OutputPower2 = 0x04,
PACONFIG_OutputPower3 = 0x08,
_PACONFIG_OutputPower_MASK = 15,
_PACONFIG_OutputPower_SHIFT = 0,
PACONFIG_MaxPower0 = 0x10,
PACONFIG_MaxPower1 = 0x20,
PACONFIG_MaxPower2 = 0x40,
_PACONFIG_MaxPower_MASK = 7,
_PACONFIG_MaxPower_SHIFT = 4,
PACONFIG_PaSelect = 0x80 // PA output pin,
// 0 = 14dBm, 1 = 20dBm
} PACONFIG_BITS_T;
/**
* RegPaRamp register
*/
typedef enum {
PARAMP_PaRamp0 = 0x01, // rise/fall of ramp up/down
PARAMP_PaRamp1 = 0x02,
PARAMP_PaRamp2 = 0x04,
PARAMP_PaRamp3 = 0x08,
_PARAMP_PaRamp_MASK = 15,
_PARAMP_PaRamp_SHIFT = 0,
// 0x10 reserved
// LORA 0x20-0x40 reserved
PARAMP_FSK_ModulationShaping0 = 0x20,
PARAMP_FSK_ModulationShaping1 = 0x40,
_PARAMP_FSK_ModulationShaping_MASK = 3,
_PARAMP_FSK_ModulationShaping_SHIFT = 5
// 0x80 reserved
} PARAMP_BITS_T;
/**
* PARAMP_PaRamp values
*/
typedef enum {
PARAMP_3_4MS = 0, // 3.4ms
PARAMP_2MS = 1,
PARAMP_1MS = 2,
PARAMP_500US = 3, // 500us
PARAMP_250US = 4,
PARAMP_125US = 5,
PARAMP_100US = 6,
PARAMP_62US = 7,
PARAMP_50US = 8,
PARAMP_40US = 9,
PARAMP_31US = 10,
PARAMP_25US = 11,
PARAMP_20US = 12,
PARAMP_15US = 13,
PARAMP_12US = 14,
PARAMP_10US = 15
} PARAMP_T;
/**
* PARAMP_ModulationShaping values. Note, these mean different
* things depending on whether you are using FSK or OOK. Hence
* the FSK/OOK dups. We will also name these as 'MODSHAPING_', rather
* than the lengthy 'MODULATIONSHAPING... '
*/
typedef enum {
MODSHAPING_NOSHAPING = 0,
// FSK
MODSHAPING_FSK_GaussianFilterBT1 = 1, // BT = 1.0
MODSHAPING_FSK_GaussianFilterBT05 = 2, // BT = 0.5
MODSHAPING_FSK_GaussianFilterBT03 = 3, // BT = 0.3
// OOK
MODSHAPING_OOK_FCutoffBitRate = 1, // Fcutoff = BitRate
MODSHAPING_OOK_FCutoffBitRate2 = 2 // Fcutoff = 2*BitRate
// for OOK, 3 is reserved
} MODSHAPING_T;
/**
* RegOcp register (see datasheet for OcpTrim values)
*/
typedef enum {
OCP_OcpTrim0 = 0x01,
OCP_OcpTrim1 = 0x02,
OCP_OcpTrim2 = 0x04,
OCP_OcpTrim3 = 0x08,
_OCP_OcpTrim_MASK = 15,
_OCP_OcpTrim_SHIFT = 0,
OCP_OcpOn = 0x10
// 0x20-0x80 reserved
} OCP_BITS_T;
/**
* Lna register
*/
typedef enum {
LNA_LnaBoostHf0 = 0x01,
LNA_LnaBoostHf1 = 0x02,
_LNA_LnaBoostHf_MASK = 3,
_LNA_LnaBoostHf_SHIFT = 0,
// 0x04 reserved
LNA_LnaBoostLf0 = 0x08,
LNA_LnaBoostLf1 = 0x10,
_LNA_LnaBoostLf_MASK = 3,
_LNA_LnaBoostLf_SHIFT = 3,
LNA_LnaGain0 = 0x20,
LNA_LnaGain1 = 0x40,
LNA_LnaGain2 = 0x80,
_LNA_LnaGain_MASK = 7,
_LNA_LnaGain_SHIFT = 5
} LNA_BITS_T;
/**
* LnaBoostHf values
*/
typedef enum {
LNABOOSTHF_Default = 0,
// 1-2 reserved
LNABOOSTHF_BoostOn = 3, // 150% LNA current
} LNABOOSTHF_T;
/**
* LnaBoostLf values
*/
typedef enum {
LNABOOSTLF_Default = 0
// 1-3 reserved
} LNABOOSTLF_T;
/**
* LnaGain values
*/
typedef enum {
// 0 reserved
LNAGAIN_G1 = 1, // max gain
LNAGAIN_G2 = 2,
LNAGAIN_G3 = 3,
LNAGAIN_G4 = 4,
LNAGAIN_G5 = 5,
LNAGAIN_G6 = 6 // minimum gain
// 7 reserved
} LNAGAIN_T;
/**
* FSK_RxConfig register. See Table 24 in the data sheet for
* the meanings of the RxTrigger values.
*/
typedef enum {
RXCONFIG_RxTrigger0 = 0x01,
RXCONFIG_RxTrigger1 = 0x02,
RXCONFIG_RxTrigger2 = 0x04,
_RXCONFIG_RxTrigger_MASK = 7,
_RXCONFIG_RxTrigger_SHIFT = 0,
RXCONFIG_AgcAutoOn = 0x08,
RXCONFIG_AfcAutoOn = 0x10,
RXCONFIG_RestartRxWithPllLock = 0x20,
RXCONFIG_RestartRxWithoutPllLock = 0x40,
RXCONFIG_RestartRxOnCollision = 0x80
} RXCONFIG_BITS_T;
/**
* FSK_RssiConfig register
*/
typedef enum {
RSSICONFIG_RssiSmoothing0 = 0x01, // RSSI sampling/averaging
RSSICONFIG_RssiSmoothing1 = 0x02,
RSSICONFIG_RssiSmoothing2 = 0x04,
_RSSICONFIG_RssiSmoothing_MASK = 7,
_RSSICONFIG_RssiSmoothing_SHIFT = 0,
RSSICONFIG_RssiOffset0 = 0x08, // 2's complement offset
RSSICONFIG_RssiOffset1 = 0x10,
RSSICONFIG_RssiOffset2 = 0x20,
RSSICONFIG_RssiOffset3 = 0x40,
RSSICONFIG_RssiOffset4 = 0x80,
_RSSICONFIG_RssiOffset_MASK = 31,
_RSSICONFIG_RssiOffset_SHIFT = 3
} RSSICONFIG_BITS_T;
/**
* RssiSmoothing values
*/
typedef enum {
RSSISMOOTHING_2 = 0, // 2 samples used
RSSISMOOTHING_4 = 1,
RSSISMOOTHING_8 = 2,
RSSISMOOTHING_16 = 3,
RSSISMOOTHING_32 = 4,
RSSISMOOTHING_64 = 5,
RSSISMOOTHING_128 = 6,
RSSISMOOTHING_256 = 7
} RSSISMOOTHING_T;
/**
* LOR_RegIrqFlagsMask and LOR_RegIrqFlags registers
*/
typedef enum {
LOR_IRQFLAG_CadDetected = 0x01,
LOR_IRQFLAG_FhssChangeChannel = 0x02,
LOR_IRQFLAG_CadDone = 0x04,
LOR_IRQFLAG_TxDone = 0x08,
LOR_IRQFLAG_ValidHeader = 0x10,
LOR_IRQFLAG_PayloadCrcError = 0x20,
LOR_IRQFLAG_RxDone = 0x40,
LOR_IRQFLAG_RxTimeout = 0x80
} LOR_IRQFLAG_BITS_T;
/**
* FSK_RxBw register and FSK_RegAfcBw registers
*/
typedef enum {
RXBW_RxBwExp0 = 0x01,
RXBW_RxBwExp1 = 0x02,
RXBW_RxBwExp2 = 0x04,
_RXBW_RxBwExp_MASK = 7,
_RXBW_RxBwExp_SHIFT = 0,
RXBW_RxBwMant0 = 0x08,
RXBW_RxBwMant1 = 0x10,
_RXBW_RxBwMant_MASK = 3,
_RXBW_RxBwMant_SHIFT = 3,
// 0x20-0x80 reserved
} RXBW_BITS_T;
/**
* RXBW_RxBwMant values
*/
typedef enum {
RXBWMANT_0 = 0,
RXBWMANT_1 = 1,
RXBWMANT_2 = 2
// 3 reserved
} RXBWMANT_T;
/**
* RXBW_RxBwExp values
*/
typedef enum {
RXBWEXP_1 = 1,
RXBWEXP_2 = 2,
RXBWEXP_3 = 3,
RXBWEXP_4 = 4,
RXBWEXP_5 = 5,
RXBWEXP_6 = 6,
RXBWEXP_7 = 7
// other values reserved
} RXBWEXP_T;
/**
* FSK_OokPeak register
*/
typedef enum {
OOKPEAK_OokPeakThreshStep0 = 0x01,
OOKPEAK_OokPeakThreshStep1 = 0x02,
OOKPEAK_OokPeakThreshStep2 = 0x04,
_OOKPEAK_OokPeakThreshStep_MASK = 7,
_OOKPEAK_OokPeakThreshStep_SHIFT = 0,
OOKPEAK_OokThreshType0 = 0x08,
OOKPEAK_OokThreshType1 = 0x10,
_OOKPEAK_OokThreshType_MASK = 3,
_OOKPEAK_OokThreshType_SHIFT = 3,
OOKPEAK_BitSyncOn = 0x20,
// 0x40-0x80 reserved
} OOKPEAK_BITS_T;
/**
* OokPeakThreshStep values
*/
typedef enum {
OOKPEAKTHRESHSTEP_05dB = 0, // dec of RSSI threshold 0.5dB
OOKPEAKTHRESHSTEP_1dB = 1, // 1 dB
OOKPEAKTHRESHSTEP_15dB = 2, // 1.5 dB
OOKPEAKTHRESHSTEP_2dB = 3, // 2 dB
OOKPEAKTHRESHSTEP_3dB = 4,
OOKPEAKTHRESHSTEP_4dB = 5,
OOKPEAKTHRESHSTEP_5dB = 6,
OOKPEAKTHRESHSTEP_6dB = 7
} OOKPEAKTHRESHSTEP_T;
/**
* OokPeakThreshType values
*/
typedef enum {
OOKTHRESHTYPE_FIXED = 0,
OOKTHRESHTYPE_PEAK = 1,
OOKTHRESHTYPE_AVERAGE = 2
// 3 reserved
} OOKTHRESHTYPE_T;
/**
* FSK_OokAvg register
*/
typedef enum {
OOKAVG_OokAvgThreshFilt0 = 0x01,
OOKAVG_OokAvgThreshFilt1 = 0x02,
_OOKAVG_OokAvgThreshFilt_MASK = 3,
_OOKAVG_OokAvgThreshFilt_SHIFT = 0,
OOKAVG_OokAvgOffset0 = 0x04,
OOKAVG_OokAvgOffset1 = 0x08,
_OOKAVG_OokAvgOffset_MASK = 3,
_OOKAVG_OokAvgOffset_SHIFT = 2,
// 0x10 reserved
OOKAVG_OokPeakThreshDec0 = 0x20,
OOKAVG_OokPeakThreshDec1 = 0x40,
OOKAVG_OokPeakThreshDec2 = 0x80,
_OOKAVG_OokPeakThreshDec_MASK = 7,
_OOKAVG_OokPeakThreshDec_SHIFT = 5
} OOKAVG_BITS_T;
/**
* OokAvgThreshFilt values
*/
typedef enum {
OOKAVGTHRESHFILT_32 = 0, // filter coedd in avg mode
OOKAVGTHRESHFILT_8 = 1,
OOKAVGTHRESHFILT_4 = 2,
OOKAVGTHRESHFILT_2 = 3
} OOKAVGTHRESHFILT_T;
/**
* OokAvgOffset values
*/
typedef enum {
OOKAVGOFFSET_0 = 0, // 0.0dB
OOKAVGOFFSET_2 = 1,
OOKAVGOFFSET_4 = 2,
OOKAVGOFFSET_6 = 3
} OOKAVGOFFSET_T;
/**
* OokPeakThreshDec values
*/
typedef enum {
OOKPEAKTHRESHDEC_1_1 = 0, // once per chip
OOKPEAKTHRESHDEC_1_2 = 1, // once every 2 chips...
OOKPEAKTHRESHDEC_1_4 = 2,
OOKPEAKTHRESHDEC_1_8 = 3,
OOKPEAKTHRESHDEC_2_1 = 4, // twice per chip
OOKPEAKTHRESHDEC_4_1 = 5, // 4 times every chip...
OOKPEAKTHRESHDEC_8_1 = 6,
OOKPEAKTHRESHDEC_16_1 = 7
} OOKPEAKTHRESHDEC_T;
/**
* LOR_ModemStat register
*/
typedef enum {
MODEMSTAT_SignalDetected = 0x01,
MODEMSTAT_SignalSynchronized = 0x02,
MODEMSTAT_RxOngoing = 0x04,
MODEMSTAT_HeaderInfoValid = 0x08,
MODEMSTAT_ModemClear = 0x10,
MODEMSTAT_RxCodingRate0 = 0x20,
MODEMSTAT_RxCodingRate1 = 0x40,
MODEMSTAT_RxCodingRate2 = 0x80,
_MODEMSTAT_RxCodingRate_MASK = 7,
_MODEMSTAT_RxCodingRate_SHIFT = 5
} MODEMSTAT_BITS_T;
/**
* FSK_RegAfcFei register
*/
typedef enum {
AFCFEI_AfcAutoClearOn = 0x01,
AFCFEI_AfcClear = 0x02,
// 0x04-0x08 reserved
AFCFEI_AgcStart = 0x10
// 0x20-0x80 reserved
} AFCFEI_BITS_T;
/**
* LOR_HopChannel register
*/
typedef enum {
HOPCHANNEL_FhssPresentChannel0 = 0x01, // current freq hopping channel
HOPCHANNEL_FhssPresentChannel1 = 0x02,
HOPCHANNEL_FhssPresentChannel2 = 0x04,
HOPCHANNEL_FhssPresentChannel3 = 0x08,
HOPCHANNEL_FhssPresentChannel4 = 0x10,
HOPCHANNEL_FhssPresentChannel5 = 0x20,
_HOPCHANNEL_FhssPresentChannel_MASK = 63,
_HOPCHANNEL_FhssPresentChannel_SHIFT = 0,
HOPCHANNEL_CrcOnPayload = 0x40,
HOPCHANNEL_PllTimeout = 0x80
} HOPCHANNEL_BITS_T;
/**
* LOR_ModemConfig1 register
*/
typedef enum {
MODEMCONFIG1_ImplicitHeaderModeOn = 0x01,
MODEMCONFIG1_CodingRate0 = 0x02,
MODEMCONFIG1_CodingRate1 = 0x04,
MODEMCONFIG1_CodingRate2 = 0x08,
_MODEMCONFIG1_CodingRate_MASK = 7,
_MODEMCONFIG1_CodingRate_SHIFT = 0,
MODEMCONFIG1_Bw0 = 0x10,
MODEMCONFIG1_Bw1 = 0x20,
MODEMCONFIG1_Bw2 = 0x40,
MODEMCONFIG1_Bw3 = 0x80,
_MODEMCONFIG1_Bw_MASK = 15,
_MODEMCONFIG1_Bw_SHIFT = 4
} MODEMCONFIG1_BITS_T;
/**
* CodingRate values
*/
typedef enum {
CODINGRATE_4_5 = 1, // Error coding rate 4/5
CODINGRATE_4_6 = 2,
CODINGRATE_4_7 = 3,
CODINGRATE_4_8 = 4
} CODINGRATE_T;
/**
* Bw values
*/
typedef enum {
BW_7_8 = 0, // 7.8Khz
BW_10_4 = 1,
BW_15_6 = 2,
BW_20_8 = 3,
BW_31_25 = 4,
BW_41_7 = 5,
BW_62_5 = 6,
BW_125 = 7,
BW_250 = 8,
BW_500 = 9
// BW250 and BW500 not supported in lower band (169Mhz)
} BW_T;
/**
* LOR_ModemConfig2 register
*/
typedef enum {
MODEMCONFIG2_SymbTimeoutMsb0 = 0x01,
MODEMCONFIG2_SymbTimeoutMsb1 = 0x02,
_MODEMCONFIG2_SymbTimeoutMsb_MASK = 3,
_MODEMCONFIG2_SymbTimeoutMsb_SHIFT = 0,
MODEMCONFIG2_RxPayloadCrcOn = 0x04,
MODEMCONFIG2_TxContinuousMode = 0x08,
MODEMCONFIG2_SpreadingFactor0 = 0x10,
MODEMCONFIG2_SpreadingFactor1 = 0x20,
MODEMCONFIG2_SpreadingFactor2 = 0x40,
MODEMCONFIG2_SpreadingFactor3 = 0x80,
_MODEMCONFIG2_SpreadingFactor_MASK = 15,
_MODEMCONFIG2_SpreadingFactor_SHIFT = 4,
} MODEMCONFIG2_BITS_T;
/**
* SpreadingFactor values (expressed as a base-2 logarithm)
*/
typedef enum {
SPREADINGFACTOR_64 = 6, // 64 chips/symbol
SPREADINGFACTOR_128 = 7,
SPREADINGFACTOR_256 = 8,
SPREADINGFACTOR_512 = 9,
SPREADINGFACTOR_1024 = 10,
SPREADINGFACTOR_2048 = 11,
SPREADINGFACTOR_4096 = 12
// other values reserved
} SPREADINGFACTOR_T;
/**
* FSK_PreableDetect register
*/
typedef enum {
PREABLEDETECT_PreambleDetectorTol0 = 0x01,
PREABLEDETECT_PreambleDetectorTol1 = 0x02,
PREABLEDETECT_PreambleDetectorTol2 = 0x04,
PREABLEDETECT_PreambleDetectorTol3 = 0x08,
PREABLEDETECT_PreambleDetectorTol4 = 0x10,
_PREABLEDETECT_PreambleDetectorTol4_MASK = 31,
_PREABLEDETECT_PreambleDetectorTol4_SHIFT = 0,
PREABLEDETECT_PreambleDetectorSize0 = 0x20,
PREABLEDETECT_PreambleDetectorSize1 = 0x40,
_PREABLEDETECT_PreambleDetectorSize_MASK = 3,
_PREABLEDETECT_PreambleDetectorSize_SHIFT = 5,
PREABLEDETECT_PreambleDetectorOn = 0x80
} PREAMBLEDETECT_BITS_T;
/**
* PreambleDetectorSize values
*/
typedef enum {
PREAMBLEDETECTORSIZE_1 = 0, // 1 byte
PREAMBLEDETECTORSIZE_2 = 1,
PREAMBLEDETECTORSIZE_3 = 2
// other values reserved
} PREAMBLEDETECTORSIZE_T;
/**
* FSK_Osc register
*/
typedef enum {
OSC_ClkOut0 = 0x01, // clk output freq
OSC_ClkOut1 = 0x02,
OSC_ClkOut2 = 0x04,
_OSC_ClkOut_MASK = 7,
_OSC_ClkOut_SHIFT = 0,
OSC_RcCalStart = 0x08
// other bits reserved
} OSC_BITS_T;
/**
* ClkOut values
*/
typedef enum {
CLKOUT_1 = 0, // FXOSC
CLKOUT_2 = 1, // FXOSC / 2 ...
CLKOUT_4 = 2,
CLKOUT_8 = 3,
CLKOUT_16 = 4,
CLKOUT_32 = 5,
CLKOUT_RC = 6, // RC, (automatically enabled)
CLKOUT_OFF = 7 // clkout off
} CLKOUT_T;
/**
* LOR_ModemConfig3 register
*/
typedef enum {
// 0x01-0x02 reserved
MODEMCONFIG3_AgcAutoOn = 0x04,
MODEMCONFIG3_LowDataRateOptimize = 0x08 // req. for SF11 and SF12 and
// BW125
// 0x10-0x80 reserved
} MODEMCONFIG3_BITS_T;
/**
* FSK_SyncConfig register
*/
typedef enum {
SYNCCONFIG_SyncSize0 = 0x01,
SYNCCONFIG_SyncSize1 = 0x02,
SYNCCONFIG_SyncSize2 = 0x04,
_SYNCCONFIG_SyncSize_MASK = 7,
_SYNCCONFIG_SyncSize_SHIFT = 0,
// 0x08 reserved
SYNCCONFIG_SyncOn = 0x10,
SYNCCONFIG_PreamblePolarity = 0x20,
SYNCCONFIG_AutoRestartMode0 = 0x40,
SYNCCONFIG_AutoRestartMode1 = 0x80,
_SYNCCONFIG_AutoRestartMode_MASK = 3,
_SYNCCONFIG_AutoRestartMode_SHIFT = 6,
} SYNCCONFIG_BITS_T;
/**
* AutoRestartMode values
*/
typedef enum {
AUTORESTARTMODE_OFF = 0,
AUTORESTARTMODE_ON_NOPLL = 1, // don't wait for PLL resync
AUTORESTARTMODE_ON_PLL = 2 // wait for PLL resync
// other values reserved
} AUTORESTARTMODE_T;
/**
* LOR_FeiMsb register (4 bit MSB of Fei value)
*/
typedef enum {
FEIMSB_FreqError0 = 0x01,
FEIMSB_FreqError1 = 0x02,
FEIMSB_FreqError2 = 0x04,
FEIMSB_FreqError3 = 0x08,
_FEIMSB_FreqError_MASK = 15,
_FEIMSB_FreqError_SHIFT = 0
// 0x10-0x80 reserved
} FEIMSB_BITS_T;
/**
* FSK_PacketConfig1 register
*/
typedef enum {
PACKETCONFIG1_CrcWhiteningType = 0x01,
PACKETCONFIG1_AddressFiltering0 = 0x02,
PACKETCONFIG1_AddressFiltering1 = 0x04,
_PACKETCONFIG1_AddressFiltering_MASK = 3,
_PACKETCONFIG1_AddressFiltering_SHIFT = 1,
PACKETCONFIG1_CrcAutoClearOff = 0x08,
PACKETCONFIG1_CrcOn = 0x10,
PACKETCONFIG1_DcFree0 = 0x20,
PACKETCONFIG1_DcFree1 = 0x40,
_PACKETCONFIG1_DcFree_MASK = 3,
_PACKETCONFIG1_DcFree_SHIFT = 5,
PACKETCONFIG1_PacketFormat = 0x80 // fixed(0) or variable(1)
} PACKETCONFIG1_BITS_T;
/**
* AddressFiltering values
*/
typedef enum {
ADDRESSFILTERING_NONE = 0,
ADDRESSFILTERING_NODE = 1, // must match node addr
ADDRESSFILTERING_NODE_BROADCAST = 2, // match node or broadcast
} ADDRESSFILTERING_T;
/**
* DcFree values (DC-free encoding/decoding schemes)
*/
typedef enum {
DCFREE_NONE = 0,
DCFREE_MANCHESTER = 1,
DCFREE_WHITENING = 2
// other values reserved
} DCFREE_T;
/**
* FSK_PacketConfig2 register
*/
typedef enum {
PACKETCONFIG2_PayloadLengthMsb0 = 0x01,
PACKETCONFIG2_PayloadLengthMsb1 = 0x02,
PACKETCONFIG2_PayloadLengthMsb2 = 0x04,
_PACKETCONFIG2_PayloadLengthMsb_MASK = 7,
_PACKETCONFIG2_PayloadLengthMsb_SHIFT = 0,
PACKETCONFIG2_BeaconOn = 0x08,
// 0x10 reserved (linked to io-homecontrol compat mode (?))
PACKETCONFIG2_IoHomeOn = 0x20,
PACKETCONFIG2_DataMode = 0x40, // continuous(0), packet(1)
// 0x80 reserved
} PACKETCONFIG2_BITS_T;
/**
* LOR_DetectOptimize register
*/
typedef enum {
DETECTOPTIMIZE_DetectionOptimize0 = 0x01,
DETECTOPTIMIZE_DetectionOptimize1 = 0x02,
DETECTOPTIMIZE_DetectionOptimize2 = 0x04,
_DETECTOPTIMIZE_DetectionOptimize_MASK = 7,
_DETECTOPTIMIZE_DetectionOptimize_SHIFT = 0
// 0x08-0x80 reserved
} DETECTOPTIMIZE_BITS_T;
/**
* DetectionOptimize values
*/
typedef enum {
DETECTIONOPTIMIZE_SF7_SF12 = 3,
DETECTIONOPTIMIZE_SF6 = 5
// other values reserved
} DETECTIONOPTIMIZE_T;
/**
* LOR_InvertIQ register
*/
typedef enum {
INVERTIQ_InvertIQTxOff = 0x01, // invert LoRa I & Q signals
// UNDOCUMENTED
// 0x01-0x20 reserved
INVERTIQ_InvertIQRx = 0x40 // invert LoRa I & Q signals
// 0x80 reserved
} INVERTIQ_BITS_T;
/**
* FSK_FifoThresh register
*/
typedef enum {
FIFOTHRESH_FifoThreshold0 = 0x01,
FIFOTHRESH_FifoThreshold1 = 0x02,
FIFOTHRESH_FifoThreshold2 = 0x04,
FIFOTHRESH_FifoThreshold3 = 0x08,
FIFOTHRESH_FifoThreshold4 = 0x10,
FIFOTHRESH_FifoThreshold5 = 0x20,
_FIFOTHRESH_FifoThreshold_MASK = 63,
_FIFOTHRESH_FifoThreshold_SHIFT = 0,
// 0x40 reserved
FIFOTHRESH_TxStartCondition = 0x80
} FIFOTHRESH_BITS_T;
/**
* FSK_SeqConfig1 register
*/
typedef enum {
SEQCONFIG1_FromTransit = 0x01,
SEQCONFIG1_FromIdle = 0x02,
SEQCONFIG1_LowPowerSelection = 0x04,
SEQCONFIG1_FromStart0 = 0x08,
SEQCONFIG1_FromStart1 = 0x10,
_SEQCONFIG1_FromStart_MASK = 3,
_SEQCONFIG1_FromStart_SHIFT = 3,
SEQCONFIG1_IdleMode = 0x20,
SEQCONFIG1_SequencerStop = 0x40,
SEQCONFIG1_SequencerStart = 0x80
} SEQCONFIG1_BITS_T;
/**
* FromStart values
*/
typedef enum {
FROMSTART_ToLowPowerSelection = 0,
FROMSTART_ToReceiveState = 1,
FROMSTART_ToTransmitState = 2,
FROMSTART_ToTransmitStateOnFifoLevel = 3
} FROMSTART_T;
/**
* FSK_SeqConfig2 register
*/
typedef enum {
SEQCONFIG2_FromPacketReceived0 = 0x01,
SEQCONFIG2_FromPacketReceived1 = 0x02,
SEQCONFIG2_FromPacketReceived2 = 0x04,
_SEQCONFIG2_FromPacketReceived_MASK = 7,
_SEQCONFIG2_FromPacketReceived_SHIFT = 0,
SEQCONFIG2_FromRxTimeout0 = 0x08,
SEQCONFIG2_FromRxTimeout1 = 0x10,
_SEQCONFIG2_FromRxTimeout_MASK = 3,
_SEQCONFIG2_FromRxTimeout_SHIFT = 3,
SEQCONFIG2_FromReceive0 = 0x20,
SEQCONFIG2_FromReceive1 = 0x40,
SEQCONFIG2_FromReceive2 = 0x80,
_SEQCONFIG2_FromReceive_MASK = 3,
_SEQCONFIG2_FromReceive_SHIFT = 5
} SEQCONFIG2_BITS_T;
/**
* FromPacketReceived values
*/
typedef enum {
FROMPACKETRECEIVED_ToSequencerOff = 0,
FROMPACKETRECEIVED_ToTransmitStateOnFifoEmpty = 1,
FROMPACKETRECEIVED_ToLowPowerSelection = 2,
FROMPACKETRECEIVED_ToReceiveViaFS = 3, // if freq was changed
FROMPACKETRECEIVED_ToReceive = 4 // if freq was not changed
// other values reserved
} FROMPACKETRECEIVED_T;
/**
* FromRxTimeout values
*/
typedef enum {
FROMRXTIMEOUT_ToReceiveViaReceiveStart = 0,
FROMRXTIMEOUT_ToTransmitState = 1,
FROMRXTIMEOUT_ToLowPowerSelection = 2,
FROMRXTIMEOUT_ToSequencerOffState = 3
} FROMRXTIMEOUT_T;
/**
* FromReceive values
*/
typedef enum {
FROMRECEIVE_ToPcketReceived = 1,
FROMRECEIVE_ToLowPowerSelection = 2,
FROMRECEIVE_ToPacketReceived = 3,
FROMRECEIVE_ToSequencerOffOnRSSI = 4, // RSSI interrupt
FROMRECEIVE_ToSequencerOffOnSync = 5, // SyncAddr interrupt
FROMRECEIVE_ToSequencerOffOnPreambleDetect = 6, // PreambleDetect intr
// other values reserved
} FROMRECEIVE_T;
/**
* FSK_TimerResol register
*/
typedef enum {
TIMERRESOL_Timer2Resolution0 = 0x01,
TIMERRESOL_Timer2Resolution1 = 0x02,
_TIMERRESOL_Timer2Resolution_MASK = 3,
_TIMERRESOL_Timer2Resolution_SHIFT = 0,
TIMERRESOL_Timer1Resolution0 = 0x04,
TIMERRESOL_Timer1Resolution1 = 0x08,
_TIMERRESOL_Timer1Resolution_MASK = 3,
_TIMERRESOL_Timer1Resolution_SHIFT = 2
// 0x10-0x80 reserved
} TIMERRESOL_BITS_T;
/**
* Timer1/Timer2Resolution values
*/
typedef enum {
TIMERRESOLUTION_DISABLED = 0,
TIMERRESOLUTION_64us = 1, // 64us
TIMERRESOLUTION_4_1ms = 2, // 4.1ms
TIMERRESOLUTION_262ms = 3 // 262ms
} TIMERRESOLUTION_T;
/**
* FSK_ImageCal register
*/
typedef enum {
IMAGECAL_TempMonitorOff = 0x01,
IMAGECAL_TempThreshold0 = 0x02,
IMAGECAL_TempThreshold1 = 0x04,
_IMAGECAL_TempThreshold_MASK = 3,
_IMAGECAL_TempThreshold_SHIFT = 1,
IMAGECAL_TenpChange = 0x08,
// 0x10 reserved
IMAGECAL_ImageCalRunning = 0x20,
IMAGECAL_ImageCalStart = 0x40,
IMAGECAL_AutoImageCalOn = 0x80
} IMAGECAL_BITS_T;
/**
* TempThreshold values
*/
typedef enum {
TEMPTHRESHOLD_5C = 0, // temp change to trigger new I/Q
TEMPTHRESHOLD_10C = 1, // calibration
TEMPTHRESHOLD_15C = 2,
TEMPTHRESHOLD_20C = 3
} TEMPTHRESHOLD_T;
/**
* FSK_LowBat register
*/
typedef enum {
LOWBAT_LowBatTrim0 = 0x01,
LOWBAT_LowBatTrim1 = 0x02,
LOWBAT_LowBatTrim2 = 0x04,
_LOWBAT_LowBatTrim_MASK = 7,
_LOWBAT_LowBatTrim_SHIFT = 0,
LOWBAT_LowBatOn = 0x08
// 0x10-0z80 reserved
} LOWBAT_BITS_T;
/**
* LowBatTrim values
*/
typedef enum {
LOWBATTRIM_1_695 = 0, // 1.695v
LOWBATTRIM_1_764 = 1,
LOWBATTRIM_1_835 = 2,
LOWBATTRIM_1_905 = 3,
LOWBATTRIM_1_976 = 4,
LOWBATTRIM_2_045 = 5,
LOWBATTRIM_2_116 = 6,
LOWBATTRIM_2_185 = 7
} LOWBATTRIM_T;
/**
* FSK_IrqFlags1 register
*/
typedef enum {
IRQFLAGS1_SyncAddressMatch = 0x01,
IRQFLAGS1_PreambleDetect = 0x02,
IRQFLAGS1_Timeout = 0x04,
IRQFLAGS1_Rssi = 0x08,
IRQFLAGS1_PllLock = 0x10,
IRQFLAGS1_TxReady = 0x20,
IRQFLAGS1_RxReady = 0x40,
IRQFLAGS1_ModeReady = 0x80
} IRQFLAGS1_BITS_T;
/**
* FSK_IrqFlags2 register
*/
typedef enum {
IRQFLAGS2_LowBat = 0x01,
IRQFLAGS2_CrcOk = 0x02,
IRQFLAGS2_PayloadReady = 0x04,
IRQFLAGS2_PacketSent = 0x08,
IRQFLAGS2_FifoOverrun = 0x10,
IRQFLAGS2_FifoLevel = 0x20,
IRQFLAGS2_FifoEmpty = 0x40,
IRQFLAGS2_FifoFull = 0x80
} IRQFLAGS2_BITS_T;
/**
* COM_DioMapping1 register. See Tables 18, 29, and 30 in the
* datasheet for the different mappings depending on mode.
*/
typedef enum {
DOIMAPPING1_Dio3Mapping0 = 0x01,
DOIMAPPING1_Dio3Mapping1 = 0x02,
DOIMAPPING1_Dio3Mapping_MASK = 3,
DOIMAPPING1_Dio3Mapping_SHIFT = 0,
DOIMAPPING1_Dio2Mapping0 = 0x04,
DOIMAPPING1_Dio2Mapping1 = 0x08,
DOIMAPPING1_Dio2Mapping_MASK = 3,
DOIMAPPING1_Dio2Mapping_SHIFT = 2,
DOIMAPPING1_Dio1Mapping0 = 0x10,
DOIMAPPING1_Dio1Mapping1 = 0x20,
DOIMAPPING1_Dio1Mapping_MASK = 3,
DOIMAPPING1_Dio1Mapping_SHIFT = 4,
DOIMAPPING1_Dio0Mapping0 = 0x40,
DOIMAPPING1_Dio0Mapping1 = 0x80,
DOIMAPPING1_Dio0Mapping_MASK = 3,
DOIMAPPING1_Dio0Mapping_SHIFT = 6,
} DIOMAPPING1_BITS_T;
/**
* COM_DioMapping2 register. See Tables 18, 29, and 30 in the
* datasheet for the different mappings depending on mode.
*/
typedef enum {
DOIMAPPING2_MapPreambleDetect = 0x01, // rssi intr(0), preambledet(1)
// 0x02-0x08 reserved
DOIMAPPING2_Dio5Mapping0 = 0x10,
DOIMAPPING2_Dio5Mapping1 = 0x20,
DOIMAPPING2_Dio5Mapping_MASK = 3,
DOIMAPPING2_Dio5Mapping_SHIFT = 4,
DOIMAPPING2_Dio4Mapping0 = 0x40,
DOIMAPPING2_Dio4Mapping1 = 0x80,
DOIMAPPING2_Dio4Mapping_MASK = 3,
DOIMAPPING2_Dio4Mapping_SHIFT = 6,
} DIOMAPPING2_BITS_T;
/**
* DioXMapping values
*
* These differ depending on LoRa, FSK packet, and FSK continous
* modes. See Tables 29, 30 (FSK), and 18 (LoRa) in the datasheet
* for details.
*/
typedef enum {
DIOMAPPING_00 = 0,
DIOMAPPING_01 = 1,
DIOMAPPING_10 = 2,
DIOMAPPING_11 = 3
} DIOMAPPING_T;
/**
* LOR_PllHop (or FSK_PllHop depending on who you believe) register
*/
typedef enum {
// 0x01-0x40 reserved
PLLHOP_FastHopOn = 0x80
} PLLHOP_BITS_T;
/**
* COM_Tcxo register
*/
typedef enum {
// 0x01-0x08 reserved
TCXO_TcxoOn = 0x10
// 0x20-0x80 reserved
} TCXO_BITS_T;
/**
* COM_PaDac register
*/
typedef enum {
PADAC_PaDac0 = 0x01,
PADAC_PaDac1 = 0x02,
PADAC_PaDac2 = 0x04,
_PADAC_PaDac_MASK = 7,
_PADAC_PaDac_SHIFT = 0
// 0x08-0x80 reserved
} PADAC_BITS_T;
/**
* PaDac values
*/
typedef enum {
PADAC_DEFAULT = 4,
PADAC_BOOST = 7 // +20dBm on PA_BOOST when
// OuputPower = 1111
// other values reserved
} PADAC_T;
/**
* FSK_BitRateFrac register
*/
typedef enum {
BITRATEFRAC_BitRateFrac0 = 0x01,
BITRATEFRAC_BitRateFrac1 = 0x02,
BITRATEFRAC_BitRateFrac2 = 0x04,
BITRATEFRAC_BitRateFrac3 = 0x08,
_BITRATEFRAC_BitRateFrac_MASK = 15,
_BITRATEFRAC_BitRateFrac_SHIFT = 0
// 0x10-0x80 reserved
} BITRATEFRAC_BITS_T;
/**
* COM_AgcRef register
*
* These registers have 2 sets of values depending on whether
* LowFrequencyModeOn is set or unset.
*/
typedef enum {
AGCREF_AgcReferenceLevel0 = 0x01,
AGCREF_AgcReferenceLevel1 = 0x02,
AGCREF_AgcReferenceLevel2 = 0x04,
AGCREF_AgcReferenceLevel3 = 0x08,
AGCREF_AgcReferenceLevel4 = 0x10,
AGCREF_AgcReferenceLevel5 = 0x20,
_AGCREF_AgcReferenceLevel_MASK = 63,
_AGCREF_AgcReferenceLevel_SHIFT = 0
// 0x40-0x80 reserved
} ACFREF_BITS_T;
/**
* COM_AgcThresh1 register
*
* These registers have 2 sets of values depending on whether
* LowFrequencyModeOn is set or unset.
*/
typedef enum {
AGCTHRESH1_AcgStep10 = 0x01,
AGCTHRESH1_AcgStep11 = 0x02,
AGCTHRESH1_AcgStep12 = 0x04,
AGCTHRESH1_AcgStep13 = 0x08,
_AGCTHRESH1_AcgStep1_MASK = 15,
_AGCTHRESH1_AcgStep1_SHIFT = 0,
// 0x10-0x80 reserved
} ACGTHRESH1_BITS_T;
/**
* COM_AgcThresh2 register
*
* These registers have 2 sets of values depending on whether
* LowFrequencyModeOn is set or unset.
*/
typedef enum {
AGCTHRESH2_AcgStep30 = 0x01,
AGCTHRESH2_AcgStep31 = 0x02,
AGCTHRESH2_AcgStep32 = 0x04,
AGCTHRESH2_AcgStep33 = 0x08,
_AGCTHRESH2_AcgStep3_MASK = 15,
_AGCTHRESH2_AcgStep3_SHIFT = 0,
AGCTHRESH2_AcgStep20 = 0x10,
AGCTHRESH2_AcgStep21 = 0x20,
AGCTHRESH2_AcgStep22 = 0x40,
AGCTHRESH2_AcgStep23 = 0x80,
_AGCTHRESH2_AcgStep2_MASK = 15,
_AGCTHRESH2_AcgStep2_SHIFT = 4
} ACGTHRESH2_BITS_T;
/**
* LOR_RegDetectionThreshold values
*/
typedef enum {
LOR_DetectionThreshold_SF7_SF12 = 0x0a,
LOR_DetectionThreshold_SF6 = 0x0c
} LOR_DETECTIONTHRESHOLD_T;
/**
* COM_AgcThresh3 register
*
* These registers have 2 sets of values depending on whether
* LowFrequencyModeOn is set or unset.
*/
typedef enum {
AGCTHRESH3_AcgStep50 = 0x01,
AGCTHRESH3_AcgStep51 = 0x02,
AGCTHRESH3_AcgStep52 = 0x04,
AGCTHRESH3_AcgStep53 = 0x08,
_AGCTHRESH3_AcgStep5_MASK = 15,
_AGCTHRESH3_AcgStep5_SHIFT = 0,
AGCTHRESH3_AcgStep40 = 0x10,
AGCTHRESH3_AcgStep41 = 0x20,
AGCTHRESH3_AcgStep42 = 0x40,
AGCTHRESH3_AcgStep43 = 0x80,
_AGCTHRESH3_AcgStep4_MASK = 15,
_AGCTHRESH3_AcgStep4_SHIFT = 4
} ACGTHRESH3_BITS_T;
/**
* SX1276 constructor
*
* Since this is a shield, you will not have much choice as to
* what pins are used.
*
* @param chipRev chip revision, default is 0x12
* @param bus spi bus to use
* @param cs GPIO pin to use as SPI Chip Select
* @param reset GPIO pin to use as reset (A0=GPIO14)
* @param dio0 GPIO pin to use as reset DIO0 intr
* @param dio1 GPIO pin to use as reset DIO1 intr
* @param dio2 GPIO pin to use as reset DIO2 intr
* @param dio3 GPIO pin to use as reset DIO3 intr
* @param dio4 GPIO pin to use as reset DIO4 intr
* @param dio5 GPIO pin to use as reset DIO5 intr
*/
SX1276(uint8_t chipRev=chipRevision, int bus=1, int cs=10, int resetPin=14,
int dio0=2, int dio1=3, int dio2=4, int dio3=5, int dio4=17,
int dio5=9);
/**
* SX1276 Destructor
*/
~SX1276();
/**
* read a register
*
* @param reg the register to read
* @return the value of the register
*/
uint8_t readReg(uint8_t reg);
/**
* write to a register
*
* @param reg the register to write to
* @param val the value to write
* @return true if successful, false otherwise
*/
bool writeReg(uint8_t reg, uint8_t val);
/**
* return the chip revision
*
* @return the chip revision (usually 0x12)
*/
uint8_t getChipVersion();
/**
* reset the modem
*/
void reset();
/**
* read the FIFO into a buffer
*
* @param buffer The buffer to read data into
* @param len The length of the buffer
*/
void readFifo(uint8_t *buffer, int len);
/**
* write a buffer into the FIFO
*
* @param buffer The buffer containing the data to write
* @param len The length of the buffer
*/
void writeFifo(uint8_t *buffer, int len);
/**
* Set the frequency to transmit and receive on
*
* @param freq The frequency to set
*/
void setChannel(uint32_t freq);
/**
* Set the operating mode
*
* @param opMode One of the MODE_T values
*/
void setOpMode(MODE_T opMode);
/**
* Set the modem to access. This can be either the LORA or
* KSK/OOK modem.
*
* @param modem One of the MODEM_T values
*/
void setModem(RADIO_MODEM_T modem);
/**
* Place the SX1276 into sleep mode
*/
void setSleep();
/**
* Place the SX1276 into standby mode
*/
void setStandby();
/**
* Return the current Received Signal Strength Indicator for the
* given modem
*
* @param modem One of the MODEM_T values
*/
int16_t getRSSI(RADIO_MODEM_T modem);
/**
* Check to see if a given channel is free by comparing the RSSI
* to the supplied threshold.
*
* @param modem One of the MODEM_T values
* @param freq The channel to check
* @param rssiThreshold The RSSI threshold, over which the channel
* os considerd in use.
*/
bool isChannelFree(RADIO_MODEM_T modem, uint32_t freq, int16_t rssiThresh);
/**
* Send the supplied string. This writes the string into the FIFO
* and places the modem in transmit mode (via setTx()). This is a
* wrapper around send().
*
* @param buffer The buffer to send
* @param timeout The timeout in milliseconds
* @return one of the RADIO_EVENT_T values
*/
RADIO_EVENT_T sendStr(std::string buffer, int timeout);
/**
* Send the supplied buffer. The writes the buffer into the FIFO
* and places the modem in transmit mode (via setTx()).
*
* @param buffer The buffer to send
* @param size The size of the buffer
* @param timeout The timeout in milliseconds
* @return one of the RADIO_EVENT_T values
*/
RADIO_EVENT_T send(uint8_t *buffer, uint8_t size, int timeout);
/**
* Set the receive configuration for a modem. It is important
* that both the receive and transmit configurations match in order
* for communication to work between two radios.
*
* @param modem One of the MODEM_T values
* @param bandwidth The bandwidth to use. Valid values are
* FSK : >= 2600 and <= 250000 Hz
* LoRa: [125 kHz, 250 kHz, 500 kHz]
* @param datarate Sets the Datarate
* FSK : 600..300000 bits/s
* LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
* 10: 1024, 11: 2048, 12: 4096 chips]
* @param coderate Sets the coding rate (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
* @param bandwidthAfc Sets the AFC Bandwidth (FSK only)
* FSK : >= 2600 and <= 250000 Hz
* LoRa: N/A ( set to 0 )
* @param preambleLen Sets the Preamble length
* FSK : Number of bytes
* LoRa: Length in symbols (the hardware adds
* 4 more symbols)
* @param symbTimeout Sets the RxSingle timeout value (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: timeout in symbols
* @param fixLen Fixed length packets [false: variable, true: fixed]
* @param payloadLen Sets payload length when fixed lenght is used
* @param crcOn Enables/Disables the CRC [false: OFF, true: ON]
* @param FreqHopOn Enables disables the intra-packet frequency hopping
* FSK : N/A ( set to 0 )
* LoRa: [false: OFF, true: ON]
* @param HopPeriod Number of symbols bewteen each hop
* FSK : N/A ( set to 0 )
* LoRa: Number of symbols
* @param iqInverted Inverts IQ signals (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [false: not inverted, true: inverted]
* @param rxContinuous Sets the reception in continuous mode
* [false: single mode, true: continuous mode]
*/
void setRxConfig(RADIO_MODEM_T modem, uint32_t bandwidth,
uint32_t datarate, uint8_t coderate,
uint32_t bandwidthAfc, uint16_t preambleLen,
uint16_t symbTimeout, bool fixLen,
uint8_t payloadLen,
bool crcOn, bool freqHopOn, uint8_t hopPeriod,
bool iqInverted, bool rxContinuous);
/**
* Set the transmit configuration for a modem. It is important
* that both the receive and transmit configurations match in order
* for communication to work between two radios.
*
* @param modem One of the MODEM_T values
* @param power Sets the output power [dBm]
* @param fdev Sets the frequency deviation (FSK only)
* FSK : [Hz]
* LoRa: 0
* @param bandwidth Sets the bandwidth (LoRa only)
* FSK : 0
* LoRa: [125 kHz, 250 kHz,
* or 500 kHz]
* @param datarate Sets the Datarate
* FSK : 600..300000 bits/s
* LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
* 10: 1024, 11: 2048, 12: 4096 chips]
* @param coderate Sets the coding rate (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
* @param preambleLen Sets the preamble length
* FSK : Number of bytes
* LoRa: Length in symbols (the hardware adds
* 4 more symbols)
* @param fixLen Fixed length packets [false: variable, true: fixed]
* @param crcOn Enables disables the CRC [false: OFF, true: ON]
* @param FreqHopOn Enables disables the intra-packet frequency hopping
* FSK : N/A ( set to 0 )
* LoRa: [false: OFF, true: ON]
* @param HopPeriod Number of symbols bewteen each hop
* FSK : N/A ( set to 0 )
* LoRa: Number of symbols
* @param iqInverted Inverts IQ signals (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [false: not inverted, true: inverted]
*/
void setTxConfig(RADIO_MODEM_T modem, int8_t power, uint32_t fdev,
uint32_t bandwidth, uint32_t datarate,
uint8_t coderate, uint16_t preambleLen,
bool fixLen, bool crcOn, bool freqHopOn,
uint8_t hopPeriod, bool iqInverted);
/**
* Start a receive operation. The method will return when
* completed, either successfully, or in error (crc, or other
* issue). If completed successfully, the returned buffer can be
* read via getRxBuffer() or getRxBufferStr(). In addition,
* values for RSSI and SNR (Lora only) can be retrieved.
*
* @param timeout The timeout in milliseconds
* @return one of the RADIO_EVENT_T values
*/
RADIO_EVENT_T setRx(uint32_t timeout);
/**
* Upon a successful receive, this method can be used to retrieve
* the received packet.
*
* @return The received buffer in a std::string
*/
std::string getRxBufferStr()
{
std::string rBuffer((char *)m_rxBuffer, getRxLen());
return rBuffer;
};
/**
* Upon a successful receive, this method can be used to retrieve
* the received packet.
*
* @return a pointer to the received buffer. You can use
* getRxLen() to determine the number of valid bytes present.
*/
uint8_t *getRxBuffer()
{
return (uint8_t*)m_rxBuffer;
};
/**
* Upon a successful receive, this method can be used to retrieve
* the received packet's Received Signal Strength Indicator (RSSI)
* value.
*
* @return RSSI value
*/
int getRxRSSI()
{
return m_rxRSSI;
};
/**
* Upon a successful receive, this method can be used to retrieve
* the received packet's Signal to Noise (SNR) value.
*
* @return SNR value
*/
int getRxSNR()
{
return m_rxSNR;
};
/**
* Upon a successful receive, this method can be used to retrieve
* the number of bytes received.
*
* @return the number of bytes received
*/
int getRxLen()
{
return m_rxLen;
};
protected:
// I/O
mraa::Spi m_spi;
mraa::Gpio m_gpioCS;
mraa::Gpio m_gpioReset;
mraa::Gpio m_gpioDIO0;
mraa::Gpio m_gpioDIO1;
mraa::Gpio m_gpioDIO2;
mraa::Gpio m_gpioDIO3;
mraa::Gpio m_gpioDIO4;
mraa::Gpio m_gpioDIO5;
// calibration called during init()
void rxChainCalibration();
// interrupt handlers
static void onDio0Irq(void *ctx);
static void onDio1Irq(void *ctx);
static void onDio2Irq(void *ctx);
static void onDio3Irq(void *ctx);
static void onDio4Irq(void *ctx);
static void onDio5Irq(void *ctx);
/**
* What internal state are we in
*/
typedef enum {
STATE_IDLE = 0,
STATE_RX_RUNNING,
STATE_TX_RUNNING,
STATE_CAD
} RADIO_STATES_T;
// needs to be OR'd onto registers for SPI write
static const uint8_t m_writeMode = 0x80;
// initialize the chip
void init();
// Start a transmit event (you should use send() or sendStr()
// rather than call this function directly.
RADIO_EVENT_T setTx(int timeout);
void startCAD(); // non-functional/non-tested
// not really used, maybe it should be
void setMaxPayloadLength(RADIO_MODEM_T modem, uint8_t max);
// Chip Select control (active LOW)
void csOn()
{
m_gpioCS.write(0);
};
void csOff()
{
m_gpioCS.write(1);
};
private:
// Thse structs will generate SWIG warnings, as we do not expose
// this data, they can be ignored.
// stored settings for the FSK modem
typedef struct
{
int8_t Power;
uint32_t Fdev;
uint32_t Bandwidth;
uint32_t BandwidthAfc;
uint32_t Datarate;
uint16_t PreambleLen;
bool FixLen;
uint8_t PayloadLen;
bool CrcOn;
bool IqInverted;
bool RxContinuous;
} radioFskSettings_t;
// stored settings for the LoRa modem
typedef struct
{
int8_t Power;
uint32_t Bandwidth;
uint32_t Datarate;
bool LowDatarateOptimize;
uint8_t Coderate;
uint16_t PreambleLen;
bool FixLen;
uint8_t PayloadLen;
bool CrcOn;
bool FreqHopOn;
uint8_t HopPeriod;
bool IqInverted;
bool RxContinuous;
} radioLoRaSettings_t;
// FSK packet handler state
typedef struct
{
uint8_t PreambleDetected;
uint8_t SyncWordDetected;
int8_t RssiValue;
int32_t AfcValue;
uint8_t RxGain;
uint16_t Size;
uint16_t NbBytes;
uint8_t FifoThresh;
uint8_t ChunkSize;
} radioFskPacketHandler_t;
// LoRa packet handler state
typedef struct
{
int8_t SnrValue;
int16_t RssiValue;
uint8_t Size;
} radioLoRaPacketHandler_t;
// our radio settings
struct {
RADIO_MODEM_T modem;
volatile RADIO_STATES_T state;
uint32_t channel;
radioFskSettings_t fskSettings;
volatile radioFskPacketHandler_t fskPacketHandler;
radioLoRaSettings_t loraSettings;
volatile radioLoRaPacketHandler_t loraPacketHandler;
} m_settings;
uint8_t lookupFSKBandWidth(uint32_t bw);
// received data (on successfull completion)
volatile int m_rxRSSI;
volatile int m_rxSNR;
volatile int m_rxLen;
uint8_t m_rxBuffer[FIFO_SIZE];
// for coordinating interrupt access
pthread_mutex_t m_intrLock;
void lockIntrs() { pthread_mutex_lock(&m_intrLock); };
void unlockIntrs() { pthread_mutex_unlock(&m_intrLock); };
// current radio event status
volatile RADIO_EVENT_T m_radioEvent;
// timer support
struct timeval m_startTime;
void initClock();
uint32_t getMillis();
};
}