mirror of
https://github.com/manuelbl/ttn-esp32.git
synced 2024-09-28 10:13:58 +02:00
328 lines
11 KiB
C
328 lines
11 KiB
C
/*
|
|
* Copyright (c) 2014-2016 IBM Corporation.
|
|
* Copyright (c) 2017, 2019-2021 MCCI Corporation.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* * Neither the name of the <organization> nor the
|
|
* names of its contributors may be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#define LMIC_DR_LEGACY 0
|
|
|
|
#include "lmic_bandplan.h"
|
|
|
|
#if defined(CFG_au915)
|
|
// ================================================================================
|
|
//
|
|
// BEG: AU915 related stuff
|
|
//
|
|
|
|
CONST_TABLE(u1_t, _DR2RPS_CRC)[] = {
|
|
ILLEGAL_RPS, // [-1]
|
|
MAKERPS(SF12, BW125, CR_4_5, 0, 0), // [0]
|
|
MAKERPS(SF11, BW125, CR_4_5, 0, 0), // [1]
|
|
MAKERPS(SF10, BW125, CR_4_5, 0, 0), // [2]
|
|
MAKERPS(SF9 , BW125, CR_4_5, 0, 0), // [3]
|
|
MAKERPS(SF8 , BW125, CR_4_5, 0, 0), // [4]
|
|
MAKERPS(SF7 , BW125, CR_4_5, 0, 0), // [5]
|
|
MAKERPS(SF8 , BW500, CR_4_5, 0, 0), // [6]
|
|
ILLEGAL_RPS , // [7]
|
|
MAKERPS(SF12, BW500, CR_4_5, 0, 0), // [8]
|
|
MAKERPS(SF11, BW500, CR_4_5, 0, 0), // [9]
|
|
MAKERPS(SF10, BW500, CR_4_5, 0, 0), // [10]
|
|
MAKERPS(SF9 , BW500, CR_4_5, 0, 0), // [11]
|
|
MAKERPS(SF8 , BW500, CR_4_5, 0, 0), // [12]
|
|
MAKERPS(SF7 , BW500, CR_4_5, 0, 0), // [13]
|
|
ILLEGAL_RPS
|
|
};
|
|
|
|
bit_t
|
|
LMICau915_validDR(dr_t dr) {
|
|
// use subtract here to avoid overflow
|
|
if (dr >= LENOF_TABLE(_DR2RPS_CRC) - 2)
|
|
return 0;
|
|
return TABLE_GET_U1(_DR2RPS_CRC, dr+1)!=ILLEGAL_RPS;
|
|
}
|
|
|
|
static CONST_TABLE(u1_t, maxFrameLens_dwell0)[] = {
|
|
59+5, 59+5, 59+5, 123+5, 250+5, 250+5, 250+5, 0,
|
|
61+5, 137+5, 250+5, 250+5, 250+5, 250+5 };
|
|
|
|
static CONST_TABLE(u1_t, maxFrameLens_dwell1)[] = {
|
|
0, 0, 19+5, 61+5, 133+5, 250+5, 250+5, 0,
|
|
61+5, 137+5, 250+5, 250+5, 250+5, 250+5 };
|
|
|
|
static bit_t
|
|
LMICau915_getUplinkDwellBit() {
|
|
// if uninitialized, return default.
|
|
if (LMIC.txParam == 0xFF) {
|
|
return AU915_INITIAL_TxParam_UplinkDwellTime;
|
|
}
|
|
return (LMIC.txParam & MCMD_TxParam_TxDWELL_MASK) != 0;
|
|
}
|
|
|
|
uint8_t LMICau915_maxFrameLen(uint8_t dr) {
|
|
if (LMICau915_getUplinkDwellBit()) {
|
|
if (dr < LENOF_TABLE(maxFrameLens_dwell0))
|
|
return TABLE_GET_U1(maxFrameLens_dwell0, dr);
|
|
else
|
|
return 0;
|
|
} else {
|
|
if (dr < LENOF_TABLE(maxFrameLens_dwell1))
|
|
return TABLE_GET_U1(maxFrameLens_dwell1, dr);
|
|
else
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// from LoRaWAN 5.8: mapping from txParam to MaxEIRP
|
|
static CONST_TABLE(s1_t, TXMAXEIRP)[16] = {
|
|
8, 10, 12, 13, 14, 16, 18, 20, 21, 24, 26, 27, 29, 30, 33, 36
|
|
};
|
|
|
|
static int8_t LMICau915_getMaxEIRP(uint8_t mcmd_txparam) {
|
|
// if uninitialized, return default.
|
|
if (mcmd_txparam == 0xFF)
|
|
return AU915_TX_EIRP_MAX_DBM;
|
|
else
|
|
return TABLE_GET_S1(
|
|
TXMAXEIRP,
|
|
(mcmd_txparam & MCMD_TxParam_MaxEIRP_MASK) >>
|
|
MCMD_TxParam_MaxEIRP_SHIFT
|
|
);
|
|
}
|
|
|
|
int8_t LMICau915_pow2dbm(uint8_t mcmd_ladr_p1) {
|
|
if ((mcmd_ladr_p1 & MCMD_LinkADRReq_POW_MASK) == MCMD_LinkADRReq_POW_MASK)
|
|
return -128;
|
|
else {
|
|
return ((s1_t)(LMICau915_getMaxEIRP(LMIC.txParam) - (((mcmd_ladr_p1)&MCMD_LinkADRReq_POW_MASK)<<1)));
|
|
}
|
|
}
|
|
|
|
static CONST_TABLE(ostime_t, DR2HSYM_osticks)[] = {
|
|
us2osticksRound(128 << 7), // DR_SF12
|
|
us2osticksRound(128 << 6), // DR_SF11
|
|
us2osticksRound(128 << 5), // DR_SF10
|
|
us2osticksRound(128 << 4), // DR_SF9
|
|
us2osticksRound(128 << 3), // DR_SF8
|
|
us2osticksRound(128 << 2), // DR_SF7
|
|
us2osticksRound(128 << 1), // DR_SF8C
|
|
us2osticksRound(128 << 0), // ------
|
|
us2osticksRound(128 << 5), // DR_SF12CR
|
|
us2osticksRound(128 << 4), // DR_SF11CR
|
|
us2osticksRound(128 << 3), // DR_SF10CR
|
|
us2osticksRound(128 << 2), // DR_SF9CR
|
|
us2osticksRound(128 << 1), // DR_SF8CR
|
|
us2osticksRound(128 << 0), // DR_SF7CR
|
|
};
|
|
|
|
// get ostime for symbols based on datarate. This is not like us915,
|
|
// becuase the times don't match between the upper half and lower half
|
|
// of the table.
|
|
ostime_t LMICau915_dr2hsym(uint8_t dr) {
|
|
return TABLE_GET_OSTIME(DR2HSYM_osticks, dr);
|
|
}
|
|
|
|
|
|
|
|
u4_t LMICau915_convFreq(xref2cu1_t ptr) {
|
|
u4_t freq = (os_rlsbf4(ptr - 1) >> 8) * 100;
|
|
if (freq < AU915_FREQ_MIN || freq > AU915_FREQ_MAX)
|
|
freq = 0;
|
|
return freq;
|
|
}
|
|
|
|
///
|
|
/// \brief query number of default channels.
|
|
///
|
|
/// \note
|
|
/// For AU, we have no programmable channels; all channels
|
|
/// are fixed. Return the total channel count.
|
|
///
|
|
u1_t LMIC_queryNumDefaultChannels() {
|
|
return 64 + 8;
|
|
}
|
|
|
|
|
|
///
|
|
/// \brief LMIC_setupChannel for AU915
|
|
///
|
|
/// \note there are no progammable channels for US915, so this API
|
|
/// always returns FALSE.
|
|
///
|
|
bit_t LMIC_setupChannel(u1_t chidx, u4_t freq, u2_t drmap, s1_t band) {
|
|
LMIC_API_PARAMETER(chidx);
|
|
LMIC_API_PARAMETER(freq);
|
|
LMIC_API_PARAMETER(drmap);
|
|
LMIC_API_PARAMETER(band);
|
|
|
|
return 0; // all channels are hardwired.
|
|
}
|
|
|
|
bit_t LMIC_disableChannel(u1_t channel) {
|
|
bit_t result = 0;
|
|
if (channel < 72) {
|
|
if (ENABLED_CHANNEL(channel)) {
|
|
result = 1;
|
|
if (IS_CHANNEL_125khz(channel))
|
|
LMIC.activeChannels125khz--;
|
|
else if (IS_CHANNEL_500khz(channel))
|
|
LMIC.activeChannels500khz--;
|
|
}
|
|
LMIC.channelMap[channel >> 4] &= ~(1 << (channel & 0xF));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bit_t LMIC_enableChannel(u1_t channel) {
|
|
bit_t result = 0;
|
|
if (channel < 72) {
|
|
if (!ENABLED_CHANNEL(channel)) {
|
|
result = 1;
|
|
if (IS_CHANNEL_125khz(channel))
|
|
LMIC.activeChannels125khz++;
|
|
else if (IS_CHANNEL_500khz(channel))
|
|
LMIC.activeChannels500khz++;
|
|
}
|
|
LMIC.channelMap[channel >> 4] |= (1 << (channel & 0xF));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bit_t LMIC_enableSubBand(u1_t band) {
|
|
ASSERT(band < 8);
|
|
u1_t start = band * 8;
|
|
u1_t end = start + 8;
|
|
bit_t result = 0;
|
|
|
|
// enable all eight 125 kHz channels in this subband
|
|
for (int channel = start; channel < end; ++channel)
|
|
result |= LMIC_enableChannel(channel);
|
|
|
|
// there's a single 500 kHz channel associated with
|
|
// each group of 8 125 kHz channels. Enable it, too.
|
|
result |= LMIC_enableChannel(64 + band);
|
|
return result;
|
|
}
|
|
|
|
bit_t LMIC_disableSubBand(u1_t band) {
|
|
ASSERT(band < 8);
|
|
u1_t start = band * 8;
|
|
u1_t end = start + 8;
|
|
bit_t result = 0;
|
|
|
|
// disable all eight 125 kHz channels in this subband
|
|
for (int channel = start; channel < end; ++channel)
|
|
result |= LMIC_disableChannel(channel);
|
|
|
|
// there's a single 500 kHz channel associated with
|
|
// each group of 8 125 kHz channels. Disable it, too.
|
|
result |= LMIC_disableChannel(64 + band);
|
|
return result;
|
|
}
|
|
|
|
bit_t LMIC_selectSubBand(u1_t band) {
|
|
bit_t result = 0;
|
|
|
|
ASSERT(band < 8);
|
|
for (int b = 0; b<8; ++b) {
|
|
if (band == b)
|
|
result |= LMIC_enableSubBand(b);
|
|
else
|
|
result |= LMIC_disableSubBand(b);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void LMICau915_updateTx(ostime_t txbeg) {
|
|
u1_t chnl = LMIC.txChnl;
|
|
LMIC.txpow = LMICau915_getMaxEIRP(LMIC.txParam);
|
|
if (chnl < 64) {
|
|
LMIC.freq = AU915_125kHz_UPFBASE + chnl*AU915_125kHz_UPFSTEP;
|
|
} else {
|
|
ASSERT(chnl < 64 + 8);
|
|
LMIC.freq = AU915_500kHz_UPFBASE + (chnl - 64)*AU915_500kHz_UPFSTEP;
|
|
}
|
|
|
|
// Update global duty cycle stat and deal with dwell time.
|
|
u4_t dwellDelay;
|
|
u4_t globalDutyDelay;
|
|
dwellDelay = globalDutyDelay = 0;
|
|
|
|
if (LMIC.globalDutyRate != 0) {
|
|
ostime_t airtime = calcAirTime(LMIC.rps, LMIC.dataLen);
|
|
globalDutyDelay = txbeg + (airtime << LMIC.globalDutyRate);
|
|
}
|
|
if (LMICau915_getUplinkDwellBit(LMIC.txParam)) {
|
|
dwellDelay = AU915_UPLINK_DWELL_TIME_osticks;
|
|
}
|
|
if (dwellDelay > globalDutyDelay) {
|
|
globalDutyDelay = dwellDelay;
|
|
}
|
|
if (globalDutyDelay != 0) {
|
|
LMIC.globalDutyAvail = txbeg + globalDutyDelay;
|
|
}
|
|
}
|
|
|
|
#if !defined(DISABLE_BEACONS)
|
|
void LMICau915_setBcnRxParams(void) {
|
|
LMIC.dataLen = 0;
|
|
LMIC.freq = AU915_500kHz_DNFBASE + LMIC.bcnChnl * AU915_500kHz_DNFSTEP;
|
|
LMIC.rps = setIh(setNocrc(dndr2rps((dr_t)DR_BCN), 1), LEN_BCN);
|
|
}
|
|
#endif // !DISABLE_BEACONS
|
|
|
|
// set the Rx1 dndr, rps.
|
|
void LMICau915_setRx1Params(void) {
|
|
u1_t const txdr = LMIC.dndr;
|
|
u1_t candidateDr;
|
|
LMIC.freq = AU915_500kHz_DNFBASE + (LMIC.txChnl & 0x7) * AU915_500kHz_DNFSTEP;
|
|
if ( /* TX datarate */txdr < AU915_DR_SF8C)
|
|
candidateDr = txdr + 8 - LMIC.rx1DrOffset;
|
|
else
|
|
candidateDr = AU915_DR_SF7CR;
|
|
|
|
if (candidateDr < LORAWAN_DR8)
|
|
candidateDr = LORAWAN_DR8;
|
|
else if (candidateDr > LORAWAN_DR13)
|
|
candidateDr = LORAWAN_DR13;
|
|
|
|
LMIC.dndr = candidateDr;
|
|
LMIC.rps = dndr2rps(LMIC.dndr);
|
|
}
|
|
|
|
void LMICau915_initJoinLoop(void) {
|
|
// LMIC.txParam is set to 0xFF by the central code at init time.
|
|
LMICuslike_initJoinLoop();
|
|
|
|
// initialize the adrTxPower.
|
|
LMIC.adrTxPow = LMICau915_getMaxEIRP(LMIC.txParam); // dBm
|
|
|
|
}
|
|
|
|
//
|
|
// END: AU915 related stuff
|
|
//
|
|
// ================================================================================
|
|
#endif
|