Any packet forwarder that is not a full gateway is harmful to other users of The Things Network, and should not be used if there is even a small chance that other TTN users are in your wide area neighbourhood. So, the following solution is probably not what you need, and is only appropriate if you know what you’re doing.
I understand, show me the code.
Really, I understand, show me the code.
Really, even though I could not come up with the answer myself, I really do understand this is likely to harm others, but I still need the code.
For 1.5, if one does not want to change the library, here is how one can make an ABP or OTAA sketch work with a single channel gateway and Matthijs Kooijman’s LMiC:
-
Somewhere above
onEvent
define:// Define the single channel and data rate (SF) to use int channel = 0; int dr = DR_SF7; // Disables all channels, except for the one defined above, and sets the // data rate (SF). This only affects uplinks; for downlinks the default // channels or the configuration from the OTAA Join Accept are used. // // Not LoRaWAN compliant; FOR TESTING ONLY! // void forceTxSingleChannelDr() { for(int i=0; i<9; i++) { // For EU; for US use i<71 if(i != channel) { LMIC_disableChannel(i); } } // Set data rate (SF) and transmit power for uplink LMIC_setDrTxpow(dr, 14); }
-
For ABP, in
init()
replaceLMIC_setDrTxpow(DR_SF7,14);
with:// Only use one channel and SF forceTxSingleChannelDr();
-
For OTAA, in
init()
afterLMIC_reset();
add:// Make LMiC initialize the default channels, choose a channel, and // schedule the OTAA join LMIC_startJoining(); // LMiC will already have decided to send on one of the 3 default // channels; ensure it uses the one we want LMIC.txChnl = channel; // ...and make sure we see the EV_JOINING event being logged os_runloop_once();
-
For OTAA, for
EV_JOINED
inonEvent
use:case EV_JOINED: // Ignore the channels from the Join Accept forceTxSingleChannelDr(); // Disable link check validation (automatically enabled during join) LMIC_setLinkCheckMode(0); break;
But note:
-
Only tested with LMiC 1.5, for EU868, channel 0.
-
For OTAA this assumes the first attempt succeeds; if the Join Request or Join Accept are somehow lost, LMiC will still try different channels and data rates due to the logic in
nextJoinState
-
Only tested with an OTAA Join Accept received in RX1 (for EU868 using the same channel as the uplink/join request); when received in RX2 (for EU868 always using 869.525 on SF9), LMiC might also use other values to send? (But maybe the
LMIC_setDrTxpow(dr, 14)
suffices.)
Background
For Matthijs’ LMiC 1.5, the OTAA flow is:
-
In
examples/ttn-otaa/ttn-otaa.ino
, callingLMIC_reset
clears the keys after whichLMIC_setTxData2
is called to schedule some data to be sent. -
In
src/lmic.c
,engineUpdate
controls the flow, like if something has been scheduled for transmission. WhenLMIC.devaddr == 0
this will first triggerLMIC_startJoining
:-
LMIC_startJoining
callsinitJoinLoop
, which for EU868 also callsinitDefaultChannels
. (For US915, that’s already done inLMIC_reset
.) -
In
initJoinLoop
, for EU868 one out of 3 channels is selected (LMIC.txChnl = os_getRndU1() % 3
) while for US915 it’s set to the first channel (LMIC.txChnl = 0
). -
The actual join is not started yet;
LMIC_startJoining
basically schedules joining to be the first thing to do when time permits. So when manually callingLMIC_startJoining
, one can quickly useLMIC.txChnl = channel
to change the channel that LMiC selected.
-
-
Whenever a join attempt fails,
nextJoinState
will select another channel and/or data rate (SF), without checking if the channel is activated; see https://github.com/matthijskooijman/arduino-lmic/issues/88. One cannot change that behavior from one’s own sketch.