LMiC adapted to work with SX1272MB2xAS LoRa shield.

Fork of LMiC by Timothy Mulrooney

Committer:
GTsapparellas
Date:
Mon Apr 02 12:04:59 2018 +0000
Revision:
8:5879e83f632a
Parent:
7:29058a7ccf23
LoRa Node consisting of FRDM-K64F along with SX1272MB2xAS LoRa shield employed through IBM's LMiC library.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mluis 0:62d1edcc13d1 1 /*******************************************************************************
mluis 1:d3b7bde3995c 2 * Copyright (c) 2014-2015 IBM Corporation.
mluis 0:62d1edcc13d1 3 * All rights reserved. This program and the accompanying materials
mluis 0:62d1edcc13d1 4 * are made available under the terms of the Eclipse Public License v1.0
mluis 0:62d1edcc13d1 5 * which accompanies this distribution, and is available at
mluis 0:62d1edcc13d1 6 * http://www.eclipse.org/legal/epl-v10.html
mluis 0:62d1edcc13d1 7 *
mluis 0:62d1edcc13d1 8 * Contributors:
mluis 0:62d1edcc13d1 9 * IBM Zurich Research Lab - initial API, implementation and documentation
GTsapparellas 8:5879e83f632a 10 *
GTsapparellas 8:5879e83f632a 11 * /////////////////////////////////////////////////////////////////////////////
GTsapparellas 8:5879e83f632a 12 *
GTsapparellas 8:5879e83f632a 13 * Used by Giorgos Tsapparellas for Internet of Things (IoT) smart monitoring
GTsapparellas 8:5879e83f632a 14 * device for agriculture using LoRaWAN technology.
GTsapparellas 8:5879e83f632a 15 *
GTsapparellas 8:5879e83f632a 16 * Date of issued copy: 25 January 2018
GTsapparellas 8:5879e83f632a 17 *
GTsapparellas 8:5879e83f632a 18 * Modifications:
GTsapparellas 8:5879e83f632a 19 * - No external modifications of the existing "AS IT IS" software.
GTsapparellas 8:5879e83f632a 20 * - Comment out debug messages of each function for more clear
GTsapparellas 8:5879e83f632a 21 * debugging procedure.
GTsapparellas 8:5879e83f632a 22 *
GTsapparellas 8:5879e83f632a 23 ******************************************************************************/
mluis 0:62d1edcc13d1 24
mluis 1:d3b7bde3995c 25 //! \file
mluis 0:62d1edcc13d1 26 #include "lmic.h"
tmulrooney 5:464c1f2d6cbb 27 #include "debug.h"
mluis 0:62d1edcc13d1 28
mluis 1:d3b7bde3995c 29 #if !defined(MINRX_SYMS)
mluis 1:d3b7bde3995c 30 #define MINRX_SYMS 5
mluis 1:d3b7bde3995c 31 #endif // !defined(MINRX_SYMS)
mluis 0:62d1edcc13d1 32 #define PAMBL_SYMS 8
mluis 0:62d1edcc13d1 33 #define PAMBL_FSK 5
mluis 0:62d1edcc13d1 34 #define PRERX_FSK 1
mluis 0:62d1edcc13d1 35 #define RXLEN_FSK (1+5+2)
mluis 0:62d1edcc13d1 36
mluis 0:62d1edcc13d1 37 #define BCN_INTV_osticks sec2osticks(BCN_INTV_sec)
mluis 0:62d1edcc13d1 38 #define TXRX_GUARD_osticks ms2osticks(TXRX_GUARD_ms)
mluis 0:62d1edcc13d1 39 #define JOIN_GUARD_osticks ms2osticks(JOIN_GUARD_ms)
mluis 0:62d1edcc13d1 40 #define DELAY_DNW1_osticks sec2osticks(DELAY_DNW1)
mluis 0:62d1edcc13d1 41 #define DELAY_DNW2_osticks sec2osticks(DELAY_DNW2)
mluis 0:62d1edcc13d1 42 #define DELAY_JACC1_osticks sec2osticks(DELAY_JACC1)
mluis 0:62d1edcc13d1 43 #define DELAY_JACC2_osticks sec2osticks(DELAY_JACC2)
mluis 0:62d1edcc13d1 44 #define DELAY_EXTDNW2_osticks sec2osticks(DELAY_EXTDNW2)
mluis 0:62d1edcc13d1 45 #define BCN_RESERVE_osticks ms2osticks(BCN_RESERVE_ms)
mluis 0:62d1edcc13d1 46 #define BCN_GUARD_osticks ms2osticks(BCN_GUARD_ms)
mluis 0:62d1edcc13d1 47 #define BCN_WINDOW_osticks ms2osticks(BCN_WINDOW_ms)
mluis 0:62d1edcc13d1 48 #define AIRTIME_BCN_osticks us2osticks(AIRTIME_BCN)
mluis 1:d3b7bde3995c 49 #if defined(CFG_eu868)
mluis 1:d3b7bde3995c 50 #define DNW2_SAFETY_ZONE ms2osticks(3000)
mluis 1:d3b7bde3995c 51 #endif
mluis 1:d3b7bde3995c 52 #if defined(CFG_us915)
mluis 1:d3b7bde3995c 53 #define DNW2_SAFETY_ZONE ms2osticks(750)
mluis 1:d3b7bde3995c 54 #endif
mluis 1:d3b7bde3995c 55
mluis 1:d3b7bde3995c 56 // Special APIs - for development or testing
mluis 1:d3b7bde3995c 57 #define isTESTMODE() 0
mluis 0:62d1edcc13d1 58
mluis 0:62d1edcc13d1 59 DEFINE_LMIC;
mluis 0:62d1edcc13d1 60 DECL_ON_LMIC_EVENT;
mluis 0:62d1edcc13d1 61
mluis 0:62d1edcc13d1 62
mluis 0:62d1edcc13d1 63 // Fwd decls.
mluis 0:62d1edcc13d1 64 static void engineUpdate(void);
mluis 0:62d1edcc13d1 65 static void startScan (void);
mluis 0:62d1edcc13d1 66
mluis 0:62d1edcc13d1 67
mluis 0:62d1edcc13d1 68 // ================================================================================
mluis 0:62d1edcc13d1 69 // BEG OS - default implementations for certain OS suport functions
mluis 0:62d1edcc13d1 70
mluis 1:d3b7bde3995c 71 #if !defined(HAS_os_calls)
mluis 0:62d1edcc13d1 72
mluis 1:d3b7bde3995c 73 #if !defined(os_rlsbf2)
tmulrooney 6:eed5fd627a2b 74 u2_t os_rlsbf2 (xref2cu1_t buf)
tmulrooney 6:eed5fd627a2b 75 {
GTsapparellas 8:5879e83f632a 76 //debug("LMIC os_rlsbf2 enter\r\n");
mluis 0:62d1edcc13d1 77 return (u2_t)(buf[0] | (buf[1]<<8));
mluis 0:62d1edcc13d1 78 }
mluis 0:62d1edcc13d1 79 #endif
mluis 0:62d1edcc13d1 80
mluis 1:d3b7bde3995c 81 #if !defined(os_rlsbf4)
tmulrooney 6:eed5fd627a2b 82 u4_t os_rlsbf4 (xref2cu1_t buf)
tmulrooney 6:eed5fd627a2b 83 {
GTsapparellas 8:5879e83f632a 84 //debug("LMIC os_rlsbf4 enter\r\n");
mluis 0:62d1edcc13d1 85 return (u4_t)(buf[0] | (buf[1]<<8) | ((u4_t)buf[2]<<16) | ((u4_t)buf[3]<<24));
mluis 0:62d1edcc13d1 86 }
mluis 0:62d1edcc13d1 87 #endif
mluis 0:62d1edcc13d1 88
mluis 0:62d1edcc13d1 89
mluis 1:d3b7bde3995c 90 #if !defined(os_rmsbf4)
tmulrooney 6:eed5fd627a2b 91 u4_t os_rmsbf4 (xref2cu1_t buf)
tmulrooney 6:eed5fd627a2b 92 {
GTsapparellas 8:5879e83f632a 93 //debug("LMIC os_rmsbf4 enter\r\n");
mluis 0:62d1edcc13d1 94 return (u4_t)(buf[3] | (buf[2]<<8) | ((u4_t)buf[1]<<16) | ((u4_t)buf[0]<<24));
mluis 0:62d1edcc13d1 95 }
mluis 0:62d1edcc13d1 96 #endif
mluis 0:62d1edcc13d1 97
mluis 0:62d1edcc13d1 98
mluis 1:d3b7bde3995c 99 #if !defined(os_wlsbf2)
tmulrooney 6:eed5fd627a2b 100 void os_wlsbf2 (xref2u1_t buf, u2_t v)
tmulrooney 6:eed5fd627a2b 101 {
GTsapparellas 8:5879e83f632a 102 //debug("LMIC os_wlsbf2 enter\r\n");
mluis 0:62d1edcc13d1 103 buf[0] = v;
mluis 0:62d1edcc13d1 104 buf[1] = v>>8;
mluis 0:62d1edcc13d1 105 }
mluis 0:62d1edcc13d1 106 #endif
mluis 0:62d1edcc13d1 107
mluis 1:d3b7bde3995c 108 #if !defined(os_wlsbf4)
tmulrooney 6:eed5fd627a2b 109 void os_wlsbf4 (xref2u1_t buf, u4_t v)
tmulrooney 6:eed5fd627a2b 110 {
GTsapparellas 8:5879e83f632a 111 //debug("LMIC os_wlsbf4 enter\r\n");
mluis 0:62d1edcc13d1 112 buf[0] = v;
mluis 0:62d1edcc13d1 113 buf[1] = v>>8;
mluis 0:62d1edcc13d1 114 buf[2] = v>>16;
mluis 0:62d1edcc13d1 115 buf[3] = v>>24;
mluis 0:62d1edcc13d1 116 }
mluis 0:62d1edcc13d1 117 #endif
mluis 0:62d1edcc13d1 118
mluis 1:d3b7bde3995c 119 #if !defined(os_wmsbf4)
tmulrooney 6:eed5fd627a2b 120 void os_wmsbf4 (xref2u1_t buf, u4_t v)
tmulrooney 6:eed5fd627a2b 121 {
GTsapparellas 8:5879e83f632a 122 //debug("LMIC os_wmsbf4 enter\r\n");
mluis 0:62d1edcc13d1 123 buf[3] = v;
mluis 0:62d1edcc13d1 124 buf[2] = v>>8;
mluis 0:62d1edcc13d1 125 buf[1] = v>>16;
mluis 0:62d1edcc13d1 126 buf[0] = v>>24;
mluis 0:62d1edcc13d1 127 }
mluis 0:62d1edcc13d1 128 #endif
mluis 0:62d1edcc13d1 129
mluis 1:d3b7bde3995c 130 #if !defined(os_getBattLevel)
tmulrooney 6:eed5fd627a2b 131 u1_t os_getBattLevel (void)
tmulrooney 6:eed5fd627a2b 132 {
GTsapparellas 8:5879e83f632a 133 //debug("LMIC os_getBattLevel enter\r\n");
mluis 0:62d1edcc13d1 134 return MCMD_DEVS_BATT_NOINFO;
mluis 0:62d1edcc13d1 135 }
mluis 0:62d1edcc13d1 136 #endif
mluis 0:62d1edcc13d1 137
mluis 1:d3b7bde3995c 138 #if !defined(os_crc16)
mluis 1:d3b7bde3995c 139 // New CRC-16 CCITT(XMODEM) checksum for beacons:
tmulrooney 6:eed5fd627a2b 140 u2_t os_crc16 (xref2u1_t data, uint len)
tmulrooney 6:eed5fd627a2b 141 {
GTsapparellas 8:5879e83f632a 142 //debug("LMIC os_crc16 enter\r\n");
mluis 1:d3b7bde3995c 143 u2_t remainder = 0;
mluis 1:d3b7bde3995c 144 u2_t polynomial = 0x1021;
tmulrooney 6:eed5fd627a2b 145 for( uint i = 0; i < len; i++ )
tmulrooney 6:eed5fd627a2b 146 {
mluis 1:d3b7bde3995c 147 remainder ^= data[i] << 8;
tmulrooney 6:eed5fd627a2b 148 for( u1_t bit = 8; bit > 0; bit--)
tmulrooney 6:eed5fd627a2b 149 {
mluis 1:d3b7bde3995c 150 if( (remainder & 0x8000) )
mluis 1:d3b7bde3995c 151 remainder = (remainder << 1) ^ polynomial;
mluis 1:d3b7bde3995c 152 else
mluis 1:d3b7bde3995c 153 remainder <<= 1;
mluis 1:d3b7bde3995c 154 }
mluis 0:62d1edcc13d1 155 }
mluis 1:d3b7bde3995c 156 return remainder;
mluis 0:62d1edcc13d1 157 }
mluis 0:62d1edcc13d1 158 #endif
mluis 0:62d1edcc13d1 159
mluis 0:62d1edcc13d1 160 #endif // !HAS_os_calls
mluis 0:62d1edcc13d1 161
mluis 0:62d1edcc13d1 162 // END OS - default implementations for certain OS suport functions
mluis 0:62d1edcc13d1 163 // ================================================================================
mluis 0:62d1edcc13d1 164
mluis 0:62d1edcc13d1 165 // ================================================================================
mluis 0:62d1edcc13d1 166 // BEG AES
mluis 0:62d1edcc13d1 167
tmulrooney 5:464c1f2d6cbb 168 static void micB0 (u4_t devaddr, u4_t seqno, int dndir, int len)
tmulrooney 5:464c1f2d6cbb 169 {
GTsapparellas 8:5879e83f632a 170 //debug("LMIC micB0 enter\r\n");
mluis 0:62d1edcc13d1 171 os_clearMem(AESaux,16);
mluis 0:62d1edcc13d1 172 AESaux[0] = 0x49;
mluis 0:62d1edcc13d1 173 AESaux[5] = dndir?1:0;
mluis 0:62d1edcc13d1 174 AESaux[15] = len;
mluis 0:62d1edcc13d1 175 os_wlsbf4(AESaux+ 6,devaddr);
mluis 0:62d1edcc13d1 176 os_wlsbf4(AESaux+10,seqno);
mluis 0:62d1edcc13d1 177 }
mluis 0:62d1edcc13d1 178
mluis 0:62d1edcc13d1 179
tmulrooney 5:464c1f2d6cbb 180 static int aes_verifyMic (xref2cu1_t key, u4_t devaddr, u4_t seqno, int dndir, xref2u1_t pdu, int len)
tmulrooney 5:464c1f2d6cbb 181 {
GTsapparellas 8:5879e83f632a 182 //debug("LMIC aes_verifyMic enter\r\n");
mluis 0:62d1edcc13d1 183 micB0(devaddr, seqno, dndir, len);
mluis 0:62d1edcc13d1 184 os_copyMem(AESkey,key,16);
mluis 0:62d1edcc13d1 185 return os_aes(AES_MIC, pdu, len) == os_rmsbf4(pdu+len);
mluis 0:62d1edcc13d1 186 }
mluis 0:62d1edcc13d1 187
mluis 0:62d1edcc13d1 188
tmulrooney 5:464c1f2d6cbb 189 static void aes_appendMic (xref2cu1_t key, u4_t devaddr, u4_t seqno, int dndir, xref2u1_t pdu, int len)
tmulrooney 5:464c1f2d6cbb 190 {
GTsapparellas 8:5879e83f632a 191 //debug("LMIC aes_appendMic enter\r\n");
mluis 0:62d1edcc13d1 192 micB0(devaddr, seqno, dndir, len);
mluis 0:62d1edcc13d1 193 os_copyMem(AESkey,key,16);
mluis 0:62d1edcc13d1 194 // MSB because of internal structure of AES
mluis 0:62d1edcc13d1 195 os_wmsbf4(pdu+len, os_aes(AES_MIC, pdu, len));
mluis 0:62d1edcc13d1 196 }
mluis 0:62d1edcc13d1 197
mluis 0:62d1edcc13d1 198
tmulrooney 5:464c1f2d6cbb 199 static void aes_appendMic0 (xref2u1_t pdu, int len)
tmulrooney 5:464c1f2d6cbb 200 {
GTsapparellas 8:5879e83f632a 201 //debug("LMIC aes_appendMic0 enter\r\n");
tmulrooney 5:464c1f2d6cbb 202 os_getDevKey(AESkey);
GTsapparellas 8:5879e83f632a 203 os_wmsbf4(pdu+len, os_aes(AES_MIC|AES_MICNOAUX, pdu, len)); // MSB because of internal structure of AES
mluis 0:62d1edcc13d1 204 }
mluis 0:62d1edcc13d1 205
mluis 0:62d1edcc13d1 206
tmulrooney 5:464c1f2d6cbb 207 static int aes_verifyMic0 (xref2u1_t pdu, int len)
tmulrooney 5:464c1f2d6cbb 208 {
GTsapparellas 8:5879e83f632a 209 //debug("LMIC aes_verifyMic0 enter\r\n");
mluis 0:62d1edcc13d1 210 os_getDevKey(AESkey);
mluis 0:62d1edcc13d1 211 return os_aes(AES_MIC|AES_MICNOAUX, pdu, len) == os_rmsbf4(pdu+len);
mluis 0:62d1edcc13d1 212 }
mluis 0:62d1edcc13d1 213
mluis 0:62d1edcc13d1 214
tmulrooney 5:464c1f2d6cbb 215 static void aes_encrypt (xref2u1_t pdu, int len)
tmulrooney 5:464c1f2d6cbb 216 {
GTsapparellas 8:5879e83f632a 217 //debug("LMIC aes_encrypt enter\r\n");
mluis 0:62d1edcc13d1 218 os_getDevKey(AESkey);
mluis 0:62d1edcc13d1 219 os_aes(AES_ENC, pdu, len);
mluis 0:62d1edcc13d1 220 }
mluis 0:62d1edcc13d1 221
mluis 0:62d1edcc13d1 222
tmulrooney 5:464c1f2d6cbb 223 static void aes_cipher (xref2cu1_t key, u4_t devaddr, u4_t seqno, int dndir, xref2u1_t payload, int len)
tmulrooney 5:464c1f2d6cbb 224 {
GTsapparellas 8:5879e83f632a 225 //debug("LMIC aes_cipher enter\r\n");
tmulrooney 5:464c1f2d6cbb 226 if( len <= 0 )
mluis 1:d3b7bde3995c 227 return;
mluis 0:62d1edcc13d1 228 os_clearMem(AESaux, 16);
mluis 0:62d1edcc13d1 229 AESaux[0] = AESaux[15] = 1; // mode=cipher / dir=down / block counter=1
mluis 0:62d1edcc13d1 230 AESaux[5] = dndir?1:0;
mluis 0:62d1edcc13d1 231 os_wlsbf4(AESaux+ 6,devaddr);
mluis 0:62d1edcc13d1 232 os_wlsbf4(AESaux+10,seqno);
mluis 0:62d1edcc13d1 233 os_copyMem(AESkey,key,16);
mluis 0:62d1edcc13d1 234 os_aes(AES_CTR, payload, len);
mluis 0:62d1edcc13d1 235 }
mluis 0:62d1edcc13d1 236
mluis 0:62d1edcc13d1 237
tmulrooney 5:464c1f2d6cbb 238 static void aes_sessKeys (u2_t devnonce, xref2cu1_t artnonce, xref2u1_t nwkkey, xref2u1_t artkey)
tmulrooney 5:464c1f2d6cbb 239 {
GTsapparellas 8:5879e83f632a 240 //debug("LMIC aes_sessKeys enter\r\n");
mluis 0:62d1edcc13d1 241 os_clearMem(nwkkey, 16);
mluis 0:62d1edcc13d1 242 nwkkey[0] = 0x01;
mluis 0:62d1edcc13d1 243 os_copyMem(nwkkey+1, artnonce, LEN_ARTNONCE+LEN_NETID);
mluis 0:62d1edcc13d1 244 os_wlsbf2(nwkkey+1+LEN_ARTNONCE+LEN_NETID, devnonce);
mluis 0:62d1edcc13d1 245 os_copyMem(artkey, nwkkey, 16);
mluis 0:62d1edcc13d1 246 artkey[0] = 0x02;
mluis 0:62d1edcc13d1 247
mluis 0:62d1edcc13d1 248 os_getDevKey(AESkey);
mluis 0:62d1edcc13d1 249 os_aes(AES_ENC, nwkkey, 16);
mluis 0:62d1edcc13d1 250 os_getDevKey(AESkey);
mluis 0:62d1edcc13d1 251 os_aes(AES_ENC, artkey, 16);
mluis 0:62d1edcc13d1 252 }
mluis 0:62d1edcc13d1 253
mluis 0:62d1edcc13d1 254 // END AES
mluis 0:62d1edcc13d1 255 // ================================================================================
mluis 0:62d1edcc13d1 256
mluis 0:62d1edcc13d1 257
mluis 0:62d1edcc13d1 258 // ================================================================================
mluis 0:62d1edcc13d1 259 // BEG LORA
mluis 0:62d1edcc13d1 260
mluis 1:d3b7bde3995c 261 #if defined(CFG_eu868) // ========================================
mluis 0:62d1edcc13d1 262
mluis 0:62d1edcc13d1 263 #define maxFrameLen(dr) ((dr)<=DR_SF9 ? maxFrameLens[(dr)] : 0xFF)
mluis 0:62d1edcc13d1 264 const u1_t maxFrameLens [] = { 64,64,64,123 };
mluis 0:62d1edcc13d1 265
mluis 0:62d1edcc13d1 266 const u1_t _DR2RPS_CRC[] = {
mluis 0:62d1edcc13d1 267 ILLEGAL_RPS,
mluis 0:62d1edcc13d1 268 (u1_t)MAKERPS(SF12, BW125, CR_4_5, 0, 0),
mluis 0:62d1edcc13d1 269 (u1_t)MAKERPS(SF11, BW125, CR_4_5, 0, 0),
mluis 0:62d1edcc13d1 270 (u1_t)MAKERPS(SF10, BW125, CR_4_5, 0, 0),
mluis 0:62d1edcc13d1 271 (u1_t)MAKERPS(SF9, BW125, CR_4_5, 0, 0),
mluis 0:62d1edcc13d1 272 (u1_t)MAKERPS(SF8, BW125, CR_4_5, 0, 0),
mluis 0:62d1edcc13d1 273 (u1_t)MAKERPS(SF7, BW125, CR_4_5, 0, 0),
mluis 0:62d1edcc13d1 274 (u1_t)MAKERPS(SF7, BW250, CR_4_5, 0, 0),
mluis 0:62d1edcc13d1 275 (u1_t)MAKERPS(FSK, BW125, CR_4_5, 0, 0),
mluis 0:62d1edcc13d1 276 ILLEGAL_RPS
mluis 0:62d1edcc13d1 277 };
mluis 0:62d1edcc13d1 278
mluis 0:62d1edcc13d1 279 static const s1_t TXPOWLEVELS[] = {
mluis 0:62d1edcc13d1 280 20, 14, 11, 8, 5, 2, 0,0, 0,0,0,0, 0,0,0,0
mluis 0:62d1edcc13d1 281 };
mluis 0:62d1edcc13d1 282 #define pow2dBm(mcmd_ladr_p1) (TXPOWLEVELS[(mcmd_ladr_p1&MCMD_LADR_POW_MASK)>>MCMD_LADR_POW_SHIFT])
mluis 0:62d1edcc13d1 283
mluis 1:d3b7bde3995c 284 #elif defined(CFG_us915) // ========================================
mluis 0:62d1edcc13d1 285
mluis 0:62d1edcc13d1 286 #define maxFrameLen(dr) ((dr)<=DR_SF11CR ? maxFrameLens[(dr)] : 0xFF)
dudmuck 2:974cafbfb159 287 //const u1_t maxFrameLens [] = { 24,66,142,255,255,255,255,255, 66,142 };
mluis 0:62d1edcc13d1 288
mluis 0:62d1edcc13d1 289 const u1_t _DR2RPS_CRC[] = {
mluis 0:62d1edcc13d1 290 ILLEGAL_RPS,
mluis 0:62d1edcc13d1 291 MAKERPS(SF10, BW125, CR_4_5, 0, 0),
mluis 0:62d1edcc13d1 292 MAKERPS(SF9 , BW125, CR_4_5, 0, 0),
mluis 0:62d1edcc13d1 293 MAKERPS(SF8 , BW125, CR_4_5, 0, 0),
mluis 0:62d1edcc13d1 294 MAKERPS(SF7 , BW125, CR_4_5, 0, 0),
mluis 0:62d1edcc13d1 295 MAKERPS(SF8 , BW500, CR_4_5, 0, 0),
mluis 0:62d1edcc13d1 296 ILLEGAL_RPS ,
mluis 0:62d1edcc13d1 297 ILLEGAL_RPS ,
mluis 0:62d1edcc13d1 298 ILLEGAL_RPS ,
mluis 0:62d1edcc13d1 299 MAKERPS(SF12, BW500, CR_4_5, 0, 0),
mluis 0:62d1edcc13d1 300 MAKERPS(SF11, BW500, CR_4_5, 0, 0),
mluis 0:62d1edcc13d1 301 MAKERPS(SF10, BW500, CR_4_5, 0, 0),
mluis 0:62d1edcc13d1 302 MAKERPS(SF9 , BW500, CR_4_5, 0, 0),
mluis 0:62d1edcc13d1 303 MAKERPS(SF8 , BW500, CR_4_5, 0, 0),
mluis 0:62d1edcc13d1 304 MAKERPS(SF7 , BW500, CR_4_5, 0, 0),
mluis 0:62d1edcc13d1 305 ILLEGAL_RPS
mluis 0:62d1edcc13d1 306 };
mluis 0:62d1edcc13d1 307
mluis 0:62d1edcc13d1 308 #define pow2dBm(mcmd_ladr_p1) ((s1_t)(30 - (((mcmd_ladr_p1)&MCMD_LADR_POW_MASK)<<1)))
mluis 0:62d1edcc13d1 309
mluis 0:62d1edcc13d1 310 #endif // ================================================
mluis 0:62d1edcc13d1 311
mluis 0:62d1edcc13d1 312 static const u1_t SENSITIVITY[7][3] = {
mluis 0:62d1edcc13d1 313 // ------------bw----------
mluis 0:62d1edcc13d1 314 // 125kHz 250kHz 500kHz
mluis 0:62d1edcc13d1 315 { 141-109, 141-109, 141-109 }, // FSK
mluis 0:62d1edcc13d1 316 { 141-127, 141-124, 141-121 }, // SF7
mluis 0:62d1edcc13d1 317 { 141-129, 141-126, 141-123 }, // SF8
mluis 0:62d1edcc13d1 318 { 141-132, 141-129, 141-126 }, // SF9
mluis 0:62d1edcc13d1 319 { 141-135, 141-132, 141-129 }, // SF10
mluis 0:62d1edcc13d1 320 { 141-138, 141-135, 141-132 }, // SF11
mluis 0:62d1edcc13d1 321 { 141-141, 141-138, 141-135 } // SF12
mluis 0:62d1edcc13d1 322 };
mluis 0:62d1edcc13d1 323
tmulrooney 5:464c1f2d6cbb 324 int getSensitivity (rps_t rps)
tmulrooney 5:464c1f2d6cbb 325 {
GTsapparellas 8:5879e83f632a 326 //debug("LMIC getSensitivity enter\r\n");
mluis 0:62d1edcc13d1 327 return -141 + SENSITIVITY[getSf(rps)][getBw(rps)];
mluis 0:62d1edcc13d1 328 }
mluis 0:62d1edcc13d1 329
tmulrooney 5:464c1f2d6cbb 330 ostime_t calcAirTime (rps_t rps, u1_t plen)
tmulrooney 5:464c1f2d6cbb 331 {
GTsapparellas 8:5879e83f632a 332 //debug("LMIC calcAirTime enter\r\n");
tmulrooney 5:464c1f2d6cbb 333 u1_t bw = getBw(rps); // 0,1,2 = 125,250,500kHz
mluis 0:62d1edcc13d1 334 u1_t sf = getSf(rps); // 0=FSK, 1..6 = SF7..12
mluis 0:62d1edcc13d1 335 if( sf == FSK ) {
mluis 1:d3b7bde3995c 336 return (plen+/*preamble*/5+/*syncword*/3+/*len*/1+/*crc*/2) * /*bits/byte*/8
mluis 1:d3b7bde3995c 337 * (s4_t)OSTICKS_PER_SEC / /*kbit/s*/50000;
mluis 0:62d1edcc13d1 338 }
mluis 0:62d1edcc13d1 339 u1_t sfx = 4*(sf+(7-SF7));
mluis 0:62d1edcc13d1 340 u1_t q = sfx - (sf >= SF11 ? 8 : 0);
mluis 0:62d1edcc13d1 341 int tmp = 8*plen - sfx + 28 + (getNocrc(rps)?0:16) - (getIh(rps)?20:0);
mluis 0:62d1edcc13d1 342 if( tmp > 0 ) {
mluis 1:d3b7bde3995c 343 tmp = (tmp + q - 1) / q;
mluis 1:d3b7bde3995c 344 tmp *= getCr(rps)+5;
mluis 1:d3b7bde3995c 345 tmp += 8;
mluis 0:62d1edcc13d1 346 } else {
mluis 1:d3b7bde3995c 347 tmp = 8;
mluis 0:62d1edcc13d1 348 }
mluis 0:62d1edcc13d1 349 tmp = (tmp<<2) + /*preamble*/49 /* 4 * (8 + 4.25) */;
mluis 0:62d1edcc13d1 350 // bw = 125000 = 15625 * 2^3
mluis 0:62d1edcc13d1 351 // 250000 = 15625 * 2^4
mluis 0:62d1edcc13d1 352 // 500000 = 15625 * 2^5
mluis 0:62d1edcc13d1 353 // sf = 7..12
mluis 0:62d1edcc13d1 354 //
mluis 0:62d1edcc13d1 355 // osticks = tmp * OSTICKS_PER_SEC * 1<<sf / bw
mluis 0:62d1edcc13d1 356 //
mluis 0:62d1edcc13d1 357 // 3 => counter reduced divisor 125000/8 => 15625
mluis 0:62d1edcc13d1 358 // 2 => counter 2 shift on tmp
mluis 0:62d1edcc13d1 359 sfx = sf+(7-SF7) - (3+2) - bw;
mluis 0:62d1edcc13d1 360 int div = 15625;
mluis 0:62d1edcc13d1 361 if( sfx > 4 ) {
mluis 1:d3b7bde3995c 362 // prevent 32bit signed int overflow in last step
mluis 1:d3b7bde3995c 363 div >>= sfx-4;
mluis 1:d3b7bde3995c 364 sfx = 4;
mluis 0:62d1edcc13d1 365 }
mluis 0:62d1edcc13d1 366 // Need 32bit arithmetic for this last step
mluis 0:62d1edcc13d1 367 return (((ostime_t)tmp << sfx) * OSTICKS_PER_SEC + div/2) / div;
mluis 0:62d1edcc13d1 368 }
mluis 0:62d1edcc13d1 369
dudmuck 2:974cafbfb159 370 /*extern inline s1_t rssi2s1 (int v);
mluis 0:62d1edcc13d1 371 extern inline int s12rssi (s1_t v);
mluis 0:62d1edcc13d1 372 extern inline float s12snr (s1_t v);
dudmuck 2:974cafbfb159 373 extern inline s1_t snr2s1 (double v);*/
mluis 0:62d1edcc13d1 374
mluis 0:62d1edcc13d1 375 extern inline rps_t updr2rps (dr_t dr);
mluis 0:62d1edcc13d1 376 extern inline rps_t dndr2rps (dr_t dr);
mluis 0:62d1edcc13d1 377 extern inline int isFasterDR (dr_t dr1, dr_t dr2);
mluis 0:62d1edcc13d1 378 extern inline int isSlowerDR (dr_t dr1, dr_t dr2);
mluis 0:62d1edcc13d1 379 extern inline dr_t incDR (dr_t dr);
mluis 0:62d1edcc13d1 380 extern inline dr_t decDR (dr_t dr);
mluis 0:62d1edcc13d1 381 extern inline dr_t assertDR (dr_t dr);
mluis 0:62d1edcc13d1 382 extern inline dr_t validDR (dr_t dr);
mluis 0:62d1edcc13d1 383 extern inline dr_t lowerDR (dr_t dr, u1_t n);
mluis 0:62d1edcc13d1 384
mluis 0:62d1edcc13d1 385 extern inline sf_t getSf (rps_t params);
mluis 0:62d1edcc13d1 386 extern inline rps_t setSf (rps_t params, sf_t sf);
mluis 0:62d1edcc13d1 387 extern inline bw_t getBw (rps_t params);
mluis 0:62d1edcc13d1 388 extern inline rps_t setBw (rps_t params, bw_t cr);
mluis 0:62d1edcc13d1 389 extern inline cr_t getCr (rps_t params);
mluis 0:62d1edcc13d1 390 extern inline rps_t setCr (rps_t params, cr_t cr);
mluis 0:62d1edcc13d1 391 extern inline int getNocrc (rps_t params);
mluis 0:62d1edcc13d1 392 extern inline rps_t setNocrc (rps_t params, int nocrc);
mluis 0:62d1edcc13d1 393 extern inline int getIh (rps_t params);
mluis 0:62d1edcc13d1 394 extern inline rps_t setIh (rps_t params, int ih);
mluis 0:62d1edcc13d1 395 extern inline rps_t makeRps (sf_t sf, bw_t bw, cr_t cr, int ih, int nocrc);
mluis 0:62d1edcc13d1 396 extern inline int sameSfBw (rps_t r1, rps_t r2);
mluis 0:62d1edcc13d1 397
mluis 0:62d1edcc13d1 398 // END LORA
mluis 0:62d1edcc13d1 399 // ================================================================================
mluis 0:62d1edcc13d1 400
mluis 0:62d1edcc13d1 401
mluis 0:62d1edcc13d1 402 // Adjust DR for TX retries
mluis 0:62d1edcc13d1 403 // - indexed by retry count
mluis 0:62d1edcc13d1 404 // - return steps to lower DR
mluis 0:62d1edcc13d1 405 static const u1_t DRADJUST[2+TXCONF_ATTEMPTS] = {
mluis 0:62d1edcc13d1 406 // normal frames - 1st try / no retry
mluis 0:62d1edcc13d1 407 0,
mluis 0:62d1edcc13d1 408 // confirmed frames
mluis 1:d3b7bde3995c 409 0,0,1,0,1,0,1,0,0
mluis 0:62d1edcc13d1 410 };
mluis 0:62d1edcc13d1 411
mluis 0:62d1edcc13d1 412
mluis 0:62d1edcc13d1 413 // Table below defines the size of one symbol as
mluis 0:62d1edcc13d1 414 // symtime = 256us * 2^T(sf,bw)
mluis 0:62d1edcc13d1 415 // 256us is called one symunit.
mluis 1:d3b7bde3995c 416 // SF:
mluis 1:d3b7bde3995c 417 // BW: |__7___8___9__10__11__12
mluis 1:d3b7bde3995c 418 // 125kHz | 2 3 4 5 6 7
mluis 1:d3b7bde3995c 419 // 250kHz | 1 2 3 4 5 6
mluis 1:d3b7bde3995c 420 // 500kHz | 0 1 2 3 4 5
mluis 0:62d1edcc13d1 421 //
mluis 0:62d1edcc13d1 422 // Times for half symbol per DR
mluis 0:62d1edcc13d1 423 // Per DR table to minimize rounding errors
mluis 0:62d1edcc13d1 424 static const ostime_t DR2HSYM_osticks[] = {
mluis 1:d3b7bde3995c 425 #if defined(CFG_eu868)
mluis 0:62d1edcc13d1 426 #define dr2hsym(dr) (DR2HSYM_osticks[(dr)])
mluis 0:62d1edcc13d1 427 us2osticksRound(128<<7), // DR_SF12
mluis 0:62d1edcc13d1 428 us2osticksRound(128<<6), // DR_SF11
mluis 0:62d1edcc13d1 429 us2osticksRound(128<<5), // DR_SF10
mluis 0:62d1edcc13d1 430 us2osticksRound(128<<4), // DR_SF9
mluis 0:62d1edcc13d1 431 us2osticksRound(128<<3), // DR_SF8
mluis 0:62d1edcc13d1 432 us2osticksRound(128<<2), // DR_SF7
mluis 0:62d1edcc13d1 433 us2osticksRound(128<<1), // DR_SF7B
mluis 0:62d1edcc13d1 434 us2osticksRound(80) // FSK -- not used (time for 1/2 byte)
mluis 1:d3b7bde3995c 435 #elif defined(CFG_us915)
mluis 0:62d1edcc13d1 436 #define dr2hsym(dr) (DR2HSYM_osticks[(dr)&7]) // map DR_SFnCR -> 0-6
mluis 0:62d1edcc13d1 437 us2osticksRound(128<<5), // DR_SF10 DR_SF12CR
mluis 0:62d1edcc13d1 438 us2osticksRound(128<<4), // DR_SF9 DR_SF11CR
mluis 0:62d1edcc13d1 439 us2osticksRound(128<<3), // DR_SF8 DR_SF10CR
mluis 0:62d1edcc13d1 440 us2osticksRound(128<<2), // DR_SF7 DR_SF9CR
mluis 0:62d1edcc13d1 441 us2osticksRound(128<<1), // DR_SF8C DR_SF8CR
mluis 0:62d1edcc13d1 442 us2osticksRound(128<<0) // ------ DR_SF7CR
mluis 0:62d1edcc13d1 443 #endif
mluis 0:62d1edcc13d1 444 };
mluis 0:62d1edcc13d1 445
mluis 0:62d1edcc13d1 446
tmulrooney 5:464c1f2d6cbb 447 static ostime_t calcRxWindow (u1_t secs, dr_t dr)
tmulrooney 5:464c1f2d6cbb 448 {
GTsapparellas 8:5879e83f632a 449 //debug("LMIC calcRxWindow enter\r\n");
mluis 0:62d1edcc13d1 450 ostime_t rxoff, err;
mluis 0:62d1edcc13d1 451 if( secs==0 ) {
mluis 1:d3b7bde3995c 452 // aka 128 secs (next becaon)
mluis 1:d3b7bde3995c 453 rxoff = LMIC.drift;
mluis 1:d3b7bde3995c 454 err = LMIC.lastDriftDiff;
mluis 0:62d1edcc13d1 455 } else {
mluis 1:d3b7bde3995c 456 // scheduled RX window within secs into current beacon period
mluis 1:d3b7bde3995c 457 rxoff = (LMIC.drift * (ostime_t)secs) >> BCN_INTV_exp;
mluis 1:d3b7bde3995c 458 err = (LMIC.lastDriftDiff * (ostime_t)secs) >> BCN_INTV_exp;
mluis 0:62d1edcc13d1 459 }
mluis 0:62d1edcc13d1 460 u1_t rxsyms = MINRX_SYMS;
mluis 0:62d1edcc13d1 461 err += (ostime_t)LMIC.maxDriftDiff * LMIC.missedBcns;
mluis 0:62d1edcc13d1 462 LMIC.rxsyms = MINRX_SYMS + (err / dr2hsym(dr));
mluis 0:62d1edcc13d1 463
mluis 0:62d1edcc13d1 464 return (rxsyms-PAMBL_SYMS) * dr2hsym(dr) + rxoff;
mluis 0:62d1edcc13d1 465 }
mluis 0:62d1edcc13d1 466
mluis 0:62d1edcc13d1 467
mluis 0:62d1edcc13d1 468 // Setup beacon RX parameters assuming we have an error of ms (aka +/-(ms/2))
tmulrooney 5:464c1f2d6cbb 469 static void calcBcnRxWindowFromMillis (u1_t ms, bit_t ini)
tmulrooney 5:464c1f2d6cbb 470 {
GTsapparellas 8:5879e83f632a 471 //debug("LMIC calcBcnRxWindowFromMillis enter\r\n");
mluis 0:62d1edcc13d1 472 if( ini ) {
mluis 1:d3b7bde3995c 473 LMIC.drift = 0;
mluis 1:d3b7bde3995c 474 LMIC.maxDriftDiff = 0;
mluis 1:d3b7bde3995c 475 LMIC.missedBcns = 0;
mluis 1:d3b7bde3995c 476 LMIC.bcninfo.flags |= BCN_NODRIFT|BCN_NODDIFF;
mluis 0:62d1edcc13d1 477 }
mluis 0:62d1edcc13d1 478 ostime_t hsym = dr2hsym(DR_BCN);
mluis 0:62d1edcc13d1 479 LMIC.bcnRxsyms = MINRX_SYMS + ms2osticksCeil(ms) / hsym;
mluis 0:62d1edcc13d1 480 LMIC.bcnRxtime = LMIC.bcninfo.txtime + BCN_INTV_osticks - (LMIC.bcnRxsyms-PAMBL_SYMS) * hsym;
mluis 0:62d1edcc13d1 481 }
mluis 0:62d1edcc13d1 482
mluis 0:62d1edcc13d1 483
mluis 0:62d1edcc13d1 484 // Setup scheduled RX window (ping/multicast slot)
tmulrooney 5:464c1f2d6cbb 485 static void rxschedInit (xref2rxsched_t rxsched)
tmulrooney 5:464c1f2d6cbb 486 {
GTsapparellas 8:5879e83f632a 487 //debug("LMIC rxschedInit enter\r\n");
mluis 0:62d1edcc13d1 488 os_clearMem(AESkey,16);
mluis 0:62d1edcc13d1 489 os_clearMem(LMIC.frame+8,8);
mluis 0:62d1edcc13d1 490 os_wlsbf4(LMIC.frame, LMIC.bcninfo.time);
mluis 0:62d1edcc13d1 491 os_wlsbf4(LMIC.frame+4, LMIC.devaddr);
mluis 0:62d1edcc13d1 492 os_aes(AES_ENC,LMIC.frame,16);
mluis 0:62d1edcc13d1 493 u1_t intvExp = rxsched->intvExp;
mluis 0:62d1edcc13d1 494 ostime_t off = os_rlsbf2(LMIC.frame) & (0x0FFF >> (7 - intvExp)); // random offset (slot units)
mluis 0:62d1edcc13d1 495 rxsched->rxbase = (LMIC.bcninfo.txtime +
mluis 1:d3b7bde3995c 496 BCN_RESERVE_osticks +
mluis 1:d3b7bde3995c 497 ms2osticks(BCN_SLOT_SPAN_ms * off)); // random offset osticks
mluis 0:62d1edcc13d1 498 rxsched->slot = 0;
mluis 0:62d1edcc13d1 499 rxsched->rxtime = rxsched->rxbase - calcRxWindow(/*secs BCN_RESERVE*/2+(1<<intvExp),rxsched->dr);
mluis 0:62d1edcc13d1 500 rxsched->rxsyms = LMIC.rxsyms;
mluis 0:62d1edcc13d1 501 }
mluis 0:62d1edcc13d1 502
mluis 0:62d1edcc13d1 503
tmulrooney 5:464c1f2d6cbb 504 static bit_t rxschedNext (xref2rxsched_t rxsched, ostime_t cando)
tmulrooney 5:464c1f2d6cbb 505 {
GTsapparellas 8:5879e83f632a 506 //debug("LMIC rxschedNext enter\r\n");
mluis 0:62d1edcc13d1 507 again:
mluis 0:62d1edcc13d1 508 if( rxsched->rxtime - cando >= 0 )
mluis 1:d3b7bde3995c 509 return 1;
mluis 0:62d1edcc13d1 510 u1_t slot;
mluis 0:62d1edcc13d1 511 if( (slot=rxsched->slot) >= 128 )
mluis 1:d3b7bde3995c 512 return 0;
mluis 0:62d1edcc13d1 513 u1_t intv = 1<<rxsched->intvExp;
mluis 0:62d1edcc13d1 514 if( (rxsched->slot = (slot += (intv))) >= 128 )
mluis 1:d3b7bde3995c 515 return 0;
mluis 0:62d1edcc13d1 516 rxsched->rxtime = rxsched->rxbase
mluis 1:d3b7bde3995c 517 + ((BCN_WINDOW_osticks * (ostime_t)slot) >> BCN_INTV_exp)
mluis 1:d3b7bde3995c 518 - calcRxWindow(/*secs BCN_RESERVE*/2+slot+intv,rxsched->dr);
mluis 0:62d1edcc13d1 519 rxsched->rxsyms = LMIC.rxsyms;
mluis 0:62d1edcc13d1 520 goto again;
mluis 0:62d1edcc13d1 521 }
mluis 0:62d1edcc13d1 522
mluis 0:62d1edcc13d1 523
tmulrooney 5:464c1f2d6cbb 524 static ostime_t rndDelay (u1_t secSpan)
tmulrooney 5:464c1f2d6cbb 525 {
GTsapparellas 8:5879e83f632a 526 //debug("LMIC rndDelay enter\r\n");
mluis 0:62d1edcc13d1 527 u2_t r = os_getRndU2();
mluis 0:62d1edcc13d1 528 ostime_t delay = r;
mluis 0:62d1edcc13d1 529 if( delay > OSTICKS_PER_SEC )
mluis 1:d3b7bde3995c 530 delay = r % (u2_t)OSTICKS_PER_SEC;
mluis 0:62d1edcc13d1 531 if( secSpan > 0 )
mluis 1:d3b7bde3995c 532 delay += ((u1_t)r % secSpan) * OSTICKS_PER_SEC;
mluis 0:62d1edcc13d1 533 return delay;
mluis 0:62d1edcc13d1 534 }
mluis 0:62d1edcc13d1 535
mluis 0:62d1edcc13d1 536
tmulrooney 5:464c1f2d6cbb 537 static void txDelay (ostime_t reftime, u1_t secSpan)
tmulrooney 5:464c1f2d6cbb 538 {
GTsapparellas 8:5879e83f632a 539 //debug("LMIC txDelay enter\r\n");
mluis 0:62d1edcc13d1 540 reftime += rndDelay(secSpan);
mluis 0:62d1edcc13d1 541 if( LMIC.globalDutyRate == 0 || (reftime - LMIC.globalDutyAvail) > 0 ) {
mluis 1:d3b7bde3995c 542 LMIC.globalDutyAvail = reftime;
mluis 1:d3b7bde3995c 543 LMIC.opmode |= OP_RNDTX;
mluis 0:62d1edcc13d1 544 }
mluis 0:62d1edcc13d1 545 }
mluis 0:62d1edcc13d1 546
mluis 0:62d1edcc13d1 547
tmulrooney 5:464c1f2d6cbb 548 static void setDrJoin (u1_t reason, u1_t dr)
tmulrooney 5:464c1f2d6cbb 549 {
GTsapparellas 8:5879e83f632a 550 //debug("LMIC setDrJoin enter\r\n");
mluis 0:62d1edcc13d1 551 EV(drChange, INFO, (e_.reason = reason,
mluis 1:d3b7bde3995c 552 e_.deveui = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 553 e_.dr = dr|DR_PAGE,
mluis 1:d3b7bde3995c 554 e_.txpow = LMIC.adrTxPow,
mluis 1:d3b7bde3995c 555 e_.prevdr = LMIC.datarate|DR_PAGE,
mluis 1:d3b7bde3995c 556 e_.prevtxpow = LMIC.adrTxPow));
mluis 0:62d1edcc13d1 557 LMIC.datarate = dr;
mluis 1:d3b7bde3995c 558 DO_DEVDB(LMIC.datarate,datarate);
mluis 0:62d1edcc13d1 559 }
mluis 0:62d1edcc13d1 560
mluis 0:62d1edcc13d1 561
tmulrooney 5:464c1f2d6cbb 562 static void setDrTxpow (u1_t reason, u1_t dr, s1_t pow)
tmulrooney 5:464c1f2d6cbb 563 {
GTsapparellas 8:5879e83f632a 564 //debug("LMIC setDrTxpow enter\r\n");
tmulrooney 5:464c1f2d6cbb 565 EV(drChange, INFO, (e_.reason = reason,
mluis 1:d3b7bde3995c 566 e_.deveui = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 567 e_.dr = dr|DR_PAGE,
mluis 1:d3b7bde3995c 568 e_.txpow = pow,
mluis 1:d3b7bde3995c 569 e_.prevdr = LMIC.datarate|DR_PAGE,
mluis 1:d3b7bde3995c 570 e_.prevtxpow = LMIC.adrTxPow));
mluis 1:d3b7bde3995c 571
dudmuck 2:974cafbfb159 572 if( pow != KEEP_TXPOW ) {
dudmuck 2:974cafbfb159 573 LMIC.adrTxPow = pow;
dudmuck 2:974cafbfb159 574 if (pow < LMIC.txpow_limit)
dudmuck 2:974cafbfb159 575 LMIC.txpow = pow;
dudmuck 2:974cafbfb159 576 }
mluis 1:d3b7bde3995c 577 if( LMIC.datarate != dr ) {
mluis 1:d3b7bde3995c 578 LMIC.datarate = dr;
mluis 1:d3b7bde3995c 579 DO_DEVDB(LMIC.datarate,datarate);
mluis 1:d3b7bde3995c 580 LMIC.opmode |= OP_NEXTCHNL;
mluis 1:d3b7bde3995c 581 }
mluis 0:62d1edcc13d1 582 }
mluis 0:62d1edcc13d1 583
mluis 0:62d1edcc13d1 584
tmulrooney 5:464c1f2d6cbb 585 void LMIC_stopPingable (void)
tmulrooney 5:464c1f2d6cbb 586 {
GTsapparellas 8:5879e83f632a 587 //debug("LMIC LMIC_stopPingable enter\r\n");
tmulrooney 5:464c1f2d6cbb 588 LMIC.opmode &= ~(OP_PINGABLE|OP_PINGINI);
mluis 0:62d1edcc13d1 589 }
mluis 0:62d1edcc13d1 590
mluis 0:62d1edcc13d1 591
tmulrooney 5:464c1f2d6cbb 592 void LMIC_setPingable (u1_t intvExp)
tmulrooney 5:464c1f2d6cbb 593 {
GTsapparellas 8:5879e83f632a 594 //debug("LMIC LMIC_setPingable enter\r\n");
mluis 0:62d1edcc13d1 595 // Change setting
mluis 0:62d1edcc13d1 596 LMIC.ping.intvExp = (intvExp & 0x7);
mluis 0:62d1edcc13d1 597 LMIC.opmode |= OP_PINGABLE;
mluis 0:62d1edcc13d1 598 // App may call LMIC_enableTracking() explicitely before
mluis 0:62d1edcc13d1 599 // Otherwise tracking is implicitly enabled here
mluis 0:62d1edcc13d1 600 if( (LMIC.opmode & (OP_TRACK|OP_SCAN)) == 0 && LMIC.bcninfoTries == 0 )
mluis 1:d3b7bde3995c 601 LMIC_enableTracking(0);
mluis 0:62d1edcc13d1 602 }
mluis 0:62d1edcc13d1 603
mluis 0:62d1edcc13d1 604
mluis 1:d3b7bde3995c 605 #if defined(CFG_eu868)
mluis 0:62d1edcc13d1 606 // ================================================================================
mluis 0:62d1edcc13d1 607 //
mluis 0:62d1edcc13d1 608 // BEG: EU868 related stuff
mluis 0:62d1edcc13d1 609 //
mluis 1:d3b7bde3995c 610 enum { NUM_DEFAULT_CHANNELS=6 };
mluis 0:62d1edcc13d1 611 static const u4_t iniChannelFreq[12] = {
mluis 0:62d1edcc13d1 612 // Join frequencies and duty cycle limit (0.1%)
mluis 1:d3b7bde3995c 613 EU868_F1|BAND_MILLI, EU868_J4|BAND_MILLI,
mluis 1:d3b7bde3995c 614 EU868_F2|BAND_MILLI, EU868_J5|BAND_MILLI,
mluis 1:d3b7bde3995c 615 EU868_F3|BAND_MILLI, EU868_J6|BAND_MILLI,
mluis 0:62d1edcc13d1 616 // Default operational frequencies
mluis 0:62d1edcc13d1 617 EU868_F1|BAND_CENTI, EU868_F2|BAND_CENTI, EU868_F3|BAND_CENTI,
mluis 0:62d1edcc13d1 618 EU868_F4|BAND_MILLI, EU868_F5|BAND_MILLI, EU868_F6|BAND_DECI
mluis 0:62d1edcc13d1 619 };
mluis 0:62d1edcc13d1 620
mluis 0:62d1edcc13d1 621 static void initDefaultChannels (bit_t join) {
mluis 1:d3b7bde3995c 622 os_clearMem(&LMIC.channelFreq, sizeof(LMIC.channelFreq));
mluis 1:d3b7bde3995c 623 os_clearMem(&LMIC.channelDrMap, sizeof(LMIC.channelDrMap));
mluis 1:d3b7bde3995c 624 os_clearMem(&LMIC.bands, sizeof(LMIC.bands));
mluis 1:d3b7bde3995c 625
dudmuck 2:974cafbfb159 626 LMIC.channelMap = 0x3;
mluis 0:62d1edcc13d1 627 u1_t su = join ? 0 : 6;
mluis 0:62d1edcc13d1 628 for( u1_t fu=0; fu<6; fu++,su++ ) {
mluis 1:d3b7bde3995c 629 LMIC.channelFreq[fu] = iniChannelFreq[su];
mluis 1:d3b7bde3995c 630 LMIC.channelDrMap[fu] = DR_RANGE_MAP(DR_SF12,DR_SF7);
mluis 0:62d1edcc13d1 631 }
mluis 1:d3b7bde3995c 632 if( !join ) {
mluis 1:d3b7bde3995c 633 LMIC.channelDrMap[5] = DR_RANGE_MAP(DR_SF12,DR_SF7);
mluis 1:d3b7bde3995c 634 LMIC.channelDrMap[1] = DR_RANGE_MAP(DR_SF12,DR_FSK);
mluis 1:d3b7bde3995c 635 }
mluis 0:62d1edcc13d1 636
mluis 1:d3b7bde3995c 637 LMIC.bands[BAND_MILLI].txcap = 1000; // 0.1%
mluis 1:d3b7bde3995c 638 LMIC.bands[BAND_MILLI].txpow = 14;
mluis 1:d3b7bde3995c 639 LMIC.bands[BAND_MILLI].lastchnl = os_getRndU1() % MAX_CHANNELS;
mluis 1:d3b7bde3995c 640 LMIC.bands[BAND_CENTI].txcap = 100; // 1%
mluis 1:d3b7bde3995c 641 LMIC.bands[BAND_CENTI].txpow = 14;
mluis 1:d3b7bde3995c 642 LMIC.bands[BAND_CENTI].lastchnl = os_getRndU1() % MAX_CHANNELS;
mluis 1:d3b7bde3995c 643 LMIC.bands[BAND_DECI ].txcap = 10; // 10%
mluis 1:d3b7bde3995c 644 LMIC.bands[BAND_DECI ].txpow = 27;
mluis 1:d3b7bde3995c 645 LMIC.bands[BAND_CENTI].lastchnl = os_getRndU1() % MAX_CHANNELS;
mluis 0:62d1edcc13d1 646 LMIC.bands[BAND_MILLI].avail =
mluis 0:62d1edcc13d1 647 LMIC.bands[BAND_CENTI].avail =
mluis 0:62d1edcc13d1 648 LMIC.bands[BAND_DECI ].avail = os_getTime();
mluis 0:62d1edcc13d1 649 }
mluis 0:62d1edcc13d1 650
mluis 1:d3b7bde3995c 651 bit_t LMIC_setupBand (u1_t bandidx, s1_t txpow, u2_t txcap) {
mluis 1:d3b7bde3995c 652 if( bandidx > BAND_AUX ) return 0;
mluis 1:d3b7bde3995c 653 band_t* b = &LMIC.bands[bandidx];
mluis 1:d3b7bde3995c 654 b->txpow = txpow;
mluis 1:d3b7bde3995c 655 b->txcap = txcap;
mluis 1:d3b7bde3995c 656 b->avail = os_getTime();
mluis 1:d3b7bde3995c 657 b->lastchnl = os_getRndU1() % MAX_CHANNELS;
mluis 1:d3b7bde3995c 658 return 1;
mluis 1:d3b7bde3995c 659 }
mluis 1:d3b7bde3995c 660
mluis 1:d3b7bde3995c 661 bit_t LMIC_setupChannel (u1_t chidx, u4_t freq, u2_t drmap, s1_t band) {
mluis 1:d3b7bde3995c 662 if( chidx >= MAX_CHANNELS )
mluis 1:d3b7bde3995c 663 return 0;
mluis 1:d3b7bde3995c 664 if( band == -1 ) {
mluis 1:d3b7bde3995c 665 if( freq >= 869400000 && freq <= 869650000 )
mluis 1:d3b7bde3995c 666 freq |= BAND_DECI; // 10% 27dBm
mluis 1:d3b7bde3995c 667 else if( (freq >= 868000000 && freq <= 868600000) ||
mluis 1:d3b7bde3995c 668 (freq >= 869700000 && freq <= 870000000) )
mluis 1:d3b7bde3995c 669 freq |= BAND_CENTI; // 1% 14dBm
mluis 1:d3b7bde3995c 670 else
mluis 1:d3b7bde3995c 671 freq |= BAND_MILLI; // 0.1% 14dBm
mluis 1:d3b7bde3995c 672 } else {
mluis 1:d3b7bde3995c 673 if( band > BAND_AUX ) return 0;
mluis 1:d3b7bde3995c 674 freq = (freq&~3) | band;
mluis 1:d3b7bde3995c 675 }
mluis 1:d3b7bde3995c 676 LMIC.channelFreq [chidx] = freq;
mluis 1:d3b7bde3995c 677 LMIC.channelDrMap[chidx] = drmap==0 ? DR_RANGE_MAP(DR_SF12,DR_SF7) : drmap;
mluis 1:d3b7bde3995c 678 LMIC.channelMap |= 1<<chidx; // enabled right away
mluis 1:d3b7bde3995c 679 return 1;
mluis 1:d3b7bde3995c 680 }
mluis 1:d3b7bde3995c 681
mluis 1:d3b7bde3995c 682 void LMIC_disableChannel (u1_t channel) {
mluis 1:d3b7bde3995c 683 LMIC.channelFreq[channel] = 0;
mluis 1:d3b7bde3995c 684 LMIC.channelDrMap[channel] = 0;
mluis 1:d3b7bde3995c 685 LMIC.channelMap &= ~(1<<channel);
mluis 1:d3b7bde3995c 686 }
mluis 1:d3b7bde3995c 687
mluis 0:62d1edcc13d1 688 static u4_t convFreq (xref2u1_t ptr) {
mluis 0:62d1edcc13d1 689 u4_t freq = (os_rlsbf4(ptr-1) >> 8) * 100;
mluis 1:d3b7bde3995c 690 if( freq < EU868_FREQ_MIN || freq > EU868_FREQ_MAX )
mluis 1:d3b7bde3995c 691 freq = 0;
mluis 0:62d1edcc13d1 692 return freq;
mluis 0:62d1edcc13d1 693 }
mluis 0:62d1edcc13d1 694
mluis 0:62d1edcc13d1 695 static u1_t mapChannels (u1_t chpage, u2_t chmap) {
mluis 1:d3b7bde3995c 696 // Bad page, disable all channel, enable non-existent
mluis 1:d3b7bde3995c 697 if( chpage != 0 || chmap==0 || (chmap & ~LMIC.channelMap) != 0 )
mluis 1:d3b7bde3995c 698 return 0; // illegal input
mluis 0:62d1edcc13d1 699 for( u1_t chnl=0; chnl<MAX_CHANNELS; chnl++ ) {
mluis 1:d3b7bde3995c 700 if( (chmap & (1<<chnl)) != 0 && LMIC.channelFreq[chnl] == 0 )
mluis 1:d3b7bde3995c 701 chmap &= ~(1<<chnl); // ignore - channel is not defined
mluis 0:62d1edcc13d1 702 }
mluis 0:62d1edcc13d1 703 LMIC.channelMap = chmap;
mluis 0:62d1edcc13d1 704 return 1;
mluis 0:62d1edcc13d1 705 }
mluis 0:62d1edcc13d1 706
mluis 0:62d1edcc13d1 707 static void updateTx (ostime_t txbeg) {
mluis 0:62d1edcc13d1 708 u4_t freq = LMIC.channelFreq[LMIC.txChnl];
mluis 0:62d1edcc13d1 709 // Update global/band specific duty cycle stats
mluis 0:62d1edcc13d1 710 ostime_t airtime = calcAirTime(LMIC.rps, LMIC.dataLen);
mluis 0:62d1edcc13d1 711 // Update channel/global duty cycle stats
mluis 0:62d1edcc13d1 712 xref2band_t band = &LMIC.bands[freq & 0x3];
mluis 0:62d1edcc13d1 713 LMIC.freq = freq & ~(u4_t)3;
mluis 0:62d1edcc13d1 714 LMIC.txpow = band->txpow;
mluis 0:62d1edcc13d1 715 band->avail = txbeg + airtime * band->txcap;
mluis 0:62d1edcc13d1 716 if( LMIC.globalDutyRate != 0 )
mluis 1:d3b7bde3995c 717 LMIC.globalDutyAvail = txbeg + (airtime<<LMIC.globalDutyRate);
mluis 0:62d1edcc13d1 718 }
mluis 0:62d1edcc13d1 719
mluis 0:62d1edcc13d1 720 static ostime_t nextTx (ostime_t now) {
mluis 1:d3b7bde3995c 721 u1_t bmap=0xF;
mluis 1:d3b7bde3995c 722 do {
mluis 1:d3b7bde3995c 723 ostime_t mintime = now + /*10h*/36000*OSTICKS_PER_SEC;
mluis 1:d3b7bde3995c 724 u1_t band=0;
mluis 1:d3b7bde3995c 725 for( u1_t bi=0; bi<4; bi++ ) {
mluis 1:d3b7bde3995c 726 if( (bmap & (1<<bi)) && mintime - LMIC.bands[bi].avail > 0 )
mluis 1:d3b7bde3995c 727 mintime = LMIC.bands[band = bi].avail;
mluis 0:62d1edcc13d1 728 }
mluis 1:d3b7bde3995c 729 // Find next channel in given band
mluis 1:d3b7bde3995c 730 u1_t chnl = LMIC.bands[band].lastchnl;
mluis 1:d3b7bde3995c 731 for( u1_t ci=0; ci<MAX_CHANNELS; ci++ ) {
mluis 1:d3b7bde3995c 732 if( (chnl = (chnl+1)) >= MAX_CHANNELS )
mluis 1:d3b7bde3995c 733 chnl -= MAX_CHANNELS;
mluis 1:d3b7bde3995c 734 if( (LMIC.channelMap & (1<<chnl)) != 0 && // channel enabled
mluis 1:d3b7bde3995c 735 (LMIC.channelDrMap[chnl] & (1<<(LMIC.datarate&0xF))) != 0 &&
mluis 1:d3b7bde3995c 736 band == (LMIC.channelFreq[chnl] & 0x3) ) { // in selected band
mluis 1:d3b7bde3995c 737 LMIC.txChnl = LMIC.bands[band].lastchnl = chnl;
mluis 1:d3b7bde3995c 738 return mintime;
mluis 1:d3b7bde3995c 739 }
mluis 0:62d1edcc13d1 740 }
mluis 1:d3b7bde3995c 741 if( (bmap &= ~(1<<band)) == 0 ) {
mluis 1:d3b7bde3995c 742 // No feasible channel found!
mluis 1:d3b7bde3995c 743 return mintime;
mluis 1:d3b7bde3995c 744 }
mluis 0:62d1edcc13d1 745 } while(1);
mluis 0:62d1edcc13d1 746 }
mluis 0:62d1edcc13d1 747
mluis 1:d3b7bde3995c 748
mluis 0:62d1edcc13d1 749 static void setBcnRxParams (void) {
mluis 0:62d1edcc13d1 750 LMIC.dataLen = 0;
mluis 0:62d1edcc13d1 751 LMIC.freq = LMIC.channelFreq[LMIC.bcnChnl] & ~(u4_t)3;
mluis 0:62d1edcc13d1 752 LMIC.rps = setIh(setNocrc(dndr2rps((dr_t)DR_BCN),1),LEN_BCN);
mluis 0:62d1edcc13d1 753 }
mluis 0:62d1edcc13d1 754
mluis 0:62d1edcc13d1 755 #define setRx1Params() /*LMIC.freq/rps remain unchanged*/
mluis 0:62d1edcc13d1 756
dudmuck 2:974cafbfb159 757 static void initJoinLoop (void) { // eu868
mluis 1:d3b7bde3995c 758 LMIC.txChnl = os_getRndU1() % 6;
mluis 0:62d1edcc13d1 759 LMIC.adrTxPow = 14;
mluis 0:62d1edcc13d1 760 setDrJoin(DRCHG_SET, DR_SF7);
mluis 0:62d1edcc13d1 761 initDefaultChannels(1);
mluis 0:62d1edcc13d1 762 ASSERT((LMIC.opmode & OP_NEXTCHNL)==0);
mluis 1:d3b7bde3995c 763 LMIC.txend = LMIC.bands[BAND_MILLI].avail + rndDelay(8);
mluis 0:62d1edcc13d1 764 }
mluis 0:62d1edcc13d1 765
mluis 0:62d1edcc13d1 766 static ostime_t nextJoinState (void) {
mluis 1:d3b7bde3995c 767 u1_t failed = 0;
mluis 1:d3b7bde3995c 768
mluis 0:62d1edcc13d1 769 // Try 869.x and then 864.x with same DR
mluis 0:62d1edcc13d1 770 // If both fail try next lower datarate
mluis 1:d3b7bde3995c 771 if( ++LMIC.txChnl == 6 )
mluis 1:d3b7bde3995c 772 LMIC.txChnl = 0;
mluis 1:d3b7bde3995c 773 if( (++LMIC.txCnt & 1) == 0 ) {
mluis 1:d3b7bde3995c 774 // Lower DR every 2nd try (having tried 868.x and 864.x with the same DR)
mluis 1:d3b7bde3995c 775 if( LMIC.datarate == DR_SF12 )
mluis 1:d3b7bde3995c 776 failed = 1; // we have tried all DR - signal EV_JOIN_FAILED
mluis 1:d3b7bde3995c 777 else
mluis 1:d3b7bde3995c 778 setDrJoin(DRCHG_NOJACC, decDR((dr_t)LMIC.datarate));
mluis 1:d3b7bde3995c 779 }
mluis 1:d3b7bde3995c 780 // Clear NEXTCHNL because join state engine controls channel hopping
mluis 0:62d1edcc13d1 781 LMIC.opmode &= ~OP_NEXTCHNL;
mluis 1:d3b7bde3995c 782 // Move txend to randomize synchronized concurrent joins.
mluis 1:d3b7bde3995c 783 // Duty cycle is based on txend.
mluis 1:d3b7bde3995c 784 ostime_t time = os_getTime();
mluis 1:d3b7bde3995c 785 if( time - LMIC.bands[BAND_MILLI].avail < 0 )
mluis 1:d3b7bde3995c 786 time = LMIC.bands[BAND_MILLI].avail;
mluis 1:d3b7bde3995c 787 LMIC.txend = time +
mluis 1:d3b7bde3995c 788 (isTESTMODE()
mluis 1:d3b7bde3995c 789 // Avoid collision with JOIN ACCEPT @ SF12 being sent by GW (but we missed it)
mluis 1:d3b7bde3995c 790 ? DNW2_SAFETY_ZONE
mluis 1:d3b7bde3995c 791 // Otherwise: randomize join (street lamp case):
mluis 1:d3b7bde3995c 792 // SF12:255, SF11:127, .., SF7:8secs
mluis 1:d3b7bde3995c 793 : DNW2_SAFETY_ZONE+rndDelay(255>>LMIC.datarate));
mluis 1:d3b7bde3995c 794 // 1 - triggers EV_JOIN_FAILED event
mluis 1:d3b7bde3995c 795 return failed;
mluis 0:62d1edcc13d1 796 }
mluis 0:62d1edcc13d1 797
mluis 0:62d1edcc13d1 798 //
mluis 0:62d1edcc13d1 799 // END: EU868 related stuff
mluis 0:62d1edcc13d1 800 //
mluis 0:62d1edcc13d1 801 // ================================================================================
mluis 1:d3b7bde3995c 802 #elif defined(CFG_us915)
mluis 0:62d1edcc13d1 803 // ================================================================================
mluis 0:62d1edcc13d1 804 //
mluis 0:62d1edcc13d1 805 // BEG: US915 related stuff
mluis 0:62d1edcc13d1 806 //
mluis 0:62d1edcc13d1 807
dudmuck 2:974cafbfb159 808 static void initDefaultChannels (void)
dudmuck 2:974cafbfb159 809 {
tmulrooney 6:eed5fd627a2b 810 debug("LMIC initDefaultChannels enter\r\n");
dudmuck 2:974cafbfb159 811 #ifdef CHNL_HYBRID
dudmuck 2:974cafbfb159 812 int idx = CHNL_HYBRID >> 1;
dudmuck 2:974cafbfb159 813 LMIC.channelMap[0] = 0x0000;
dudmuck 2:974cafbfb159 814 LMIC.channelMap[1] = 0x0000;
dudmuck 2:974cafbfb159 815 LMIC.channelMap[2] = 0x0000;
dudmuck 2:974cafbfb159 816 LMIC.channelMap[3] = 0x0000;
dudmuck 2:974cafbfb159 817 if (CHNL_HYBRID & 1)
dudmuck 2:974cafbfb159 818 LMIC.channelMap[idx] = 0xff00;
dudmuck 2:974cafbfb159 819 else
dudmuck 2:974cafbfb159 820 LMIC.channelMap[idx] = 0x00ff;
dudmuck 2:974cafbfb159 821
dudmuck 2:974cafbfb159 822 LMIC.channelMap[4] = 1 << CHNL_HYBRID;
dudmuck 2:974cafbfb159 823 LMIC.txpow_limit = 20;
dudmuck 2:974cafbfb159 824 #else
mluis 0:62d1edcc13d1 825 for( u1_t i=0; i<4; i++ )
mluis 1:d3b7bde3995c 826 LMIC.channelMap[i] = 0xFFFF;
mluis 0:62d1edcc13d1 827 LMIC.channelMap[4] = 0x00FF;
dudmuck 2:974cafbfb159 828
dudmuck 2:974cafbfb159 829 LMIC.txpow_limit = 30;
dudmuck 2:974cafbfb159 830 #endif
dudmuck 2:974cafbfb159 831
dudmuck 2:974cafbfb159 832 LMIC.txpow = LMIC.txpow_limit;
dudmuck 2:974cafbfb159 833 LMIC.adrTxPow = LMIC.txpow_limit;
mluis 0:62d1edcc13d1 834 }
mluis 0:62d1edcc13d1 835
tmulrooney 5:464c1f2d6cbb 836 static u4_t convFreq (xref2u1_t ptr)
tmulrooney 5:464c1f2d6cbb 837 {
tmulrooney 6:eed5fd627a2b 838 debug("LMIC convFreq enter\r\n");
mluis 0:62d1edcc13d1 839 u4_t freq = (os_rlsbf4(ptr-1) >> 8) * 100;
dudmuck 2:974cafbfb159 840 if( freq < US915_FREQ_MIN || freq > US915_FREQ_MAX )
mluis 1:d3b7bde3995c 841 freq = 0;
mluis 0:62d1edcc13d1 842 return freq;
mluis 0:62d1edcc13d1 843 }
mluis 0:62d1edcc13d1 844
mluis 3:519c71d29a06 845
tmulrooney 5:464c1f2d6cbb 846 bit_t LMIC_setupChannel (u1_t chidx, u4_t freq, u2_t drmap, s1_t band)
tmulrooney 5:464c1f2d6cbb 847 {
tmulrooney 6:eed5fd627a2b 848 debug("LMIC LMIC_setupChannel enter\r\n");
tmulrooney 5:464c1f2d6cbb 849 if( chidx < 72 || chidx >= 72+MAX_XCHANNELS )
mluis 1:d3b7bde3995c 850 return 0; // channels 0..71 are hardwired
mluis 0:62d1edcc13d1 851 chidx -= 72;
mluis 0:62d1edcc13d1 852 LMIC.xchFreq[chidx] = freq;
mluis 1:d3b7bde3995c 853 LMIC.xchDrMap[chidx] = drmap==0 ? DR_RANGE_MAP(DR_SF10,DR_SF8C) : drmap;
mluis 0:62d1edcc13d1 854 LMIC.channelMap[chidx>>4] |= (1<<(chidx&0xF));
mluis 0:62d1edcc13d1 855 return 1;
mluis 0:62d1edcc13d1 856 }
mluis 0:62d1edcc13d1 857
tmulrooney 5:464c1f2d6cbb 858 void LMIC_disableChannel (u1_t channel)
tmulrooney 5:464c1f2d6cbb 859 {
tmulrooney 5:464c1f2d6cbb 860 debug("LMIC_disableChannel enter\r\n");
tmulrooney 5:464c1f2d6cbb 861 if( channel < 72+MAX_XCHANNELS )
mluis 1:d3b7bde3995c 862 LMIC.channelMap[channel/4] &= ~(1<<(channel&0xF));
mluis 1:d3b7bde3995c 863 }
mluis 0:62d1edcc13d1 864
tmulrooney 5:464c1f2d6cbb 865 static u1_t mapChannels (u1_t chpage, u2_t chmap)
tmulrooney 5:464c1f2d6cbb 866 {
tmulrooney 6:eed5fd627a2b 867 debug("LMIC mapChannels enter\r\n");
tmulrooney 5:464c1f2d6cbb 868 if( chpage == MCMD_LADR_CHP_125ON || chpage == MCMD_LADR_CHP_125OFF )
tmulrooney 5:464c1f2d6cbb 869 {
mluis 1:d3b7bde3995c 870 u2_t en125 = chpage == MCMD_LADR_CHP_125ON ? 0xFFFF : 0x0000;
mluis 1:d3b7bde3995c 871 for( u1_t u=0; u<4; u++ )
mluis 1:d3b7bde3995c 872 LMIC.channelMap[u] = en125;
mluis 1:d3b7bde3995c 873 LMIC.channelMap[64/16] = chmap;
mluis 0:62d1edcc13d1 874 } else {
mluis 1:d3b7bde3995c 875 if( chpage >= (72+MAX_XCHANNELS+15)/16 )
mluis 1:d3b7bde3995c 876 return 0;
mluis 1:d3b7bde3995c 877 LMIC.channelMap[chpage] = chmap;
mluis 0:62d1edcc13d1 878 }
mluis 0:62d1edcc13d1 879 return 1;
mluis 0:62d1edcc13d1 880 }
mluis 0:62d1edcc13d1 881
tmulrooney 5:464c1f2d6cbb 882 static void updateTx (ostime_t txbeg)
tmulrooney 5:464c1f2d6cbb 883 {
tmulrooney 6:eed5fd627a2b 884 debug("LMIC updateTx enter\r\n");
tmulrooney 6:eed5fd627a2b 885 u1_t chnl = LMIC.txChnl;
dudmuck 2:974cafbfb159 886 #ifdef JOIN_REQ_DEBUG
dudmuck 2:974cafbfb159 887 printf("chnl%d ", chnl);
dudmuck 2:974cafbfb159 888 #endif /* JOIN_REQ_DEBUG */
mluis 0:62d1edcc13d1 889 if( chnl < 64 ) {
mluis 1:d3b7bde3995c 890 LMIC.freq = US915_125kHz_UPFBASE + chnl*US915_125kHz_UPFSTEP;
dudmuck 2:974cafbfb159 891
dudmuck 2:974cafbfb159 892 if (LMIC.opmode & OP_JOINING) {
dudmuck 2:974cafbfb159 893 /* use max allowed power for joining */
dudmuck 2:974cafbfb159 894 if (LMIC.txpow < LMIC.txpow_limit)
dudmuck 2:974cafbfb159 895 LMIC.txpow = LMIC.txpow_limit;
dudmuck 2:974cafbfb159 896 }
dudmuck 2:974cafbfb159 897
dudmuck 2:974cafbfb159 898 #ifdef JOIN_REQ_DEBUG
dudmuck 2:974cafbfb159 899 printf("%d (125khz)\r\n", LMIC.freq);
dudmuck 2:974cafbfb159 900 #endif /* JOIN_REQ_DEBUG */
mluis 1:d3b7bde3995c 901 return;
mluis 0:62d1edcc13d1 902 }
dudmuck 2:974cafbfb159 903
dudmuck 2:974cafbfb159 904 /* using 500KHz channel */
dudmuck 2:974cafbfb159 905 if (LMIC.txpow_limit >= 26)
dudmuck 2:974cafbfb159 906 LMIC.txpow = 26;
dudmuck 2:974cafbfb159 907 else
dudmuck 2:974cafbfb159 908 LMIC.txpow = LMIC.txpow_limit;
dudmuck 2:974cafbfb159 909
mluis 0:62d1edcc13d1 910 if( chnl < 64+8 ) {
mluis 1:d3b7bde3995c 911 LMIC.freq = US915_500kHz_UPFBASE + (chnl-64)*US915_500kHz_UPFSTEP;
dudmuck 2:974cafbfb159 912 #ifdef JOIN_REQ_DEBUG
dudmuck 2:974cafbfb159 913 printf("%d (500k)\r\n", LMIC.freq);
dudmuck 2:974cafbfb159 914 #endif /* JOIN_REQ_DEBUG */
mluis 0:62d1edcc13d1 915 } else {
mluis 1:d3b7bde3995c 916 ASSERT(chnl < 64+8+MAX_XCHANNELS);
mluis 1:d3b7bde3995c 917 LMIC.freq = LMIC.xchFreq[chnl-72];
dudmuck 2:974cafbfb159 918 #ifdef JOIN_REQ_DEBUG
dudmuck 2:974cafbfb159 919 printf("%d (x)\r\n", LMIC.freq);
dudmuck 2:974cafbfb159 920 #endif /* JOIN_REQ_DEBUG */
mluis 0:62d1edcc13d1 921 }
mluis 0:62d1edcc13d1 922
mluis 0:62d1edcc13d1 923 // Update global duty cycle stats
mluis 0:62d1edcc13d1 924 if( LMIC.globalDutyRate != 0 ) {
mluis 1:d3b7bde3995c 925 ostime_t airtime = calcAirTime(LMIC.rps, LMIC.dataLen);
mluis 1:d3b7bde3995c 926 LMIC.globalDutyAvail = txbeg + (airtime<<LMIC.globalDutyRate);
mluis 0:62d1edcc13d1 927 }
mluis 0:62d1edcc13d1 928 }
mluis 0:62d1edcc13d1 929
dudmuck 2:974cafbfb159 930 int count_bits(u2_t v)
dudmuck 2:974cafbfb159 931 {
dudmuck 2:974cafbfb159 932 int c;
dudmuck 2:974cafbfb159 933
dudmuck 2:974cafbfb159 934 for (c = 0; v; c++) {
dudmuck 2:974cafbfb159 935 v &= v - 1; // clear the last significant bit set
dudmuck 2:974cafbfb159 936 }
dudmuck 2:974cafbfb159 937
dudmuck 2:974cafbfb159 938 return c;
dudmuck 2:974cafbfb159 939 }
dudmuck 2:974cafbfb159 940
mluis 0:62d1edcc13d1 941 // US does not have duty cycling - return now as earliest TX time
mluis 0:62d1edcc13d1 942 #define nextTx(now) (_nextTx(),(now))
tmulrooney 5:464c1f2d6cbb 943 static void _nextTx (void)
tmulrooney 5:464c1f2d6cbb 944 {
tmulrooney 6:eed5fd627a2b 945 debug("LMIC _nextTx enter\r\n");
dudmuck 2:974cafbfb159 946 u1_t prev_ch = LMIC.txChnl;
dudmuck 2:974cafbfb159 947 u1_t tries = 0;
dudmuck 2:974cafbfb159 948 u1_t en_cnt;
dudmuck 2:974cafbfb159 949
mluis 1:d3b7bde3995c 950 if( LMIC.datarate >= DR_SF8C ) { // 500kHz
dudmuck 2:974cafbfb159 951 #ifdef CHNL_HYBRID
dudmuck 2:974cafbfb159 952 LMIC.txChnl = 1 << CHNL_HYBRID; // only one channel possible
dudmuck 2:974cafbfb159 953 #else
dudmuck 2:974cafbfb159 954 en_cnt = count_bits(LMIC.channelMap[4]);
dudmuck 2:974cafbfb159 955 do {
dudmuck 2:974cafbfb159 956 do {
dudmuck 2:974cafbfb159 957 LMIC.chRnd = os_getRndU1() & 7;
dudmuck 2:974cafbfb159 958 if (++tries > 48)
dudmuck 2:974cafbfb159 959 return;
dudmuck 2:974cafbfb159 960 } while ( !(LMIC.channelMap[4] & (1 << LMIC.chRnd)) );
dudmuck 2:974cafbfb159 961 LMIC.txChnl = 64 + LMIC.chRnd;
dudmuck 2:974cafbfb159 962 if (en_cnt < 2)
dudmuck 2:974cafbfb159 963 prev_ch = LMIC.txChnl + 1; // not enough enabled, skip the following test
dudmuck 2:974cafbfb159 964
dudmuck 2:974cafbfb159 965 } while (prev_ch == LMIC.txChnl);
dudmuck 2:974cafbfb159 966 #endif
mluis 1:d3b7bde3995c 967 } else { // 125kHz
dudmuck 2:974cafbfb159 968 #ifdef CHNL_HYBRID
dudmuck 2:974cafbfb159 969 u1_t idx = CHNL_HYBRID >> 1;
dudmuck 2:974cafbfb159 970 en_cnt = count_bits(LMIC.channelMap[idx]);
dudmuck 2:974cafbfb159 971 do {
dudmuck 2:974cafbfb159 972 do {
dudmuck 2:974cafbfb159 973 LMIC.chRnd = os_getRndU1() & 15;
dudmuck 2:974cafbfb159 974 if (++tries > 96)
dudmuck 2:974cafbfb159 975 return;
dudmuck 2:974cafbfb159 976 } while ( !(LMIC.channelMap[idx] & (1 << LMIC.chRnd)) );
dudmuck 2:974cafbfb159 977 LMIC.txChnl = (idx << 4) + LMIC.chRnd;
dudmuck 2:974cafbfb159 978 if (en_cnt < 2)
dudmuck 2:974cafbfb159 979 prev_ch = LMIC.txChnl + 1; // not enough enabled, skip the following test
dudmuck 2:974cafbfb159 980
dudmuck 2:974cafbfb159 981 } while (prev_ch == LMIC.txChnl);
dudmuck 2:974cafbfb159 982 #else
dudmuck 2:974cafbfb159 983 en_cnt = count_bits(LMIC.channelMap[0]);
dudmuck 2:974cafbfb159 984 en_cnt += count_bits(LMIC.channelMap[1]);
dudmuck 2:974cafbfb159 985 en_cnt += count_bits(LMIC.channelMap[2]);
dudmuck 2:974cafbfb159 986 en_cnt += count_bits(LMIC.channelMap[3]);
dudmuck 2:974cafbfb159 987 do {
dudmuck 2:974cafbfb159 988 do {
dudmuck 2:974cafbfb159 989 LMIC.chRnd = os_getRndU1() & 63;
dudmuck 2:974cafbfb159 990 } while ( !(LMIC.channelMap[LMIC.chRnd >> 4] & (1 << (LMIC.chRnd & 15))) );
dudmuck 2:974cafbfb159 991 LMIC.txChnl = LMIC.chRnd;
dudmuck 2:974cafbfb159 992 if (en_cnt < 2)
dudmuck 2:974cafbfb159 993 prev_ch = LMIC.txChnl + 1; // not enough enabled, skip the following test
dudmuck 2:974cafbfb159 994
dudmuck 2:974cafbfb159 995 } while (prev_ch == LMIC.txChnl);
dudmuck 2:974cafbfb159 996 #endif
mluis 0:62d1edcc13d1 997 }
mluis 0:62d1edcc13d1 998 }
mluis 0:62d1edcc13d1 999
mluis 0:62d1edcc13d1 1000 static void setBcnRxParams (void) {
mluis 0:62d1edcc13d1 1001 LMIC.dataLen = 0;
mluis 1:d3b7bde3995c 1002 LMIC.freq = US915_500kHz_DNFBASE + LMIC.bcnChnl * US915_500kHz_DNFSTEP;
mluis 0:62d1edcc13d1 1003 LMIC.rps = setIh(setNocrc(dndr2rps((dr_t)DR_BCN),1),LEN_BCN);
mluis 0:62d1edcc13d1 1004 }
mluis 0:62d1edcc13d1 1005
mluis 1:d3b7bde3995c 1006 #define setRx1Params() { \
mluis 0:62d1edcc13d1 1007 LMIC.freq = US915_500kHz_DNFBASE + (LMIC.txChnl & 0x7) * US915_500kHz_DNFSTEP; \
mluis 1:d3b7bde3995c 1008 if( /* TX datarate */LMIC.dndr < DR_SF8C ) \
mluis 1:d3b7bde3995c 1009 LMIC.dndr += DR_SF10CR - DR_SF10; \
mluis 1:d3b7bde3995c 1010 else if( LMIC.dndr == DR_SF8C ) \
mluis 1:d3b7bde3995c 1011 LMIC.dndr = DR_SF7CR; \
mluis 1:d3b7bde3995c 1012 LMIC.rps = dndr2rps(LMIC.dndr); \
mluis 0:62d1edcc13d1 1013 }
mluis 0:62d1edcc13d1 1014
tmulrooney 5:464c1f2d6cbb 1015 static void initJoinLoop (void)
tmulrooney 5:464c1f2d6cbb 1016 {
tmulrooney 6:eed5fd627a2b 1017 debug("LMIC initJoinLoop enter\r\n");
mluis 1:d3b7bde3995c 1018 LMIC.chRnd = 0;
dudmuck 2:974cafbfb159 1019 #ifdef CHNL_HYBRID
dudmuck 2:974cafbfb159 1020 LMIC.joinBlockChnl = 0;
dudmuck 2:974cafbfb159 1021 LMIC.joinBlock = CHNL_HYBRID;
dudmuck 2:974cafbfb159 1022 LMIC.txChnl = LMIC.joinBlock << 3;
dudmuck 2:974cafbfb159 1023 #else
mluis 1:d3b7bde3995c 1024 LMIC.txChnl = 0;
dudmuck 2:974cafbfb159 1025 LMIC.joinBlockChnl = 0;
dudmuck 2:974cafbfb159 1026 LMIC.joinBlock = 0;
dudmuck 2:974cafbfb159 1027 #endif
dudmuck 2:974cafbfb159 1028 LMIC.datarate = DR_SF10;
dudmuck 2:974cafbfb159 1029 LMIC.adrTxPow = LMIC.txpow_limit;
mluis 0:62d1edcc13d1 1030 ASSERT((LMIC.opmode & OP_NEXTCHNL)==0);
mluis 0:62d1edcc13d1 1031 LMIC.txend = os_getTime();
mluis 0:62d1edcc13d1 1032 setDrJoin(DRCHG_SET, DR_SF7);
mluis 0:62d1edcc13d1 1033 }
mluis 0:62d1edcc13d1 1034
tmulrooney 5:464c1f2d6cbb 1035 static ostime_t nextJoinState (void)
tmulrooney 5:464c1f2d6cbb 1036 {
tmulrooney 6:eed5fd627a2b 1037 debug("LMIC nextJoinState enter\r\n");
tmulrooney 5:464c1f2d6cbb 1038 u1_t failed = 0;
dudmuck 2:974cafbfb159 1039
dudmuck 2:974cafbfb159 1040 if( LMIC.datarate == DR_SF8C ) {
dudmuck 2:974cafbfb159 1041 // attempted 500khz channel, try 125khz channel in next block
dudmuck 2:974cafbfb159 1042 LMIC.datarate = DR_SF10;
dudmuck 2:974cafbfb159 1043 if (++LMIC.joinBlock == 8) {
dudmuck 2:974cafbfb159 1044 LMIC.joinBlock = 0;
dudmuck 2:974cafbfb159 1045 if (++LMIC.joinBlockChnl == 8)
dudmuck 2:974cafbfb159 1046 LMIC.joinBlockChnl = 0;
dudmuck 2:974cafbfb159 1047 }
dudmuck 2:974cafbfb159 1048 LMIC.txChnl = (LMIC.joinBlock << 3) + LMIC.joinBlockChnl;
mluis 0:62d1edcc13d1 1049 } else {
dudmuck 2:974cafbfb159 1050 // attempted 125khz channel, try 500khz channel
dudmuck 2:974cafbfb159 1051 LMIC.datarate = DR_SF8C;
dudmuck 2:974cafbfb159 1052 LMIC.txChnl = LMIC.joinBlock + 64;
mluis 0:62d1edcc13d1 1053 }
dudmuck 2:974cafbfb159 1054 #ifdef JOIN_REQ_DEBUG
dudmuck 2:974cafbfb159 1055 printf("njs blk%d, dr%d, txChnl%d ", LMIC.joinBlock, LMIC.datarate, LMIC.txChnl); // crlf in updateTx()
dudmuck 2:974cafbfb159 1056 #endif /* JOIN_REQ_DEBUG */
dudmuck 2:974cafbfb159 1057
mluis 1:d3b7bde3995c 1058 LMIC.opmode &= ~OP_NEXTCHNL;
mluis 1:d3b7bde3995c 1059 LMIC.txend = os_getTime() +
mluis 1:d3b7bde3995c 1060 (isTESTMODE()
mluis 1:d3b7bde3995c 1061 // Avoid collision with JOIN ACCEPT being sent by GW (but we missed it - GW is still busy)
mluis 1:d3b7bde3995c 1062 ? DNW2_SAFETY_ZONE
mluis 1:d3b7bde3995c 1063 // Otherwise: randomize join (street lamp case):
mluis 1:d3b7bde3995c 1064 // SF10:16, SF9=8,..SF8C:1secs
mluis 1:d3b7bde3995c 1065 : rndDelay(16>>LMIC.datarate));
mluis 1:d3b7bde3995c 1066 // 1 - triggers EV_JOIN_FAILED event
mluis 1:d3b7bde3995c 1067 return failed;
mluis 0:62d1edcc13d1 1068 }
mluis 0:62d1edcc13d1 1069
mluis 0:62d1edcc13d1 1070 //
mluis 0:62d1edcc13d1 1071 // END: US915 related stuff
mluis 0:62d1edcc13d1 1072 //
mluis 0:62d1edcc13d1 1073 // ================================================================================
mluis 0:62d1edcc13d1 1074 #else
mluis 0:62d1edcc13d1 1075 #error Unsupported frequency band!
mluis 0:62d1edcc13d1 1076 #endif
mluis 0:62d1edcc13d1 1077
mluis 0:62d1edcc13d1 1078
tmulrooney 5:464c1f2d6cbb 1079 static void runEngineUpdate (xref2osjob_t osjob)
tmulrooney 5:464c1f2d6cbb 1080 {
GTsapparellas 8:5879e83f632a 1081 //debug("LMIC runEngineUpdate enter\r\n");
mluis 0:62d1edcc13d1 1082 engineUpdate();
mluis 0:62d1edcc13d1 1083 }
mluis 0:62d1edcc13d1 1084
mluis 0:62d1edcc13d1 1085
tmulrooney 5:464c1f2d6cbb 1086 static void reportEvent (ev_t ev)
tmulrooney 5:464c1f2d6cbb 1087 {
GTsapparellas 8:5879e83f632a 1088 //debug("LMIC reportEvent enter %d\r\n",ev);
mluis 0:62d1edcc13d1 1089 EV(devCond, INFO, (e_.reason = EV::devCond_t::LMIC_EV,
mluis 1:d3b7bde3995c 1090 e_.eui = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 1091 e_.info = ev));
mluis 0:62d1edcc13d1 1092 ON_LMIC_EVENT(ev);
mluis 0:62d1edcc13d1 1093 engineUpdate();
mluis 0:62d1edcc13d1 1094 }
mluis 0:62d1edcc13d1 1095
mluis 0:62d1edcc13d1 1096
tmulrooney 6:eed5fd627a2b 1097 static void runReset (xref2osjob_t osjob)
tmulrooney 6:eed5fd627a2b 1098 {
GTsapparellas 8:5879e83f632a 1099 //debug("LMIC runReset enterr\n");
mluis 1:d3b7bde3995c 1100 // Disable session
mluis 1:d3b7bde3995c 1101 LMIC_reset();
mluis 1:d3b7bde3995c 1102 LMIC_startJoining();
mluis 1:d3b7bde3995c 1103 reportEvent(EV_RESET);
mluis 1:d3b7bde3995c 1104 }
mluis 1:d3b7bde3995c 1105
tmulrooney 6:eed5fd627a2b 1106 static void stateJustJoined (void)
tmulrooney 6:eed5fd627a2b 1107 {
GTsapparellas 8:5879e83f632a 1108 //debug("LMIC stateJustJoined enter\r\n");
mluis 0:62d1edcc13d1 1109 LMIC.seqnoDn = LMIC.seqnoUp = 0;
mluis 0:62d1edcc13d1 1110 LMIC.rejoinCnt = 0;
mluis 0:62d1edcc13d1 1111 LMIC.dnConf = LMIC.adrChanged = LMIC.ladrAns = LMIC.devsAns = 0;
mluis 0:62d1edcc13d1 1112 LMIC.moreData = LMIC.dn2Ans = LMIC.snchAns = LMIC.dutyCapAns = 0;
mluis 0:62d1edcc13d1 1113 LMIC.pingSetAns = 0;
mluis 0:62d1edcc13d1 1114 LMIC.upRepeat = 0;
mluis 0:62d1edcc13d1 1115 LMIC.adrAckReq = LINK_CHECK_INIT;
mluis 0:62d1edcc13d1 1116 LMIC.dn2Dr = DR_DNW2;
mluis 0:62d1edcc13d1 1117 LMIC.dn2Freq = FREQ_DNW2;
mluis 0:62d1edcc13d1 1118 LMIC.bcnChnl = CHNL_BCN;
mluis 0:62d1edcc13d1 1119 LMIC.ping.freq = FREQ_PING;
mluis 0:62d1edcc13d1 1120 LMIC.ping.dr = DR_PING;
mluis 0:62d1edcc13d1 1121 }
mluis 0:62d1edcc13d1 1122
mluis 0:62d1edcc13d1 1123
mluis 0:62d1edcc13d1 1124 // ================================================================================
mluis 0:62d1edcc13d1 1125 // Decoding frames
mluis 0:62d1edcc13d1 1126
mluis 0:62d1edcc13d1 1127
mluis 0:62d1edcc13d1 1128 // Decode beacon - do not overwrite bcninfo unless we have a match!
tmulrooney 6:eed5fd627a2b 1129 static int decodeBeacon (void)
tmulrooney 6:eed5fd627a2b 1130 {
GTsapparellas 8:5879e83f632a 1131 //debug("LMIC decodeBeacon enter\r\n");
mluis 0:62d1edcc13d1 1132 ASSERT(LMIC.dataLen == LEN_BCN); // implicit header RX guarantees this
mluis 0:62d1edcc13d1 1133 xref2u1_t d = LMIC.frame;
mluis 1:d3b7bde3995c 1134 if(
dudmuck 2:974cafbfb159 1135 #ifdef CFG_eu868
mluis 1:d3b7bde3995c 1136 d[OFF_BCN_CRC1] != (u1_t)os_crc16(d,OFF_BCN_CRC1)
dudmuck 2:974cafbfb159 1137 #elif defined(CFG_us915)
mluis 1:d3b7bde3995c 1138 os_rlsbf2(&d[OFF_BCN_CRC1]) != os_crc16(d,OFF_BCN_CRC1)
mluis 1:d3b7bde3995c 1139 #endif
mluis 1:d3b7bde3995c 1140 )
mluis 1:d3b7bde3995c 1141 return 0; // first (common) part fails CRC check
mluis 0:62d1edcc13d1 1142 // First set of fields is ok
mluis 0:62d1edcc13d1 1143 u4_t bcnnetid = os_rlsbf4(&d[OFF_BCN_NETID]) & 0xFFFFFF;
mluis 0:62d1edcc13d1 1144 if( bcnnetid != LMIC.netid )
mluis 1:d3b7bde3995c 1145 return -1; // not the beacon we're looking for
mluis 0:62d1edcc13d1 1146
mluis 0:62d1edcc13d1 1147 LMIC.bcninfo.flags &= ~(BCN_PARTIAL|BCN_FULL);
mluis 0:62d1edcc13d1 1148 // Match - update bcninfo structure
mluis 1:d3b7bde3995c 1149 LMIC.bcninfo.snr = LMIC.snr;
mluis 1:d3b7bde3995c 1150 LMIC.bcninfo.rssi = LMIC.rssi;
mluis 0:62d1edcc13d1 1151 LMIC.bcninfo.txtime = LMIC.rxtime - AIRTIME_BCN_osticks;
mluis 0:62d1edcc13d1 1152 LMIC.bcninfo.time = os_rlsbf4(&d[OFF_BCN_TIME]);
mluis 0:62d1edcc13d1 1153 LMIC.bcninfo.flags |= BCN_PARTIAL;
mluis 0:62d1edcc13d1 1154
mluis 0:62d1edcc13d1 1155 // Check 2nd set
mluis 0:62d1edcc13d1 1156 if( os_rlsbf2(&d[OFF_BCN_CRC2]) != os_crc16(d,OFF_BCN_CRC2) )
mluis 1:d3b7bde3995c 1157 return 1;
mluis 0:62d1edcc13d1 1158 // Second set of fields is ok
mluis 0:62d1edcc13d1 1159 LMIC.bcninfo.lat = (s4_t)os_rlsbf4(&d[OFF_BCN_LAT-1]) >> 8; // read as signed 24-bit
mluis 0:62d1edcc13d1 1160 LMIC.bcninfo.lon = (s4_t)os_rlsbf4(&d[OFF_BCN_LON-1]) >> 8; // ditto
mluis 0:62d1edcc13d1 1161 LMIC.bcninfo.info = d[OFF_BCN_INFO];
mluis 0:62d1edcc13d1 1162 LMIC.bcninfo.flags |= BCN_FULL;
mluis 0:62d1edcc13d1 1163 return 2;
mluis 0:62d1edcc13d1 1164 }
mluis 0:62d1edcc13d1 1165
mluis 0:62d1edcc13d1 1166
tmulrooney 6:eed5fd627a2b 1167 static bit_t decodeFrame (void)
tmulrooney 6:eed5fd627a2b 1168 {
GTsapparellas 8:5879e83f632a 1169 //debug("LMIC decodeFrame enter\r\n");
mluis 0:62d1edcc13d1 1170 xref2u1_t d = LMIC.frame;
mluis 0:62d1edcc13d1 1171 u1_t hdr = d[0];
mluis 0:62d1edcc13d1 1172 u1_t ftype = hdr & HDR_FTYPE;
mluis 0:62d1edcc13d1 1173 int dlen = LMIC.dataLen;
mluis 0:62d1edcc13d1 1174 if( dlen < OFF_DAT_OPTS+4 ||
mluis 1:d3b7bde3995c 1175 (hdr & HDR_MAJOR) != HDR_MAJOR_V1 ||
mluis 1:d3b7bde3995c 1176 (ftype != HDR_FTYPE_DADN && ftype != HDR_FTYPE_DCDN) ) {
mluis 1:d3b7bde3995c 1177 // Basic sanity checks failed
mluis 1:d3b7bde3995c 1178 EV(specCond, WARN, (e_.reason = EV::specCond_t::UNEXPECTED_FRAME,
mluis 1:d3b7bde3995c 1179 e_.eui = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 1180 e_.info = dlen < 4 ? 0 : os_rlsbf4(&d[dlen-4]),
mluis 1:d3b7bde3995c 1181 e_.info2 = hdr + (dlen<<8)));
mluis 0:62d1edcc13d1 1182 norx:
mluis 1:d3b7bde3995c 1183 LMIC.dataLen = 0;
mluis 1:d3b7bde3995c 1184 return 0;
mluis 0:62d1edcc13d1 1185 }
mluis 0:62d1edcc13d1 1186 // Validate exact frame length
mluis 0:62d1edcc13d1 1187 // Note: device address was already read+evaluated in order to arrive here.
mluis 0:62d1edcc13d1 1188 int fct = d[OFF_DAT_FCT];
mluis 0:62d1edcc13d1 1189 u4_t addr = os_rlsbf4(&d[OFF_DAT_ADDR]);
mluis 0:62d1edcc13d1 1190 u4_t seqno = os_rlsbf2(&d[OFF_DAT_SEQNO]);
mluis 0:62d1edcc13d1 1191 int olen = fct & FCT_OPTLEN;
mluis 0:62d1edcc13d1 1192 int ackup = (fct & FCT_ACK) != 0 ? 1 : 0; // ACK last up frame
mluis 0:62d1edcc13d1 1193 int poff = OFF_DAT_OPTS+olen;
mluis 0:62d1edcc13d1 1194 int pend = dlen-4; // MIC
mluis 0:62d1edcc13d1 1195
mluis 0:62d1edcc13d1 1196 if( addr != LMIC.devaddr ) {
mluis 1:d3b7bde3995c 1197 EV(specCond, WARN, (e_.reason = EV::specCond_t::ALIEN_ADDRESS,
mluis 1:d3b7bde3995c 1198 e_.eui = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 1199 e_.info = addr,
mluis 1:d3b7bde3995c 1200 e_.info2 = LMIC.devaddr));
mluis 1:d3b7bde3995c 1201 goto norx;
mluis 0:62d1edcc13d1 1202 }
mluis 0:62d1edcc13d1 1203 if( poff > pend ) {
mluis 1:d3b7bde3995c 1204 EV(specCond, ERR, (e_.reason = EV::specCond_t::CORRUPTED_FRAME,
mluis 1:d3b7bde3995c 1205 e_.eui = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 1206 e_.info = 0x1000000 + (poff-pend) + (fct<<8) + (dlen<<16)));
mluis 1:d3b7bde3995c 1207 goto norx;
mluis 0:62d1edcc13d1 1208 }
mluis 0:62d1edcc13d1 1209
mluis 0:62d1edcc13d1 1210 int port = -1;
mluis 0:62d1edcc13d1 1211 int replayConf = 0;
mluis 0:62d1edcc13d1 1212
mluis 0:62d1edcc13d1 1213 if( pend > poff )
mluis 1:d3b7bde3995c 1214 port = d[poff++];
mluis 0:62d1edcc13d1 1215
mluis 0:62d1edcc13d1 1216 seqno = LMIC.seqnoDn + (u2_t)(seqno - LMIC.seqnoDn);
mluis 0:62d1edcc13d1 1217
mluis 0:62d1edcc13d1 1218 if( !aes_verifyMic(LMIC.nwkKey, LMIC.devaddr, seqno, /*dn*/1, d, pend) ) {
mluis 1:d3b7bde3995c 1219 EV(spe3Cond, ERR, (e_.reason = EV::spe3Cond_t::CORRUPTED_MIC,
mluis 1:d3b7bde3995c 1220 e_.eui1 = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 1221 e_.info1 = Base::lsbf4(&d[pend]),
mluis 1:d3b7bde3995c 1222 e_.info2 = seqno,
mluis 1:d3b7bde3995c 1223 e_.info3 = LMIC.devaddr));
mluis 0:62d1edcc13d1 1224 goto norx;
mluis 0:62d1edcc13d1 1225 }
mluis 1:d3b7bde3995c 1226 if( seqno < LMIC.seqnoDn ) {
mluis 1:d3b7bde3995c 1227 if( (s4_t)seqno > (s4_t)LMIC.seqnoDn ) {
mluis 1:d3b7bde3995c 1228 EV(specCond, INFO, (e_.reason = EV::specCond_t::DNSEQNO_ROLL_OVER,
mluis 1:d3b7bde3995c 1229 e_.eui = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 1230 e_.info = LMIC.seqnoDn,
mluis 1:d3b7bde3995c 1231 e_.info2 = seqno));
mluis 1:d3b7bde3995c 1232 goto norx;
mluis 1:d3b7bde3995c 1233 }
mluis 1:d3b7bde3995c 1234 if( seqno != LMIC.seqnoDn-1 || !LMIC.dnConf || ftype != HDR_FTYPE_DCDN ) {
mluis 1:d3b7bde3995c 1235 EV(specCond, INFO, (e_.reason = EV::specCond_t::DNSEQNO_OBSOLETE,
mluis 1:d3b7bde3995c 1236 e_.eui = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 1237 e_.info = LMIC.seqnoDn,
mluis 1:d3b7bde3995c 1238 e_.info2 = seqno));
mluis 1:d3b7bde3995c 1239 goto norx;
mluis 1:d3b7bde3995c 1240 }
mluis 1:d3b7bde3995c 1241 // Replay of previous sequence number allowed only if
mluis 1:d3b7bde3995c 1242 // previous frame and repeated both requested confirmation
mluis 1:d3b7bde3995c 1243 replayConf = 1;
mluis 0:62d1edcc13d1 1244 }
mluis 0:62d1edcc13d1 1245 else {
mluis 1:d3b7bde3995c 1246 if( seqno > LMIC.seqnoDn ) {
mluis 1:d3b7bde3995c 1247 EV(specCond, INFO, (e_.reason = EV::specCond_t::DNSEQNO_SKIP,
mluis 1:d3b7bde3995c 1248 e_.eui = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 1249 e_.info = LMIC.seqnoDn,
mluis 1:d3b7bde3995c 1250 e_.info2 = seqno));
mluis 1:d3b7bde3995c 1251 }
mluis 1:d3b7bde3995c 1252 LMIC.seqnoDn = seqno+1; // next number to be expected
mluis 1:d3b7bde3995c 1253 DO_DEVDB(LMIC.seqnoDn,seqnoDn);
mluis 1:d3b7bde3995c 1254 // DN frame requested confirmation - provide ACK once with next UP frame
mluis 1:d3b7bde3995c 1255 LMIC.dnConf = (ftype == HDR_FTYPE_DCDN ? FCT_ACK : 0);
mluis 0:62d1edcc13d1 1256 }
mluis 0:62d1edcc13d1 1257
mluis 0:62d1edcc13d1 1258 if( LMIC.dnConf || (fct & FCT_MORE) )
mluis 1:d3b7bde3995c 1259 LMIC.opmode |= OP_POLL;
mluis 0:62d1edcc13d1 1260
mluis 0:62d1edcc13d1 1261 // We heard from network
mluis 1:d3b7bde3995c 1262 LMIC.adrChanged = LMIC.rejoinCnt = 0;
mluis 1:d3b7bde3995c 1263 if( LMIC.adrAckReq != LINK_CHECK_OFF )
mluis 1:d3b7bde3995c 1264 LMIC.adrAckReq = LINK_CHECK_INIT;
mluis 0:62d1edcc13d1 1265
mluis 0:62d1edcc13d1 1266 // Process OPTS
mluis 1:d3b7bde3995c 1267 int m = LMIC.rssi - RSSI_OFF - getSensitivity(LMIC.rps);
mluis 0:62d1edcc13d1 1268 LMIC.margin = m < 0 ? 0 : m > 254 ? 254 : m;
mluis 0:62d1edcc13d1 1269
mluis 0:62d1edcc13d1 1270 xref2u1_t opts = &d[OFF_DAT_OPTS];
mluis 0:62d1edcc13d1 1271 int oidx = 0;
mluis 0:62d1edcc13d1 1272 while( oidx < olen ) {
mluis 1:d3b7bde3995c 1273 switch( opts[oidx] ) {
mluis 1:d3b7bde3995c 1274 case MCMD_LCHK_ANS: {
mluis 1:d3b7bde3995c 1275 //int gwmargin = opts[oidx+1];
mluis 1:d3b7bde3995c 1276 //int ngws = opts[oidx+2];
mluis 1:d3b7bde3995c 1277 oidx += 3;
mluis 1:d3b7bde3995c 1278 continue;
mluis 1:d3b7bde3995c 1279 }
mluis 1:d3b7bde3995c 1280 case MCMD_LADR_REQ: {
mluis 1:d3b7bde3995c 1281 u1_t p1 = opts[oidx+1]; // txpow + DR
mluis 1:d3b7bde3995c 1282 u2_t chmap = os_rlsbf2(&opts[oidx+2]);// list of enabled channels
mluis 1:d3b7bde3995c 1283 u1_t chpage = opts[oidx+4] & MCMD_LADR_CHPAGE_MASK; // channel page
mluis 1:d3b7bde3995c 1284 u1_t uprpt = opts[oidx+4] & MCMD_LADR_REPEAT_MASK; // up repeat count
mluis 1:d3b7bde3995c 1285 oidx += 5;
mluis 0:62d1edcc13d1 1286
mluis 1:d3b7bde3995c 1287 LMIC.ladrAns = 0x80 | // Include an answer into next frame up
mluis 1:d3b7bde3995c 1288 MCMD_LADR_ANS_POWACK | MCMD_LADR_ANS_CHACK | MCMD_LADR_ANS_DRACK;
mluis 1:d3b7bde3995c 1289 if( !mapChannels(chpage, chmap) )
mluis 1:d3b7bde3995c 1290 LMIC.ladrAns &= ~MCMD_LADR_ANS_CHACK;
mluis 1:d3b7bde3995c 1291 dr_t dr = (dr_t)(p1>>MCMD_LADR_DR_SHIFT);
mluis 1:d3b7bde3995c 1292 if( !validDR(dr) ) {
mluis 1:d3b7bde3995c 1293 LMIC.ladrAns &= ~MCMD_LADR_ANS_DRACK;
mluis 1:d3b7bde3995c 1294 EV(specCond, ERR, (e_.reason = EV::specCond_t::BAD_MAC_CMD,
mluis 1:d3b7bde3995c 1295 e_.eui = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 1296 e_.info = Base::lsbf4(&d[pend]),
mluis 1:d3b7bde3995c 1297 e_.info2 = Base::msbf4(&opts[oidx-4])));
mluis 1:d3b7bde3995c 1298 }
mluis 1:d3b7bde3995c 1299 if( (LMIC.ladrAns & 0x7F) == (MCMD_LADR_ANS_POWACK | MCMD_LADR_ANS_CHACK | MCMD_LADR_ANS_DRACK) ) {
mluis 1:d3b7bde3995c 1300 // Nothing went wrong - use settings
mluis 1:d3b7bde3995c 1301 LMIC.upRepeat = uprpt;
mluis 1:d3b7bde3995c 1302 setDrTxpow(DRCHG_NWKCMD, dr, pow2dBm(p1));
mluis 1:d3b7bde3995c 1303 }
mluis 1:d3b7bde3995c 1304 LMIC.adrChanged = 1; // Trigger an ACK to NWK
mluis 1:d3b7bde3995c 1305 continue;
mluis 0:62d1edcc13d1 1306 }
mluis 1:d3b7bde3995c 1307 case MCMD_DEVS_REQ: {
mluis 1:d3b7bde3995c 1308 LMIC.devsAns = 1;
mluis 1:d3b7bde3995c 1309 oidx += 1;
mluis 1:d3b7bde3995c 1310 continue;
mluis 1:d3b7bde3995c 1311 }
mluis 1:d3b7bde3995c 1312 case MCMD_DN2P_SET: {
mluis 1:d3b7bde3995c 1313 dr_t dr = (dr_t)(opts[oidx+1] & 0x0F);
mluis 1:d3b7bde3995c 1314 u4_t freq = convFreq(&opts[oidx+2]);
mluis 1:d3b7bde3995c 1315 oidx += 5;
mluis 1:d3b7bde3995c 1316 LMIC.dn2Ans = 0x80; // answer pending
mluis 1:d3b7bde3995c 1317 if( validDR(dr) )
mluis 1:d3b7bde3995c 1318 LMIC.dn2Ans |= MCMD_DN2P_ANS_DRACK;
mluis 1:d3b7bde3995c 1319 if( freq != 0 )
mluis 1:d3b7bde3995c 1320 LMIC.dn2Ans |= MCMD_DN2P_ANS_CHACK;
mluis 1:d3b7bde3995c 1321 if( LMIC.dn2Ans == (0x80|MCMD_DN2P_ANS_DRACK|MCMD_DN2P_ANS_CHACK) ) {
mluis 1:d3b7bde3995c 1322 LMIC.dn2Dr = dr;
mluis 1:d3b7bde3995c 1323 LMIC.dn2Freq = freq;
mluis 1:d3b7bde3995c 1324 DO_DEVDB(LMIC.dn2Dr,dn2Dr);
mluis 1:d3b7bde3995c 1325 DO_DEVDB(LMIC.dn2Freq,dn2Freq);
mluis 1:d3b7bde3995c 1326 }
mluis 1:d3b7bde3995c 1327 continue;
mluis 0:62d1edcc13d1 1328 }
mluis 1:d3b7bde3995c 1329 case MCMD_DCAP_REQ: {
mluis 1:d3b7bde3995c 1330 u1_t cap = opts[oidx+1];
mluis 1:d3b7bde3995c 1331 oidx += 2;
mluis 1:d3b7bde3995c 1332 // A value cap=0xFF means device is OFF unless enabled again manually.
mluis 1:d3b7bde3995c 1333 if( cap==0xFF )
mluis 1:d3b7bde3995c 1334 LMIC.opmode |= OP_SHUTDOWN; // stop any sending
mluis 1:d3b7bde3995c 1335 LMIC.globalDutyRate = cap & 0xF;
mluis 1:d3b7bde3995c 1336 LMIC.globalDutyAvail = os_getTime();
mluis 1:d3b7bde3995c 1337 DO_DEVDB(cap,dutyCap);
mluis 1:d3b7bde3995c 1338 LMIC.dutyCapAns = 1;
mluis 1:d3b7bde3995c 1339 continue;
mluis 1:d3b7bde3995c 1340 }
mluis 1:d3b7bde3995c 1341 case MCMD_SNCH_REQ: {
mluis 1:d3b7bde3995c 1342 u1_t chidx = opts[oidx+1]; // channel
mluis 1:d3b7bde3995c 1343 u4_t freq = convFreq(&opts[oidx+2]); // freq
mluis 1:d3b7bde3995c 1344 u1_t drs = opts[oidx+5]; // datarate span
mluis 1:d3b7bde3995c 1345 LMIC.snchAns = 0x80;
mluis 1:d3b7bde3995c 1346 if( freq != 0 && LMIC_setupChannel(chidx, freq, DR_RANGE_MAP(drs&0xF,drs>>4), -1) )
mluis 1:d3b7bde3995c 1347 LMIC.snchAns |= MCMD_SNCH_ANS_DRACK|MCMD_SNCH_ANS_FQACK;
mluis 1:d3b7bde3995c 1348 oidx += 6;
mluis 1:d3b7bde3995c 1349 continue;
mluis 0:62d1edcc13d1 1350 }
mluis 1:d3b7bde3995c 1351 case MCMD_PING_SET: {
mluis 1:d3b7bde3995c 1352 u4_t freq = convFreq(&opts[oidx+1]);
mluis 1:d3b7bde3995c 1353 oidx += 4;
mluis 1:d3b7bde3995c 1354 u1_t flags = 0x80;
mluis 1:d3b7bde3995c 1355 if( freq != 0 ) {
mluis 1:d3b7bde3995c 1356 flags |= MCMD_PING_ANS_FQACK;
mluis 1:d3b7bde3995c 1357 LMIC.ping.freq = freq;
mluis 1:d3b7bde3995c 1358 DO_DEVDB(LMIC.ping.intvExp, pingIntvExp);
mluis 1:d3b7bde3995c 1359 DO_DEVDB(LMIC.ping.freq, pingFreq);
mluis 1:d3b7bde3995c 1360 DO_DEVDB(LMIC.ping.dr, pingDr);
mluis 1:d3b7bde3995c 1361 }
mluis 1:d3b7bde3995c 1362 LMIC.pingSetAns = flags;
mluis 1:d3b7bde3995c 1363 continue;
mluis 1:d3b7bde3995c 1364 }
mluis 1:d3b7bde3995c 1365 case MCMD_BCNI_ANS: {
mluis 1:d3b7bde3995c 1366 // Ignore if tracking already enabled
mluis 1:d3b7bde3995c 1367 if( (LMIC.opmode & OP_TRACK) == 0 ) {
mluis 1:d3b7bde3995c 1368 LMIC.bcnChnl = opts[oidx+3];
mluis 1:d3b7bde3995c 1369 // Enable tracking - bcninfoTries
mluis 1:d3b7bde3995c 1370 LMIC.opmode |= OP_TRACK;
mluis 1:d3b7bde3995c 1371 // Cleared later in txComplete handling - triggers EV_BEACON_FOUND
mluis 1:d3b7bde3995c 1372 ASSERT(LMIC.bcninfoTries!=0);
mluis 1:d3b7bde3995c 1373 // Setup RX parameters
mluis 1:d3b7bde3995c 1374 LMIC.bcninfo.txtime = (LMIC.rxtime
mluis 1:d3b7bde3995c 1375 + ms2osticks(os_rlsbf2(&opts[oidx+1]) * MCMD_BCNI_TUNIT)
mluis 1:d3b7bde3995c 1376 + ms2osticksCeil(MCMD_BCNI_TUNIT/2)
mluis 1:d3b7bde3995c 1377 - BCN_INTV_osticks);
mluis 1:d3b7bde3995c 1378 LMIC.bcninfo.flags = 0; // txtime above cannot be used as reference (BCN_PARTIAL|BCN_FULL cleared)
mluis 1:d3b7bde3995c 1379 calcBcnRxWindowFromMillis(MCMD_BCNI_TUNIT,1); // error of +/-N ms
mluis 0:62d1edcc13d1 1380
mluis 1:d3b7bde3995c 1381 EV(lostFrame, INFO, (e_.reason = EV::lostFrame_t::MCMD_BCNI_ANS,
mluis 1:d3b7bde3995c 1382 e_.eui = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 1383 e_.lostmic = Base::lsbf4(&d[pend]),
mluis 1:d3b7bde3995c 1384 e_.info = (LMIC.missedBcns |
mluis 1:d3b7bde3995c 1385 (osticks2us(LMIC.bcninfo.txtime + BCN_INTV_osticks
mluis 1:d3b7bde3995c 1386 - LMIC.bcnRxtime) << 8)),
mluis 1:d3b7bde3995c 1387 e_.time = MAIN::CDEV->ostime2ustime(LMIC.bcninfo.txtime + BCN_INTV_osticks)));
mluis 1:d3b7bde3995c 1388 }
mluis 1:d3b7bde3995c 1389 oidx += 4;
mluis 1:d3b7bde3995c 1390 continue;
mluis 0:62d1edcc13d1 1391 }
mluis 1:d3b7bde3995c 1392 }
mluis 1:d3b7bde3995c 1393 EV(specCond, ERR, (e_.reason = EV::specCond_t::BAD_MAC_CMD,
mluis 1:d3b7bde3995c 1394 e_.eui = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 1395 e_.info = Base::lsbf4(&d[pend]),
mluis 1:d3b7bde3995c 1396 e_.info2 = Base::msbf4(&opts[oidx])));
mluis 1:d3b7bde3995c 1397 break;
mluis 0:62d1edcc13d1 1398 }
mluis 0:62d1edcc13d1 1399 if( oidx != olen ) {
mluis 1:d3b7bde3995c 1400 EV(specCond, ERR, (e_.reason = EV::specCond_t::CORRUPTED_FRAME,
mluis 1:d3b7bde3995c 1401 e_.eui = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 1402 e_.info = 0x1000000 + (oidx) + (olen<<8)));
mluis 0:62d1edcc13d1 1403 }
mluis 0:62d1edcc13d1 1404
mluis 0:62d1edcc13d1 1405 if( !replayConf ) {
mluis 1:d3b7bde3995c 1406 // Handle payload only if not a replay
mluis 1:d3b7bde3995c 1407 // Decrypt payload - if any
mluis 1:d3b7bde3995c 1408 if( port >= 0 && pend-poff > 0 )
mluis 1:d3b7bde3995c 1409 aes_cipher(port <= 0 ? LMIC.nwkKey : LMIC.artKey, LMIC.devaddr, seqno, /*dn*/1, d+poff, pend-poff);
mluis 0:62d1edcc13d1 1410
mluis 1:d3b7bde3995c 1411 EV(dfinfo, DEBUG, (e_.deveui = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 1412 e_.devaddr = LMIC.devaddr,
mluis 1:d3b7bde3995c 1413 e_.seqno = seqno,
mluis 1:d3b7bde3995c 1414 e_.flags = (port < 0 ? EV::dfinfo_t::NOPORT : 0) | EV::dfinfo_t::DN,
mluis 1:d3b7bde3995c 1415 e_.mic = Base::lsbf4(&d[pend]),
mluis 1:d3b7bde3995c 1416 e_.hdr = d[LORA::OFF_DAT_HDR],
mluis 1:d3b7bde3995c 1417 e_.fct = d[LORA::OFF_DAT_FCT],
mluis 1:d3b7bde3995c 1418 e_.port = port,
mluis 1:d3b7bde3995c 1419 e_.plen = dlen,
mluis 1:d3b7bde3995c 1420 e_.opts.length = olen,
mluis 1:d3b7bde3995c 1421 memcpy(&e_.opts[0], opts, olen)));
mluis 0:62d1edcc13d1 1422 } else {
mluis 1:d3b7bde3995c 1423 EV(specCond, INFO, (e_.reason = EV::specCond_t::DNSEQNO_REPLAY,
mluis 1:d3b7bde3995c 1424 e_.eui = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 1425 e_.info = Base::lsbf4(&d[pend]),
mluis 1:d3b7bde3995c 1426 e_.info2 = seqno));
mluis 0:62d1edcc13d1 1427 }
mluis 0:62d1edcc13d1 1428
mluis 0:62d1edcc13d1 1429 if( // NWK acks but we don't have a frame pending
mluis 1:d3b7bde3995c 1430 (ackup && LMIC.txCnt == 0) ||
mluis 1:d3b7bde3995c 1431 // We sent up confirmed and we got a response in DNW1/DNW2
mluis 1:d3b7bde3995c 1432 // BUT it did not carry an ACK - this should never happen
mluis 1:d3b7bde3995c 1433 // Do not resend and assume frame was not ACKed.
mluis 1:d3b7bde3995c 1434 (!ackup && LMIC.txCnt != 0) ) {
mluis 1:d3b7bde3995c 1435 EV(specCond, ERR, (e_.reason = EV::specCond_t::SPURIOUS_ACK,
mluis 1:d3b7bde3995c 1436 e_.eui = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 1437 e_.info = seqno,
mluis 1:d3b7bde3995c 1438 e_.info2 = ackup));
mluis 0:62d1edcc13d1 1439 }
mluis 0:62d1edcc13d1 1440
mluis 0:62d1edcc13d1 1441 if( LMIC.txCnt != 0 ) // we requested an ACK
mluis 1:d3b7bde3995c 1442 LMIC.txrxFlags |= ackup ? TXRX_ACK : TXRX_NACK;
mluis 0:62d1edcc13d1 1443
mluis 0:62d1edcc13d1 1444 if( port < 0 ) {
mluis 1:d3b7bde3995c 1445 LMIC.txrxFlags |= TXRX_NOPORT;
mluis 1:d3b7bde3995c 1446 LMIC.dataBeg = poff;
mluis 1:d3b7bde3995c 1447 LMIC.dataLen = 0;
mluis 0:62d1edcc13d1 1448 } else {
mluis 1:d3b7bde3995c 1449 LMIC.txrxFlags |= TXRX_PORT;
mluis 1:d3b7bde3995c 1450 LMIC.dataBeg = poff;
mluis 1:d3b7bde3995c 1451 LMIC.dataLen = pend-poff;
mluis 0:62d1edcc13d1 1452 }
mluis 0:62d1edcc13d1 1453 return 1;
mluis 0:62d1edcc13d1 1454 }
mluis 0:62d1edcc13d1 1455
mluis 0:62d1edcc13d1 1456
mluis 0:62d1edcc13d1 1457 // ================================================================================
mluis 0:62d1edcc13d1 1458 // TX/RX transaction support
mluis 0:62d1edcc13d1 1459
mluis 0:62d1edcc13d1 1460
tmulrooney 6:eed5fd627a2b 1461 static void setupRx2 (void)
tmulrooney 6:eed5fd627a2b 1462 {
GTsapparellas 8:5879e83f632a 1463 //debug("LMIC setupRx2 enter\r\n");
mluis 0:62d1edcc13d1 1464 LMIC.txrxFlags = TXRX_DNW2;
mluis 0:62d1edcc13d1 1465 LMIC.rps = dndr2rps(LMIC.dn2Dr);
mluis 0:62d1edcc13d1 1466 LMIC.freq = LMIC.dn2Freq;
mluis 0:62d1edcc13d1 1467 LMIC.dataLen = 0;
mluis 0:62d1edcc13d1 1468 os_radio(RADIO_RX);
mluis 0:62d1edcc13d1 1469 }
mluis 0:62d1edcc13d1 1470
mluis 0:62d1edcc13d1 1471
tmulrooney 6:eed5fd627a2b 1472 static void schedRx2 (ostime_t delay, osjobcb_t func)
tmulrooney 6:eed5fd627a2b 1473 {
GTsapparellas 8:5879e83f632a 1474 //debug("LMIC schedRx2 enter\r\n");
mluis 0:62d1edcc13d1 1475 // Add 1.5 symbols we need 5 out of 8. Try to sync 1.5 symbols into the preamble.
tmulrooney 7:29058a7ccf23 1476 LMIC.rxtime = LMIC.txend + delay + (PAMBL_SYMS-MINRX_SYMS)*dr2hsym(LMIC.dn2Dr);
GTsapparellas 8:5879e83f632a 1477 //LMIC.rxtime = LMIC.txend + delay;
mluis 0:62d1edcc13d1 1478 os_setTimedCallback(&LMIC.osjob, LMIC.rxtime - RX_RAMPUP, func);
mluis 0:62d1edcc13d1 1479 }
mluis 0:62d1edcc13d1 1480
tmulrooney 6:eed5fd627a2b 1481 static void setupRx1 (osjobcb_t func)
tmulrooney 6:eed5fd627a2b 1482 {
GTsapparellas 8:5879e83f632a 1483 //debug("LMIC setupRx1 enter\r\n");
mluis 0:62d1edcc13d1 1484 LMIC.txrxFlags = TXRX_DNW1;
mluis 0:62d1edcc13d1 1485 // Turn LMIC.rps from TX over to RX
mluis 0:62d1edcc13d1 1486 LMIC.rps = setNocrc(LMIC.rps,1);
mluis 0:62d1edcc13d1 1487 LMIC.dataLen = 0;
mluis 0:62d1edcc13d1 1488 LMIC.osjob.func = func;
mluis 0:62d1edcc13d1 1489 os_radio(RADIO_RX);
mluis 0:62d1edcc13d1 1490 }
mluis 0:62d1edcc13d1 1491
mluis 0:62d1edcc13d1 1492
mluis 0:62d1edcc13d1 1493 // Called by HAL once TX complete and delivers exact end of TX time stamp in LMIC.rxtime
tmulrooney 6:eed5fd627a2b 1494 static void txDone (ostime_t delay, osjobcb_t func)
tmulrooney 6:eed5fd627a2b 1495 {
GTsapparellas 8:5879e83f632a 1496 //debug("LMIC txDone enter\r\n");
tmulrooney 6:eed5fd627a2b 1497 if( (LMIC.opmode & (OP_TRACK|OP_PINGABLE|OP_PINGINI)) == (OP_TRACK|OP_PINGABLE) )
tmulrooney 6:eed5fd627a2b 1498 {
mluis 1:d3b7bde3995c 1499 rxschedInit(&LMIC.ping); // note: reuses LMIC.frame buffer!
mluis 1:d3b7bde3995c 1500 LMIC.opmode |= OP_PINGINI;
mluis 0:62d1edcc13d1 1501 }
mluis 0:62d1edcc13d1 1502 // Change RX frequency / rps (US only) before we increment txChnl
mluis 0:62d1edcc13d1 1503 setRx1Params();
mluis 0:62d1edcc13d1 1504 // LMIC.rxsyms carries the TX datarate (can be != LMIC.datarate [confirm retries etc.])
mluis 0:62d1edcc13d1 1505 // Setup receive - LMIC.rxtime is preloaded with 1.5 symbols offset to tune
mluis 0:62d1edcc13d1 1506 // into the middle of the 8 symbols preamble.
mluis 1:d3b7bde3995c 1507 #if defined(CFG_eu868)
tmulrooney 6:eed5fd627a2b 1508 if( /* TX datarate */LMIC.rxsyms == DR_FSK )
tmulrooney 6:eed5fd627a2b 1509 {
mluis 1:d3b7bde3995c 1510 LMIC.rxtime = LMIC.txend + delay - PRERX_FSK*us2osticksRound(160);
mluis 1:d3b7bde3995c 1511 LMIC.rxsyms = RXLEN_FSK;
mluis 0:62d1edcc13d1 1512 }
mluis 0:62d1edcc13d1 1513 else
mluis 0:62d1edcc13d1 1514 #endif
mluis 0:62d1edcc13d1 1515 {
tmulrooney 7:29058a7ccf23 1516 LMIC.rxtime = LMIC.txend + delay + (PAMBL_SYMS-MINRX_SYMS)*dr2hsym(LMIC.dndr);
GTsapparellas 8:5879e83f632a 1517 // LMIC.rxtime = LMIC.txend + delay;
mluis 1:d3b7bde3995c 1518 LMIC.rxsyms = MINRX_SYMS;
mluis 0:62d1edcc13d1 1519 }
mluis 0:62d1edcc13d1 1520 os_setTimedCallback(&LMIC.osjob, LMIC.rxtime - RX_RAMPUP, func);
mluis 0:62d1edcc13d1 1521 }
mluis 0:62d1edcc13d1 1522
mluis 0:62d1edcc13d1 1523
mluis 0:62d1edcc13d1 1524 // ======================================== Join frames
mluis 0:62d1edcc13d1 1525
mluis 0:62d1edcc13d1 1526
tmulrooney 6:eed5fd627a2b 1527 static void onJoinFailed (xref2osjob_t osjob)
tmulrooney 6:eed5fd627a2b 1528 {
GTsapparellas 8:5879e83f632a 1529 //debug("LMIC onJoinFailed enter\r\n");
mluis 0:62d1edcc13d1 1530 // Notify app - must call LMIC_reset() to stop joining
mluis 0:62d1edcc13d1 1531 // otherwise join procedure continues.
mluis 0:62d1edcc13d1 1532 reportEvent(EV_JOIN_FAILED);
mluis 0:62d1edcc13d1 1533 }
mluis 0:62d1edcc13d1 1534
mluis 0:62d1edcc13d1 1535
tmulrooney 6:eed5fd627a2b 1536 static bit_t processJoinAccept (void)
tmulrooney 6:eed5fd627a2b 1537 {
GTsapparellas 8:5879e83f632a 1538 //debug("LMIC processJoinAccept enter\r\n");
mluis 0:62d1edcc13d1 1539 ASSERT(LMIC.txrxFlags != TXRX_DNW1 || LMIC.dataLen != 0);
mluis 0:62d1edcc13d1 1540 ASSERT((LMIC.opmode & OP_TXRXPEND)!=0);
mluis 0:62d1edcc13d1 1541
tmulrooney 6:eed5fd627a2b 1542 if( LMIC.dataLen == 0 )
tmulrooney 6:eed5fd627a2b 1543 {
mluis 0:62d1edcc13d1 1544 nojoinframe:
dudmuck 2:974cafbfb159 1545 /* keep retrying -- if( (LMIC.opmode & OP_JOINING) == 0 ) {
mluis 1:d3b7bde3995c 1546 ASSERT((LMIC.opmode & OP_REJOIN) != 0);
mluis 1:d3b7bde3995c 1547 // REJOIN attempt for roaming
mluis 1:d3b7bde3995c 1548 LMIC.opmode &= ~(OP_REJOIN|OP_TXRXPEND);
mluis 1:d3b7bde3995c 1549 if( LMIC.rejoinCnt < 10 )
mluis 1:d3b7bde3995c 1550 LMIC.rejoinCnt++;
mluis 1:d3b7bde3995c 1551 reportEvent(EV_REJOIN_FAILED);
mluis 1:d3b7bde3995c 1552 return 1;
dudmuck 2:974cafbfb159 1553 }*/
mluis 1:d3b7bde3995c 1554 LMIC.opmode &= ~OP_TXRXPEND;
mluis 1:d3b7bde3995c 1555 ostime_t delay = nextJoinState();
mluis 1:d3b7bde3995c 1556 EV(devCond, DEBUG, (e_.reason = EV::devCond_t::NO_JACC,
mluis 1:d3b7bde3995c 1557 e_.eui = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 1558 e_.info = LMIC.datarate|DR_PAGE,
mluis 1:d3b7bde3995c 1559 e_.info2 = osticks2ms(delay)));
mluis 1:d3b7bde3995c 1560 // Build next JOIN REQUEST with next engineUpdate call
mluis 1:d3b7bde3995c 1561 // Optionally, report join failed.
mluis 1:d3b7bde3995c 1562 // Both after a random/chosen amount of ticks.
mluis 1:d3b7bde3995c 1563 os_setTimedCallback(&LMIC.osjob, os_getTime()+delay,
mluis 1:d3b7bde3995c 1564 (delay&1) != 0
mluis 1:d3b7bde3995c 1565 ? FUNC_ADDR(onJoinFailed) // one JOIN iteration done and failed
mluis 1:d3b7bde3995c 1566 : FUNC_ADDR(runEngineUpdate)); // next step to be delayed
mluis 0:62d1edcc13d1 1567 return 1;
mluis 0:62d1edcc13d1 1568 }
mluis 0:62d1edcc13d1 1569 u1_t hdr = LMIC.frame[0];
mluis 0:62d1edcc13d1 1570 u1_t dlen = LMIC.dataLen;
mluis 0:62d1edcc13d1 1571 u4_t mic = os_rlsbf4(&LMIC.frame[dlen-4]); // safe before modified by encrypt!
mluis 0:62d1edcc13d1 1572 if( (dlen != LEN_JA && dlen != LEN_JAEXT)
mluis 1:d3b7bde3995c 1573 || (hdr & (HDR_FTYPE|HDR_MAJOR)) != (HDR_FTYPE_JACC|HDR_MAJOR_V1) ) {
mluis 1:d3b7bde3995c 1574 EV(specCond, ERR, (e_.reason = EV::specCond_t::UNEXPECTED_FRAME,
mluis 1:d3b7bde3995c 1575 e_.eui = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 1576 e_.info = dlen < 4 ? 0 : mic,
mluis 1:d3b7bde3995c 1577 e_.info2 = hdr + (dlen<<8)));
mluis 0:62d1edcc13d1 1578 badframe:
mluis 1:d3b7bde3995c 1579 if( (LMIC.txrxFlags & TXRX_DNW1) != 0 )
mluis 1:d3b7bde3995c 1580 return 0;
mluis 1:d3b7bde3995c 1581 goto nojoinframe;
mluis 0:62d1edcc13d1 1582 }
mluis 0:62d1edcc13d1 1583 aes_encrypt(LMIC.frame+1, dlen-1);
mluis 0:62d1edcc13d1 1584 if( !aes_verifyMic0(LMIC.frame, dlen-4) ) {
mluis 1:d3b7bde3995c 1585 EV(specCond, ERR, (e_.reason = EV::specCond_t::JOIN_BAD_MIC,
mluis 1:d3b7bde3995c 1586 e_.info = mic));
mluis 1:d3b7bde3995c 1587 goto badframe;
mluis 0:62d1edcc13d1 1588 }
mluis 0:62d1edcc13d1 1589
mluis 0:62d1edcc13d1 1590 u4_t addr = os_rlsbf4(LMIC.frame+OFF_JA_DEVADDR);
mluis 0:62d1edcc13d1 1591 LMIC.devaddr = addr;
mluis 1:d3b7bde3995c 1592 LMIC.netid = os_rlsbf4(&LMIC.frame[OFF_JA_NETID]) & 0xFFFFFF;
mluis 0:62d1edcc13d1 1593
mluis 1:d3b7bde3995c 1594 #if defined(CFG_eu868)
mluis 0:62d1edcc13d1 1595 initDefaultChannels(0);
mluis 0:62d1edcc13d1 1596 #endif
mluis 0:62d1edcc13d1 1597 if( dlen > LEN_JA ) {
mluis 1:d3b7bde3995c 1598 dlen = OFF_CFLIST;
mluis 1:d3b7bde3995c 1599 #if defined(CFG_eu868)
mluis 1:d3b7bde3995c 1600 u1_t chidx=3;
mluis 1:d3b7bde3995c 1601 #elif defined(CFG_us915)
mluis 1:d3b7bde3995c 1602 u1_t chidx=72;
mluis 0:62d1edcc13d1 1603 #endif
mluis 1:d3b7bde3995c 1604 for( ; chidx<8; chidx++, dlen+=3 )
mluis 3:519c71d29a06 1605 LMIC_setupChannel(chidx, convFreq(&LMIC.frame[dlen]), 0, -1);
mluis 0:62d1edcc13d1 1606 }
mluis 0:62d1edcc13d1 1607
mluis 0:62d1edcc13d1 1608 // already incremented when JOIN REQ got sent off
mluis 0:62d1edcc13d1 1609 aes_sessKeys(LMIC.devNonce-1, &LMIC.frame[OFF_JA_ARTNONCE], LMIC.nwkKey, LMIC.artKey);
mluis 1:d3b7bde3995c 1610 DO_DEVDB(LMIC.netid, netid);
mluis 1:d3b7bde3995c 1611 DO_DEVDB(LMIC.devaddr, devaddr);
mluis 1:d3b7bde3995c 1612 DO_DEVDB(LMIC.nwkKey, nwkkey);
mluis 1:d3b7bde3995c 1613 DO_DEVDB(LMIC.artKey, artkey);
mluis 0:62d1edcc13d1 1614
mluis 0:62d1edcc13d1 1615 EV(joininfo, INFO, (e_.arteui = MAIN::CDEV->getArtEui(),
mluis 1:d3b7bde3995c 1616 e_.deveui = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 1617 e_.devaddr = LMIC.devaddr,
mluis 1:d3b7bde3995c 1618 e_.oldaddr = oldaddr,
mluis 1:d3b7bde3995c 1619 e_.nonce = LMIC.devNonce-1,
mluis 1:d3b7bde3995c 1620 e_.mic = mic,
mluis 1:d3b7bde3995c 1621 e_.reason = ((LMIC.opmode & OP_REJOIN) != 0
mluis 1:d3b7bde3995c 1622 ? EV::joininfo_t::REJOIN_ACCEPT
mluis 1:d3b7bde3995c 1623 : EV::joininfo_t::ACCEPT)));
mluis 0:62d1edcc13d1 1624
mluis 0:62d1edcc13d1 1625 ASSERT((LMIC.opmode & (OP_JOINING|OP_REJOIN))!=0);
mluis 0:62d1edcc13d1 1626 if( (LMIC.opmode & OP_REJOIN) != 0 ) {
mluis 1:d3b7bde3995c 1627 // Lower DR every try below current UP DR
mluis 1:d3b7bde3995c 1628 LMIC.datarate = lowerDR(LMIC.datarate, LMIC.rejoinCnt);
mluis 0:62d1edcc13d1 1629 }
mluis 0:62d1edcc13d1 1630 LMIC.opmode &= ~(OP_JOINING|OP_TRACK|OP_REJOIN|OP_TXRXPEND|OP_PINGINI) | OP_NEXTCHNL;
mluis 0:62d1edcc13d1 1631 stateJustJoined();
mluis 0:62d1edcc13d1 1632 reportEvent(EV_JOINED);
mluis 0:62d1edcc13d1 1633 return 1;
mluis 0:62d1edcc13d1 1634 }
mluis 0:62d1edcc13d1 1635
mluis 1:d3b7bde3995c 1636
tmulrooney 6:eed5fd627a2b 1637 static void processRx2Jacc (xref2osjob_t osjob)
tmulrooney 6:eed5fd627a2b 1638 {
GTsapparellas 8:5879e83f632a 1639 //debug("LMIC processRx2Jacc enter\r\n");
mluis 0:62d1edcc13d1 1640 if( LMIC.dataLen == 0 )
mluis 1:d3b7bde3995c 1641 LMIC.txrxFlags = 0; // nothing in 1st/2nd DN slot
mluis 0:62d1edcc13d1 1642 processJoinAccept();
mluis 0:62d1edcc13d1 1643 }
mluis 0:62d1edcc13d1 1644
mluis 1:d3b7bde3995c 1645
tmulrooney 6:eed5fd627a2b 1646 static void setupRx2Jacc (xref2osjob_t osjob)
tmulrooney 6:eed5fd627a2b 1647 {
GTsapparellas 8:5879e83f632a 1648 //debug("LMIC setupRx2Jacc enter\r\n");
mluis 1:d3b7bde3995c 1649 LMIC.osjob.func = FUNC_ADDR(processRx2Jacc);
mluis 1:d3b7bde3995c 1650 setupRx2();
mluis 1:d3b7bde3995c 1651 }
mluis 1:d3b7bde3995c 1652
mluis 1:d3b7bde3995c 1653
tmulrooney 6:eed5fd627a2b 1654 static void processRx1Jacc (xref2osjob_t osjob)
tmulrooney 6:eed5fd627a2b 1655 {
GTsapparellas 8:5879e83f632a 1656 //debug("LMIC processRx1Jacc enter\r\n");
mluis 1:d3b7bde3995c 1657 if( LMIC.dataLen == 0 || !processJoinAccept() )
mluis 1:d3b7bde3995c 1658 schedRx2(DELAY_JACC2_osticks, FUNC_ADDR(setupRx2Jacc));
mluis 1:d3b7bde3995c 1659 }
mluis 1:d3b7bde3995c 1660
mluis 1:d3b7bde3995c 1661
tmulrooney 6:eed5fd627a2b 1662 static void setupRx1Jacc (xref2osjob_t osjob)
tmulrooney 6:eed5fd627a2b 1663 {
GTsapparellas 8:5879e83f632a 1664 //debug("LMIC setupRx1Jacc enter\r\n");
mluis 0:62d1edcc13d1 1665 setupRx1(FUNC_ADDR(processRx1Jacc));
mluis 0:62d1edcc13d1 1666 }
mluis 0:62d1edcc13d1 1667
mluis 0:62d1edcc13d1 1668
tmulrooney 6:eed5fd627a2b 1669 static void jreqDone (xref2osjob_t osjob)
tmulrooney 6:eed5fd627a2b 1670 {
GTsapparellas 8:5879e83f632a 1671 //debug("LMIC jreqDone enter\r\n");
mluis 0:62d1edcc13d1 1672 txDone(DELAY_JACC1_osticks, FUNC_ADDR(setupRx1Jacc));
mluis 0:62d1edcc13d1 1673 }
mluis 0:62d1edcc13d1 1674
mluis 0:62d1edcc13d1 1675 // ======================================== Data frames
mluis 0:62d1edcc13d1 1676
mluis 0:62d1edcc13d1 1677 // Fwd decl.
mluis 0:62d1edcc13d1 1678 static bit_t processDnData(void);
mluis 0:62d1edcc13d1 1679
tmulrooney 6:eed5fd627a2b 1680 static void processRx2DnDataDelay (xref2osjob_t osjob)
tmulrooney 6:eed5fd627a2b 1681 {
GTsapparellas 8:5879e83f632a 1682 //debug("LMIC processRx2DnDataDelay enter\r\n");
mluis 1:d3b7bde3995c 1683 processDnData();
mluis 1:d3b7bde3995c 1684 }
mluis 1:d3b7bde3995c 1685
tmulrooney 6:eed5fd627a2b 1686 static void processRx2DnData (xref2osjob_t osjob)
tmulrooney 6:eed5fd627a2b 1687 {
GTsapparellas 8:5879e83f632a 1688 //debug("LMIC processRx2DnData enter\r\n");
mluis 1:d3b7bde3995c 1689 if( LMIC.dataLen == 0 ) {
mluis 1:d3b7bde3995c 1690 LMIC.txrxFlags = 0; // nothing in 1st/2nd DN slot
mluis 1:d3b7bde3995c 1691 // Delay callback processing to avoid up TX while gateway is txing our missed frame!
mluis 1:d3b7bde3995c 1692 // Since DNW2 uses SF12 by default we wait 3 secs.
mluis 1:d3b7bde3995c 1693 os_setTimedCallback(&LMIC.osjob,
mluis 1:d3b7bde3995c 1694 (os_getTime() + DNW2_SAFETY_ZONE + rndDelay(2)),
mluis 1:d3b7bde3995c 1695 processRx2DnDataDelay);
mluis 1:d3b7bde3995c 1696 return;
mluis 1:d3b7bde3995c 1697 }
mluis 0:62d1edcc13d1 1698 processDnData();
mluis 0:62d1edcc13d1 1699 }
mluis 0:62d1edcc13d1 1700
mluis 0:62d1edcc13d1 1701
tmulrooney 6:eed5fd627a2b 1702 static void setupRx2DnData (xref2osjob_t osjob)
tmulrooney 6:eed5fd627a2b 1703 {
GTsapparellas 8:5879e83f632a 1704 //debug("LMIC setupRx2DnData enter\r\n");
mluis 0:62d1edcc13d1 1705 LMIC.osjob.func = FUNC_ADDR(processRx2DnData);
mluis 0:62d1edcc13d1 1706 setupRx2();
mluis 0:62d1edcc13d1 1707 }
mluis 0:62d1edcc13d1 1708
mluis 0:62d1edcc13d1 1709
tmulrooney 6:eed5fd627a2b 1710 static void processRx1DnData (xref2osjob_t osjob)
tmulrooney 6:eed5fd627a2b 1711 {
GTsapparellas 8:5879e83f632a 1712 //debug("LMIC processRx1DnData enter\r\n");
mluis 0:62d1edcc13d1 1713 if( LMIC.dataLen == 0 || !processDnData() )
mluis 1:d3b7bde3995c 1714 schedRx2(DELAY_DNW2_osticks, FUNC_ADDR(setupRx2DnData));
mluis 0:62d1edcc13d1 1715 }
mluis 0:62d1edcc13d1 1716
mluis 0:62d1edcc13d1 1717
tmulrooney 6:eed5fd627a2b 1718 static void setupRx1DnData (xref2osjob_t osjob)
tmulrooney 6:eed5fd627a2b 1719 {
GTsapparellas 8:5879e83f632a 1720 //debug("LMIC setupRx1DnData enter\r\n");
mluis 0:62d1edcc13d1 1721 setupRx1(FUNC_ADDR(processRx1DnData));
mluis 0:62d1edcc13d1 1722 }
mluis 0:62d1edcc13d1 1723
mluis 0:62d1edcc13d1 1724
tmulrooney 6:eed5fd627a2b 1725 static void updataDone (xref2osjob_t osjob)
tmulrooney 6:eed5fd627a2b 1726 {
GTsapparellas 8:5879e83f632a 1727 //debug("LMIC updataDone enter\r\n");
mluis 0:62d1edcc13d1 1728 txDone(DELAY_DNW1_osticks, FUNC_ADDR(setupRx1DnData));
mluis 0:62d1edcc13d1 1729 }
mluis 0:62d1edcc13d1 1730
mluis 0:62d1edcc13d1 1731 // ========================================
mluis 0:62d1edcc13d1 1732
mluis 0:62d1edcc13d1 1733
tmulrooney 6:eed5fd627a2b 1734 static void buildDataFrame (void)
tmulrooney 6:eed5fd627a2b 1735 {
GTsapparellas 8:5879e83f632a 1736 //debug("LMIC buildDataFrame enter\r\n");
mluis 0:62d1edcc13d1 1737 bit_t txdata = ((LMIC.opmode & (OP_TXDATA|OP_POLL)) != OP_POLL);
mluis 0:62d1edcc13d1 1738 u1_t dlen = txdata ? LMIC.pendTxLen : 0;
mluis 0:62d1edcc13d1 1739
mluis 0:62d1edcc13d1 1740 // Piggyback MAC options
mluis 0:62d1edcc13d1 1741 // Prioritize by importance
mluis 0:62d1edcc13d1 1742 int end = OFF_DAT_OPTS;
mluis 0:62d1edcc13d1 1743 if( (LMIC.opmode & (OP_TRACK|OP_PINGABLE)) == (OP_TRACK|OP_PINGABLE) ) {
mluis 1:d3b7bde3995c 1744 // Indicate pingability in every UP frame
mluis 1:d3b7bde3995c 1745 LMIC.frame[end] = MCMD_PING_IND;
mluis 1:d3b7bde3995c 1746 LMIC.frame[end+1] = LMIC.ping.dr | (LMIC.ping.intvExp<<4);
mluis 1:d3b7bde3995c 1747 end += 2;
mluis 0:62d1edcc13d1 1748 }
mluis 0:62d1edcc13d1 1749 if( LMIC.dutyCapAns ) {
mluis 1:d3b7bde3995c 1750 LMIC.frame[end] = MCMD_DCAP_ANS;
mluis 1:d3b7bde3995c 1751 end += 1;
mluis 1:d3b7bde3995c 1752 LMIC.dutyCapAns = 0;
mluis 0:62d1edcc13d1 1753 }
mluis 0:62d1edcc13d1 1754 if( LMIC.dn2Ans ) {
mluis 1:d3b7bde3995c 1755 LMIC.frame[end+0] = MCMD_DN2P_ANS;
mluis 1:d3b7bde3995c 1756 LMIC.frame[end+1] = LMIC.dn2Ans & ~MCMD_DN2P_ANS_RFU;
mluis 1:d3b7bde3995c 1757 end += 2;
mluis 1:d3b7bde3995c 1758 LMIC.dn2Ans = 0;
mluis 0:62d1edcc13d1 1759 }
mluis 0:62d1edcc13d1 1760 if( LMIC.devsAns ) { // answer to device status
mluis 1:d3b7bde3995c 1761 LMIC.frame[end+0] = MCMD_DEVS_ANS;
mluis 1:d3b7bde3995c 1762 LMIC.frame[end+1] = LMIC.margin;
mluis 1:d3b7bde3995c 1763 LMIC.frame[end+2] = os_getBattLevel();
mluis 1:d3b7bde3995c 1764 end += 3;
mluis 1:d3b7bde3995c 1765 LMIC.devsAns = 0;
mluis 0:62d1edcc13d1 1766 }
mluis 0:62d1edcc13d1 1767 if( LMIC.ladrAns ) { // answer to ADR change
mluis 1:d3b7bde3995c 1768 LMIC.frame[end+0] = MCMD_LADR_ANS;
mluis 1:d3b7bde3995c 1769 LMIC.frame[end+1] = LMIC.ladrAns & ~MCMD_LADR_ANS_RFU;
mluis 1:d3b7bde3995c 1770 end += 2;
mluis 1:d3b7bde3995c 1771 LMIC.ladrAns = 0;
mluis 0:62d1edcc13d1 1772 }
mluis 0:62d1edcc13d1 1773 if( LMIC.bcninfoTries > 0 ) {
mluis 1:d3b7bde3995c 1774 LMIC.frame[end] = MCMD_BCNI_REQ;
mluis 1:d3b7bde3995c 1775 end += 1;
mluis 0:62d1edcc13d1 1776 }
mluis 0:62d1edcc13d1 1777 if( LMIC.adrChanged ) {
mluis 1:d3b7bde3995c 1778 if( LMIC.adrAckReq < 0 )
mluis 1:d3b7bde3995c 1779 LMIC.adrAckReq = 0;
mluis 1:d3b7bde3995c 1780 LMIC.adrChanged = 0;
mluis 0:62d1edcc13d1 1781 }
mluis 0:62d1edcc13d1 1782 if( LMIC.pingSetAns != 0 ) {
mluis 1:d3b7bde3995c 1783 LMIC.frame[end+0] = MCMD_PING_ANS;
mluis 1:d3b7bde3995c 1784 LMIC.frame[end+1] = LMIC.pingSetAns & ~MCMD_PING_ANS_RFU;
mluis 1:d3b7bde3995c 1785 end += 2;
mluis 1:d3b7bde3995c 1786 LMIC.pingSetAns = 0;
mluis 0:62d1edcc13d1 1787 }
mluis 0:62d1edcc13d1 1788 if( LMIC.snchAns ) {
mluis 1:d3b7bde3995c 1789 LMIC.frame[end+0] = MCMD_SNCH_ANS;
mluis 1:d3b7bde3995c 1790 LMIC.frame[end+1] = LMIC.snchAns & ~MCMD_SNCH_ANS_RFU;
mluis 1:d3b7bde3995c 1791 end += 2;
mluis 1:d3b7bde3995c 1792 LMIC.snchAns = 0;
mluis 0:62d1edcc13d1 1793 }
mluis 0:62d1edcc13d1 1794 ASSERT(end <= OFF_DAT_OPTS+16);
mluis 0:62d1edcc13d1 1795
mluis 0:62d1edcc13d1 1796 u1_t flen = end + (txdata ? 5+dlen : 4);
mluis 0:62d1edcc13d1 1797 if( flen > MAX_LEN_FRAME ) {
mluis 1:d3b7bde3995c 1798 // Options and payload too big - delay payload
mluis 1:d3b7bde3995c 1799 txdata = 0;
mluis 1:d3b7bde3995c 1800 flen = end+4;
mluis 0:62d1edcc13d1 1801 }
mluis 0:62d1edcc13d1 1802 LMIC.frame[OFF_DAT_HDR] = HDR_FTYPE_DAUP | HDR_MAJOR_V1;
mluis 0:62d1edcc13d1 1803 LMIC.frame[OFF_DAT_FCT] = (LMIC.dnConf | LMIC.adrEnabled
mluis 1:d3b7bde3995c 1804 | (LMIC.adrAckReq >= 0 ? FCT_ADRARQ : 0)
mluis 1:d3b7bde3995c 1805 | (end-OFF_DAT_OPTS));
mluis 0:62d1edcc13d1 1806 os_wlsbf4(LMIC.frame+OFF_DAT_ADDR, LMIC.devaddr);
mluis 0:62d1edcc13d1 1807
mluis 0:62d1edcc13d1 1808 if( LMIC.txCnt == 0 ) {
mluis 1:d3b7bde3995c 1809 LMIC.seqnoUp += 1;
mluis 1:d3b7bde3995c 1810 DO_DEVDB(LMIC.seqnoUp,seqnoUp);
mluis 0:62d1edcc13d1 1811 } else {
mluis 1:d3b7bde3995c 1812 EV(devCond, INFO, (e_.reason = EV::devCond_t::RE_TX,
mluis 1:d3b7bde3995c 1813 e_.eui = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 1814 e_.info = LMIC.seqnoUp-1,
mluis 1:d3b7bde3995c 1815 e_.info2 = ((LMIC.txCnt+1) |
mluis 1:d3b7bde3995c 1816 (DRADJUST[LMIC.txCnt+1] << 8) |
mluis 1:d3b7bde3995c 1817 ((LMIC.datarate|DR_PAGE)<<16))));
mluis 0:62d1edcc13d1 1818 }
mluis 0:62d1edcc13d1 1819 os_wlsbf2(LMIC.frame+OFF_DAT_SEQNO, LMIC.seqnoUp-1);
mluis 0:62d1edcc13d1 1820
mluis 0:62d1edcc13d1 1821 // Clear pending DN confirmation
mluis 0:62d1edcc13d1 1822 LMIC.dnConf = 0;
mluis 0:62d1edcc13d1 1823
mluis 0:62d1edcc13d1 1824 if( txdata ) {
mluis 1:d3b7bde3995c 1825 if( LMIC.pendTxConf ) {
mluis 1:d3b7bde3995c 1826 // Confirmed only makes sense if we have a payload (or at least a port)
mluis 1:d3b7bde3995c 1827 LMIC.frame[OFF_DAT_HDR] = HDR_FTYPE_DCUP | HDR_MAJOR_V1;
mluis 1:d3b7bde3995c 1828 if( LMIC.txCnt == 0 ) LMIC.txCnt = 1;
mluis 1:d3b7bde3995c 1829 }
mluis 1:d3b7bde3995c 1830 LMIC.frame[end] = LMIC.pendTxPort;
mluis 1:d3b7bde3995c 1831 os_copyMem(LMIC.frame+end+1, LMIC.pendTxData, dlen);
mluis 1:d3b7bde3995c 1832 aes_cipher(LMIC.pendTxPort==0 ? LMIC.nwkKey : LMIC.artKey,
mluis 1:d3b7bde3995c 1833 LMIC.devaddr, LMIC.seqnoUp-1,
mluis 1:d3b7bde3995c 1834 /*up*/0, LMIC.frame+end+1, dlen);
mluis 0:62d1edcc13d1 1835 }
mluis 0:62d1edcc13d1 1836 aes_appendMic(LMIC.nwkKey, LMIC.devaddr, LMIC.seqnoUp-1, /*up*/0, LMIC.frame, flen-4);
mluis 0:62d1edcc13d1 1837
mluis 0:62d1edcc13d1 1838 EV(dfinfo, DEBUG, (e_.deveui = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 1839 e_.devaddr = LMIC.devaddr,
mluis 1:d3b7bde3995c 1840 e_.seqno = LMIC.seqnoUp-1,
mluis 1:d3b7bde3995c 1841 e_.flags = (LMIC.pendTxPort < 0 ? EV::dfinfo_t::NOPORT : EV::dfinfo_t::NOP),
mluis 1:d3b7bde3995c 1842 e_.mic = Base::lsbf4(&LMIC.frame[flen-4]),
mluis 1:d3b7bde3995c 1843 e_.hdr = LMIC.frame[LORA::OFF_DAT_HDR],
mluis 1:d3b7bde3995c 1844 e_.fct = LMIC.frame[LORA::OFF_DAT_FCT],
mluis 1:d3b7bde3995c 1845 e_.port = LMIC.pendTxPort,
mluis 1:d3b7bde3995c 1846 e_.plen = txdata ? dlen : 0,
mluis 1:d3b7bde3995c 1847 e_.opts.length = end-LORA::OFF_DAT_OPTS,
mluis 1:d3b7bde3995c 1848 memcpy(&e_.opts[0], LMIC.frame+LORA::OFF_DAT_OPTS, end-LORA::OFF_DAT_OPTS)));
mluis 0:62d1edcc13d1 1849 LMIC.dataLen = flen;
mluis 0:62d1edcc13d1 1850 }
mluis 0:62d1edcc13d1 1851
mluis 0:62d1edcc13d1 1852
mluis 0:62d1edcc13d1 1853 // Callback from HAL during scan mode or when job timer expires.
tmulrooney 6:eed5fd627a2b 1854 static void onBcnRx (xref2osjob_t job)
tmulrooney 6:eed5fd627a2b 1855 {
GTsapparellas 8:5879e83f632a 1856 //debug("LMIC onBcnRx enter\r\n");
mluis 0:62d1edcc13d1 1857 // If we arrive via job timer make sure to put radio to rest.
mluis 0:62d1edcc13d1 1858 os_radio(RADIO_RST);
mluis 0:62d1edcc13d1 1859 os_clearCallback(&LMIC.osjob);
mluis 0:62d1edcc13d1 1860 if( LMIC.dataLen == 0 ) {
mluis 1:d3b7bde3995c 1861 // Nothing received - timeout
mluis 1:d3b7bde3995c 1862 LMIC.opmode &= ~(OP_SCAN | OP_TRACK);
mluis 1:d3b7bde3995c 1863 reportEvent(EV_SCAN_TIMEOUT);
mluis 1:d3b7bde3995c 1864 return;
mluis 0:62d1edcc13d1 1865 }
mluis 0:62d1edcc13d1 1866 if( decodeBeacon() <= 0 ) {
mluis 1:d3b7bde3995c 1867 // Something is wrong with the beacon - continue scan
mluis 1:d3b7bde3995c 1868 LMIC.dataLen = 0;
mluis 1:d3b7bde3995c 1869 os_radio(RADIO_RXON);
mluis 1:d3b7bde3995c 1870 os_setTimedCallback(&LMIC.osjob, LMIC.bcninfo.txtime, FUNC_ADDR(onBcnRx));
mluis 1:d3b7bde3995c 1871 return;
mluis 0:62d1edcc13d1 1872 }
mluis 0:62d1edcc13d1 1873 // Found our 1st beacon
mluis 0:62d1edcc13d1 1874 // We don't have a previous beacon to calc some drift - assume
mluis 0:62d1edcc13d1 1875 // an max error of 13ms = 128sec*100ppm which is roughly +/-100ppm
mluis 0:62d1edcc13d1 1876 calcBcnRxWindowFromMillis(13,1);
mluis 0:62d1edcc13d1 1877 LMIC.opmode &= ~OP_SCAN; // turn SCAN off
mluis 0:62d1edcc13d1 1878 LMIC.opmode |= OP_TRACK; // auto enable tracking
mluis 0:62d1edcc13d1 1879 reportEvent(EV_BEACON_FOUND); // can be disabled in callback
mluis 0:62d1edcc13d1 1880 }
mluis 0:62d1edcc13d1 1881
mluis 0:62d1edcc13d1 1882
mluis 0:62d1edcc13d1 1883 // Enable receiver to listen to incoming beacons
mluis 0:62d1edcc13d1 1884 // netid defines when scan stops (any or specific beacon)
mluis 0:62d1edcc13d1 1885 // This mode ends with events: EV_SCAN_TIMEOUT/EV_SCAN_BEACON
mluis 0:62d1edcc13d1 1886 // Implicitely cancels any pending TX/RX transaction.
mluis 0:62d1edcc13d1 1887 // Also cancels an onpoing joining procedure.
tmulrooney 6:eed5fd627a2b 1888 static void startScan (void)
tmulrooney 6:eed5fd627a2b 1889 {
GTsapparellas 8:5879e83f632a 1890 //debug("LMIC startScan enter\r\n");
mluis 0:62d1edcc13d1 1891 ASSERT(LMIC.devaddr!=0 && (LMIC.opmode & OP_JOINING)==0);
mluis 0:62d1edcc13d1 1892 if( (LMIC.opmode & OP_SHUTDOWN) != 0 )
mluis 1:d3b7bde3995c 1893 return;
mluis 0:62d1edcc13d1 1894 // Cancel onging TX/RX transaction
mluis 0:62d1edcc13d1 1895 LMIC.txCnt = LMIC.dnConf = LMIC.bcninfo.flags = 0;
mluis 0:62d1edcc13d1 1896 LMIC.opmode = (LMIC.opmode | OP_SCAN) & ~(OP_TXRXPEND);
mluis 0:62d1edcc13d1 1897 setBcnRxParams();
mluis 0:62d1edcc13d1 1898 LMIC.rxtime = LMIC.bcninfo.txtime = os_getTime() + sec2osticks(BCN_INTV_sec+1);
mluis 0:62d1edcc13d1 1899 os_setTimedCallback(&LMIC.osjob, LMIC.rxtime, FUNC_ADDR(onBcnRx));
mluis 0:62d1edcc13d1 1900 os_radio(RADIO_RXON);
mluis 0:62d1edcc13d1 1901 }
mluis 0:62d1edcc13d1 1902
mluis 0:62d1edcc13d1 1903
tmulrooney 6:eed5fd627a2b 1904 bit_t LMIC_enableTracking (u1_t tryBcnInfo)
tmulrooney 6:eed5fd627a2b 1905 {
GTsapparellas 8:5879e83f632a 1906 //debug("LMIC LMIC_enableTracking enter\r\n");
mluis 0:62d1edcc13d1 1907 if( (LMIC.opmode & (OP_SCAN|OP_TRACK|OP_SHUTDOWN)) != 0 )
mluis 1:d3b7bde3995c 1908 return 0; // already in progress or failed to enable
mluis 0:62d1edcc13d1 1909 // If BCN info requested from NWK then app has to take are
mluis 0:62d1edcc13d1 1910 // of sending data up so that MCMD_BCNI_REQ can be attached.
mluis 0:62d1edcc13d1 1911 if( (LMIC.bcninfoTries = tryBcnInfo) == 0 )
mluis 1:d3b7bde3995c 1912 startScan();
mluis 0:62d1edcc13d1 1913 return 1; // enabled
mluis 0:62d1edcc13d1 1914 }
mluis 0:62d1edcc13d1 1915
mluis 0:62d1edcc13d1 1916
tmulrooney 6:eed5fd627a2b 1917 void LMIC_disableTracking (void)
tmulrooney 6:eed5fd627a2b 1918 {
GTsapparellas 8:5879e83f632a 1919 //debug("LMIC LMIC_disableTracking enter\r\n");
mluis 0:62d1edcc13d1 1920 LMIC.opmode &= ~(OP_SCAN|OP_TRACK);
mluis 0:62d1edcc13d1 1921 LMIC.bcninfoTries = 0;
mluis 0:62d1edcc13d1 1922 engineUpdate();
mluis 0:62d1edcc13d1 1923 }
mluis 0:62d1edcc13d1 1924
mluis 0:62d1edcc13d1 1925
mluis 0:62d1edcc13d1 1926 // ================================================================================
mluis 0:62d1edcc13d1 1927 //
mluis 0:62d1edcc13d1 1928 // Join stuff
mluis 0:62d1edcc13d1 1929 //
mluis 0:62d1edcc13d1 1930 // ================================================================================
mluis 0:62d1edcc13d1 1931
tmulrooney 6:eed5fd627a2b 1932 static void buildJoinRequest (u1_t ftype)
tmulrooney 6:eed5fd627a2b 1933 {
GTsapparellas 8:5879e83f632a 1934 //debug("LMIC buildJoinRequest enter\r\n");
mluis 0:62d1edcc13d1 1935 // Do not use pendTxData since we might have a pending
mluis 0:62d1edcc13d1 1936 // user level frame in there. Use RX holding area instead.
mluis 0:62d1edcc13d1 1937 xref2u1_t d = LMIC.frame;
mluis 0:62d1edcc13d1 1938 d[OFF_JR_HDR] = ftype;
mluis 0:62d1edcc13d1 1939 os_getArtEui(d + OFF_JR_ARTEUI);
mluis 0:62d1edcc13d1 1940 os_getDevEui(d + OFF_JR_DEVEUI);
mluis 0:62d1edcc13d1 1941 os_wlsbf2(d + OFF_JR_DEVNONCE, LMIC.devNonce);
mluis 0:62d1edcc13d1 1942 aes_appendMic0(d, OFF_JR_MIC);
mluis 0:62d1edcc13d1 1943
mluis 0:62d1edcc13d1 1944 EV(joininfo,INFO,(e_.deveui = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 1945 e_.arteui = MAIN::CDEV->getArtEui(),
mluis 1:d3b7bde3995c 1946 e_.nonce = LMIC.devNonce,
mluis 1:d3b7bde3995c 1947 e_.oldaddr = LMIC.devaddr,
mluis 1:d3b7bde3995c 1948 e_.mic = Base::lsbf4(&d[LORA::OFF_JR_MIC]),
mluis 1:d3b7bde3995c 1949 e_.reason = ((LMIC.opmode & OP_REJOIN) != 0
mluis 1:d3b7bde3995c 1950 ? EV::joininfo_t::REJOIN_REQUEST
mluis 1:d3b7bde3995c 1951 : EV::joininfo_t::REQUEST)));
mluis 0:62d1edcc13d1 1952 LMIC.dataLen = LEN_JR;
mluis 0:62d1edcc13d1 1953 LMIC.devNonce++;
mluis 1:d3b7bde3995c 1954 DO_DEVDB(LMIC.devNonce,devNonce);
mluis 0:62d1edcc13d1 1955 }
mluis 0:62d1edcc13d1 1956
tmulrooney 6:eed5fd627a2b 1957 static void startJoining (xref2osjob_t osjob)
tmulrooney 6:eed5fd627a2b 1958 {
GTsapparellas 8:5879e83f632a 1959 //debug("LMIC startJoining enter\r\n");
mluis 0:62d1edcc13d1 1960 reportEvent(EV_JOINING);
mluis 0:62d1edcc13d1 1961 }
mluis 0:62d1edcc13d1 1962
mluis 0:62d1edcc13d1 1963 // Start join procedure if not already joined.
tmulrooney 6:eed5fd627a2b 1964 bit_t LMIC_startJoining (void)
tmulrooney 6:eed5fd627a2b 1965 {
GTsapparellas 8:5879e83f632a 1966 //debug("LMIC LMIC_startJoining enter\r\n");
tmulrooney 6:eed5fd627a2b 1967 if( LMIC.devaddr == 0 )
tmulrooney 6:eed5fd627a2b 1968 {
mluis 1:d3b7bde3995c 1969 // There should be no TX/RX going on
mluis 1:d3b7bde3995c 1970 ASSERT((LMIC.opmode & (OP_POLL|OP_TXRXPEND)) == 0);
mluis 1:d3b7bde3995c 1971 // Lift any previous duty limitation
mluis 1:d3b7bde3995c 1972 LMIC.globalDutyRate = 0;
mluis 1:d3b7bde3995c 1973 // Cancel scanning
mluis 1:d3b7bde3995c 1974 LMIC.opmode &= ~(OP_SCAN|OP_REJOIN|OP_LINKDEAD|OP_NEXTCHNL);
mluis 1:d3b7bde3995c 1975 // Setup state
mluis 1:d3b7bde3995c 1976 LMIC.rejoinCnt = LMIC.txCnt = LMIC.pendTxConf = 0;
mluis 1:d3b7bde3995c 1977 initJoinLoop();
mluis 1:d3b7bde3995c 1978 LMIC.opmode |= OP_JOINING;
mluis 1:d3b7bde3995c 1979 // reportEvent will call engineUpdate which then starts sending JOIN REQUESTS
mluis 1:d3b7bde3995c 1980 os_setCallback(&LMIC.osjob, FUNC_ADDR(startJoining));
mluis 1:d3b7bde3995c 1981 return 1;
mluis 0:62d1edcc13d1 1982 }
mluis 1:d3b7bde3995c 1983 return 0; // already joined
mluis 0:62d1edcc13d1 1984 }
mluis 0:62d1edcc13d1 1985
mluis 0:62d1edcc13d1 1986
mluis 0:62d1edcc13d1 1987 // ================================================================================
mluis 0:62d1edcc13d1 1988 //
mluis 0:62d1edcc13d1 1989 //
mluis 0:62d1edcc13d1 1990 //
mluis 0:62d1edcc13d1 1991 // ================================================================================
mluis 0:62d1edcc13d1 1992
tmulrooney 6:eed5fd627a2b 1993 static void processPingRx (xref2osjob_t osjob)
tmulrooney 6:eed5fd627a2b 1994 {
GTsapparellas 8:5879e83f632a 1995 //debug("LMIC processPingRx enter\r\n");
mluis 0:62d1edcc13d1 1996 if( LMIC.dataLen != 0 ) {
mluis 1:d3b7bde3995c 1997 LMIC.txrxFlags = TXRX_PING;
mluis 1:d3b7bde3995c 1998 if( decodeFrame() ) {
mluis 1:d3b7bde3995c 1999 reportEvent(EV_RXCOMPLETE);
mluis 1:d3b7bde3995c 2000 return;
mluis 1:d3b7bde3995c 2001 }
mluis 0:62d1edcc13d1 2002 }
mluis 0:62d1edcc13d1 2003 // Pick next ping slot
mluis 0:62d1edcc13d1 2004 engineUpdate();
mluis 0:62d1edcc13d1 2005 }
mluis 0:62d1edcc13d1 2006
mluis 0:62d1edcc13d1 2007
tmulrooney 6:eed5fd627a2b 2008 static bit_t processDnData (void)
tmulrooney 6:eed5fd627a2b 2009 {
GTsapparellas 8:5879e83f632a 2010 //debug("LMIC processDnData enter\r\n");
mluis 0:62d1edcc13d1 2011 ASSERT((LMIC.opmode & OP_TXRXPEND)!=0);
mluis 0:62d1edcc13d1 2012
mluis 0:62d1edcc13d1 2013 if( LMIC.dataLen == 0 ) {
mluis 0:62d1edcc13d1 2014 norx:
mluis 1:d3b7bde3995c 2015 if( LMIC.txCnt != 0 ) {
mluis 1:d3b7bde3995c 2016 if( LMIC.txCnt < TXCONF_ATTEMPTS ) {
mluis 1:d3b7bde3995c 2017 LMIC.txCnt += 1;
mluis 1:d3b7bde3995c 2018 setDrTxpow(DRCHG_NOACK, lowerDR(LMIC.datarate, DRADJUST[LMIC.txCnt]), KEEP_TXPOW);
mluis 1:d3b7bde3995c 2019 // Schedule another retransmission
mluis 1:d3b7bde3995c 2020 txDelay(LMIC.rxtime, RETRY_PERIOD_secs);
mluis 1:d3b7bde3995c 2021 LMIC.opmode &= ~OP_TXRXPEND;
mluis 1:d3b7bde3995c 2022 engineUpdate();
mluis 1:d3b7bde3995c 2023 return 1;
mluis 1:d3b7bde3995c 2024 }
mluis 1:d3b7bde3995c 2025 LMIC.txrxFlags = TXRX_NACK | TXRX_NOPORT;
mluis 1:d3b7bde3995c 2026 } else {
mluis 1:d3b7bde3995c 2027 // Nothing received - implies no port
mluis 1:d3b7bde3995c 2028 LMIC.txrxFlags = TXRX_NOPORT;
mluis 0:62d1edcc13d1 2029 }
mluis 1:d3b7bde3995c 2030 if( LMIC.adrAckReq != LINK_CHECK_OFF )
mluis 1:d3b7bde3995c 2031 LMIC.adrAckReq += 1;
mluis 1:d3b7bde3995c 2032 LMIC.dataBeg = LMIC.dataLen = 0;
mluis 0:62d1edcc13d1 2033 txcomplete:
mluis 1:d3b7bde3995c 2034 LMIC.opmode &= ~(OP_TXDATA|OP_TXRXPEND);
mluis 1:d3b7bde3995c 2035 if( (LMIC.txrxFlags & (TXRX_DNW1|TXRX_DNW2|TXRX_PING)) != 0 && (LMIC.opmode & OP_LINKDEAD) != 0 ) {
mluis 1:d3b7bde3995c 2036 LMIC.opmode &= ~OP_LINKDEAD;
mluis 1:d3b7bde3995c 2037 reportEvent(EV_LINK_ALIVE);
mluis 1:d3b7bde3995c 2038 }
mluis 1:d3b7bde3995c 2039 reportEvent(EV_TXCOMPLETE);
mluis 1:d3b7bde3995c 2040 // If we haven't heard from NWK in a while although we asked for a sign
mluis 1:d3b7bde3995c 2041 // assume link is dead - notify application and keep going
mluis 1:d3b7bde3995c 2042 if( LMIC.adrAckReq > LINK_CHECK_DEAD ) {
mluis 1:d3b7bde3995c 2043 // We haven't heard from NWK for some time although we
mluis 1:d3b7bde3995c 2044 // asked for a response for some time - assume we're disconnected. Lower DR one notch.
mluis 1:d3b7bde3995c 2045 EV(devCond, ERR, (e_.reason = EV::devCond_t::LINK_DEAD,
mluis 1:d3b7bde3995c 2046 e_.eui = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 2047 e_.info = LMIC.adrAckReq));
mluis 1:d3b7bde3995c 2048 setDrTxpow(DRCHG_NOADRACK, decDR((dr_t)LMIC.datarate), KEEP_TXPOW);
mluis 1:d3b7bde3995c 2049 LMIC.adrAckReq = LINK_CHECK_CONT;
mluis 0:62d1edcc13d1 2050 LMIC.opmode |= OP_REJOIN|OP_LINKDEAD;
mluis 1:d3b7bde3995c 2051 reportEvent(EV_LINK_DEAD);
mluis 0:62d1edcc13d1 2052 }
mluis 1:d3b7bde3995c 2053 // If this falls to zero the NWK did not answer our MCMD_BCNI_REQ commands - try full scan
mluis 1:d3b7bde3995c 2054 if( LMIC.bcninfoTries > 0 ) {
mluis 1:d3b7bde3995c 2055 if( (LMIC.opmode & OP_TRACK) != 0 ) {
mluis 1:d3b7bde3995c 2056 reportEvent(EV_BEACON_FOUND);
mluis 1:d3b7bde3995c 2057 LMIC.bcninfoTries = 0;
mluis 1:d3b7bde3995c 2058 }
mluis 1:d3b7bde3995c 2059 else if( --LMIC.bcninfoTries == 0 ) {
mluis 1:d3b7bde3995c 2060 startScan(); // NWK did not answer - try scan
mluis 1:d3b7bde3995c 2061 }
mluis 0:62d1edcc13d1 2062 }
mluis 1:d3b7bde3995c 2063 return 1;
mluis 0:62d1edcc13d1 2064 }
mluis 0:62d1edcc13d1 2065 if( !decodeFrame() ) {
mluis 1:d3b7bde3995c 2066 if( (LMIC.txrxFlags & TXRX_DNW1) != 0 )
mluis 1:d3b7bde3995c 2067 return 0;
mluis 1:d3b7bde3995c 2068 goto norx;
mluis 0:62d1edcc13d1 2069 }
mluis 0:62d1edcc13d1 2070 goto txcomplete;
mluis 0:62d1edcc13d1 2071 }
mluis 0:62d1edcc13d1 2072
mluis 0:62d1edcc13d1 2073
tmulrooney 6:eed5fd627a2b 2074 static void processBeacon (xref2osjob_t osjob)
tmulrooney 6:eed5fd627a2b 2075 {
GTsapparellas 8:5879e83f632a 2076 //debug("LMIC processBeacon enter\r\n");
mluis 0:62d1edcc13d1 2077 ostime_t lasttx = LMIC.bcninfo.txtime; // save here - decodeBeacon might overwrite
mluis 0:62d1edcc13d1 2078 u1_t flags = LMIC.bcninfo.flags;
mluis 0:62d1edcc13d1 2079 ev_t ev;
mluis 0:62d1edcc13d1 2080
mluis 0:62d1edcc13d1 2081 if( LMIC.dataLen != 0 && decodeBeacon() >= 1 ) {
mluis 1:d3b7bde3995c 2082 ev = EV_BEACON_TRACKED;
mluis 1:d3b7bde3995c 2083 if( (flags & (BCN_PARTIAL|BCN_FULL)) == 0 ) {
mluis 1:d3b7bde3995c 2084 // We don't have a previous beacon to calc some drift - assume
mluis 1:d3b7bde3995c 2085 // an max error of 13ms = 128sec*100ppm which is roughly +/-100ppm
mluis 1:d3b7bde3995c 2086 calcBcnRxWindowFromMillis(13,0);
mluis 1:d3b7bde3995c 2087 goto rev;
mluis 1:d3b7bde3995c 2088 }
mluis 1:d3b7bde3995c 2089 // We have a previous BEACON to calculate some drift
mluis 1:d3b7bde3995c 2090 s2_t drift = BCN_INTV_osticks - (LMIC.bcninfo.txtime - lasttx);
mluis 1:d3b7bde3995c 2091 if( LMIC.missedBcns > 0 ) {
mluis 1:d3b7bde3995c 2092 drift = LMIC.drift + (drift - LMIC.drift) / (LMIC.missedBcns+1);
mluis 1:d3b7bde3995c 2093 }
mluis 1:d3b7bde3995c 2094 if( (LMIC.bcninfo.flags & BCN_NODRIFT) == 0 ) {
mluis 1:d3b7bde3995c 2095 s2_t diff = LMIC.drift - drift;
mluis 1:d3b7bde3995c 2096 if( diff < 0 ) diff = -diff;
mluis 1:d3b7bde3995c 2097 LMIC.lastDriftDiff = diff;
mluis 1:d3b7bde3995c 2098 if( LMIC.maxDriftDiff < diff )
mluis 1:d3b7bde3995c 2099 LMIC.maxDriftDiff = diff;
mluis 1:d3b7bde3995c 2100 LMIC.bcninfo.flags &= ~BCN_NODDIFF;
mluis 1:d3b7bde3995c 2101 }
mluis 1:d3b7bde3995c 2102 LMIC.drift = drift;
mluis 1:d3b7bde3995c 2103 LMIC.missedBcns = LMIC.rejoinCnt = 0;
mluis 1:d3b7bde3995c 2104 LMIC.bcninfo.flags &= ~BCN_NODRIFT;
mluis 1:d3b7bde3995c 2105 EV(devCond,INFO,(e_.reason = EV::devCond_t::CLOCK_DRIFT,
mluis 1:d3b7bde3995c 2106 e_.eui = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 2107 e_.info = drift,
mluis 1:d3b7bde3995c 2108 e_.info2 = /*occasion BEACON*/0));
mluis 1:d3b7bde3995c 2109 ASSERT((LMIC.bcninfo.flags & (BCN_PARTIAL|BCN_FULL)) != 0);
mluis 0:62d1edcc13d1 2110 } else {
mluis 1:d3b7bde3995c 2111 ev = EV_BEACON_MISSED;
mluis 1:d3b7bde3995c 2112 LMIC.bcninfo.txtime += BCN_INTV_osticks - LMIC.drift;
mluis 1:d3b7bde3995c 2113 LMIC.bcninfo.time += BCN_INTV_sec;
mluis 1:d3b7bde3995c 2114 LMIC.missedBcns++;
mluis 1:d3b7bde3995c 2115 // Delay any possible TX after surmised beacon - it's there although we missed it
mluis 1:d3b7bde3995c 2116 txDelay(LMIC.bcninfo.txtime + BCN_RESERVE_osticks, 4);
mluis 1:d3b7bde3995c 2117 if( LMIC.missedBcns > MAX_MISSED_BCNS )
mluis 1:d3b7bde3995c 2118 LMIC.opmode |= OP_REJOIN; // try if we can roam to another network
mluis 1:d3b7bde3995c 2119 if( LMIC.bcnRxsyms > MAX_RXSYMS ) {
mluis 1:d3b7bde3995c 2120 LMIC.opmode &= ~(OP_TRACK|OP_PINGABLE|OP_PINGINI|OP_REJOIN);
mluis 1:d3b7bde3995c 2121 reportEvent(EV_LOST_TSYNC);
mluis 1:d3b7bde3995c 2122 return;
mluis 1:d3b7bde3995c 2123 }
mluis 0:62d1edcc13d1 2124 }
mluis 0:62d1edcc13d1 2125 LMIC.bcnRxtime = LMIC.bcninfo.txtime + BCN_INTV_osticks - calcRxWindow(0,DR_BCN);
mluis 0:62d1edcc13d1 2126 LMIC.bcnRxsyms = LMIC.rxsyms;
mluis 0:62d1edcc13d1 2127 rev:
dudmuck 2:974cafbfb159 2128 #ifdef CFG_us915
mluis 1:d3b7bde3995c 2129 LMIC.bcnChnl = (LMIC.bcnChnl+1) & 7;
mluis 1:d3b7bde3995c 2130 #endif
mluis 0:62d1edcc13d1 2131 if( (LMIC.opmode & OP_PINGINI) != 0 )
mluis 1:d3b7bde3995c 2132 rxschedInit(&LMIC.ping); // note: reuses LMIC.frame buffer!
mluis 0:62d1edcc13d1 2133 reportEvent(ev);
mluis 0:62d1edcc13d1 2134 }
mluis 0:62d1edcc13d1 2135
mluis 0:62d1edcc13d1 2136
tmulrooney 6:eed5fd627a2b 2137 static void startRxBcn (xref2osjob_t osjob)
tmulrooney 6:eed5fd627a2b 2138 {
GTsapparellas 8:5879e83f632a 2139 //debug("LMIC startRxBcn enter\r\n");
mluis 0:62d1edcc13d1 2140 LMIC.osjob.func = FUNC_ADDR(processBeacon);
mluis 0:62d1edcc13d1 2141 os_radio(RADIO_RX);
mluis 0:62d1edcc13d1 2142 }
mluis 0:62d1edcc13d1 2143
mluis 0:62d1edcc13d1 2144
tmulrooney 6:eed5fd627a2b 2145 static void startRxPing (xref2osjob_t osjob)
tmulrooney 6:eed5fd627a2b 2146 {
GTsapparellas 8:5879e83f632a 2147 //debug("LMIC startRxPing enter\r\n");
mluis 0:62d1edcc13d1 2148 LMIC.osjob.func = FUNC_ADDR(processPingRx);
mluis 0:62d1edcc13d1 2149 os_radio(RADIO_RX);
mluis 0:62d1edcc13d1 2150 }
mluis 0:62d1edcc13d1 2151
mluis 0:62d1edcc13d1 2152
mluis 0:62d1edcc13d1 2153 // Decide what to do next for the MAC layer of a device
tmulrooney 6:eed5fd627a2b 2154 static void engineUpdate (void)
tmulrooney 6:eed5fd627a2b 2155 {
GTsapparellas 8:5879e83f632a 2156 //debug("LMIC engineUpdate enter\r\n");
mluis 0:62d1edcc13d1 2157 // Check for ongoing state: scan or TX/RX transaction
mluis 0:62d1edcc13d1 2158 if( (LMIC.opmode & (OP_SCAN|OP_TXRXPEND|OP_SHUTDOWN)) != 0 )
mluis 1:d3b7bde3995c 2159 return;
mluis 0:62d1edcc13d1 2160
mluis 0:62d1edcc13d1 2161 if( LMIC.devaddr == 0 && (LMIC.opmode & OP_JOINING) == 0 ) {
mluis 1:d3b7bde3995c 2162 LMIC_startJoining();
mluis 1:d3b7bde3995c 2163 return;
mluis 0:62d1edcc13d1 2164 }
mluis 0:62d1edcc13d1 2165
mluis 0:62d1edcc13d1 2166 ostime_t now = os_getTime();
mluis 0:62d1edcc13d1 2167 ostime_t rxtime = 0;
mluis 0:62d1edcc13d1 2168 ostime_t txbeg = 0;
mluis 0:62d1edcc13d1 2169
mluis 0:62d1edcc13d1 2170 if( (LMIC.opmode & OP_TRACK) != 0 ) {
mluis 1:d3b7bde3995c 2171 // We are tracking a beacon
mluis 1:d3b7bde3995c 2172 ASSERT( now + RX_RAMPUP - LMIC.bcnRxtime <= 0 );
mluis 1:d3b7bde3995c 2173 rxtime = LMIC.bcnRxtime - RX_RAMPUP;
mluis 0:62d1edcc13d1 2174 }
mluis 0:62d1edcc13d1 2175
mluis 0:62d1edcc13d1 2176 if( (LMIC.opmode & (OP_JOINING|OP_REJOIN|OP_TXDATA|OP_POLL)) != 0 ) {
mluis 1:d3b7bde3995c 2177 // Need to TX some data...
mluis 1:d3b7bde3995c 2178 // Assuming txChnl points to channel which first becomes available again.
mluis 1:d3b7bde3995c 2179 bit_t jacc = ((LMIC.opmode & (OP_JOINING|OP_REJOIN)) != 0 ? 1 : 0);
mluis 1:d3b7bde3995c 2180 // Find next suitable channel and return availability time
mluis 1:d3b7bde3995c 2181 if( (LMIC.opmode & OP_NEXTCHNL) != 0 ) {
mluis 1:d3b7bde3995c 2182 txbeg = LMIC.txend = nextTx(now);
mluis 1:d3b7bde3995c 2183 LMIC.opmode &= ~OP_NEXTCHNL;
mluis 0:62d1edcc13d1 2184 } else {
mluis 1:d3b7bde3995c 2185 txbeg = LMIC.txend;
mluis 1:d3b7bde3995c 2186 }
mluis 1:d3b7bde3995c 2187 // Delayed TX or waiting for duty cycle?
mluis 1:d3b7bde3995c 2188 if( (LMIC.globalDutyRate != 0 || (LMIC.opmode & OP_RNDTX) != 0) && (txbeg - LMIC.globalDutyAvail) < 0 )
mluis 1:d3b7bde3995c 2189 txbeg = LMIC.globalDutyAvail;
mluis 1:d3b7bde3995c 2190 // If we're tracking a beacon...
mluis 1:d3b7bde3995c 2191 // then make sure TX-RX transaction is complete before beacon
mluis 1:d3b7bde3995c 2192 if( (LMIC.opmode & OP_TRACK) != 0 &&
mluis 1:d3b7bde3995c 2193 txbeg + (jacc ? JOIN_GUARD_osticks : TXRX_GUARD_osticks) - rxtime > 0 ) {
mluis 1:d3b7bde3995c 2194 // Not enough time to complete TX-RX before beacon - postpone after beacon.
mluis 1:d3b7bde3995c 2195 // In order to avoid clustering of postponed TX right after beacon randomize start!
mluis 1:d3b7bde3995c 2196 txDelay(rxtime + BCN_RESERVE_osticks, 16);
mluis 1:d3b7bde3995c 2197 txbeg = 0;
mluis 1:d3b7bde3995c 2198 goto checkrx;
mluis 0:62d1edcc13d1 2199 }
mluis 1:d3b7bde3995c 2200 // Earliest possible time vs overhead to setup radio
mluis 1:d3b7bde3995c 2201 if( txbeg - (now + TX_RAMPUP) < 0 ) {
mluis 1:d3b7bde3995c 2202 // We could send right now!
mluis 1:d3b7bde3995c 2203 dr_t txdr = (dr_t)LMIC.datarate;
dudmuck 2:974cafbfb159 2204 txbeg = now;
mluis 1:d3b7bde3995c 2205 if( jacc ) {
mluis 1:d3b7bde3995c 2206 u1_t ftype;
mluis 1:d3b7bde3995c 2207 if( (LMIC.opmode & OP_REJOIN) != 0 ) {
mluis 1:d3b7bde3995c 2208 txdr = lowerDR(txdr, LMIC.rejoinCnt);
dudmuck 2:974cafbfb159 2209 //ftype = HDR_FTYPE_REJOIN;
dudmuck 2:974cafbfb159 2210 ftype = HDR_FTYPE_JREQ;
mluis 1:d3b7bde3995c 2211 } else {
mluis 1:d3b7bde3995c 2212 ftype = HDR_FTYPE_JREQ;
mluis 1:d3b7bde3995c 2213 }
mluis 1:d3b7bde3995c 2214 buildJoinRequest(ftype);
mluis 1:d3b7bde3995c 2215 LMIC.osjob.func = FUNC_ADDR(jreqDone);
mluis 1:d3b7bde3995c 2216 } else {
mluis 1:d3b7bde3995c 2217 if( LMIC.seqnoDn >= 0xFFFFFF80 ) {
mluis 1:d3b7bde3995c 2218 // Imminent roll over - proactively reset MAC
mluis 1:d3b7bde3995c 2219 EV(specCond, INFO, (e_.reason = EV::specCond_t::DNSEQNO_ROLL_OVER,
mluis 1:d3b7bde3995c 2220 e_.eui = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 2221 e_.info = LMIC.seqnoDn,
mluis 1:d3b7bde3995c 2222 e_.info2 = 0));
mluis 1:d3b7bde3995c 2223 // Device has to react! NWK will not roll over and just stop sending.
mluis 1:d3b7bde3995c 2224 // Thus, we have N frames to detect a possible lock up.
mluis 1:d3b7bde3995c 2225 reset:
mluis 1:d3b7bde3995c 2226 os_setCallback(&LMIC.osjob, FUNC_ADDR(runReset));
mluis 1:d3b7bde3995c 2227 return;
mluis 1:d3b7bde3995c 2228 }
mluis 1:d3b7bde3995c 2229 if( (LMIC.txCnt==0 && LMIC.seqnoUp == 0xFFFFFFFF) ) {
mluis 1:d3b7bde3995c 2230 // Roll over of up seq counter
mluis 1:d3b7bde3995c 2231 EV(specCond, ERR, (e_.reason = EV::specCond_t::UPSEQNO_ROLL_OVER,
mluis 1:d3b7bde3995c 2232 e_.eui = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 2233 e_.info2 = LMIC.seqnoUp));
mluis 1:d3b7bde3995c 2234 // Do not run RESET event callback from here!
mluis 1:d3b7bde3995c 2235 // App code might do some stuff after send unaware of RESET.
mluis 1:d3b7bde3995c 2236 goto reset;
mluis 1:d3b7bde3995c 2237 }
mluis 1:d3b7bde3995c 2238 buildDataFrame();
mluis 1:d3b7bde3995c 2239 LMIC.osjob.func = FUNC_ADDR(updataDone);
mluis 1:d3b7bde3995c 2240 }
mluis 1:d3b7bde3995c 2241 LMIC.rps = setCr(updr2rps(txdr), (cr_t)LMIC.errcr);
mluis 1:d3b7bde3995c 2242 LMIC.dndr = txdr; // carry TX datarate (can be != LMIC.datarate) over to txDone/setupRx1
mluis 1:d3b7bde3995c 2243 LMIC.opmode = (LMIC.opmode & ~(OP_POLL|OP_RNDTX)) | OP_TXRXPEND | OP_NEXTCHNL;
mluis 1:d3b7bde3995c 2244 updateTx(txbeg);
mluis 1:d3b7bde3995c 2245 os_radio(RADIO_TX);
mluis 0:62d1edcc13d1 2246 return;
mluis 0:62d1edcc13d1 2247 }
mluis 1:d3b7bde3995c 2248 // Cannot yet TX
mluis 1:d3b7bde3995c 2249 if( (LMIC.opmode & OP_TRACK) == 0 )
mluis 1:d3b7bde3995c 2250 goto txdelay; // We don't track the beacon - nothing else to do - so wait for the time to TX
mluis 1:d3b7bde3995c 2251 // Consider RX tasks
mluis 1:d3b7bde3995c 2252 if( txbeg == 0 ) // zero indicates no TX pending
mluis 1:d3b7bde3995c 2253 txbeg += 1; // TX delayed by one tick (insignificant amount of time)
mluis 0:62d1edcc13d1 2254 } else {
mluis 1:d3b7bde3995c 2255 // No TX pending - no scheduled RX
mluis 1:d3b7bde3995c 2256 if( (LMIC.opmode & OP_TRACK) == 0 )
mluis 1:d3b7bde3995c 2257 return;
mluis 0:62d1edcc13d1 2258 }
mluis 0:62d1edcc13d1 2259
mluis 0:62d1edcc13d1 2260 // Are we pingable?
mluis 0:62d1edcc13d1 2261 checkrx:
mluis 0:62d1edcc13d1 2262 if( (LMIC.opmode & OP_PINGINI) != 0 ) {
mluis 1:d3b7bde3995c 2263 // One more RX slot in this beacon period?
mluis 1:d3b7bde3995c 2264 if( rxschedNext(&LMIC.ping, now+RX_RAMPUP) ) {
mluis 1:d3b7bde3995c 2265 if( txbeg != 0 && (txbeg - LMIC.ping.rxtime) < 0 )
mluis 1:d3b7bde3995c 2266 goto txdelay;
mluis 1:d3b7bde3995c 2267 LMIC.rxsyms = LMIC.ping.rxsyms;
mluis 1:d3b7bde3995c 2268 LMIC.rxtime = LMIC.ping.rxtime;
mluis 1:d3b7bde3995c 2269 LMIC.freq = LMIC.ping.freq;
mluis 1:d3b7bde3995c 2270 LMIC.rps = dndr2rps(LMIC.ping.dr);
mluis 1:d3b7bde3995c 2271 LMIC.dataLen = 0;
mluis 1:d3b7bde3995c 2272 ASSERT(LMIC.rxtime - now+RX_RAMPUP >= 0 );
mluis 1:d3b7bde3995c 2273 os_setTimedCallback(&LMIC.osjob, LMIC.rxtime - RX_RAMPUP, FUNC_ADDR(startRxPing));
mluis 1:d3b7bde3995c 2274 return;
mluis 1:d3b7bde3995c 2275 }
mluis 1:d3b7bde3995c 2276 // no - just wait for the beacon
mluis 0:62d1edcc13d1 2277 }
mluis 0:62d1edcc13d1 2278
mluis 0:62d1edcc13d1 2279 if( txbeg != 0 && (txbeg - rxtime) < 0 )
mluis 1:d3b7bde3995c 2280 goto txdelay;
mluis 0:62d1edcc13d1 2281
mluis 0:62d1edcc13d1 2282 setBcnRxParams();
mluis 0:62d1edcc13d1 2283 LMIC.rxsyms = LMIC.bcnRxsyms;
mluis 0:62d1edcc13d1 2284 LMIC.rxtime = LMIC.bcnRxtime;
mluis 0:62d1edcc13d1 2285 if( now - rxtime >= 0 ) {
mluis 1:d3b7bde3995c 2286 LMIC.osjob.func = FUNC_ADDR(processBeacon);
mluis 1:d3b7bde3995c 2287 os_radio(RADIO_RX);
mluis 1:d3b7bde3995c 2288 return;
mluis 0:62d1edcc13d1 2289 }
mluis 0:62d1edcc13d1 2290 os_setTimedCallback(&LMIC.osjob, rxtime, FUNC_ADDR(startRxBcn));
mluis 0:62d1edcc13d1 2291 return;
mluis 0:62d1edcc13d1 2292
mluis 0:62d1edcc13d1 2293 txdelay:
mluis 0:62d1edcc13d1 2294 EV(devCond, INFO, (e_.reason = EV::devCond_t::TX_DELAY,
mluis 1:d3b7bde3995c 2295 e_.eui = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 2296 e_.info = osticks2ms(txbeg-now),
mluis 1:d3b7bde3995c 2297 e_.info2 = LMIC.seqnoUp-1));
mluis 0:62d1edcc13d1 2298 os_setTimedCallback(&LMIC.osjob, txbeg-TX_RAMPUP, FUNC_ADDR(runEngineUpdate));
mluis 0:62d1edcc13d1 2299 }
mluis 0:62d1edcc13d1 2300
mluis 0:62d1edcc13d1 2301
tmulrooney 6:eed5fd627a2b 2302 void LMIC_setAdrMode (bit_t enabled)
tmulrooney 6:eed5fd627a2b 2303 {
GTsapparellas 8:5879e83f632a 2304 //debug("LMIC LMIC_setAdrMode enter\r\n");
mluis 0:62d1edcc13d1 2305 LMIC.adrEnabled = enabled ? FCT_ADREN : 0;
mluis 0:62d1edcc13d1 2306 }
mluis 0:62d1edcc13d1 2307
mluis 0:62d1edcc13d1 2308
mluis 0:62d1edcc13d1 2309 // Should we have/need an ext. API like this?
tmulrooney 6:eed5fd627a2b 2310 void LMIC_setDrTxpow (dr_t dr, s1_t txpow)
tmulrooney 6:eed5fd627a2b 2311 {
GTsapparellas 8:5879e83f632a 2312 //debug("LMIC LMIC_setDrTxpow enter\r\n");
mluis 0:62d1edcc13d1 2313 setDrTxpow(DRCHG_SET, dr, txpow);
mluis 0:62d1edcc13d1 2314 }
mluis 0:62d1edcc13d1 2315
mluis 0:62d1edcc13d1 2316
tmulrooney 6:eed5fd627a2b 2317 void LMIC_shutdown (void)
tmulrooney 6:eed5fd627a2b 2318 {
GTsapparellas 8:5879e83f632a 2319 //debug("LMIC LMIC_shutdown enter\r\n");
mluis 0:62d1edcc13d1 2320 os_clearCallback(&LMIC.osjob);
mluis 0:62d1edcc13d1 2321 os_radio(RADIO_RST);
mluis 0:62d1edcc13d1 2322 LMIC.opmode |= OP_SHUTDOWN;
mluis 0:62d1edcc13d1 2323 }
mluis 0:62d1edcc13d1 2324
mluis 0:62d1edcc13d1 2325
tmulrooney 6:eed5fd627a2b 2326 void LMIC_reset (void)
tmulrooney 6:eed5fd627a2b 2327 {
GTsapparellas 8:5879e83f632a 2328 //debug("LMIC LMIC_reset enter\r\n");
mluis 0:62d1edcc13d1 2329 EV(devCond, INFO, (e_.reason = EV::devCond_t::LMIC_EV,
mluis 1:d3b7bde3995c 2330 e_.eui = MAIN::CDEV->getEui(),
mluis 1:d3b7bde3995c 2331 e_.info = EV_RESET));
mluis 0:62d1edcc13d1 2332 os_radio(RADIO_RST);
mluis 0:62d1edcc13d1 2333 os_clearCallback(&LMIC.osjob);
mluis 0:62d1edcc13d1 2334
mluis 0:62d1edcc13d1 2335 os_clearMem((xref2u1_t)&LMIC,SIZEOFEXPR(LMIC));
mluis 1:d3b7bde3995c 2336 LMIC.devaddr = 0;
mluis 1:d3b7bde3995c 2337 LMIC.devNonce = os_getRndU2();
mluis 1:d3b7bde3995c 2338 LMIC.opmode = OP_NONE;
mluis 1:d3b7bde3995c 2339 LMIC.errcr = CR_4_5;
mluis 1:d3b7bde3995c 2340 LMIC.adrEnabled = FCT_ADREN;
mluis 1:d3b7bde3995c 2341 LMIC.dn2Dr = DR_DNW2; // we need this for 2nd DN window of join accept
mluis 1:d3b7bde3995c 2342 LMIC.dn2Freq = FREQ_DNW2; // ditto
mluis 1:d3b7bde3995c 2343 LMIC.ping.freq = FREQ_PING; // defaults for ping
mluis 1:d3b7bde3995c 2344 LMIC.ping.dr = DR_PING; // ditto
mluis 1:d3b7bde3995c 2345 LMIC.ping.intvExp = 0xFF;
mluis 1:d3b7bde3995c 2346 #if defined(CFG_us915)
mluis 0:62d1edcc13d1 2347 initDefaultChannels();
mluis 0:62d1edcc13d1 2348 #endif
mluis 1:d3b7bde3995c 2349 DO_DEVDB(LMIC.devaddr, devaddr);
mluis 1:d3b7bde3995c 2350 DO_DEVDB(LMIC.devNonce, devNonce);
mluis 1:d3b7bde3995c 2351 DO_DEVDB(LMIC.dn2Dr, dn2Dr);
mluis 1:d3b7bde3995c 2352 DO_DEVDB(LMIC.dn2Freq, dn2Freq);
mluis 1:d3b7bde3995c 2353 DO_DEVDB(LMIC.ping.freq, pingFreq);
mluis 1:d3b7bde3995c 2354 DO_DEVDB(LMIC.ping.dr, pingDr);
mluis 1:d3b7bde3995c 2355 DO_DEVDB(LMIC.ping.intvExp, pingIntvExp);
mluis 0:62d1edcc13d1 2356 }
mluis 0:62d1edcc13d1 2357
mluis 0:62d1edcc13d1 2358
mluis 0:62d1edcc13d1 2359 void LMIC_init (void) {
GTsapparellas 8:5879e83f632a 2360 // debug("LMIC_init enter\r\n");
mluis 0:62d1edcc13d1 2361 LMIC.opmode = OP_SHUTDOWN;
mluis 0:62d1edcc13d1 2362 }
mluis 0:62d1edcc13d1 2363
mluis 0:62d1edcc13d1 2364
tmulrooney 6:eed5fd627a2b 2365 void LMIC_clrTxData (void)
tmulrooney 6:eed5fd627a2b 2366 {
GTsapparellas 8:5879e83f632a 2367 //debug("LMIC LMIC_clrTxData enter\r\n");
mluis 0:62d1edcc13d1 2368 LMIC.opmode &= ~(OP_TXDATA|OP_TXRXPEND|OP_POLL);
mluis 0:62d1edcc13d1 2369 LMIC.pendTxLen = 0;
mluis 0:62d1edcc13d1 2370 if( (LMIC.opmode & (OP_JOINING|OP_SCAN)) != 0 ) // do not interfere with JOINING
mluis 1:d3b7bde3995c 2371 return;
mluis 0:62d1edcc13d1 2372 os_clearCallback(&LMIC.osjob);
mluis 0:62d1edcc13d1 2373 os_radio(RADIO_RST);
mluis 0:62d1edcc13d1 2374 engineUpdate();
mluis 0:62d1edcc13d1 2375 }
mluis 0:62d1edcc13d1 2376
mluis 0:62d1edcc13d1 2377
tmulrooney 6:eed5fd627a2b 2378 void LMIC_setTxData (void)
tmulrooney 6:eed5fd627a2b 2379 {
GTsapparellas 8:5879e83f632a 2380 //debug("LMIC LMIC_setTxData enter\r\n");
mluis 0:62d1edcc13d1 2381 LMIC.opmode |= OP_TXDATA;
mluis 0:62d1edcc13d1 2382 if( (LMIC.opmode & OP_JOINING) == 0 )
mluis 1:d3b7bde3995c 2383 LMIC.txCnt = 0; // cancel any ongoing TX/RX retries
mluis 0:62d1edcc13d1 2384 engineUpdate();
mluis 0:62d1edcc13d1 2385 }
mluis 0:62d1edcc13d1 2386
mluis 0:62d1edcc13d1 2387
mluis 0:62d1edcc13d1 2388 //
tmulrooney 6:eed5fd627a2b 2389 int LMIC_setTxData2 (u1_t port, xref2u1_t data, u1_t dlen, u1_t confirmed)
tmulrooney 6:eed5fd627a2b 2390 {
GTsapparellas 8:5879e83f632a 2391 //debug("LMIC LMIC_setTxData2 enter\r\n");
mluis 0:62d1edcc13d1 2392 if( dlen > SIZEOFEXPR(LMIC.pendTxData) )
mluis 1:d3b7bde3995c 2393 return -2;
mluis 0:62d1edcc13d1 2394 if( data != (xref2u1_t)0 )
mluis 1:d3b7bde3995c 2395 os_copyMem(LMIC.pendTxData, data, dlen);
mluis 0:62d1edcc13d1 2396 LMIC.pendTxConf = confirmed;
mluis 0:62d1edcc13d1 2397 LMIC.pendTxPort = port;
mluis 0:62d1edcc13d1 2398 LMIC.pendTxLen = dlen;
mluis 0:62d1edcc13d1 2399 LMIC_setTxData();
mluis 0:62d1edcc13d1 2400 return 0;
mluis 0:62d1edcc13d1 2401 }
mluis 0:62d1edcc13d1 2402
mluis 0:62d1edcc13d1 2403
mluis 0:62d1edcc13d1 2404 // Send a payload-less message to signal device is alive
tmulrooney 6:eed5fd627a2b 2405 void LMIC_sendAlive (void)
tmulrooney 6:eed5fd627a2b 2406 {
GTsapparellas 8:5879e83f632a 2407 //debug("LMIC LMIC_sendAlive enter\r\n");
mluis 0:62d1edcc13d1 2408 LMIC.opmode |= OP_POLL;
mluis 0:62d1edcc13d1 2409 engineUpdate();
mluis 0:62d1edcc13d1 2410 }
mluis 0:62d1edcc13d1 2411
mluis 0:62d1edcc13d1 2412
mluis 0:62d1edcc13d1 2413 // Check if other networks are around.
tmulrooney 6:eed5fd627a2b 2414 void LMIC_tryRejoin (void)
tmulrooney 6:eed5fd627a2b 2415 {
GTsapparellas 8:5879e83f632a 2416 //debug("LMIC LMIC_tryRejoin enter\r\n");
mluis 0:62d1edcc13d1 2417 LMIC.opmode |= OP_REJOIN;
mluis 0:62d1edcc13d1 2418 engineUpdate();
mluis 0:62d1edcc13d1 2419 }
mluis 0:62d1edcc13d1 2420
mluis 1:d3b7bde3995c 2421 //! \brief Setup given session keys
mluis 1:d3b7bde3995c 2422 //! and put the MAC in a state as if
mluis 1:d3b7bde3995c 2423 //! a join request/accept would have negotiated just these keys.
mluis 1:d3b7bde3995c 2424 //! It is crucial that the combinations `devaddr/nwkkey` and `devaddr/artkey`
mluis 1:d3b7bde3995c 2425 //! are unique within the network identified by `netid`.
mluis 1:d3b7bde3995c 2426 //! NOTE: on Harvard architectures when session keys are in flash:
mluis 1:d3b7bde3995c 2427 //! Caller has to fill in LMIC.{nwk,art}Key before and pass {nwk,art}Key are NULL
mluis 1:d3b7bde3995c 2428 //! \param netid a 24 bit number describing the network id this device is using
mluis 1:d3b7bde3995c 2429 //! \param devaddr the 32 bit session address of the device. It is strongly recommended
mluis 1:d3b7bde3995c 2430 //! to ensure that different devices use different numbers with high probability.
mluis 1:d3b7bde3995c 2431 //! \param nwkKey the 16 byte network session key used for message integrity.
mluis 1:d3b7bde3995c 2432 //! If NULL the caller has copied the key into `LMIC.nwkKey` before.
mluis 1:d3b7bde3995c 2433 //! \param artKey the 16 byte application router session key used for message confidentiality.
mluis 1:d3b7bde3995c 2434 //! If NULL the caller has copied the key into `LMIC.artKey` before.
tmulrooney 6:eed5fd627a2b 2435 void LMIC_setSession (u4_t netid, devaddr_t devaddr, xref2u1_t nwkKey, xref2u1_t artKey)
tmulrooney 6:eed5fd627a2b 2436 {
GTsapparellas 8:5879e83f632a 2437 //debug("LMIC LMIC_setSession enter\r\n");
mluis 0:62d1edcc13d1 2438 LMIC.netid = netid;
mluis 0:62d1edcc13d1 2439 LMIC.devaddr = devaddr;
mluis 1:d3b7bde3995c 2440 if( nwkKey != (xref2u1_t)0 )
mluis 1:d3b7bde3995c 2441 os_copyMem(LMIC.nwkKey, nwkKey, 16);
mluis 1:d3b7bde3995c 2442 if( artKey != (xref2u1_t)0 )
mluis 1:d3b7bde3995c 2443 os_copyMem(LMIC.artKey, artKey, 16);
mluis 0:62d1edcc13d1 2444
mluis 1:d3b7bde3995c 2445 #if defined(CFG_eu868)
mluis 0:62d1edcc13d1 2446 initDefaultChannels(0);
mluis 0:62d1edcc13d1 2447 #endif
mluis 1:d3b7bde3995c 2448
mluis 1:d3b7bde3995c 2449 LMIC.opmode &= ~(OP_JOINING|OP_TRACK|OP_REJOIN|OP_TXRXPEND|OP_PINGINI);
mluis 1:d3b7bde3995c 2450 LMIC.opmode |= OP_NEXTCHNL;
mluis 0:62d1edcc13d1 2451 stateJustJoined();
mluis 0:62d1edcc13d1 2452 }
mluis 1:d3b7bde3995c 2453
mluis 1:d3b7bde3995c 2454 // Enable/disable link check validation.
mluis 1:d3b7bde3995c 2455 // LMIC sets the ADRACKREQ bit in UP frames if there were no DN frames
mluis 1:d3b7bde3995c 2456 // for a while. It expects the network to provide a DN message to prove
mluis 1:d3b7bde3995c 2457 // connectivity with a span of UP frames. If this no such prove is coming
mluis 1:d3b7bde3995c 2458 // then the datarate is lowered and a LINK_DEAD event is generated.
mluis 1:d3b7bde3995c 2459 // This mode can be disabled and no connectivity prove (ADRACKREQ) is requested
mluis 1:d3b7bde3995c 2460 // nor is the datarate changed.
mluis 1:d3b7bde3995c 2461 // This must be called only if a session is established (e.g. after EV_JOINED)
tmulrooney 6:eed5fd627a2b 2462 void LMIC_setLinkCheckMode (bit_t enabled)
tmulrooney 6:eed5fd627a2b 2463 {
GTsapparellas 8:5879e83f632a 2464 //debug("LMIC LMIC_setLinkCheckMode enter\r\n");
mluis 1:d3b7bde3995c 2465 LMIC.adrChanged = 0;
mluis 1:d3b7bde3995c 2466 LMIC.adrAckReq = enabled ? LINK_CHECK_INIT : LINK_CHECK_OFF;
mluis 1:d3b7bde3995c 2467 }
mluis 1:d3b7bde3995c 2468
dudmuck 2:974cafbfb159 2469 void LMIC_reverse_memcpy(u1_t *dst, const u1_t *src, size_t n)
dudmuck 2:974cafbfb159 2470 {
dudmuck 2:974cafbfb159 2471 size_t i;
dudmuck 2:974cafbfb159 2472
dudmuck 2:974cafbfb159 2473 for (i=0; i < n; ++i)
dudmuck 2:974cafbfb159 2474 dst[n-1-i] = src[i];
dudmuck 2:974cafbfb159 2475 }