From 49b495def976212b954b0af3904ae492d8f468da Mon Sep 17 00:00:00 2001 From: Terry Moore Date: Mon, 20 May 2019 16:42:22 -0400 Subject: [PATCH 1/8] Fix #46: make Tx Pwr policy explicit; see #300 --- src/arduino_lmic_hal_configuration.h | 22 ++++ src/hal/hal.cpp | 14 +- src/lmic/hal.h | 19 +++ src/lmic/lmic.h | 6 +- src/lmic/radio.c | 186 +++++++++++++++++++++++---- 5 files changed, 223 insertions(+), 24 deletions(-) diff --git a/src/arduino_lmic_hal_configuration.h b/src/arduino_lmic_hal_configuration.h index 29d1e16e..f10218b9 100644 --- a/src/arduino_lmic_hal_configuration.h +++ b/src/arduino_lmic_hal_configuration.h @@ -71,6 +71,14 @@ class HalConfiguration_t public: HalConfiguration_t() {}; + // these must match the constants in radio.c + enum class TxPowerPolicy_t : uint8_t + { + RFO, + PA_BOOST, + PA_BOOST_20dBm + }; + virtual ostime_t setModuleActive(bool state) { LMIC_API_PARAMETER(state); @@ -83,6 +91,20 @@ class HalConfiguration_t virtual void begin(void) {} virtual void end(void) {} virtual bool queryUsingTcxo(void) { return false; } + + // compute desired transmit power policy. + virtual TxPowerPolicy_t getTxPowerPolicy( + TxPowerPolicy_t policy, + int8_t requestedPower, + uint32_t frequency + ) + { + // default: do use PA_BOOST, don't use PA_BOOST_20dBm + if (policy == TxPowerPolicy_t::PA_BOOST_20dBm) + return TxPowerPolicy_t::PA_BOOST; + else + return policy; + } }; bool hal_init_with_pinmap(const HalPinmap_t *pPinmap); diff --git a/src/hal/hal.cpp b/src/hal/hal.cpp index 098cf517..91b0b4f8 100644 --- a/src/hal/hal.cpp +++ b/src/hal/hal.cpp @@ -424,4 +424,16 @@ ostime_t hal_setModuleActive (bit_t val) { bit_t hal_queryUsingTcxo(void) { return pHalConfig->queryUsingTcxo(); -} \ No newline at end of file +} + +uint8_t hal_getTxPowerPolicy( + u1_t inputPolicy, + s1_t requestedPower, + u4_t frequency + ) { + return (uint8_t) pHalConfig->getTxPowerPolicy( + Arduino_LMIC::HalConfiguration_t::TxPowerPolicy_t(inputPolicy), + requestedPower, + frequency + ); +} diff --git a/src/lmic/hal.h b/src/lmic/hal.h index 8fadeb63..00a6e585 100644 --- a/src/lmic/hal.h +++ b/src/lmic/hal.h @@ -147,8 +147,27 @@ s1_t hal_getRssiCal (void); */ ostime_t hal_setModuleActive (bit_t val); +/* find out if we're using Tcxo */ bit_t hal_queryUsingTcxo(void); +/* represent the various radio TX power policy */ +enum { + LMICHAL_radio_tx_power_policy_rfo = 0, + LMICHAL_radio_tx_power_policy_paboost = 1, + LMICHAL_radio_tx_power_policy_20dBm = 2, +}; + +/* + * query the configuration as to the Tx Power Policy + * to be used on this board, given our desires and + * requested power. + */ +uint8_t hal_getTxPowerPolicy( + u1_t inputPolicy, + s1_t requestedPower, + u4_t freq + ); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/lmic/lmic.h b/src/lmic/lmic.h index faa0799b..decdb75b 100644 --- a/src/lmic/lmic.h +++ b/src/lmic/lmic.h @@ -429,7 +429,11 @@ struct lmic_t { u1_t rxsyms; u1_t dndr; s1_t txpow; // transmit dBm (administrative) - s1_t radio_txpow; // the radio driver's copy of txpow, limited by adrTxPow. + s1_t radio_txpow; // the radio driver's copy of txpow, in dB limited by adrTxPow, and + // also adjusted for EIRP/antenna gain considerations. + // This is just the radio's idea of power. So if you are + // controlling EIRP, and you have 3 dB antenna gain, this + // needs to reduced by 3 dB. s1_t lbt_dbmax; // max permissible dB on our channel (eg -80) u1_t txChnl; // channel for next TX diff --git a/src/lmic/radio.c b/src/lmic/radio.c index 4d33cf07..9df03903 100644 --- a/src/lmic/radio.c +++ b/src/lmic/radio.c @@ -194,6 +194,28 @@ # define SX127X_MC1_IMPLICIT_HEADER_MODE_ON SX1272_MC1_IMPLICIT_HEADER_MODE_ON #endif +// transmit power configuration for RegPaConfig +#define SX1276_PAC_PA_SELECT_PA_BOOST 0x80 +#define SX1276_PAC_PA_SELECT_RFIO_PIN 0x00 +#define SX1276_PAC_MAX_POWER_MASK 0x70 + +// the bits to change for max power. +#define SX127X_PADAC_POWER_MASK 0x07 +#define SX127X_PADAC_POWER_NORMAL 0x04 +#define SX127X_PADAC_POWER_20dBm 0x07 + +// convert milliamperes to equivalent value for +// RegOcp; delivers conservative value. +#define SX127X_OCP_MAtoBITS(mA) \ + ((mA) < 45 ? 0 : \ + (mA) <= 120 ? ((mA) - 45) / 5 : \ + (mA) < 130 ? 0xF : \ + (mA) < 240 ? ((mA) - 130) / 10 + 0x10 : \ + 27) + +// bit in RegOcp that enables overcurrent protect. +#define SX127X_OCP_ENA 0x20 + // sx1276 RegModemConfig2 #define SX1276_MC2_RX_PAYLOAD_CRCON 0x04 @@ -214,7 +236,7 @@ //----------------------------------------- // Parameters for RSSI monitoring #define SX127X_FREQ_LF_MAX 525000000 // per datasheet 6.3 - + // per datasheet 5.5.3: #define SX127X_RSSI_ADJUST_LF -164 // add to rssi value to get dB (LF) #define SX127X_RSSI_ADJUST_HF -157 // add to rssi value to get dB (HF) @@ -446,37 +468,157 @@ static void configChannel () { writeReg(RegFrfLsb, (u1_t)(frf>> 0)); } - +// On the SX1276, we have several possible configs. +// 1) using RFO, MaxPower==0: in that case power is -4 to 11 dBm +// 2) using RFO, MaxPower==7: in that case, power is 0 to 14 dBm +// (can't select 15 dBm). +// note we can use -4..11 w/o Max and then 12..14 w/Max, and +// we really don't need to ask anybody. +// 3) using PA_BOOST, PaDac = 4: in that case power range is 2 to 17 dBm; +// use this for 15..17 if authorized. +// 4) using PA_BOOST, PaDac = 7, OutputPower=0xF: in that case, power is 20 dBm +// (and perhaps 0xE is 19, 0xD is 18 dBm, but datasheet isn't clear.) +// and duty cycle must be <= 1%. +// +// In addition, there are some boards for which PA_BOOST can only be used if the +// channel frequency is greater than SX127X_FREQ_LF_MAX. +// +// The SX1272 is similar but has no MaxPower bit: +// 1) using RFO: power is -1 to 13 dBm (datasheet implies max OutputPower value is 14 for 13 dBm) +// 2) using PA_BOOST, PaDac = 0x84: power is 2 to 17 dBm; +// use this for 14..17 if authorized +// 3) using PA_BOOST, PaDac = 0x87, OutptuPower = 0xF: power is 20dBm +// and duty cycle must be <= 1% +// +// The general policy is to use the lowest power variant that will get us where we +// need to be. +// static void configPower () { + // our input paramter -- might be different than LMIC.txpow! + s1_t const req_pw = (s1_t)LMIC.radio_txpow; + // the effective power + s1_t eff_pw; + // the policy; we're going to compute this. + u1_t policy; + // what we'll write to RegPaConfig + u1_t rPaConfig; + // what we'll write to RegPaDac + u1_t rPaDac; + // what we'll write to RegOcp + u1_t rOcp; + #ifdef CFG_sx1276_radio - // PA_BOOST output is assumed but not 20 dBm. - s1_t pw = (s1_t)LMIC.radio_txpow; - if(pw > 17) { - pw = 17; - } else if(pw < 2) { - pw = 2; + if (req_pw >= 20) { + policy = LMICHAL_radio_tx_power_policy_20dBm; + eff_pw = 20; + } else if (req_pw >= 14) { + policy = LMICHAL_radio_tx_power_policy_paboost; + if (req_pw > 17) { + eff_pw = 17; + } else { + eff_pw = req_pw; + } + } else { + policy = LMICHAL_radio_tx_power_policy_rfo; + if (req_pw < -4) { + eff_pw = -4; + } else { + eff_pw = req_pw; + } + } + + policy = hal_getTxPowerPolicy(policy, eff_pw, LMIC.freq); + + switch (policy) { + default: + case LMICHAL_radio_tx_power_policy_rfo: + rPaDac = SX127X_PADAC_POWER_NORMAL; + rOcp = SX127X_OCP_MAtoBITS(50); + + if (eff_pw > 14) + eff_pw = 14; + if (eff_pw > 11) { + // some Semtech code uses this down to eff_pw == 0. + rPaConfig = eff_pw | SX1276_PAC_MAX_POWER_MASK; + } else { + rPaConfig = eff_pw + 4; + } + break; + + case LMICHAL_radio_tx_power_policy_paboost: + rPaDac = SX127X_PADAC_POWER_NORMAL; + rOcp = SX127X_OCP_MAtoBITS(100); + if (eff_pw > 17) + eff_pw = 17; + rPaConfig = (eff_pw - 2) | SX1276_PAC_PA_SELECT_PA_BOOST; + break; + + case LMICHAL_radio_tx_power_policy_20dBm: + rPaDac = SX127X_PADAC_POWER_20dBm; + rOcp = SX127X_OCP_MAtoBITS(130); + rPaConfig = 0xF | SX1276_PAC_PA_SELECT_PA_BOOST; + break; } - // 0x80 forces use of PA_BOOST; but we don't - // turn on 20 dBm mode. So powers are: - // 0000 => 2dBm, 0001 => 3dBm, ... 1111 => 17dBm - // But we also enforce that the high-power mode - // is off by writing RegPaDac. - writeReg(RegPaConfig, (u1_t)(0x80|(pw - 2))); - writeReg(RegPaDac, readReg(RegPaDac)|0x4); #elif CFG_sx1272_radio - // set PA config (2-17 dBm using PA_BOOST) - s1_t pw = (s1_t)LMIC.radio_txpow; - if(pw > 17) { - pw = 17; - } else if(pw < 2) { - pw = 2; + if (req_pw >= 20) { + policy = LMICHAL_radio_tx_power_policy_20dBm; + eff_pw = 20; + } else if (eff_pw >= 14) { + policy = LMICHAL_radio_tx_power_policy_paboost; + if (eff_pw > 17) { + eff_pw = 17; + } else { + eff_pw = req_pw; + } + } else { + policy = LMICHAL_radio_tx_power_policy_rfo; + if (req_pw < -1) { + eff_pw = -1; + } else { + eff_pw = req_pw; + } + } + + policy = hal_getTxPowerPolicy(policy, eff_pw, LMIC.freq); + + switch (policy) { + default: + case LMICHAL_radio_tx_power_policy_rfo: + rPaDac = SX127X_PADAC_POWER_NORMAL; + rOcp = SX127X_OCP_MAtoBITS(50); + + if (eff_pw > 13) + eff_pw = 13; + + rPaConfig = eff_pw + 1; + break; + + case LMICHAL_radio_tx_power_policy_paboost: + rPaDac = SX127X_PADAC_POWER_NORMAL; + rOcp = SX127X_OCP_MAtoBITS(100); + + if (eff_pw > 17) + eff_pw = 17; + + rPaConfig = (eff_pw - 2) | SX1272_PAC_PA_SELECT_PA_BOOST; + break; + + case LMICHAL_radio_tx_power_policy_20dBm: + rPaDac = SX127X_PADAC_POWER_20dBm; + rOcp = SX127X_OCP_MAtoBITS(130); + + rPaConfig = 0xF | SX1276_PAC_PA_SELECT_PA_BOOST; + break; } - writeReg(RegPaConfig, (u1_t)(0x80|(pw-2))); #else #error Missing CFG_sx1272_radio/CFG_sx1276_radio #endif /* CFG_sx1272_radio */ + + writeReg(RegPaConfig, rPaConfig); + writeReg(RegPaDac, (readReg(RegPaDac) & ~SX127X_PADAC_POWER_MASK) | rPaDac); + writeReg(RegOcp, rOcp | SX127X_OCP_ENA); } static void txfsk () { From 7f6453084d041f85249c06be0aafb983cfa92805 Mon Sep 17 00:00:00 2001 From: Terry Moore Date: Mon, 20 May 2019 17:27:11 -0400 Subject: [PATCH 2/8] Fix #261: correct the LNA_RX_GAIN value for RegLna --- src/lmic/radio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lmic/radio.c b/src/lmic/radio.c index 9df03903..a5c56216 100644 --- a/src/lmic/radio.c +++ b/src/lmic/radio.c @@ -318,7 +318,7 @@ static u1_t randbuf[16]; #ifdef CFG_sx1276_radio -#define LNA_RX_GAIN (0x20|0x1) +#define LNA_RX_GAIN (0x20|0x3) #elif CFG_sx1272_radio #define LNA_RX_GAIN (0x20|0x03) #else From bffef41004d37905cc810bc2306fdf8f1ee7cb22 Mon Sep 17 00:00:00 2001 From: Terry Moore Date: Mon, 20 May 2019 17:59:03 -0400 Subject: [PATCH 3/8] Fix #262: Add fix for Errata 2.1 --- src/lmic/radio.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/lmic/radio.c b/src/lmic/radio.c index a5c56216..6fb826da 100644 --- a/src/lmic/radio.c +++ b/src/lmic/radio.c @@ -116,12 +116,14 @@ #define FSKRegBroadcastAdrs 0x34 #define FSKRegFifoThresh 0x35 #define FSKRegSeqConfig1 0x36 +#define LORARegHighBwOptimize1 0x36 #define FSKRegSeqConfig2 0x37 #define LORARegDetectionThreshold 0x37 #define FSKRegTimerResol 0x38 #define FSKRegTimer1Coef 0x39 #define LORARegSyncWord 0x39 #define FSKRegTimer2Coef 0x3A +#define LORARegHighBwOptimize2 0x3A #define FSKRegImageCal 0x3B #define FSKRegTemp 0x3C #define FSKRegLowBat 0x3D @@ -387,7 +389,9 @@ static void configLoraModem () { #ifdef CFG_sx1276_radio u1_t mc1 = 0, mc2 = 0, mc3 = 0; - switch (getBw(LMIC.rps)) { + bw_t const bw = getBw(LMIC.rps); + + switch (bw) { case BW125: mc1 |= SX1276_MC1_BW_125; break; case BW250: mc1 |= SX1276_MC1_BW_250; break; case BW500: mc1 |= SX1276_MC1_BW_500; break; @@ -417,10 +421,33 @@ static void configLoraModem () { writeReg(LORARegModemConfig2, mc2); mc3 = SX1276_MC3_AGCAUTO; - if ((sf == SF11 || sf == SF12) && getBw(LMIC.rps) == BW125) { + + if ((sf == SF11 || sf == SF12) && bw == BW125) { mc3 |= SX1276_MC3_LOW_DATA_RATE_OPTIMIZE; } writeReg(LORARegModemConfig3, mc3); + + // Errata 2.1: Sensitivity optimization with 500 kHz bandwidth + u1_t rHighBwOptimize1; + u1_t rHighBwOptimize2; + + rHighBwOptimize1 = 0x03; + rHighBwOptimize2 = 0; + + if (bw == BW500) { + if (LMIC.freq > SX127X_FREQ_LF_MAX) { + rHighBwOptimize1 = 0x02; + rHighBwOptimize2 = 0x64; + } else { + rHighBwOptimize1 = 0x02; + rHighBwOptimize2 = 0x7F; + } + } + + writeReg(LORARegHighBwOptimize1, rHighBwOptimize1); + if (rHighBwOptimize2 != 0) + writeReg(LORARegHighBwOptimize2, rHighBwOptimize2); + #elif CFG_sx1272_radio u1_t mc1 = (getBw(LMIC.rps)<<6); From 376244ebae77ab6d4a244b6df3c7043e41138214 Mon Sep 17 00:00:00 2001 From: Terry Moore Date: Mon, 20 May 2019 18:15:30 -0400 Subject: [PATCH 4/8] Fix #321: add workaround for SX1276 errata 2.3 --- src/lmic/radio.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/lmic/radio.c b/src/lmic/radio.c index 6fb826da..3a6bae48 100644 --- a/src/lmic/radio.c +++ b/src/lmic/radio.c @@ -107,7 +107,9 @@ #define FSKRegSyncValue6 0x2D #define FSKRegSyncValue7 0x2E #define FSKRegSyncValue8 0x2F +#define LORARegIffReq1 0x2F #define FSKRegPacketConfig1 0x30 +#define LORARegIffReq2 0x30 #define FSKRegPacketConfig2 0x31 #define LORARegDetectOptimize 0x31 #define FSKRegPayloadLength 0x32 @@ -820,6 +822,18 @@ static void rxlora (u1_t rxmode) { writeReg(LORARegInvertIQ, readReg(LORARegInvertIQ)|(1<<6)); } #endif + + // Errata 2.3 - receiver spurious reception of a LoRa signal + bw_t const bw = getBw(LMIC.rps); + u1_t const rDetectOptimize = readReg(LORARegDetectOptimize); + if (bw < BW500) { + writeReg(LORARegDetectOptimize, rDetectOptimize & 0x7F); + writeReg(LORARegIffReq1, 0x40); + writeReg(LORARegIffReq2, 0x40); + } else { + writeReg(LORARegDetectOptimize, rDetectOptimize | 0x80); + } + // set symbol timeout (for single rx) writeReg(LORARegSymbTimeoutLsb, LMIC.rxsyms); // set sync word From 4dfeecd35fb71fa46f5d641bef0c412bd1ad5186 Mon Sep 17 00:00:00 2001 From: Terry Moore Date: Mon, 20 May 2019 18:26:42 -0400 Subject: [PATCH 5/8] Fix #263: complete LOW_DATA_RATE_OPTIMIZE for 250KHz --- src/lmic/radio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lmic/radio.c b/src/lmic/radio.c index 3a6bae48..5697c1ee 100644 --- a/src/lmic/radio.c +++ b/src/lmic/radio.c @@ -424,7 +424,8 @@ static void configLoraModem () { mc3 = SX1276_MC3_AGCAUTO; - if ((sf == SF11 || sf == SF12) && bw == BW125) { + if ( ((sf == SF11 || sf == SF12) && bw == BW125) || + ((sf == SF12) && bw == BW250) ) { mc3 |= SX1276_MC3_LOW_DATA_RATE_OPTIMIZE; } writeReg(LORARegModemConfig3, mc3); From 2c7b10fdfa9ff2e1bb9906fbc76cf9507fb994f7 Mon Sep 17 00:00:00 2001 From: Terry Moore Date: Mon, 20 May 2019 23:07:46 -0400 Subject: [PATCH 6/8] Allow radios to veto RFO mode --- src/arduino_lmic_hal_configuration.h | 12 ++++++------ src/lmic/radio.c | 14 +++++++++++--- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/arduino_lmic_hal_configuration.h b/src/arduino_lmic_hal_configuration.h index f10218b9..a270bc81 100644 --- a/src/arduino_lmic_hal_configuration.h +++ b/src/arduino_lmic_hal_configuration.h @@ -92,18 +92,18 @@ class HalConfiguration_t virtual void end(void) {} virtual bool queryUsingTcxo(void) { return false; } - // compute desired transmit power policy. + // compute desired transmit power policy. HopeRF needs + // (and previous versions of this library always chose) + // PA_BOOST mode. So that's our default. Override this + // for the Murata module. virtual TxPowerPolicy_t getTxPowerPolicy( TxPowerPolicy_t policy, int8_t requestedPower, uint32_t frequency ) { - // default: do use PA_BOOST, don't use PA_BOOST_20dBm - if (policy == TxPowerPolicy_t::PA_BOOST_20dBm) - return TxPowerPolicy_t::PA_BOOST; - else - return policy; + // default: use PA_BOOST exclusively + return TxPowerPolicy_t::PA_BOOST; } }; diff --git a/src/lmic/radio.c b/src/lmic/radio.c index 5697c1ee..8931143b 100644 --- a/src/lmic/radio.c +++ b/src/lmic/radio.c @@ -541,7 +541,7 @@ static void configPower () { #ifdef CFG_sx1276_radio if (req_pw >= 20) { policy = LMICHAL_radio_tx_power_policy_20dBm; - eff_pw = 20; + eff_pw = 20; } else if (req_pw >= 14) { policy = LMICHAL_radio_tx_power_policy_paboost; if (req_pw > 17) { @@ -564,7 +564,7 @@ static void configPower () { default: case LMICHAL_radio_tx_power_policy_rfo: rPaDac = SX127X_PADAC_POWER_NORMAL; - rOcp = SX127X_OCP_MAtoBITS(50); + rOcp = SX127X_OCP_MAtoBITS(80); if (eff_pw > 14) eff_pw = 14; @@ -572,15 +572,23 @@ static void configPower () { // some Semtech code uses this down to eff_pw == 0. rPaConfig = eff_pw | SX1276_PAC_MAX_POWER_MASK; } else { + if (eff_pw < -4) + eff_pw = -4; rPaConfig = eff_pw + 4; } break; + // some radios (HopeRF RFM95W) don't support RFO well, + // so the policy might *raise* rfo to paboost. That means + // we have to re-check eff_pw, which might be too small. + // (And, of course, it might also be too large.) case LMICHAL_radio_tx_power_policy_paboost: rPaDac = SX127X_PADAC_POWER_NORMAL; rOcp = SX127X_OCP_MAtoBITS(100); if (eff_pw > 17) eff_pw = 17; + else if (eff_pw < 2) + eff_pw = 2; rPaConfig = (eff_pw - 2) | SX1276_PAC_PA_SELECT_PA_BOOST; break; @@ -594,7 +602,7 @@ static void configPower () { #elif CFG_sx1272_radio if (req_pw >= 20) { policy = LMICHAL_radio_tx_power_policy_20dBm; - eff_pw = 20; + eff_pw = 20; } else if (eff_pw >= 14) { policy = LMICHAL_radio_tx_power_policy_paboost; if (eff_pw > 17) { From 80383483553417152945e1dba8f0dd185dd58e9d Mon Sep 17 00:00:00 2001 From: Terry Moore Date: Mon, 20 May 2019 23:08:16 -0400 Subject: [PATCH 7/8] tabs to spaces --- src/lmic/radio.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/lmic/radio.c b/src/lmic/radio.c index 8931143b..a7f3db21 100644 --- a/src/lmic/radio.c +++ b/src/lmic/radio.c @@ -773,7 +773,7 @@ static void starttx () { oslmic_radio_rssi_t rssi; radio_monitor_rssi(LMIC.lbt_ticks, &rssi); #if LMIC_X_DEBUG_LEVEL > 0 - LMIC_X_DEBUG_PRINTF("LBT rssi max:min=%d:%d %d times in %d\n", rssi.max_rssi, rssi.min_rssi, rssi.n_rssi, LMIC.lbt_ticks); + LMIC_X_DEBUG_PRINTF("LBT rssi max:min=%d:%d %d times in %d\n", rssi.max_rssi, rssi.min_rssi, rssi.n_rssi, LMIC.lbt_ticks); #endif if (rssi.max_rssi >= LMIC.lbt_dbmax) { @@ -866,8 +866,8 @@ static void rxlora (u1_t rxmode) { hal_waitUntil(LMIC.rxtime); // busy wait until exact rx time opmode(OPMODE_RX_SINGLE); #if LMIC_DEBUG_LEVEL > 0 - ostime_t now = os_getTime(); - LMIC_DEBUG_PRINTF("start single rx: now-rxtime: %"LMIC_PRId_ostime_t"\n", now - LMIC.rxtime); + ostime_t now = os_getTime(); + LMIC_DEBUG_PRINTF("start single rx: now-rxtime: %"LMIC_PRId_ostime_t"\n", now - LMIC.rxtime); #endif } else { // continous rx (scan or rssi) opmode(OPMODE_RX); @@ -1104,7 +1104,7 @@ void radio_monitor_rssi(ostime_t nTicks, oslmic_radio_rssi_t *pRssi) { rssiMin = rssiNow; rssiSum += rssiNow; ++rssiN; - // TODO(tmm@mcci.com) move this to os_getTime(). + // TODO(tmm@mcci.com) move this to os_getTime(). hal_enableIRQs(); now = os_getTime(); hal_disableIRQs(); @@ -1159,7 +1159,7 @@ void radio_irq_handler_v2 (u1_t dio, ostime_t now) { #endif if( (readReg(RegOpMode) & OPMODE_LORA) != 0) { // LORA modem u1_t flags = readReg(LORARegIrqFlags); - LMIC.saveIrqFlags = flags; + LMIC.saveIrqFlags = flags; LMIC_X_DEBUG_PRINTF("IRQ=%02x\n", flags); if( flags & IRQ_LORA_TXDONE_MASK ) { // save exact tx time @@ -1186,8 +1186,8 @@ void radio_irq_handler_v2 (u1_t dio, ostime_t now) { // indicate timeout LMIC.dataLen = 0; #if LMIC_DEBUG_LEVEL > 0 - ostime_t now2 = os_getTime(); - LMIC_DEBUG_PRINTF("rxtimeout: entry: %"LMIC_PRId_ostime_t" rxtime: %"LMIC_PRId_ostime_t" entry-rxtime: %"LMIC_PRId_ostime_t" now-entry: %"LMIC_PRId_ostime_t" rxtime-txend: %"LMIC_PRId_ostime_t"\n", entry, + ostime_t now2 = os_getTime(); + LMIC_DEBUG_PRINTF("rxtimeout: entry: %"LMIC_PRId_ostime_t" rxtime: %"LMIC_PRId_ostime_t" entry-rxtime: %"LMIC_PRId_ostime_t" now-entry: %"LMIC_PRId_ostime_t" rxtime-txend: %"LMIC_PRId_ostime_t"\n", entry, LMIC.rxtime, entry - LMIC.rxtime, now2 - entry, LMIC.rxtime-LMIC.txend); #endif } From 85fa71799d88f9264b2c0783e761d40030578ac5 Mon Sep 17 00:00:00 2001 From: Terry Moore Date: Sun, 23 Jun 2019 05:25:48 -0400 Subject: [PATCH 8/8] Update documentation --- README.md | 60 ++++++++++++++++++++++++++-- src/arduino_lmic_hal_configuration.h | 2 +- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6e0ff816..27d88519 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,8 @@ requires C99 mode to be enabled by default. - [RXTX](#rxtx) - [RXTX Polarity](#rxtx-polarity) - [Pin mapping](#pin-mapping) + - [Advanced initialization](#advanced-initialization) + - [HalConfiguration_t methods](#halconfiguration_t-methods) - [LoRa Nexus by Ideetron](#lora-nexus-by-ideetron) - [Example Sketches](#example-sketches) - [Timing](#timing) @@ -521,9 +523,9 @@ We have details for the following manually-configured boards here: - [LoRa Nexus by Ideetron](#lora-nexus-by-ideetron) -If you don't have the board documentation, you need to provide your own `lmic_pinmap` values. As described above, a variety of configurations are possible. To tell the LMIC library how your board is configured, you must declare a variable containing a pin mapping struct in the sketch file. +If your board is not configured, you need at least to provide your own `lmic_pinmap`. As described above, a variety of configurations are possible. To tell the LMIC library how your board is configured, you must declare a variable containing a pin mapping struct in your sketch file. If you call `os_init()` to initialize the LMIC, you must name this structure `lmic_pins`. If you call `os_init_ex()`, you may name the structure what you like, but you pass a pointer as the parameter to `os_init_ex()`. -For example, this could look like this: +Here's an example of a simple initialization: ```c++ lmic_pinmap lmic_pins = { @@ -552,7 +554,59 @@ respectively. Any pins that are not needed should be specified as potentially left out (depending on the environments and requirements, see the notes above for when a pin can or cannot be left out). -The name of the variable containing this struct must always be `lmic_pins`, which is a special name recognized by the library. +#### Advanced initialization + +In some boards require much more advanced management. The LMIC has a very flexible framework to support this, but it requires you to do some C++ work. + +1. You must define a new class derived from `Arduino_LMIC::HalConfiguration_t`. (We'll call this `cMyHalConfiguration_t`). + +2. This class *may* define overrides for several methods (discussed below). + +3. You must create an instance of your class, e.g. + + ```c++ + cMyHalConfiguration_t myHalConfigInstance; + ``` + +4. You add another entry in your `lmic_pinmap`, `pConfig = &myHalConfigInstance`, to link your pinmap to your object. + +The full example looks like this: + +```c++ +class cMyHlaConfiguration_t : public Arduino_LMIC::HalConfiguration_t + { +public: + // ... + // put your method function override declarations here. + + // this example uses RFO at 10 dBm or less, PA_BOOST up to 17 dBm, + // or the high-power mode above 17 dBm. In other words, it lets the + // LMIC-determined policy determine what's to be done. + + virutal TxPowerPolicy_t getTxPowerPolicy( + TxPowerPolicy_t policy, + int8_t requestedPower, + uint32_t frequency + ) override + { + return policy; + } + } +``` + +#### HalConfiguration_t methods + +- `ostime_t setModuleActive(bool state)` is called by the LMIC to make the module active or to deactivate it (the value of `state` is true to activate). The implementation must turn power to the module on and otherwise prepare for it to go to work, and must return the number of OS ticks to wait before starting to use the radio. + +- `void begin(void)` is called during intialization, and is your code's chance to do any early setup. + +- `void end(void)` is (to be) called during late shutdown. (Late shutdown is not implemented yet; but we wanted to add the API for consistency.) + +- `bool queryUsingTcxo(void)` shall return `true` if the module uses a TCXO; `false` otherwise. + +- `TxPowerPolicy_t getTxPowerPolicy(TxPowerPolicy_t policy, int8_t requestedPower, uint32_t frequency)` allows you to override the LMIC's selection of transmit power. If not provided, the default method forces the LMIC to use PA_BOOST mode. (We chose to do this becuase we found empirically that the Hope RF module doesn't support RFO, and because legacy LMIC code never used anything except PA_BOOST mode.) + +Caution: the LMIC has no way of knowing whether the mode you return makes sense. Use of 20 dBm mode without limiting duty cycle can over-stress your module. The LMIC currently does not have any code to duty-cycle US transmissions at 20 dBm. If properly limiting transmissions to 400 ms, 1% duty-cycle means at most one message every 40 seconds. This shoudln't be a problem in practice, but buggy upper level software still might do things more rapidly. #### LoRa Nexus by Ideetron diff --git a/src/arduino_lmic_hal_configuration.h b/src/arduino_lmic_hal_configuration.h index a270bc81..0da70bb5 100644 --- a/src/arduino_lmic_hal_configuration.h +++ b/src/arduino_lmic_hal_configuration.h @@ -62,7 +62,7 @@ struct HalPinmap_t { // Must include noise guardband! uint32_t spi_freq; // bytes 8..11: SPI freq in Hz. - // optional pointer to configuration object (byest 12..15) + // optional pointer to configuration object (bytes 12..15) HalConfiguration_t *pConfig; };