From 50d45e7fb708674a8b5bb79dc6e6238b82549e9d Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Wed, 21 Sep 2022 20:48:49 +0200 Subject: [PATCH] Upgrade to latest LMIC code (v4.2.0-1) --- src/lmic/config.h | 2 +- src/lmic/hal.h | 2 +- src/lmic/lmic.c | 50 +++++++++++++++++++++++++++++++++- src/lmic/lmic.h | 7 +++-- src/lmic/lmic_as923.c | 11 ++++++-- src/lmic/lmic_channelshuffle.c | 4 +-- src/lmic/lmic_us_like.c | 22 ++++++++++----- src/lmic/lorabase.h | 22 +++++++-------- src/lmic/lorabase_as923.h | 13 +++++---- src/lmic/oslmic.h | 2 +- 10 files changed, 100 insertions(+), 35 deletions(-) diff --git a/src/lmic/config.h b/src/lmic/config.h index abd0538..9a857d4 100644 --- a/src/lmic/config.h +++ b/src/lmic/config.h @@ -169,7 +169,7 @@ // enable support for MCMD_DeviceTimeReq and MCMD_DeviceTimeAns // this is always defined, and non-zero to enable it. #if !defined(LMIC_ENABLE_DeviceTimeReq) -# define LMIC_ENABLE_DeviceTimeReq 0 +# define LMIC_ENABLE_DeviceTimeReq 1 #endif // LMIC_ENABLE_user_events diff --git a/src/lmic/hal.h b/src/lmic/hal.h index 59af982..51d22bf 100644 --- a/src/lmic/hal.h +++ b/src/lmic/hal.h @@ -174,7 +174,7 @@ void hal_pollPendingIRQs_helper(); void hal_processPendingIRQs(void); /// \brief check for any pending interrupts: stub if interrupts are enabled. -static void inline hal_pollPendingIRQs(void) +static inline void hal_pollPendingIRQs(void) { #if !defined(LMIC_USE_INTERRUPTS) hal_pollPendingIRQs_helper(); diff --git a/src/lmic/lmic.c b/src/lmic/lmic.c index 472e62c..98d18ca 100644 --- a/src/lmic/lmic.c +++ b/src/lmic/lmic.c @@ -119,7 +119,7 @@ void os_wmsbf4 (xref2u1_t buf, u4_t v) { #if !defined(os_getBattLevel) u1_t os_getBattLevel (void) { - return MCMD_DEVS_BATT_NOINFO; + return LMIC.client.devStatusAns_battery; } #endif @@ -764,6 +764,9 @@ applyAdrRequests( p4 = opts[oidx+4]; // ChMaskCtl, NbTrans u1_t chpage = p4 & MCMD_LinkADRReq_Redundancy_ChMaskCntl_MASK; // channel page + // notice that we ignore map_ok except on the last setting. + // so LMICbandplan_mapChannels should report failure status, but do + // the work; if it fails, we'll back it out. map_ok = LMICbandplan_mapChannels(chpage, chmap); LMICOS_logEventUint32("applyAdrRequests: mapChannels", ((u4_t)chpage << 16)|(chmap << 0)); } @@ -2815,6 +2818,7 @@ void LMIC_reset (void) { void LMIC_init (void) { LMIC.opmode = OP_SHUTDOWN; + LMIC.client.devStatusAns_battery = MCMD_DEVS_BATT_NOINFO; LMICbandplan_init(); } @@ -3102,3 +3106,47 @@ int LMIC_getNetworkTimeReference(lmic_time_reference_t *pReference) { #endif // LMIC_ENABLE_DeviceTimeReq return 0; } + +/// +/// \brief set battery level to be returned by `DevStatusAns`. +/// +/// \param uBattLevel is the 8-bit value to be returned. Per LoRaWAN 1.0.3 line 769, +/// this is \c MCMD_DEVS_EXT_POWER (0) if on external power, +/// \c MCMD_DEVS_NOINFO (255) if not able to measure battery level, +/// or a value in [ \c MCMD_DEVS_BATT_MIN, \c MCMD_DEVS_BATT_MAX ], numerically +/// [1, 254], to represent the charge state of the battery. Note that +/// this is not millivolts. +/// +/// \returns +/// This function returns the previous value of the battery level. +/// +/// \details +/// The LMIC maintains an idea of the current battery state, initially set to +/// \c MCMD_DEVS_NOINFO after the call to LMIC_init(). The appplication then calls +/// this function from time to time to update the battery level. +/// +/// It is possible (in non-Arduino environments) to supply a local implementation +/// of os_getBatteryLevel(). In that case, it's up to the implementation to decide +/// whether to use the value supplied by this API. +/// +/// This implementation was chosen to minimize the risk of a battery measurement +/// introducting breaking delays into the LMIC. +/// +u1_t LMIC_setBatteryLevel(u1_t uBattLevel) { + const u1_t result = LMIC.client.devStatusAns_battery; + + LMIC.client.devStatusAns_battery = uBattLevel; + return result; +} + +/// +/// \brief get battery level that is to be returned by `DevStatusAns`. +/// +/// \returns +/// This function returns the saved value of the battery level. +/// +/// \see LMIC_setBatteryLevel() +/// +u1_t LMIC_getBatteryLevel(void) { + return LMIC.client.devStatusAns_battery; +} diff --git a/src/lmic/lmic.h b/src/lmic/lmic.h index 49703ae..d2153b3 100644 --- a/src/lmic/lmic.h +++ b/src/lmic/lmic.h @@ -106,7 +106,7 @@ extern "C"{ ((((major)*UINT32_C(1)) << 24) | (((minor)*UINT32_C(1)) << 16) | (((patch)*UINT32_C(1)) << 8) | (((local)*UINT32_C(1)) << 0)) #define ARDUINO_LMIC_VERSION \ - ARDUINO_LMIC_VERSION_CALC(4, 0, 1, 1) /* 4.0.1-pre1 */ + ARDUINO_LMIC_VERSION_CALC(4, 2, 0, 1) /* 4.2.0-1 */ #define ARDUINO_LMIC_VERSION_GET_MAJOR(v) \ ((((v)*UINT32_C(1)) >> 24u) & 0xFFu) @@ -459,7 +459,7 @@ struct lmic_client_data_s { u2_t clockError; //! Inaccuracy in the clock. CLOCK_ERROR_MAX represents +/-100% error /* finally, things that are (u)int8_t */ - /* none at the moment */ + u1_t devStatusAns_battery; //!< value to report in MCMD_DevStatusAns message. }; /* @@ -740,6 +740,9 @@ int LMIC_registerEventCb(lmic_event_cb_t *pEventCb, void *pUserData); int LMIC_findNextChannel(uint16_t *, const uint16_t *, uint16_t, int); +u1_t LMIC_getBatteryLevel(void); +u1_t LMIC_setBatteryLevel(u1_t /* uBattLevel */); + // APIs for client half of compliance. typedef u1_t lmic_compliance_rx_action_t; diff --git a/src/lmic/lmic_as923.c b/src/lmic/lmic_as923.c index 5366d71..5c4c05d 100644 --- a/src/lmic/lmic_as923.c +++ b/src/lmic/lmic_as923.c @@ -35,6 +35,11 @@ // // BEG: AS923 related stuff // +enum { + AS923_REGION_TX_EIRP_MAX_DBM = + (LMIC_COUNTRY_CODE == LMIC_COUNTRY_CODE_JP) ? AS923_JP_TX_EIRP_MAX_DBM + : AS923_TX_EIRP_MAX_DBM + }; // see table in section 2.7.3 CONST_TABLE(u1_t, _DR2RPS_CRC)[] = { @@ -130,7 +135,7 @@ static CONST_TABLE(s1_t, TXMAXEIRP)[16] = { static int8_t LMICas923_getMaxEIRP(uint8_t mcmd_txparam) { // if uninitialized, return default. if (mcmd_txparam == 0xFF) - return AS923_TX_EIRP_MAX_DBM; + return AS923_REGION_TX_EIRP_MAX_DBM; else return TABLE_GET_S1( TXMAXEIRP, @@ -199,7 +204,7 @@ void LMICas923_initDefaultChannels(bit_t join) { } LMIC.bands[BAND_CENTI].txcap = AS923_TX_CAP; - LMIC.bands[BAND_CENTI].txpow = AS923_TX_EIRP_MAX_DBM; + LMIC.bands[BAND_CENTI].txpow = AS923_REGION_TX_EIRP_MAX_DBM; LMIC.bands[BAND_CENTI].lastchnl = os_getRndU1() % MAX_CHANNELS; LMIC.bands[BAND_CENTI].avail = os_getTime(); } @@ -457,7 +462,7 @@ ostime_t LMICas923_nextJoinState(void) { void LMICas923_initJoinLoop(void) { // LMIC.txParam is set to 0xFF by the central code at init time. - LMICeulike_initJoinLoop(NUM_DEFAULT_CHANNELS, /* adr dBm */ AS923_TX_EIRP_MAX_DBM); + LMICeulike_initJoinLoop(NUM_DEFAULT_CHANNELS, /* adr dBm */ AS923_REGION_TX_EIRP_MAX_DBM); } void diff --git a/src/lmic/lmic_channelshuffle.c b/src/lmic/lmic_channelshuffle.c index 252bbee..f5e819b 100644 --- a/src/lmic/lmic_channelshuffle.c +++ b/src/lmic/lmic_channelshuffle.c @@ -108,7 +108,7 @@ int LMIC_findNextChannel( memcpy(pShuffleMask, pEnableMask, nEntries * sizeof(*pShuffleMask)); nSet16 = sidewaysSum16(pShuffleMask, nEntries); } else { - // don't try to skip the last channel becuase it can't be chosen. + // don't try to skip the last channel because it can't be chosen. lastChannel = -1; } @@ -121,7 +121,7 @@ int LMIC_findNextChannel( // the last channel bit. Post condition: if we really clered a bit, // saveLastChannelVal will be non-zero. saveLastChannelVal = 0; - if (nSet16 > 16 && lastChannel >= 0 && lastChannel <= nEntries * 16) { + if (nSet16 > 16 && lastChannel >= 0 && lastChannel <= (int)(nEntries * 16)) { uint16_t const saveLastChannelMask = (1 << (lastChannel & 0xF)); saveLastChannelVal = pShuffleMask[lastChannel >> 4] & saveLastChannelMask; diff --git a/src/lmic/lmic_us_like.c b/src/lmic/lmic_us_like.c index 31e4cc1..fa91cb8 100644 --- a/src/lmic/lmic_us_like.c +++ b/src/lmic/lmic_us_like.c @@ -99,6 +99,9 @@ bit_t LMICuslike_canMapChannels(u1_t chpage, u2_t chmap) { || channel map appllies to 500kHz (ch 64..71) and in addition || all channels 0..63 are turned off or on. MCMC_LADR_CHP_BANK || is also special, in that it enables subbands. + || + || TODO(tmm@mcci.com) revise the 0xFF00 mask for regions with other than + || eight 500 kHz channels. */ if (chpage < MCMD_LinkADRReq_ChMaskCntl_USLIKE_SPECIAL) { // operate on channels 0..15, 16..31, 32..47, 48..63, 64..71 @@ -111,17 +114,22 @@ bit_t LMICuslike_canMapChannels(u1_t chpage, u2_t chmap) { return 1; } } else if (chpage == MCMD_LinkADRReq_ChMaskCntl_USLIKE_BANK) { - if (chmap == 0 || (chmap & 0xFF00) != 0) { - // no bits set, or reserved bitsset , fail. + if ((chmap & 0xFF00) != 0) { + // Reserved bits set, fail. return 0; } } else if (chpage == MCMD_LinkADRReq_ChMaskCntl_USLIKE_125ON || chpage == MCMD_LinkADRReq_ChMaskCntl_USLIKE_125OFF) { - u1_t const en125 = chpage == MCMD_LinkADRReq_ChMaskCntl_USLIKE_125ON; - - // if disabling all 125kHz chans, must have at least one 500kHz chan - // don't allow reserved bits to be set in chmap. - if ((! en125 && chmap == 0) || (chmap & 0xFF00) != 0) + // + // if disabling all 125kHz chans, you might think we must have + // at least one 500kHz chan; but that's a local conclusion. + // Some network servers will disable all (including 500kHz) + // then turn things back on in the next LinkADRReq. So + // we can't fail that here. + // + // But don't allow reserved bits to be set in chmap. + // + if ((chmap & 0xFF00) != 0) return 0; } else { return 0; diff --git a/src/lmic/lorabase.h b/src/lmic/lorabase.h index 632a8b4..2e83540 100644 --- a/src/lmic/lorabase.h +++ b/src/lmic/lorabase.h @@ -589,20 +589,20 @@ enum { // Bit fields byte#3 of MCMD_LinkADRReq payload enum { - MCMD_LinkADRReq_Redundancy_RFU = 0x80, - MCMD_LinkADRReq_Redundancy_ChMaskCntl_MASK= 0x70, - MCMD_LinkADRReq_Redundancy_NbTrans_MASK = 0x0F, + MCMD_LinkADRReq_Redundancy_RFU = 0x80, ///< mask for RFU bit + MCMD_LinkADRReq_Redundancy_ChMaskCntl_MASK= 0x70, ///< mask for the channel-mask control field. + MCMD_LinkADRReq_Redundancy_NbTrans_MASK = 0x0F, ///< mask for the `NbTrans` (repetition) field. - MCMD_LinkADRReq_ChMaskCntl_EULIKE_DIRECT = 0x00, // direct masking for EU - MCMD_LinkADRReq_ChMaskCntl_EULIKE_ALL_ON = 0x60, // EU: enable everything. + MCMD_LinkADRReq_ChMaskCntl_EULIKE_DIRECT = 0x00, ///< EU-like: direct masking for EU + MCMD_LinkADRReq_ChMaskCntl_EULIKE_ALL_ON = 0x60, ///< EU-like: enable everything. - MCMD_LinkADRReq_ChMaskCntl_USLIKE_500K = 0x40, // mask is for the 8 us-like 500 kHz channels - MCMD_LinkADRReq_ChMaskCntl_USLIKE_SPECIAL = 0x50, // first special for us-like - MCMD_LinkADRReq_ChMaskCntl_USLIKE_BANK = 0x50, // special: bits are banks. - MCMD_LinkADRReq_ChMaskCntl_USLIKE_125ON = 0x60, // special channel page enable, bits applied to 64..71 - MCMD_LinkADRReq_ChMaskCntl_USLIKE_125OFF = 0x70, // special channel page: disble 125K, bits apply to 64..71 + MCMD_LinkADRReq_ChMaskCntl_USLIKE_500K = 0x40, ///< US-like: mask is for the 8 us-like 500 kHz channels + MCMD_LinkADRReq_ChMaskCntl_USLIKE_SPECIAL = 0x50, ///< US-like: first special for us-like + MCMD_LinkADRReq_ChMaskCntl_USLIKE_BANK = 0x50, ///< US-like: special: bits are banks. + MCMD_LinkADRReq_ChMaskCntl_USLIKE_125ON = 0x60, ///< US-like: special channel page enable, bits applied to 64..71 + MCMD_LinkADRReq_ChMaskCntl_USLIKE_125OFF = 0x70, ///< US-like: special channel page: disable 125K, bits apply to 64..71 - MCMD_LinkADRReq_ChMaskCntl_CN470_ALL_ON = 0x60, // turn all on for China. + MCMD_LinkADRReq_ChMaskCntl_CN470_ALL_ON = 0x60, ///< CN-470: turn all on for China. }; // Bit fields byte#0 of MCMD_LinkADRReq payload diff --git a/src/lmic/lorabase_as923.h b/src/lmic/lorabase_as923.h index d65bb75..735c97a 100644 --- a/src/lmic/lorabase_as923.h +++ b/src/lmic/lorabase_as923.h @@ -68,6 +68,7 @@ enum { AS923_FREQ_MAX = 928000000 }; enum { + AS923_JP_TX_EIRP_MAX_DBM = 13, // 13 dBm = 19.95mW < 20mW AS923_TX_EIRP_MAX_DBM = 16 // 16 dBm }; enum { DR_PAGE_AS923 = 0x10 * (LMIC_REGION_as923 - 1) }; @@ -75,14 +76,14 @@ enum { DR_PAGE_AS923 = 0x10 * (LMIC_REGION_as923 - 1) }; enum { AS923_LMIC_REGION_EIRP = 1 }; // region uses EIRP enum { AS923JP_LBT_US = 5000 }; // microseconds of LBT time -- 5000 ==> - // 5 ms. We use us rather than ms for - // future 128us support, and just for - // backward compatibility -- there - // is code that uses the _US constant, - // and it's awkward to break it. + // 5 ms. We use us rather than ms for + // future 128us support, and just for + // backward compatibility -- there + // is code that uses the _US constant, + // and it's awkward to break it. enum { AS923JP_LBT_DB_MAX = -80 }; // maximum channel strength in dB; if TX - // we measure more than this, we don't tx. + // we measure more than this, we don't tx. // AS923 v1.1, all channels face a 1% duty cycle. So this will have to change // in the future via a config. But this code base needs major changes for diff --git a/src/lmic/oslmic.h b/src/lmic/oslmic.h index 448b029..0aa4916 100644 --- a/src/lmic/oslmic.h +++ b/src/lmic/oslmic.h @@ -238,7 +238,7 @@ void os_wmsbf4 (xref2u1_t buf, u4_t value); u2_t os_rlsbf2 (xref2cu1_t buf); #endif #ifndef os_wlsbf2 -//! Write 16-bit quntity into buffer in little endian byte order. +//! Write 16-bit quantity into buffer in little endian byte order. void os_wlsbf2 (xref2u1_t buf, u2_t value); #endif