first test
Dependents: LoRaWAN-lmic-app_tjm
Fork of LMiC by
lmic.cpp
00001 /******************************************************************************* 00002 * Copyright (c) 2014-2015 IBM Corporation. 00003 * All rights reserved. This program and the accompanying materials 00004 * are made available under the terms of the Eclipse Public License v1.0 00005 * which accompanies this distribution, and is available at 00006 * http://www.eclipse.org/legal/epl-v10.html 00007 * 00008 * Contributors: 00009 * IBM Zurich Research Lab - initial API, implementation and documentation 00010 *******************************************************************************/ 00011 00012 //! \file 00013 #include "lmic.h" 00014 #include "debug.h" 00015 00016 #if !defined(MINRX_SYMS) 00017 #define MINRX_SYMS 5 00018 #endif // !defined(MINRX_SYMS) 00019 #define PAMBL_SYMS 8 00020 #define PAMBL_FSK 5 00021 #define PRERX_FSK 1 00022 #define RXLEN_FSK (1+5+2) 00023 00024 #define BCN_INTV_osticks sec2osticks(BCN_INTV_sec) 00025 #define TXRX_GUARD_osticks ms2osticks(TXRX_GUARD_ms) 00026 #define JOIN_GUARD_osticks ms2osticks(JOIN_GUARD_ms) 00027 #define DELAY_DNW1_osticks sec2osticks(DELAY_DNW1) 00028 #define DELAY_DNW2_osticks sec2osticks(DELAY_DNW2) 00029 #define DELAY_JACC1_osticks sec2osticks(DELAY_JACC1) 00030 #define DELAY_JACC2_osticks sec2osticks(DELAY_JACC2) 00031 #define DELAY_EXTDNW2_osticks sec2osticks(DELAY_EXTDNW2) 00032 #define BCN_RESERVE_osticks ms2osticks(BCN_RESERVE_ms) 00033 #define BCN_GUARD_osticks ms2osticks(BCN_GUARD_ms) 00034 #define BCN_WINDOW_osticks ms2osticks(BCN_WINDOW_ms) 00035 #define AIRTIME_BCN_osticks us2osticks(AIRTIME_BCN) 00036 #if defined(CFG_eu868) 00037 #define DNW2_SAFETY_ZONE ms2osticks(3000) 00038 #endif 00039 #if defined(CFG_us915) 00040 #define DNW2_SAFETY_ZONE ms2osticks(750) 00041 #endif 00042 00043 // Special APIs - for development or testing 00044 #define isTESTMODE() 0 00045 00046 DEFINE_LMIC; 00047 DECL_ON_LMIC_EVENT; 00048 00049 00050 // Fwd decls. 00051 static void engineUpdate(void); 00052 static void startScan (void); 00053 00054 00055 // ================================================================================ 00056 // BEG OS - default implementations for certain OS suport functions 00057 00058 #if !defined(HAS_os_calls) 00059 00060 #if !defined(os_rlsbf2) 00061 u2_t os_rlsbf2 (xref2cu1_t buf) 00062 { 00063 debug("LMIC os_rlsbf2 enter\r\n"); 00064 return (u2_t)(buf[0] | (buf[1]<<8)); 00065 } 00066 #endif 00067 00068 #if !defined(os_rlsbf4) 00069 u4_t os_rlsbf4 (xref2cu1_t buf) 00070 { 00071 debug("LMIC os_rlsbf4 enter\r\n"); 00072 return (u4_t)(buf[0] | (buf[1]<<8) | ((u4_t)buf[2]<<16) | ((u4_t)buf[3]<<24)); 00073 } 00074 #endif 00075 00076 00077 #if !defined(os_rmsbf4) 00078 u4_t os_rmsbf4 (xref2cu1_t buf) 00079 { 00080 debug("LMIC os_rmsbf4 enter\r\n"); 00081 return (u4_t)(buf[3] | (buf[2]<<8) | ((u4_t)buf[1]<<16) | ((u4_t)buf[0]<<24)); 00082 } 00083 #endif 00084 00085 00086 #if !defined(os_wlsbf2) 00087 void os_wlsbf2 (xref2u1_t buf, u2_t v) 00088 { 00089 debug("LMIC os_wlsbf2 enter\r\n"); 00090 buf[0] = v; 00091 buf[1] = v>>8; 00092 } 00093 #endif 00094 00095 #if !defined(os_wlsbf4) 00096 void os_wlsbf4 (xref2u1_t buf, u4_t v) 00097 { 00098 debug("LMIC os_wlsbf4 enter\r\n"); 00099 buf[0] = v; 00100 buf[1] = v>>8; 00101 buf[2] = v>>16; 00102 buf[3] = v>>24; 00103 } 00104 #endif 00105 00106 #if !defined(os_wmsbf4) 00107 void os_wmsbf4 (xref2u1_t buf, u4_t v) 00108 { 00109 debug("LMIC os_wmsbf4 enter\r\n"); 00110 buf[3] = v; 00111 buf[2] = v>>8; 00112 buf[1] = v>>16; 00113 buf[0] = v>>24; 00114 } 00115 #endif 00116 00117 #if !defined(os_getBattLevel) 00118 u1_t os_getBattLevel (void) 00119 { 00120 debug("LMIC os_getBattLevel enter\r\n"); 00121 return MCMD_DEVS_BATT_NOINFO; 00122 } 00123 #endif 00124 00125 #if !defined(os_crc16) 00126 // New CRC-16 CCITT(XMODEM) checksum for beacons: 00127 u2_t os_crc16 (xref2u1_t data, uint len) 00128 { 00129 debug("LMIC os_crc16 enter\r\n"); 00130 u2_t remainder = 0; 00131 u2_t polynomial = 0x1021; 00132 for( uint i = 0; i < len; i++ ) 00133 { 00134 remainder ^= data[i] << 8; 00135 for( u1_t bit = 8; bit > 0; bit--) 00136 { 00137 if( (remainder & 0x8000) ) 00138 remainder = (remainder << 1) ^ polynomial; 00139 else 00140 remainder <<= 1; 00141 } 00142 } 00143 return remainder; 00144 } 00145 #endif 00146 00147 #endif // !HAS_os_calls 00148 00149 // END OS - default implementations for certain OS suport functions 00150 // ================================================================================ 00151 00152 // ================================================================================ 00153 // BEG AES 00154 00155 static void micB0 (u4_t devaddr, u4_t seqno, int dndir, int len) 00156 { 00157 debug("LMIC micB0 enter\r\n"); 00158 os_clearMem(AESaux,16); 00159 AESaux[0] = 0x49; 00160 AESaux[5] = dndir?1:0; 00161 AESaux[15] = len; 00162 os_wlsbf4(AESaux+ 6,devaddr); 00163 os_wlsbf4(AESaux+10,seqno); 00164 } 00165 00166 00167 static int aes_verifyMic (xref2cu1_t key, u4_t devaddr, u4_t seqno, int dndir, xref2u1_t pdu, int len) 00168 { 00169 debug("LMIC aes_verifyMic enter\r\n"); 00170 micB0(devaddr, seqno, dndir, len); 00171 os_copyMem(AESkey,key,16); 00172 return os_aes(AES_MIC, pdu, len) == os_rmsbf4(pdu+len); 00173 } 00174 00175 00176 static void aes_appendMic (xref2cu1_t key, u4_t devaddr, u4_t seqno, int dndir, xref2u1_t pdu, int len) 00177 { 00178 debug("LMIC aes_appendMic enter\r\n"); 00179 micB0(devaddr, seqno, dndir, len); 00180 os_copyMem(AESkey,key,16); 00181 // MSB because of internal structure of AES 00182 os_wmsbf4(pdu+len, os_aes(AES_MIC, pdu, len)); 00183 } 00184 00185 00186 static void aes_appendMic0 (xref2u1_t pdu, int len) 00187 { 00188 debug("LMIC aes_appendMic0 enter\r\n"); 00189 os_getDevKey(AESkey); 00190 os_wmsbf4(pdu+len, os_aes(AES_MIC|AES_MICNOAUX, pdu, len)); // MSB because of internal structure of AES 00191 } 00192 00193 00194 static int aes_verifyMic0 (xref2u1_t pdu, int len) 00195 { 00196 debug("LMIC aes_verifyMic0 enter\r\n"); 00197 os_getDevKey(AESkey); 00198 return os_aes(AES_MIC|AES_MICNOAUX, pdu, len) == os_rmsbf4(pdu+len); 00199 } 00200 00201 00202 static void aes_encrypt (xref2u1_t pdu, int len) 00203 { 00204 debug("LMIC aes_encrypt enter\r\n"); 00205 os_getDevKey(AESkey); 00206 os_aes(AES_ENC, pdu, len); 00207 } 00208 00209 00210 static void aes_cipher (xref2cu1_t key, u4_t devaddr, u4_t seqno, int dndir, xref2u1_t payload, int len) 00211 { 00212 debug("LMIC aes_cipher enter\r\n"); 00213 if( len <= 0 ) 00214 return; 00215 os_clearMem(AESaux, 16); 00216 AESaux[0] = AESaux[15] = 1; // mode=cipher / dir=down / block counter=1 00217 AESaux[5] = dndir?1:0; 00218 os_wlsbf4(AESaux+ 6,devaddr); 00219 os_wlsbf4(AESaux+10,seqno); 00220 os_copyMem(AESkey,key,16); 00221 os_aes(AES_CTR, payload, len); 00222 } 00223 00224 00225 static void aes_sessKeys (u2_t devnonce, xref2cu1_t artnonce, xref2u1_t nwkkey, xref2u1_t artkey) 00226 { 00227 debug("LMIC aes_sessKeys enter\r\n"); 00228 os_clearMem(nwkkey, 16); 00229 nwkkey[0] = 0x01; 00230 os_copyMem(nwkkey+1, artnonce, LEN_ARTNONCE+LEN_NETID); 00231 os_wlsbf2(nwkkey+1+LEN_ARTNONCE+LEN_NETID, devnonce); 00232 os_copyMem(artkey, nwkkey, 16); 00233 artkey[0] = 0x02; 00234 00235 os_getDevKey(AESkey); 00236 os_aes(AES_ENC, nwkkey, 16); 00237 os_getDevKey(AESkey); 00238 os_aes(AES_ENC, artkey, 16); 00239 } 00240 00241 // END AES 00242 // ================================================================================ 00243 00244 00245 // ================================================================================ 00246 // BEG LORA 00247 00248 #if defined(CFG_eu868) // ======================================== 00249 00250 #define maxFrameLen(dr) ((dr)<=DR_SF9 ? maxFrameLens[(dr)] : 0xFF) 00251 const u1_t maxFrameLens [] = { 64,64,64,123 }; 00252 00253 const u1_t _DR2RPS_CRC[] = { 00254 ILLEGAL_RPS, 00255 (u1_t)MAKERPS(SF12, BW125, CR_4_5, 0, 0), 00256 (u1_t)MAKERPS(SF11, BW125, CR_4_5, 0, 0), 00257 (u1_t)MAKERPS(SF10, BW125, CR_4_5, 0, 0), 00258 (u1_t)MAKERPS(SF9, BW125, CR_4_5, 0, 0), 00259 (u1_t)MAKERPS(SF8, BW125, CR_4_5, 0, 0), 00260 (u1_t)MAKERPS(SF7, BW125, CR_4_5, 0, 0), 00261 (u1_t)MAKERPS(SF7, BW250, CR_4_5, 0, 0), 00262 (u1_t)MAKERPS(FSK, BW125, CR_4_5, 0, 0), 00263 ILLEGAL_RPS 00264 }; 00265 00266 static const s1_t TXPOWLEVELS[] = { 00267 20, 14, 11, 8, 5, 2, 0,0, 0,0,0,0, 0,0,0,0 00268 }; 00269 #define pow2dBm(mcmd_ladr_p1) (TXPOWLEVELS[(mcmd_ladr_p1&MCMD_LADR_POW_MASK)>>MCMD_LADR_POW_SHIFT]) 00270 00271 #elif defined(CFG_us915) // ======================================== 00272 00273 #define maxFrameLen(dr) ((dr)<=DR_SF11CR ? maxFrameLens[(dr)] : 0xFF) 00274 //const u1_t maxFrameLens [] = { 24,66,142,255,255,255,255,255, 66,142 }; 00275 00276 const u1_t _DR2RPS_CRC[] = { 00277 ILLEGAL_RPS, 00278 MAKERPS(SF10, BW125, CR_4_5, 0, 0), 00279 MAKERPS(SF9 , BW125, CR_4_5, 0, 0), 00280 MAKERPS(SF8 , BW125, CR_4_5, 0, 0), 00281 MAKERPS(SF7 , BW125, CR_4_5, 0, 0), 00282 MAKERPS(SF8 , BW500, CR_4_5, 0, 0), 00283 ILLEGAL_RPS , 00284 ILLEGAL_RPS , 00285 ILLEGAL_RPS , 00286 MAKERPS(SF12, BW500, CR_4_5, 0, 0), 00287 MAKERPS(SF11, BW500, CR_4_5, 0, 0), 00288 MAKERPS(SF10, BW500, CR_4_5, 0, 0), 00289 MAKERPS(SF9 , BW500, CR_4_5, 0, 0), 00290 MAKERPS(SF8 , BW500, CR_4_5, 0, 0), 00291 MAKERPS(SF7 , BW500, CR_4_5, 0, 0), 00292 ILLEGAL_RPS 00293 }; 00294 00295 #define pow2dBm(mcmd_ladr_p1) ((s1_t)(30 - (((mcmd_ladr_p1)&MCMD_LADR_POW_MASK)<<1))) 00296 00297 #endif // ================================================ 00298 00299 static const u1_t SENSITIVITY[7][3] = { 00300 // ------------bw---------- 00301 // 125kHz 250kHz 500kHz 00302 { 141-109, 141-109, 141-109 }, // FSK 00303 { 141-127, 141-124, 141-121 }, // SF7 00304 { 141-129, 141-126, 141-123 }, // SF8 00305 { 141-132, 141-129, 141-126 }, // SF9 00306 { 141-135, 141-132, 141-129 }, // SF10 00307 { 141-138, 141-135, 141-132 }, // SF11 00308 { 141-141, 141-138, 141-135 } // SF12 00309 }; 00310 00311 int getSensitivity (rps_t rps) 00312 { 00313 debug("LMIC getSensitivity enter\r\n"); 00314 return -141 + SENSITIVITY[getSf(rps)][getBw(rps)]; 00315 } 00316 00317 ostime_t calcAirTime (rps_t rps, u1_t plen) 00318 { 00319 debug("LMIC calcAirTime enter\r\n"); 00320 u1_t bw = getBw(rps); // 0,1,2 = 125,250,500kHz 00321 u1_t sf = getSf(rps); // 0=FSK, 1..6 = SF7..12 00322 if( sf == FSK ) { 00323 return (plen+/*preamble*/5+/*syncword*/3+/*len*/1+/*crc*/2) * /*bits/byte*/8 00324 * (s4_t)OSTICKS_PER_SEC / /*kbit/s*/50000; 00325 } 00326 u1_t sfx = 4*(sf+(7-SF7)); 00327 u1_t q = sfx - (sf >= SF11 ? 8 : 0); 00328 int tmp = 8*plen - sfx + 28 + (getNocrc(rps)?0:16) - (getIh(rps)?20:0); 00329 if( tmp > 0 ) { 00330 tmp = (tmp + q - 1) / q; 00331 tmp *= getCr(rps)+5; 00332 tmp += 8; 00333 } else { 00334 tmp = 8; 00335 } 00336 tmp = (tmp<<2) + /*preamble*/49 /* 4 * (8 + 4.25) */; 00337 // bw = 125000 = 15625 * 2^3 00338 // 250000 = 15625 * 2^4 00339 // 500000 = 15625 * 2^5 00340 // sf = 7..12 00341 // 00342 // osticks = tmp * OSTICKS_PER_SEC * 1<<sf / bw 00343 // 00344 // 3 => counter reduced divisor 125000/8 => 15625 00345 // 2 => counter 2 shift on tmp 00346 sfx = sf+(7-SF7) - (3+2) - bw; 00347 int div = 15625; 00348 if( sfx > 4 ) { 00349 // prevent 32bit signed int overflow in last step 00350 div >>= sfx-4; 00351 sfx = 4; 00352 } 00353 // Need 32bit arithmetic for this last step 00354 return (((ostime_t)tmp << sfx) * OSTICKS_PER_SEC + div/2) / div; 00355 } 00356 00357 /*extern inline s1_t rssi2s1 (int v); 00358 extern inline int s12rssi (s1_t v); 00359 extern inline float s12snr (s1_t v); 00360 extern inline s1_t snr2s1 (double v);*/ 00361 00362 extern inline rps_t updr2rps (dr_t dr); 00363 extern inline rps_t dndr2rps (dr_t dr); 00364 extern inline int isFasterDR (dr_t dr1, dr_t dr2); 00365 extern inline int isSlowerDR (dr_t dr1, dr_t dr2); 00366 extern inline dr_t incDR (dr_t dr); 00367 extern inline dr_t decDR (dr_t dr); 00368 extern inline dr_t assertDR (dr_t dr); 00369 extern inline dr_t validDR (dr_t dr); 00370 extern inline dr_t lowerDR (dr_t dr, u1_t n); 00371 00372 extern inline sf_t getSf (rps_t params); 00373 extern inline rps_t setSf (rps_t params, sf_t sf); 00374 extern inline bw_t getBw (rps_t params); 00375 extern inline rps_t setBw (rps_t params, bw_t cr); 00376 extern inline cr_t getCr (rps_t params); 00377 extern inline rps_t setCr (rps_t params, cr_t cr); 00378 extern inline int getNocrc (rps_t params); 00379 extern inline rps_t setNocrc (rps_t params, int nocrc); 00380 extern inline int getIh (rps_t params); 00381 extern inline rps_t setIh (rps_t params, int ih); 00382 extern inline rps_t makeRps (sf_t sf, bw_t bw, cr_t cr, int ih, int nocrc); 00383 extern inline int sameSfBw (rps_t r1, rps_t r2); 00384 00385 // END LORA 00386 // ================================================================================ 00387 00388 00389 // Adjust DR for TX retries 00390 // - indexed by retry count 00391 // - return steps to lower DR 00392 static const u1_t DRADJUST[2+TXCONF_ATTEMPTS] = { 00393 // normal frames - 1st try / no retry 00394 0, 00395 // confirmed frames 00396 0,0,1,0,1,0,1,0,0 00397 }; 00398 00399 00400 // Table below defines the size of one symbol as 00401 // symtime = 256us * 2^T(sf,bw) 00402 // 256us is called one symunit. 00403 // SF: 00404 // BW: |__7___8___9__10__11__12 00405 // 125kHz | 2 3 4 5 6 7 00406 // 250kHz | 1 2 3 4 5 6 00407 // 500kHz | 0 1 2 3 4 5 00408 // 00409 // Times for half symbol per DR 00410 // Per DR table to minimize rounding errors 00411 static const ostime_t DR2HSYM_osticks[] = { 00412 #if defined(CFG_eu868) 00413 #define dr2hsym(dr) (DR2HSYM_osticks[(dr)]) 00414 us2osticksRound(128<<7), // DR_SF12 00415 us2osticksRound(128<<6), // DR_SF11 00416 us2osticksRound(128<<5), // DR_SF10 00417 us2osticksRound(128<<4), // DR_SF9 00418 us2osticksRound(128<<3), // DR_SF8 00419 us2osticksRound(128<<2), // DR_SF7 00420 us2osticksRound(128<<1), // DR_SF7B 00421 us2osticksRound(80) // FSK -- not used (time for 1/2 byte) 00422 #elif defined(CFG_us915) 00423 #define dr2hsym(dr) (DR2HSYM_osticks[(dr)&7]) // map DR_SFnCR -> 0-6 00424 us2osticksRound(128<<5), // DR_SF10 DR_SF12CR 00425 us2osticksRound(128<<4), // DR_SF9 DR_SF11CR 00426 us2osticksRound(128<<3), // DR_SF8 DR_SF10CR 00427 us2osticksRound(128<<2), // DR_SF7 DR_SF9CR 00428 us2osticksRound(128<<1), // DR_SF8C DR_SF8CR 00429 us2osticksRound(128<<0) // ------ DR_SF7CR 00430 #endif 00431 }; 00432 00433 00434 static ostime_t calcRxWindow (u1_t secs, dr_t dr) 00435 { 00436 debug("LMIC calcRxWindow enter\r\n"); 00437 ostime_t rxoff, err; 00438 if( secs==0 ) { 00439 // aka 128 secs (next becaon) 00440 rxoff = LMIC.drift; 00441 err = LMIC.lastDriftDiff; 00442 } else { 00443 // scheduled RX window within secs into current beacon period 00444 rxoff = (LMIC.drift * (ostime_t)secs) >> BCN_INTV_exp; 00445 err = (LMIC.lastDriftDiff * (ostime_t)secs) >> BCN_INTV_exp; 00446 } 00447 u1_t rxsyms = MINRX_SYMS; 00448 err += (ostime_t)LMIC.maxDriftDiff * LMIC.missedBcns; 00449 LMIC.rxsyms = MINRX_SYMS + (err / dr2hsym(dr)); 00450 00451 return (rxsyms-PAMBL_SYMS) * dr2hsym(dr) + rxoff; 00452 } 00453 00454 00455 // Setup beacon RX parameters assuming we have an error of ms (aka +/-(ms/2)) 00456 static void calcBcnRxWindowFromMillis (u1_t ms, bit_t ini) 00457 { 00458 debug("LMIC calcBcnRxWindowFromMillis enter\r\n"); 00459 if( ini ) { 00460 LMIC.drift = 0; 00461 LMIC.maxDriftDiff = 0; 00462 LMIC.missedBcns = 0; 00463 LMIC.bcninfo.flags |= BCN_NODRIFT|BCN_NODDIFF; 00464 } 00465 ostime_t hsym = dr2hsym(DR_BCN); 00466 LMIC.bcnRxsyms = MINRX_SYMS + ms2osticksCeil(ms) / hsym; 00467 LMIC.bcnRxtime = LMIC.bcninfo.txtime + BCN_INTV_osticks - (LMIC.bcnRxsyms-PAMBL_SYMS) * hsym; 00468 } 00469 00470 00471 // Setup scheduled RX window (ping/multicast slot) 00472 static void rxschedInit (xref2rxsched_t rxsched) 00473 { 00474 debug("LMIC rxschedInit enter\r\n"); 00475 os_clearMem(AESkey,16); 00476 os_clearMem(LMIC.frame+8,8); 00477 os_wlsbf4(LMIC.frame, LMIC.bcninfo.time); 00478 os_wlsbf4(LMIC.frame+4, LMIC.devaddr); 00479 os_aes(AES_ENC,LMIC.frame,16); 00480 u1_t intvExp = rxsched->intvExp; 00481 ostime_t off = os_rlsbf2(LMIC.frame) & (0x0FFF >> (7 - intvExp)); // random offset (slot units) 00482 rxsched->rxbase = (LMIC.bcninfo.txtime + 00483 BCN_RESERVE_osticks + 00484 ms2osticks(BCN_SLOT_SPAN_ms * off)); // random offset osticks 00485 rxsched->slot = 0; 00486 rxsched->rxtime = rxsched->rxbase - calcRxWindow(/*secs BCN_RESERVE*/2+(1<<intvExp),rxsched->dr); 00487 rxsched->rxsyms = LMIC.rxsyms; 00488 } 00489 00490 00491 static bit_t rxschedNext (xref2rxsched_t rxsched, ostime_t cando) 00492 { 00493 debug("LMIC rxschedNext enter\r\n"); 00494 again: 00495 if( rxsched->rxtime - cando >= 0 ) 00496 return 1; 00497 u1_t slot; 00498 if( (slot=rxsched->slot) >= 128 ) 00499 return 0; 00500 u1_t intv = 1<<rxsched->intvExp; 00501 if( (rxsched->slot = (slot += (intv))) >= 128 ) 00502 return 0; 00503 rxsched->rxtime = rxsched->rxbase 00504 + ((BCN_WINDOW_osticks * (ostime_t)slot) >> BCN_INTV_exp) 00505 - calcRxWindow(/*secs BCN_RESERVE*/2+slot+intv,rxsched->dr); 00506 rxsched->rxsyms = LMIC.rxsyms; 00507 goto again; 00508 } 00509 00510 00511 static ostime_t rndDelay (u1_t secSpan) 00512 { 00513 debug("LMIC rndDelay enter\r\n"); 00514 u2_t r = os_getRndU2(); 00515 ostime_t delay = r; 00516 if( delay > OSTICKS_PER_SEC ) 00517 delay = r % (u2_t)OSTICKS_PER_SEC; 00518 if( secSpan > 0 ) 00519 delay += ((u1_t)r % secSpan) * OSTICKS_PER_SEC; 00520 return delay; 00521 } 00522 00523 00524 static void txDelay (ostime_t reftime, u1_t secSpan) 00525 { 00526 debug("LMIC txDelay enter\r\n"); 00527 reftime += rndDelay(secSpan); 00528 if( LMIC.globalDutyRate == 0 || (reftime - LMIC.globalDutyAvail) > 0 ) { 00529 LMIC.globalDutyAvail = reftime; 00530 LMIC.opmode |= OP_RNDTX; 00531 } 00532 } 00533 00534 00535 static void setDrJoin (u1_t reason, u1_t dr) 00536 { 00537 debug("LMIC setDrJoin enter\r\n"); 00538 EV(drChange, INFO, (e_.reason = reason, 00539 e_.deveui = MAIN::CDEV->getEui(), 00540 e_.dr = dr|DR_PAGE, 00541 e_.txpow = LMIC.adrTxPow, 00542 e_.prevdr = LMIC.datarate|DR_PAGE, 00543 e_.prevtxpow = LMIC.adrTxPow)); 00544 LMIC.datarate = dr; 00545 DO_DEVDB(LMIC.datarate,datarate); 00546 } 00547 00548 00549 static void setDrTxpow (u1_t reason, u1_t dr, s1_t pow) 00550 { 00551 debug("LMIC setDrTxpow enter\r\n"); 00552 EV(drChange, INFO, (e_.reason = reason, 00553 e_.deveui = MAIN::CDEV->getEui(), 00554 e_.dr = dr|DR_PAGE, 00555 e_.txpow = pow, 00556 e_.prevdr = LMIC.datarate|DR_PAGE, 00557 e_.prevtxpow = LMIC.adrTxPow)); 00558 00559 if( pow != KEEP_TXPOW ) { 00560 LMIC.adrTxPow = pow; 00561 if (pow < LMIC.txpow_limit) 00562 LMIC.txpow = pow; 00563 } 00564 if( LMIC.datarate != dr ) { 00565 LMIC.datarate = dr; 00566 DO_DEVDB(LMIC.datarate,datarate); 00567 LMIC.opmode |= OP_NEXTCHNL; 00568 } 00569 } 00570 00571 00572 void LMIC_stopPingable (void) 00573 { 00574 debug("LMIC LMIC_stopPingable enter\r\n"); 00575 LMIC.opmode &= ~(OP_PINGABLE|OP_PINGINI); 00576 } 00577 00578 00579 void LMIC_setPingable (u1_t intvExp) 00580 { 00581 debug("LMIC LMIC_setPingable enter\r\n"); 00582 // Change setting 00583 LMIC.ping.intvExp = (intvExp & 0x7); 00584 LMIC.opmode |= OP_PINGABLE; 00585 // App may call LMIC_enableTracking() explicitely before 00586 // Otherwise tracking is implicitly enabled here 00587 if( (LMIC.opmode & (OP_TRACK|OP_SCAN)) == 0 && LMIC.bcninfoTries == 0 ) 00588 LMIC_enableTracking(0); 00589 } 00590 00591 00592 #if defined(CFG_eu868) 00593 // ================================================================================ 00594 // 00595 // BEG: EU868 related stuff 00596 // 00597 enum { NUM_DEFAULT_CHANNELS=6 }; 00598 static const u4_t iniChannelFreq[12] = { 00599 // Join frequencies and duty cycle limit (0.1%) 00600 EU868_F1|BAND_MILLI, EU868_J4|BAND_MILLI, 00601 EU868_F2|BAND_MILLI, EU868_J5|BAND_MILLI, 00602 EU868_F3|BAND_MILLI, EU868_J6|BAND_MILLI, 00603 // Default operational frequencies 00604 EU868_F1|BAND_CENTI, EU868_F2|BAND_CENTI, EU868_F3|BAND_CENTI, 00605 EU868_F4|BAND_MILLI, EU868_F5|BAND_MILLI, EU868_F6|BAND_DECI 00606 }; 00607 00608 static void initDefaultChannels (bit_t join) { 00609 os_clearMem(&LMIC.channelFreq, sizeof(LMIC.channelFreq)); 00610 os_clearMem(&LMIC.channelDrMap, sizeof(LMIC.channelDrMap)); 00611 os_clearMem(&LMIC.bands, sizeof(LMIC.bands)); 00612 00613 LMIC.channelMap = 0x3; 00614 u1_t su = join ? 0 : 6; 00615 for( u1_t fu=0; fu<6; fu++,su++ ) { 00616 LMIC.channelFreq[fu] = iniChannelFreq[su]; 00617 LMIC.channelDrMap[fu] = DR_RANGE_MAP(DR_SF12,DR_SF7); 00618 } 00619 if( !join ) { 00620 LMIC.channelDrMap[5] = DR_RANGE_MAP(DR_SF12,DR_SF7); 00621 LMIC.channelDrMap[1] = DR_RANGE_MAP(DR_SF12,DR_FSK); 00622 } 00623 00624 LMIC.bands[BAND_MILLI].txcap = 1000; // 0.1% 00625 LMIC.bands[BAND_MILLI].txpow = 14; 00626 LMIC.bands[BAND_MILLI].lastchnl = os_getRndU1() % MAX_CHANNELS; 00627 LMIC.bands[BAND_CENTI].txcap = 100; // 1% 00628 LMIC.bands[BAND_CENTI].txpow = 14; 00629 LMIC.bands[BAND_CENTI].lastchnl = os_getRndU1() % MAX_CHANNELS; 00630 LMIC.bands[BAND_DECI ].txcap = 10; // 10% 00631 LMIC.bands[BAND_DECI ].txpow = 27; 00632 LMIC.bands[BAND_CENTI].lastchnl = os_getRndU1() % MAX_CHANNELS; 00633 LMIC.bands[BAND_MILLI].avail = 00634 LMIC.bands[BAND_CENTI].avail = 00635 LMIC.bands[BAND_DECI ].avail = os_getTime(); 00636 } 00637 00638 bit_t LMIC_setupBand (u1_t bandidx, s1_t txpow, u2_t txcap) { 00639 if( bandidx > BAND_AUX ) return 0; 00640 band_t* b = &LMIC.bands[bandidx]; 00641 b->txpow = txpow; 00642 b->txcap = txcap; 00643 b->avail = os_getTime(); 00644 b->lastchnl = os_getRndU1() % MAX_CHANNELS; 00645 return 1; 00646 } 00647 00648 bit_t LMIC_setupChannel (u1_t chidx, u4_t freq, u2_t drmap, s1_t band) { 00649 if( chidx >= MAX_CHANNELS ) 00650 return 0; 00651 if( band == -1 ) { 00652 if( freq >= 869400000 && freq <= 869650000 ) 00653 freq |= BAND_DECI; // 10% 27dBm 00654 else if( (freq >= 868000000 && freq <= 868600000) || 00655 (freq >= 869700000 && freq <= 870000000) ) 00656 freq |= BAND_CENTI; // 1% 14dBm 00657 else 00658 freq |= BAND_MILLI; // 0.1% 14dBm 00659 } else { 00660 if( band > BAND_AUX ) return 0; 00661 freq = (freq&~3) | band; 00662 } 00663 LMIC.channelFreq [chidx] = freq; 00664 LMIC.channelDrMap[chidx] = drmap==0 ? DR_RANGE_MAP(DR_SF12,DR_SF7) : drmap; 00665 LMIC.channelMap |= 1<<chidx; // enabled right away 00666 return 1; 00667 } 00668 00669 void LMIC_disableChannel (u1_t channel) { 00670 LMIC.channelFreq[channel] = 0; 00671 LMIC.channelDrMap[channel] = 0; 00672 LMIC.channelMap &= ~(1<<channel); 00673 } 00674 00675 static u4_t convFreq (xref2u1_t ptr) { 00676 u4_t freq = (os_rlsbf4(ptr-1) >> 8) * 100; 00677 if( freq < EU868_FREQ_MIN || freq > EU868_FREQ_MAX ) 00678 freq = 0; 00679 return freq; 00680 } 00681 00682 static u1_t mapChannels (u1_t chpage, u2_t chmap) { 00683 // Bad page, disable all channel, enable non-existent 00684 if( chpage != 0 || chmap==0 || (chmap & ~LMIC.channelMap) != 0 ) 00685 return 0; // illegal input 00686 for( u1_t chnl=0; chnl<MAX_CHANNELS; chnl++ ) { 00687 if( (chmap & (1<<chnl)) != 0 && LMIC.channelFreq[chnl] == 0 ) 00688 chmap &= ~(1<<chnl); // ignore - channel is not defined 00689 } 00690 LMIC.channelMap = chmap; 00691 return 1; 00692 } 00693 00694 00695 static void updateTx (ostime_t txbeg) { 00696 u4_t freq = LMIC.channelFreq[LMIC.txChnl]; 00697 // Update global/band specific duty cycle stats 00698 ostime_t airtime = calcAirTime(LMIC.rps, LMIC.dataLen); 00699 // Update channel/global duty cycle stats 00700 xref2band_t band = &LMIC.bands[freq & 0x3]; 00701 LMIC.freq = freq & ~(u4_t)3; 00702 LMIC.txpow = band->txpow; 00703 band->avail = txbeg + airtime * band->txcap; 00704 if( LMIC.globalDutyRate != 0 ) 00705 LMIC.globalDutyAvail = txbeg + (airtime<<LMIC.globalDutyRate); 00706 } 00707 00708 static ostime_t nextTx (ostime_t now) { 00709 u1_t bmap=0xF; 00710 do { 00711 ostime_t mintime = now + /*10h*/36000*OSTICKS_PER_SEC; 00712 u1_t band=0; 00713 for( u1_t bi=0; bi<4; bi++ ) { 00714 if( (bmap & (1<<bi)) && mintime - LMIC.bands[bi].avail > 0 ) 00715 mintime = LMIC.bands[band = bi].avail; 00716 } 00717 // Find next channel in given band 00718 u1_t chnl = LMIC.bands[band].lastchnl; 00719 for( u1_t ci=0; ci<MAX_CHANNELS; ci++ ) { 00720 if( (chnl = (chnl+1)) >= MAX_CHANNELS ) 00721 chnl -= MAX_CHANNELS; 00722 if( (LMIC.channelMap & (1<<chnl)) != 0 && // channel enabled 00723 (LMIC.channelDrMap[chnl] & (1<<(LMIC.datarate&0xF))) != 0 && 00724 band == (LMIC.channelFreq[chnl] & 0x3) ) { // in selected band 00725 LMIC.txChnl = LMIC.bands[band].lastchnl = chnl; 00726 return mintime; 00727 } 00728 } 00729 if( (bmap &= ~(1<<band)) == 0 ) { 00730 // No feasible channel found! 00731 return mintime; 00732 } 00733 } while(1); 00734 } 00735 00736 00737 static void setBcnRxParams (void) { 00738 LMIC.dataLen = 0; 00739 LMIC.freq = LMIC.channelFreq[LMIC.bcnChnl] & ~(u4_t)3; 00740 LMIC.rps = setIh(setNocrc(dndr2rps((dr_t)DR_BCN),1),LEN_BCN); 00741 } 00742 00743 #define setRx1Params() /*LMIC.freq/rps remain unchanged*/ 00744 00745 static void initJoinLoop (void) { // eu868 00746 LMIC.txChnl = os_getRndU1() % 6; 00747 LMIC.adrTxPow = 14; 00748 setDrJoin(DRCHG_SET, DR_SF7); 00749 initDefaultChannels(1); 00750 ASSERT((LMIC.opmode & OP_NEXTCHNL)==0); 00751 LMIC.txend = LMIC.bands[BAND_MILLI].avail + rndDelay(8); 00752 } 00753 00754 static ostime_t nextJoinState (void) { 00755 u1_t failed = 0; 00756 00757 // Try 869.x and then 864.x with same DR 00758 // If both fail try next lower datarate 00759 if( ++LMIC.txChnl == 6 ) 00760 LMIC.txChnl = 0; 00761 if( (++LMIC.txCnt & 1) == 0 ) { 00762 // Lower DR every 2nd try (having tried 868.x and 864.x with the same DR) 00763 if( LMIC.datarate == DR_SF12 ) 00764 failed = 1; // we have tried all DR - signal EV_JOIN_FAILED 00765 else 00766 setDrJoin(DRCHG_NOJACC, decDR((dr_t)LMIC.datarate)); 00767 } 00768 // Clear NEXTCHNL because join state engine controls channel hopping 00769 LMIC.opmode &= ~OP_NEXTCHNL; 00770 // Move txend to randomize synchronized concurrent joins. 00771 // Duty cycle is based on txend. 00772 ostime_t time = os_getTime(); 00773 if( time - LMIC.bands[BAND_MILLI].avail < 0 ) 00774 time = LMIC.bands[BAND_MILLI].avail; 00775 LMIC.txend = time + 00776 (isTESTMODE() 00777 // Avoid collision with JOIN ACCEPT @ SF12 being sent by GW (but we missed it) 00778 ? DNW2_SAFETY_ZONE 00779 // Otherwise: randomize join (street lamp case): 00780 // SF12:255, SF11:127, .., SF7:8secs 00781 : DNW2_SAFETY_ZONE+rndDelay(255>>LMIC.datarate)); 00782 // 1 - triggers EV_JOIN_FAILED event 00783 return failed; 00784 } 00785 00786 // 00787 // END: EU868 related stuff 00788 // 00789 // ================================================================================ 00790 #elif defined(CFG_us915) 00791 // ================================================================================ 00792 // 00793 // BEG: US915 related stuff 00794 // 00795 00796 static void initDefaultChannels (void) 00797 { 00798 debug("LMIC initDefaultChannels enter\r\n"); 00799 #ifdef CHNL_HYBRID 00800 int idx = CHNL_HYBRID >> 1; 00801 LMIC.channelMap[0] = 0x0000; 00802 LMIC.channelMap[1] = 0x0000; 00803 LMIC.channelMap[2] = 0x0000; 00804 LMIC.channelMap[3] = 0x0000; 00805 if (CHNL_HYBRID & 1) 00806 LMIC.channelMap[idx] = 0xff00; 00807 else 00808 LMIC.channelMap[idx] = 0x00ff; 00809 00810 LMIC.channelMap[4] = 1 << CHNL_HYBRID; 00811 LMIC.txpow_limit = 20; 00812 #else 00813 for( u1_t i=0; i<4; i++ ) 00814 LMIC.channelMap[i] = 0xFFFF; 00815 LMIC.channelMap[4] = 0x00FF; 00816 00817 LMIC.txpow_limit = 30; 00818 #endif 00819 00820 LMIC.txpow = LMIC.txpow_limit; 00821 LMIC.adrTxPow = LMIC.txpow_limit; 00822 } 00823 00824 static u4_t convFreq (xref2u1_t ptr) 00825 { 00826 debug("LMIC convFreq enter\r\n"); 00827 u4_t freq = (os_rlsbf4(ptr-1) >> 8) * 100; 00828 if( freq < US915_FREQ_MIN || freq > US915_FREQ_MAX ) 00829 freq = 0; 00830 return freq; 00831 } 00832 00833 00834 bit_t LMIC_setupChannel (u1_t chidx, u4_t freq, u2_t drmap, s1_t band) 00835 { 00836 debug("LMIC LMIC_setupChannel enter\r\n"); 00837 if( chidx < 72 || chidx >= 72+MAX_XCHANNELS ) 00838 return 0; // channels 0..71 are hardwired 00839 chidx -= 72; 00840 LMIC.xchFreq[chidx] = freq; 00841 LMIC.xchDrMap[chidx] = drmap==0 ? DR_RANGE_MAP(DR_SF10,DR_SF8C) : drmap; 00842 LMIC.channelMap[chidx>>4] |= (1<<(chidx&0xF)); 00843 return 1; 00844 } 00845 00846 void LMIC_disableChannel (u1_t channel) 00847 { 00848 debug("LMIC_disableChannel enter\r\n"); 00849 if( channel < 72+MAX_XCHANNELS ) 00850 LMIC.channelMap[channel/4] &= ~(1<<(channel&0xF)); 00851 } 00852 00853 static u1_t mapChannels (u1_t chpage, u2_t chmap) 00854 { 00855 debug("LMIC mapChannels enter\r\n"); 00856 if( chpage == MCMD_LADR_CHP_125ON || chpage == MCMD_LADR_CHP_125OFF ) 00857 { 00858 u2_t en125 = chpage == MCMD_LADR_CHP_125ON ? 0xFFFF : 0x0000; 00859 for( u1_t u=0; u<4; u++ ) 00860 LMIC.channelMap[u] = en125; 00861 LMIC.channelMap[64/16] = chmap; 00862 } else { 00863 if( chpage >= (72+MAX_XCHANNELS+15)/16 ) 00864 return 0; 00865 LMIC.channelMap[chpage] = chmap; 00866 } 00867 return 1; 00868 } 00869 00870 static void updateTx (ostime_t txbeg) 00871 { 00872 debug("LMIC updateTx enter\r\n"); 00873 u1_t chnl = LMIC.txChnl; 00874 #ifdef JOIN_REQ_DEBUG 00875 printf("chnl%d ", chnl); 00876 #endif /* JOIN_REQ_DEBUG */ 00877 if( chnl < 64 ) { 00878 LMIC.freq = US915_125kHz_UPFBASE + chnl*US915_125kHz_UPFSTEP; 00879 00880 if (LMIC.opmode & OP_JOINING) { 00881 /* use max allowed power for joining */ 00882 if (LMIC.txpow < LMIC.txpow_limit) 00883 LMIC.txpow = LMIC.txpow_limit; 00884 } 00885 00886 #ifdef JOIN_REQ_DEBUG 00887 printf("%d (125khz)\r\n", LMIC.freq); 00888 #endif /* JOIN_REQ_DEBUG */ 00889 return; 00890 } 00891 00892 /* using 500KHz channel */ 00893 if (LMIC.txpow_limit >= 26) 00894 LMIC.txpow = 26; 00895 else 00896 LMIC.txpow = LMIC.txpow_limit; 00897 00898 if( chnl < 64+8 ) { 00899 LMIC.freq = US915_500kHz_UPFBASE + (chnl-64)*US915_500kHz_UPFSTEP; 00900 #ifdef JOIN_REQ_DEBUG 00901 printf("%d (500k)\r\n", LMIC.freq); 00902 #endif /* JOIN_REQ_DEBUG */ 00903 } else { 00904 ASSERT(chnl < 64+8+MAX_XCHANNELS); 00905 LMIC.freq = LMIC.xchFreq[chnl-72]; 00906 #ifdef JOIN_REQ_DEBUG 00907 printf("%d (x)\r\n", LMIC.freq); 00908 #endif /* JOIN_REQ_DEBUG */ 00909 } 00910 00911 // Update global duty cycle stats 00912 if( LMIC.globalDutyRate != 0 ) { 00913 ostime_t airtime = calcAirTime(LMIC.rps, LMIC.dataLen); 00914 LMIC.globalDutyAvail = txbeg + (airtime<<LMIC.globalDutyRate); 00915 } 00916 } 00917 00918 int count_bits(u2_t v) 00919 { 00920 int c; 00921 00922 for (c = 0; v; c++) { 00923 v &= v - 1; // clear the last significant bit set 00924 } 00925 00926 return c; 00927 } 00928 00929 // US does not have duty cycling - return now as earliest TX time 00930 #define nextTx(now) (_nextTx(),(now)) 00931 static void _nextTx (void) 00932 { 00933 debug("LMIC _nextTx enter\r\n"); 00934 u1_t prev_ch = LMIC.txChnl; 00935 u1_t tries = 0; 00936 u1_t en_cnt; 00937 00938 if( LMIC.datarate >= DR_SF8C ) { // 500kHz 00939 #ifdef CHNL_HYBRID 00940 LMIC.txChnl = 1 << CHNL_HYBRID; // only one channel possible 00941 #else 00942 en_cnt = count_bits(LMIC.channelMap[4]); 00943 do { 00944 do { 00945 LMIC.chRnd = os_getRndU1() & 7; 00946 if (++tries > 48) 00947 return; 00948 } while ( !(LMIC.channelMap[4] & (1 << LMIC.chRnd)) ); 00949 LMIC.txChnl = 64 + LMIC.chRnd; 00950 if (en_cnt < 2) 00951 prev_ch = LMIC.txChnl + 1; // not enough enabled, skip the following test 00952 00953 } while (prev_ch == LMIC.txChnl); 00954 #endif 00955 } else { // 125kHz 00956 #ifdef CHNL_HYBRID 00957 u1_t idx = CHNL_HYBRID >> 1; 00958 en_cnt = count_bits(LMIC.channelMap[idx]); 00959 do { 00960 do { 00961 LMIC.chRnd = os_getRndU1() & 15; 00962 if (++tries > 96) 00963 return; 00964 } while ( !(LMIC.channelMap[idx] & (1 << LMIC.chRnd)) ); 00965 LMIC.txChnl = (idx << 4) + LMIC.chRnd; 00966 if (en_cnt < 2) 00967 prev_ch = LMIC.txChnl + 1; // not enough enabled, skip the following test 00968 00969 } while (prev_ch == LMIC.txChnl); 00970 #else 00971 en_cnt = count_bits(LMIC.channelMap[0]); 00972 en_cnt += count_bits(LMIC.channelMap[1]); 00973 en_cnt += count_bits(LMIC.channelMap[2]); 00974 en_cnt += count_bits(LMIC.channelMap[3]); 00975 do { 00976 do { 00977 LMIC.chRnd = os_getRndU1() & 63; 00978 } while ( !(LMIC.channelMap[LMIC.chRnd >> 4] & (1 << (LMIC.chRnd & 15))) ); 00979 LMIC.txChnl = LMIC.chRnd; 00980 if (en_cnt < 2) 00981 prev_ch = LMIC.txChnl + 1; // not enough enabled, skip the following test 00982 00983 } while (prev_ch == LMIC.txChnl); 00984 #endif 00985 } 00986 } 00987 00988 static void setBcnRxParams (void) { 00989 LMIC.dataLen = 0; 00990 LMIC.freq = US915_500kHz_DNFBASE + LMIC.bcnChnl * US915_500kHz_DNFSTEP; 00991 LMIC.rps = setIh(setNocrc(dndr2rps((dr_t)DR_BCN),1),LEN_BCN); 00992 } 00993 00994 #define setRx1Params() { \ 00995 LMIC.freq = US915_500kHz_DNFBASE + (LMIC.txChnl & 0x7) * US915_500kHz_DNFSTEP; \ 00996 if( /* TX datarate */LMIC.dndr < DR_SF8C ) \ 00997 LMIC.dndr += DR_SF10CR - DR_SF10; \ 00998 else if( LMIC.dndr == DR_SF8C ) \ 00999 LMIC.dndr = DR_SF7CR; \ 01000 LMIC.rps = dndr2rps(LMIC.dndr); \ 01001 } 01002 01003 static void initJoinLoop (void) 01004 { 01005 debug("LMIC initJoinLoop enter\r\n"); 01006 LMIC.chRnd = 0; 01007 #ifdef CHNL_HYBRID 01008 LMIC.joinBlockChnl = 0; 01009 LMIC.joinBlock = CHNL_HYBRID; 01010 LMIC.txChnl = LMIC.joinBlock << 3; 01011 #else 01012 LMIC.txChnl = 0; 01013 LMIC.joinBlockChnl = 0; 01014 LMIC.joinBlock = 0; 01015 #endif 01016 LMIC.datarate = DR_SF10; 01017 LMIC.adrTxPow = LMIC.txpow_limit; 01018 ASSERT((LMIC.opmode & OP_NEXTCHNL)==0); 01019 LMIC.txend = os_getTime(); 01020 setDrJoin(DRCHG_SET, DR_SF7); 01021 } 01022 01023 static ostime_t nextJoinState (void) 01024 { 01025 debug("LMIC nextJoinState enter\r\n"); 01026 u1_t failed = 0; 01027 01028 if( LMIC.datarate == DR_SF8C ) { 01029 // attempted 500khz channel, try 125khz channel in next block 01030 LMIC.datarate = DR_SF10; 01031 if (++LMIC.joinBlock == 8) { 01032 LMIC.joinBlock = 0; 01033 if (++LMIC.joinBlockChnl == 8) 01034 LMIC.joinBlockChnl = 0; 01035 } 01036 LMIC.txChnl = (LMIC.joinBlock << 3) + LMIC.joinBlockChnl; 01037 } else { 01038 // attempted 125khz channel, try 500khz channel 01039 LMIC.datarate = DR_SF8C; 01040 LMIC.txChnl = LMIC.joinBlock + 64; 01041 } 01042 #ifdef JOIN_REQ_DEBUG 01043 printf("njs blk%d, dr%d, txChnl%d ", LMIC.joinBlock, LMIC.datarate, LMIC.txChnl); // crlf in updateTx() 01044 #endif /* JOIN_REQ_DEBUG */ 01045 01046 LMIC.opmode &= ~OP_NEXTCHNL; 01047 LMIC.txend = os_getTime() + 01048 (isTESTMODE() 01049 // Avoid collision with JOIN ACCEPT being sent by GW (but we missed it - GW is still busy) 01050 ? DNW2_SAFETY_ZONE 01051 // Otherwise: randomize join (street lamp case): 01052 // SF10:16, SF9=8,..SF8C:1secs 01053 : rndDelay(16>>LMIC.datarate)); 01054 // 1 - triggers EV_JOIN_FAILED event 01055 return failed; 01056 } 01057 01058 // 01059 // END: US915 related stuff 01060 // 01061 // ================================================================================ 01062 #else 01063 #error Unsupported frequency band! 01064 #endif 01065 01066 01067 static void runEngineUpdate (xref2osjob_t osjob) 01068 { 01069 debug("LMIC runEngineUpdate enter\r\n"); 01070 engineUpdate(); 01071 } 01072 01073 01074 static void reportEvent (ev_t ev) 01075 { 01076 debug("LMIC reportEvent enter %d\r\n",ev); 01077 EV(devCond, INFO, (e_.reason = EV::devCond_t::LMIC_EV, 01078 e_.eui = MAIN::CDEV->getEui(), 01079 e_.info = ev)); 01080 ON_LMIC_EVENT(ev); 01081 engineUpdate(); 01082 } 01083 01084 01085 static void runReset (xref2osjob_t osjob) 01086 { 01087 debug("LMIC runReset enterr\n"); 01088 // Disable session 01089 LMIC_reset(); 01090 LMIC_startJoining(); 01091 reportEvent(EV_RESET); 01092 } 01093 01094 static void stateJustJoined (void) 01095 { 01096 debug("LMIC stateJustJoined enter\r\n"); 01097 LMIC.seqnoDn = LMIC.seqnoUp = 0; 01098 LMIC.rejoinCnt = 0; 01099 LMIC.dnConf = LMIC.adrChanged = LMIC.ladrAns = LMIC.devsAns = 0; 01100 LMIC.moreData = LMIC.dn2Ans = LMIC.snchAns = LMIC.dutyCapAns = 0; 01101 LMIC.pingSetAns = 0; 01102 LMIC.upRepeat = 0; 01103 LMIC.adrAckReq = LINK_CHECK_INIT; 01104 LMIC.dn2Dr = DR_DNW2; 01105 LMIC.dn2Freq = FREQ_DNW2; 01106 LMIC.bcnChnl = CHNL_BCN; 01107 LMIC.ping.freq = FREQ_PING; 01108 LMIC.ping.dr = DR_PING; 01109 } 01110 01111 01112 // ================================================================================ 01113 // Decoding frames 01114 01115 01116 // Decode beacon - do not overwrite bcninfo unless we have a match! 01117 static int decodeBeacon (void) 01118 { 01119 debug("LMIC decodeBeacon enter\r\n"); 01120 ASSERT(LMIC.dataLen == LEN_BCN); // implicit header RX guarantees this 01121 xref2u1_t d = LMIC.frame; 01122 if( 01123 #ifdef CFG_eu868 01124 d[OFF_BCN_CRC1] != (u1_t)os_crc16(d,OFF_BCN_CRC1) 01125 #elif defined(CFG_us915) 01126 os_rlsbf2(&d[OFF_BCN_CRC1]) != os_crc16(d,OFF_BCN_CRC1) 01127 #endif 01128 ) 01129 return 0; // first (common) part fails CRC check 01130 // First set of fields is ok 01131 u4_t bcnnetid = os_rlsbf4(&d[OFF_BCN_NETID]) & 0xFFFFFF; 01132 if( bcnnetid != LMIC.netid ) 01133 return -1; // not the beacon we're looking for 01134 01135 LMIC.bcninfo.flags &= ~(BCN_PARTIAL|BCN_FULL); 01136 // Match - update bcninfo structure 01137 LMIC.bcninfo.snr = LMIC.snr; 01138 LMIC.bcninfo.rssi = LMIC.rssi; 01139 LMIC.bcninfo.txtime = LMIC.rxtime - AIRTIME_BCN_osticks; 01140 LMIC.bcninfo.time = os_rlsbf4(&d[OFF_BCN_TIME]); 01141 LMIC.bcninfo.flags |= BCN_PARTIAL; 01142 01143 // Check 2nd set 01144 if( os_rlsbf2(&d[OFF_BCN_CRC2]) != os_crc16(d,OFF_BCN_CRC2) ) 01145 return 1; 01146 // Second set of fields is ok 01147 LMIC.bcninfo.lat = (s4_t)os_rlsbf4(&d[OFF_BCN_LAT-1]) >> 8; // read as signed 24-bit 01148 LMIC.bcninfo.lon = (s4_t)os_rlsbf4(&d[OFF_BCN_LON-1]) >> 8; // ditto 01149 LMIC.bcninfo.info = d[OFF_BCN_INFO]; 01150 LMIC.bcninfo.flags |= BCN_FULL; 01151 return 2; 01152 } 01153 01154 01155 static bit_t decodeFrame (void) 01156 { 01157 debug("LMIC decodeFrame enter\r\n"); 01158 xref2u1_t d = LMIC.frame; 01159 u1_t hdr = d[0]; 01160 u1_t ftype = hdr & HDR_FTYPE; 01161 int dlen = LMIC.dataLen; 01162 if( dlen < OFF_DAT_OPTS+4 || 01163 (hdr & HDR_MAJOR) != HDR_MAJOR_V1 || 01164 (ftype != HDR_FTYPE_DADN && ftype != HDR_FTYPE_DCDN) ) { 01165 // Basic sanity checks failed 01166 EV(specCond, WARN, (e_.reason = EV::specCond_t::UNEXPECTED_FRAME, 01167 e_.eui = MAIN::CDEV->getEui(), 01168 e_.info = dlen < 4 ? 0 : os_rlsbf4(&d[dlen-4]), 01169 e_.info2 = hdr + (dlen<<8))); 01170 norx: 01171 LMIC.dataLen = 0; 01172 return 0; 01173 } 01174 // Validate exact frame length 01175 // Note: device address was already read+evaluated in order to arrive here. 01176 int fct = d[OFF_DAT_FCT]; 01177 u4_t addr = os_rlsbf4(&d[OFF_DAT_ADDR]); 01178 u4_t seqno = os_rlsbf2(&d[OFF_DAT_SEQNO]); 01179 int olen = fct & FCT_OPTLEN; 01180 int ackup = (fct & FCT_ACK) != 0 ? 1 : 0; // ACK last up frame 01181 int poff = OFF_DAT_OPTS+olen; 01182 int pend = dlen-4; // MIC 01183 01184 if( addr != LMIC.devaddr ) { 01185 EV(specCond, WARN, (e_.reason = EV::specCond_t::ALIEN_ADDRESS, 01186 e_.eui = MAIN::CDEV->getEui(), 01187 e_.info = addr, 01188 e_.info2 = LMIC.devaddr)); 01189 goto norx; 01190 } 01191 if( poff > pend ) { 01192 EV(specCond, ERR, (e_.reason = EV::specCond_t::CORRUPTED_FRAME, 01193 e_.eui = MAIN::CDEV->getEui(), 01194 e_.info = 0x1000000 + (poff-pend) + (fct<<8) + (dlen<<16))); 01195 goto norx; 01196 } 01197 01198 int port = -1; 01199 int replayConf = 0; 01200 01201 if( pend > poff ) 01202 port = d[poff++]; 01203 01204 seqno = LMIC.seqnoDn + (u2_t)(seqno - LMIC.seqnoDn); 01205 01206 if( !aes_verifyMic(LMIC.nwkKey, LMIC.devaddr, seqno, /*dn*/1, d, pend) ) { 01207 EV(spe3Cond, ERR, (e_.reason = EV::spe3Cond_t::CORRUPTED_MIC, 01208 e_.eui1 = MAIN::CDEV->getEui(), 01209 e_.info1 = Base::lsbf4(&d[pend]), 01210 e_.info2 = seqno, 01211 e_.info3 = LMIC.devaddr)); 01212 goto norx; 01213 } 01214 if( seqno < LMIC.seqnoDn ) { 01215 if( (s4_t)seqno > (s4_t)LMIC.seqnoDn ) { 01216 EV(specCond, INFO, (e_.reason = EV::specCond_t::DNSEQNO_ROLL_OVER, 01217 e_.eui = MAIN::CDEV->getEui(), 01218 e_.info = LMIC.seqnoDn, 01219 e_.info2 = seqno)); 01220 goto norx; 01221 } 01222 if( seqno != LMIC.seqnoDn-1 || !LMIC.dnConf || ftype != HDR_FTYPE_DCDN ) { 01223 EV(specCond, INFO, (e_.reason = EV::specCond_t::DNSEQNO_OBSOLETE, 01224 e_.eui = MAIN::CDEV->getEui(), 01225 e_.info = LMIC.seqnoDn, 01226 e_.info2 = seqno)); 01227 goto norx; 01228 } 01229 // Replay of previous sequence number allowed only if 01230 // previous frame and repeated both requested confirmation 01231 replayConf = 1; 01232 } 01233 else { 01234 if( seqno > LMIC.seqnoDn ) { 01235 EV(specCond, INFO, (e_.reason = EV::specCond_t::DNSEQNO_SKIP, 01236 e_.eui = MAIN::CDEV->getEui(), 01237 e_.info = LMIC.seqnoDn, 01238 e_.info2 = seqno)); 01239 } 01240 LMIC.seqnoDn = seqno+1; // next number to be expected 01241 DO_DEVDB(LMIC.seqnoDn,seqnoDn); 01242 // DN frame requested confirmation - provide ACK once with next UP frame 01243 LMIC.dnConf = (ftype == HDR_FTYPE_DCDN ? FCT_ACK : 0); 01244 } 01245 01246 if( LMIC.dnConf || (fct & FCT_MORE) ) 01247 LMIC.opmode |= OP_POLL; 01248 01249 // We heard from network 01250 LMIC.adrChanged = LMIC.rejoinCnt = 0; 01251 if( LMIC.adrAckReq != LINK_CHECK_OFF ) 01252 LMIC.adrAckReq = LINK_CHECK_INIT; 01253 01254 // Process OPTS 01255 int m = LMIC.rssi - RSSI_OFF - getSensitivity(LMIC.rps); 01256 LMIC.margin = m < 0 ? 0 : m > 254 ? 254 : m; 01257 01258 xref2u1_t opts = &d[OFF_DAT_OPTS]; 01259 int oidx = 0; 01260 while( oidx < olen ) { 01261 switch( opts[oidx] ) { 01262 case MCMD_LCHK_ANS: { 01263 //int gwmargin = opts[oidx+1]; 01264 //int ngws = opts[oidx+2]; 01265 oidx += 3; 01266 continue; 01267 } 01268 case MCMD_LADR_REQ: { 01269 u1_t p1 = opts[oidx+1]; // txpow + DR 01270 u2_t chmap = os_rlsbf2(&opts[oidx+2]);// list of enabled channels 01271 u1_t chpage = opts[oidx+4] & MCMD_LADR_CHPAGE_MASK; // channel page 01272 u1_t uprpt = opts[oidx+4] & MCMD_LADR_REPEAT_MASK; // up repeat count 01273 oidx += 5; 01274 01275 LMIC.ladrAns = 0x80 | // Include an answer into next frame up 01276 MCMD_LADR_ANS_POWACK | MCMD_LADR_ANS_CHACK | MCMD_LADR_ANS_DRACK; 01277 if( !mapChannels(chpage, chmap) ) 01278 LMIC.ladrAns &= ~MCMD_LADR_ANS_CHACK; 01279 dr_t dr = (dr_t)(p1>>MCMD_LADR_DR_SHIFT); 01280 if( !validDR(dr) ) { 01281 LMIC.ladrAns &= ~MCMD_LADR_ANS_DRACK; 01282 EV(specCond, ERR, (e_.reason = EV::specCond_t::BAD_MAC_CMD, 01283 e_.eui = MAIN::CDEV->getEui(), 01284 e_.info = Base::lsbf4(&d[pend]), 01285 e_.info2 = Base::msbf4(&opts[oidx-4]))); 01286 } 01287 if( (LMIC.ladrAns & 0x7F) == (MCMD_LADR_ANS_POWACK | MCMD_LADR_ANS_CHACK | MCMD_LADR_ANS_DRACK) ) { 01288 // Nothing went wrong - use settings 01289 LMIC.upRepeat = uprpt; 01290 setDrTxpow(DRCHG_NWKCMD, dr, pow2dBm(p1)); 01291 } 01292 LMIC.adrChanged = 1; // Trigger an ACK to NWK 01293 continue; 01294 } 01295 case MCMD_DEVS_REQ: { 01296 LMIC.devsAns = 1; 01297 oidx += 1; 01298 continue; 01299 } 01300 case MCMD_DN2P_SET: { 01301 dr_t dr = (dr_t)(opts[oidx+1] & 0x0F); 01302 u4_t freq = convFreq(&opts[oidx+2]); 01303 oidx += 5; 01304 LMIC.dn2Ans = 0x80; // answer pending 01305 if( validDR(dr) ) 01306 LMIC.dn2Ans |= MCMD_DN2P_ANS_DRACK; 01307 if( freq != 0 ) 01308 LMIC.dn2Ans |= MCMD_DN2P_ANS_CHACK; 01309 if( LMIC.dn2Ans == (0x80|MCMD_DN2P_ANS_DRACK|MCMD_DN2P_ANS_CHACK) ) { 01310 LMIC.dn2Dr = dr; 01311 LMIC.dn2Freq = freq; 01312 DO_DEVDB(LMIC.dn2Dr,dn2Dr); 01313 DO_DEVDB(LMIC.dn2Freq,dn2Freq); 01314 } 01315 continue; 01316 } 01317 case MCMD_DCAP_REQ: { 01318 u1_t cap = opts[oidx+1]; 01319 oidx += 2; 01320 // A value cap=0xFF means device is OFF unless enabled again manually. 01321 if( cap==0xFF ) 01322 LMIC.opmode |= OP_SHUTDOWN; // stop any sending 01323 LMIC.globalDutyRate = cap & 0xF; 01324 LMIC.globalDutyAvail = os_getTime(); 01325 DO_DEVDB(cap,dutyCap); 01326 LMIC.dutyCapAns = 1; 01327 continue; 01328 } 01329 case MCMD_SNCH_REQ: { 01330 u1_t chidx = opts[oidx+1]; // channel 01331 u4_t freq = convFreq(&opts[oidx+2]); // freq 01332 u1_t drs = opts[oidx+5]; // datarate span 01333 LMIC.snchAns = 0x80; 01334 if( freq != 0 && LMIC_setupChannel(chidx, freq, DR_RANGE_MAP(drs&0xF,drs>>4), -1) ) 01335 LMIC.snchAns |= MCMD_SNCH_ANS_DRACK|MCMD_SNCH_ANS_FQACK; 01336 oidx += 6; 01337 continue; 01338 } 01339 case MCMD_PING_SET: { 01340 u4_t freq = convFreq(&opts[oidx+1]); 01341 oidx += 4; 01342 u1_t flags = 0x80; 01343 if( freq != 0 ) { 01344 flags |= MCMD_PING_ANS_FQACK; 01345 LMIC.ping.freq = freq; 01346 DO_DEVDB(LMIC.ping.intvExp, pingIntvExp); 01347 DO_DEVDB(LMIC.ping.freq, pingFreq); 01348 DO_DEVDB(LMIC.ping.dr, pingDr); 01349 } 01350 LMIC.pingSetAns = flags; 01351 continue; 01352 } 01353 case MCMD_BCNI_ANS: { 01354 // Ignore if tracking already enabled 01355 if( (LMIC.opmode & OP_TRACK) == 0 ) { 01356 LMIC.bcnChnl = opts[oidx+3]; 01357 // Enable tracking - bcninfoTries 01358 LMIC.opmode |= OP_TRACK; 01359 // Cleared later in txComplete handling - triggers EV_BEACON_FOUND 01360 ASSERT(LMIC.bcninfoTries!=0); 01361 // Setup RX parameters 01362 LMIC.bcninfo.txtime = (LMIC.rxtime 01363 + ms2osticks(os_rlsbf2(&opts[oidx+1]) * MCMD_BCNI_TUNIT) 01364 + ms2osticksCeil(MCMD_BCNI_TUNIT/2) 01365 - BCN_INTV_osticks); 01366 LMIC.bcninfo.flags = 0; // txtime above cannot be used as reference (BCN_PARTIAL|BCN_FULL cleared) 01367 calcBcnRxWindowFromMillis(MCMD_BCNI_TUNIT,1); // error of +/-N ms 01368 01369 EV(lostFrame, INFO, (e_.reason = EV::lostFrame_t::MCMD_BCNI_ANS, 01370 e_.eui = MAIN::CDEV->getEui(), 01371 e_.lostmic = Base::lsbf4(&d[pend]), 01372 e_.info = (LMIC.missedBcns | 01373 (osticks2us(LMIC.bcninfo.txtime + BCN_INTV_osticks 01374 - LMIC.bcnRxtime) << 8)), 01375 e_.time = MAIN::CDEV->ostime2ustime(LMIC.bcninfo.txtime + BCN_INTV_osticks))); 01376 } 01377 oidx += 4; 01378 continue; 01379 } 01380 } 01381 EV(specCond, ERR, (e_.reason = EV::specCond_t::BAD_MAC_CMD, 01382 e_.eui = MAIN::CDEV->getEui(), 01383 e_.info = Base::lsbf4(&d[pend]), 01384 e_.info2 = Base::msbf4(&opts[oidx]))); 01385 break; 01386 } 01387 if( oidx != olen ) { 01388 EV(specCond, ERR, (e_.reason = EV::specCond_t::CORRUPTED_FRAME, 01389 e_.eui = MAIN::CDEV->getEui(), 01390 e_.info = 0x1000000 + (oidx) + (olen<<8))); 01391 } 01392 01393 if( !replayConf ) { 01394 // Handle payload only if not a replay 01395 // Decrypt payload - if any 01396 if( port >= 0 && pend-poff > 0 ) 01397 aes_cipher(port <= 0 ? LMIC.nwkKey : LMIC.artKey, LMIC.devaddr, seqno, /*dn*/1, d+poff, pend-poff); 01398 01399 EV(dfinfo, DEBUG, (e_.deveui = MAIN::CDEV->getEui(), 01400 e_.devaddr = LMIC.devaddr, 01401 e_.seqno = seqno, 01402 e_.flags = (port < 0 ? EV::dfinfo_t::NOPORT : 0) | EV::dfinfo_t::DN, 01403 e_.mic = Base::lsbf4(&d[pend]), 01404 e_.hdr = d[LORA::OFF_DAT_HDR], 01405 e_.fct = d[LORA::OFF_DAT_FCT], 01406 e_.port = port, 01407 e_.plen = dlen, 01408 e_.opts.length = olen, 01409 memcpy(&e_.opts[0], opts, olen))); 01410 } else { 01411 EV(specCond, INFO, (e_.reason = EV::specCond_t::DNSEQNO_REPLAY, 01412 e_.eui = MAIN::CDEV->getEui(), 01413 e_.info = Base::lsbf4(&d[pend]), 01414 e_.info2 = seqno)); 01415 } 01416 01417 if( // NWK acks but we don't have a frame pending 01418 (ackup && LMIC.txCnt == 0) || 01419 // We sent up confirmed and we got a response in DNW1/DNW2 01420 // BUT it did not carry an ACK - this should never happen 01421 // Do not resend and assume frame was not ACKed. 01422 (!ackup && LMIC.txCnt != 0) ) { 01423 EV(specCond, ERR, (e_.reason = EV::specCond_t::SPURIOUS_ACK, 01424 e_.eui = MAIN::CDEV->getEui(), 01425 e_.info = seqno, 01426 e_.info2 = ackup)); 01427 } 01428 01429 if( LMIC.txCnt != 0 ) // we requested an ACK 01430 LMIC.txrxFlags |= ackup ? TXRX_ACK : TXRX_NACK; 01431 01432 if( port < 0 ) { 01433 LMIC.txrxFlags |= TXRX_NOPORT; 01434 LMIC.dataBeg = poff; 01435 LMIC.dataLen = 0; 01436 } else { 01437 LMIC.txrxFlags |= TXRX_PORT; 01438 LMIC.dataBeg = poff; 01439 LMIC.dataLen = pend-poff; 01440 } 01441 return 1; 01442 } 01443 01444 01445 // ================================================================================ 01446 // TX/RX transaction support 01447 01448 01449 static void setupRx2 (void) 01450 { 01451 debug("LMIC setupRx2 enter\r\n"); 01452 LMIC.txrxFlags = TXRX_DNW2; 01453 LMIC.rps = dndr2rps(LMIC.dn2Dr); 01454 LMIC.freq = LMIC.dn2Freq; 01455 LMIC.dataLen = 0; 01456 os_radio(RADIO_RX); 01457 } 01458 01459 01460 static void schedRx2 (ostime_t delay, osjobcb_t func) 01461 { 01462 debug("LMIC schedRx2 enter\r\n"); 01463 // Add 1.5 symbols we need 5 out of 8. Try to sync 1.5 symbols into the preamble. 01464 LMIC.rxtime = LMIC.txend + delay + (PAMBL_SYMS-MINRX_SYMS)*dr2hsym(LMIC.dn2Dr); 01465 // LMIC.rxtime = LMIC.txend + delay; 01466 os_setTimedCallback(&LMIC.osjob, LMIC.rxtime - RX_RAMPUP, func); 01467 } 01468 01469 static void setupRx1 (osjobcb_t func) 01470 { 01471 debug("LMIC setupRx1 enter\r\n"); 01472 LMIC.txrxFlags = TXRX_DNW1; 01473 // Turn LMIC.rps from TX over to RX 01474 LMIC.rps = setNocrc(LMIC.rps,1); 01475 LMIC.dataLen = 0; 01476 LMIC.osjob.func = func; 01477 os_radio(RADIO_RX); 01478 } 01479 01480 01481 // Called by HAL once TX complete and delivers exact end of TX time stamp in LMIC.rxtime 01482 static void txDone (ostime_t delay, osjobcb_t func) 01483 { 01484 debug("LMIC txDone enter\r\n"); 01485 if( (LMIC.opmode & (OP_TRACK|OP_PINGABLE|OP_PINGINI)) == (OP_TRACK|OP_PINGABLE) ) 01486 { 01487 rxschedInit(&LMIC.ping); // note: reuses LMIC.frame buffer! 01488 LMIC.opmode |= OP_PINGINI; 01489 } 01490 // Change RX frequency / rps (US only) before we increment txChnl 01491 setRx1Params(); 01492 // LMIC.rxsyms carries the TX datarate (can be != LMIC.datarate [confirm retries etc.]) 01493 // Setup receive - LMIC.rxtime is preloaded with 1.5 symbols offset to tune 01494 // into the middle of the 8 symbols preamble. 01495 #if defined(CFG_eu868) 01496 if( /* TX datarate */LMIC.rxsyms == DR_FSK ) 01497 { 01498 LMIC.rxtime = LMIC.txend + delay - PRERX_FSK*us2osticksRound(160); 01499 LMIC.rxsyms = RXLEN_FSK; 01500 } 01501 else 01502 #endif 01503 { 01504 LMIC.rxtime = LMIC.txend + delay + (PAMBL_SYMS-MINRX_SYMS)*dr2hsym(LMIC.dndr); 01505 // LMIC.rxtime = LMIC.txend + delay; 01506 LMIC.rxsyms = MINRX_SYMS; 01507 } 01508 os_setTimedCallback(&LMIC.osjob, LMIC.rxtime - RX_RAMPUP, func); 01509 } 01510 01511 01512 // ======================================== Join frames 01513 01514 01515 static void onJoinFailed (xref2osjob_t osjob) 01516 { 01517 debug("LMIC onJoinFailed enter\r\n"); 01518 // Notify app - must call LMIC_reset() to stop joining 01519 // otherwise join procedure continues. 01520 reportEvent(EV_JOIN_FAILED); 01521 } 01522 01523 01524 static bit_t processJoinAccept (void) 01525 { 01526 debug("LMIC processJoinAccept enter\r\n"); 01527 ASSERT(LMIC.txrxFlags != TXRX_DNW1 || LMIC.dataLen != 0); 01528 ASSERT((LMIC.opmode & OP_TXRXPEND)!=0); 01529 01530 if( LMIC.dataLen == 0 ) 01531 { 01532 nojoinframe: 01533 /* keep retrying -- if( (LMIC.opmode & OP_JOINING) == 0 ) { 01534 ASSERT((LMIC.opmode & OP_REJOIN) != 0); 01535 // REJOIN attempt for roaming 01536 LMIC.opmode &= ~(OP_REJOIN|OP_TXRXPEND); 01537 if( LMIC.rejoinCnt < 10 ) 01538 LMIC.rejoinCnt++; 01539 reportEvent(EV_REJOIN_FAILED); 01540 return 1; 01541 }*/ 01542 LMIC.opmode &= ~OP_TXRXPEND; 01543 ostime_t delay = nextJoinState(); 01544 EV(devCond, DEBUG, (e_.reason = EV::devCond_t::NO_JACC, 01545 e_.eui = MAIN::CDEV->getEui(), 01546 e_.info = LMIC.datarate|DR_PAGE, 01547 e_.info2 = osticks2ms(delay))); 01548 // Build next JOIN REQUEST with next engineUpdate call 01549 // Optionally, report join failed. 01550 // Both after a random/chosen amount of ticks. 01551 os_setTimedCallback(&LMIC.osjob, os_getTime()+delay, 01552 (delay&1) != 0 01553 ? FUNC_ADDR(onJoinFailed) // one JOIN iteration done and failed 01554 : FUNC_ADDR(runEngineUpdate)); // next step to be delayed 01555 return 1; 01556 } 01557 u1_t hdr = LMIC.frame[0]; 01558 u1_t dlen = LMIC.dataLen; 01559 u4_t mic = os_rlsbf4(&LMIC.frame[dlen-4]); // safe before modified by encrypt! 01560 if( (dlen != LEN_JA && dlen != LEN_JAEXT) 01561 || (hdr & (HDR_FTYPE|HDR_MAJOR)) != (HDR_FTYPE_JACC|HDR_MAJOR_V1) ) { 01562 EV(specCond, ERR, (e_.reason = EV::specCond_t::UNEXPECTED_FRAME, 01563 e_.eui = MAIN::CDEV->getEui(), 01564 e_.info = dlen < 4 ? 0 : mic, 01565 e_.info2 = hdr + (dlen<<8))); 01566 badframe: 01567 if( (LMIC.txrxFlags & TXRX_DNW1) != 0 ) 01568 return 0; 01569 goto nojoinframe; 01570 } 01571 aes_encrypt(LMIC.frame+1, dlen-1); 01572 if( !aes_verifyMic0(LMIC.frame, dlen-4) ) { 01573 EV(specCond, ERR, (e_.reason = EV::specCond_t::JOIN_BAD_MIC, 01574 e_.info = mic)); 01575 goto badframe; 01576 } 01577 01578 u4_t addr = os_rlsbf4(LMIC.frame+OFF_JA_DEVADDR); 01579 LMIC.devaddr = addr; 01580 LMIC.netid = os_rlsbf4(&LMIC.frame[OFF_JA_NETID]) & 0xFFFFFF; 01581 01582 #if defined(CFG_eu868) 01583 initDefaultChannels(0); 01584 #endif 01585 if( dlen > LEN_JA ) { 01586 dlen = OFF_CFLIST; 01587 #if defined(CFG_eu868) 01588 u1_t chidx=3; 01589 #elif defined(CFG_us915) 01590 u1_t chidx=72; 01591 #endif 01592 for( ; chidx<8; chidx++, dlen+=3 ) 01593 LMIC_setupChannel(chidx, convFreq(&LMIC.frame[dlen]), 0, -1); 01594 } 01595 01596 // already incremented when JOIN REQ got sent off 01597 aes_sessKeys(LMIC.devNonce-1, &LMIC.frame[OFF_JA_ARTNONCE], LMIC.nwkKey, LMIC.artKey); 01598 DO_DEVDB(LMIC.netid, netid); 01599 DO_DEVDB(LMIC.devaddr, devaddr); 01600 DO_DEVDB(LMIC.nwkKey, nwkkey); 01601 DO_DEVDB(LMIC.artKey, artkey); 01602 01603 EV(joininfo, INFO, (e_.arteui = MAIN::CDEV->getArtEui(), 01604 e_.deveui = MAIN::CDEV->getEui(), 01605 e_.devaddr = LMIC.devaddr, 01606 e_.oldaddr = oldaddr, 01607 e_.nonce = LMIC.devNonce-1, 01608 e_.mic = mic, 01609 e_.reason = ((LMIC.opmode & OP_REJOIN) != 0 01610 ? EV::joininfo_t::REJOIN_ACCEPT 01611 : EV::joininfo_t::ACCEPT))); 01612 01613 ASSERT((LMIC.opmode & (OP_JOINING|OP_REJOIN))!=0); 01614 if( (LMIC.opmode & OP_REJOIN) != 0 ) { 01615 // Lower DR every try below current UP DR 01616 LMIC.datarate = lowerDR(LMIC.datarate, LMIC.rejoinCnt); 01617 } 01618 LMIC.opmode &= ~(OP_JOINING|OP_TRACK|OP_REJOIN|OP_TXRXPEND|OP_PINGINI) | OP_NEXTCHNL; 01619 stateJustJoined(); 01620 reportEvent(EV_JOINED); 01621 return 1; 01622 } 01623 01624 01625 static void processRx2Jacc (xref2osjob_t osjob) 01626 { 01627 debug("LMIC processRx2Jacc enter\r\n"); 01628 if( LMIC.dataLen == 0 ) 01629 LMIC.txrxFlags = 0; // nothing in 1st/2nd DN slot 01630 processJoinAccept(); 01631 } 01632 01633 01634 static void setupRx2Jacc (xref2osjob_t osjob) 01635 { 01636 debug("LMIC setupRx2Jacc enter\r\n"); 01637 LMIC.osjob.func = FUNC_ADDR(processRx2Jacc); 01638 setupRx2(); 01639 } 01640 01641 01642 static void processRx1Jacc (xref2osjob_t osjob) 01643 { 01644 debug("LMIC processRx1Jacc enter\r\n"); 01645 if( LMIC.dataLen == 0 || !processJoinAccept() ) 01646 schedRx2(DELAY_JACC2_osticks, FUNC_ADDR(setupRx2Jacc)); 01647 } 01648 01649 01650 static void setupRx1Jacc (xref2osjob_t osjob) 01651 { 01652 debug("LMIC setupRx1Jacc enter\r\n"); 01653 setupRx1(FUNC_ADDR(processRx1Jacc)); 01654 } 01655 01656 01657 static void jreqDone (xref2osjob_t osjob) 01658 { 01659 debug("LMIC jreqDone enter\r\n"); 01660 txDone(DELAY_JACC1_osticks, FUNC_ADDR(setupRx1Jacc)); 01661 } 01662 01663 // ======================================== Data frames 01664 01665 // Fwd decl. 01666 static bit_t processDnData(void); 01667 01668 static void processRx2DnDataDelay (xref2osjob_t osjob) 01669 { 01670 debug("LMIC processRx2DnDataDelay enter\r\n"); 01671 processDnData(); 01672 } 01673 01674 static void processRx2DnData (xref2osjob_t osjob) 01675 { 01676 debug("LMIC processRx2DnData enter\r\n"); 01677 if( LMIC.dataLen == 0 ) { 01678 LMIC.txrxFlags = 0; // nothing in 1st/2nd DN slot 01679 // Delay callback processing to avoid up TX while gateway is txing our missed frame! 01680 // Since DNW2 uses SF12 by default we wait 3 secs. 01681 os_setTimedCallback(&LMIC.osjob, 01682 (os_getTime() + DNW2_SAFETY_ZONE + rndDelay(2)), 01683 processRx2DnDataDelay); 01684 return; 01685 } 01686 processDnData(); 01687 } 01688 01689 01690 static void setupRx2DnData (xref2osjob_t osjob) 01691 { 01692 debug("LMIC setupRx2DnData enter\r\n"); 01693 LMIC.osjob.func = FUNC_ADDR(processRx2DnData); 01694 setupRx2(); 01695 } 01696 01697 01698 static void processRx1DnData (xref2osjob_t osjob) 01699 { 01700 debug("LMIC processRx1DnData enter\r\n"); 01701 if( LMIC.dataLen == 0 || !processDnData() ) 01702 schedRx2(DELAY_DNW2_osticks, FUNC_ADDR(setupRx2DnData)); 01703 } 01704 01705 01706 static void setupRx1DnData (xref2osjob_t osjob) 01707 { 01708 debug("LMIC setupRx1DnData enter\r\n"); 01709 setupRx1(FUNC_ADDR(processRx1DnData)); 01710 } 01711 01712 01713 static void updataDone (xref2osjob_t osjob) 01714 { 01715 debug("LMIC updataDone enter\r\n"); 01716 txDone(DELAY_DNW1_osticks, FUNC_ADDR(setupRx1DnData)); 01717 } 01718 01719 // ======================================== 01720 01721 01722 static void buildDataFrame (void) 01723 { 01724 debug("LMIC buildDataFrame enter\r\n"); 01725 bit_t txdata = ((LMIC.opmode & (OP_TXDATA|OP_POLL)) != OP_POLL); 01726 u1_t dlen = txdata ? LMIC.pendTxLen : 0; 01727 01728 // Piggyback MAC options 01729 // Prioritize by importance 01730 int end = OFF_DAT_OPTS; 01731 if( (LMIC.opmode & (OP_TRACK|OP_PINGABLE)) == (OP_TRACK|OP_PINGABLE) ) { 01732 // Indicate pingability in every UP frame 01733 LMIC.frame[end] = MCMD_PING_IND; 01734 LMIC.frame[end+1] = LMIC.ping.dr | (LMIC.ping.intvExp<<4); 01735 end += 2; 01736 } 01737 if( LMIC.dutyCapAns ) { 01738 LMIC.frame[end] = MCMD_DCAP_ANS; 01739 end += 1; 01740 LMIC.dutyCapAns = 0; 01741 } 01742 if( LMIC.dn2Ans ) { 01743 LMIC.frame[end+0] = MCMD_DN2P_ANS; 01744 LMIC.frame[end+1] = LMIC.dn2Ans & ~MCMD_DN2P_ANS_RFU; 01745 end += 2; 01746 LMIC.dn2Ans = 0; 01747 } 01748 if( LMIC.devsAns ) { // answer to device status 01749 LMIC.frame[end+0] = MCMD_DEVS_ANS; 01750 LMIC.frame[end+1] = LMIC.margin; 01751 LMIC.frame[end+2] = os_getBattLevel(); 01752 end += 3; 01753 LMIC.devsAns = 0; 01754 } 01755 if( LMIC.ladrAns ) { // answer to ADR change 01756 LMIC.frame[end+0] = MCMD_LADR_ANS; 01757 LMIC.frame[end+1] = LMIC.ladrAns & ~MCMD_LADR_ANS_RFU; 01758 end += 2; 01759 LMIC.ladrAns = 0; 01760 } 01761 if( LMIC.bcninfoTries > 0 ) { 01762 LMIC.frame[end] = MCMD_BCNI_REQ; 01763 end += 1; 01764 } 01765 if( LMIC.adrChanged ) { 01766 if( LMIC.adrAckReq < 0 ) 01767 LMIC.adrAckReq = 0; 01768 LMIC.adrChanged = 0; 01769 } 01770 if( LMIC.pingSetAns != 0 ) { 01771 LMIC.frame[end+0] = MCMD_PING_ANS; 01772 LMIC.frame[end+1] = LMIC.pingSetAns & ~MCMD_PING_ANS_RFU; 01773 end += 2; 01774 LMIC.pingSetAns = 0; 01775 } 01776 if( LMIC.snchAns ) { 01777 LMIC.frame[end+0] = MCMD_SNCH_ANS; 01778 LMIC.frame[end+1] = LMIC.snchAns & ~MCMD_SNCH_ANS_RFU; 01779 end += 2; 01780 LMIC.snchAns = 0; 01781 } 01782 ASSERT(end <= OFF_DAT_OPTS+16); 01783 01784 u1_t flen = end + (txdata ? 5+dlen : 4); 01785 if( flen > MAX_LEN_FRAME ) { 01786 // Options and payload too big - delay payload 01787 txdata = 0; 01788 flen = end+4; 01789 } 01790 LMIC.frame[OFF_DAT_HDR] = HDR_FTYPE_DAUP | HDR_MAJOR_V1; 01791 LMIC.frame[OFF_DAT_FCT] = (LMIC.dnConf | LMIC.adrEnabled 01792 | (LMIC.adrAckReq >= 0 ? FCT_ADRARQ : 0) 01793 | (end-OFF_DAT_OPTS)); 01794 os_wlsbf4(LMIC.frame+OFF_DAT_ADDR, LMIC.devaddr); 01795 01796 if( LMIC.txCnt == 0 ) { 01797 LMIC.seqnoUp += 1; 01798 DO_DEVDB(LMIC.seqnoUp,seqnoUp); 01799 } else { 01800 EV(devCond, INFO, (e_.reason = EV::devCond_t::RE_TX, 01801 e_.eui = MAIN::CDEV->getEui(), 01802 e_.info = LMIC.seqnoUp-1, 01803 e_.info2 = ((LMIC.txCnt+1) | 01804 (DRADJUST[LMIC.txCnt+1] << 8) | 01805 ((LMIC.datarate|DR_PAGE)<<16)))); 01806 } 01807 os_wlsbf2(LMIC.frame+OFF_DAT_SEQNO, LMIC.seqnoUp-1); 01808 01809 // Clear pending DN confirmation 01810 LMIC.dnConf = 0; 01811 01812 if( txdata ) { 01813 if( LMIC.pendTxConf ) { 01814 // Confirmed only makes sense if we have a payload (or at least a port) 01815 LMIC.frame[OFF_DAT_HDR] = HDR_FTYPE_DCUP | HDR_MAJOR_V1; 01816 if( LMIC.txCnt == 0 ) LMIC.txCnt = 1; 01817 } 01818 LMIC.frame[end] = LMIC.pendTxPort; 01819 os_copyMem(LMIC.frame+end+1, LMIC.pendTxData, dlen); 01820 aes_cipher(LMIC.pendTxPort==0 ? LMIC.nwkKey : LMIC.artKey, 01821 LMIC.devaddr, LMIC.seqnoUp-1, 01822 /*up*/0, LMIC.frame+end+1, dlen); 01823 } 01824 aes_appendMic(LMIC.nwkKey, LMIC.devaddr, LMIC.seqnoUp-1, /*up*/0, LMIC.frame, flen-4); 01825 01826 EV(dfinfo, DEBUG, (e_.deveui = MAIN::CDEV->getEui(), 01827 e_.devaddr = LMIC.devaddr, 01828 e_.seqno = LMIC.seqnoUp-1, 01829 e_.flags = (LMIC.pendTxPort < 0 ? EV::dfinfo_t::NOPORT : EV::dfinfo_t::NOP), 01830 e_.mic = Base::lsbf4(&LMIC.frame[flen-4]), 01831 e_.hdr = LMIC.frame[LORA::OFF_DAT_HDR], 01832 e_.fct = LMIC.frame[LORA::OFF_DAT_FCT], 01833 e_.port = LMIC.pendTxPort, 01834 e_.plen = txdata ? dlen : 0, 01835 e_.opts.length = end-LORA::OFF_DAT_OPTS, 01836 memcpy(&e_.opts[0], LMIC.frame+LORA::OFF_DAT_OPTS, end-LORA::OFF_DAT_OPTS))); 01837 LMIC.dataLen = flen; 01838 } 01839 01840 01841 // Callback from HAL during scan mode or when job timer expires. 01842 static void onBcnRx (xref2osjob_t job) 01843 { 01844 debug("LMIC onBcnRx enter\r\n"); 01845 // If we arrive via job timer make sure to put radio to rest. 01846 os_radio(RADIO_RST); 01847 os_clearCallback(&LMIC.osjob); 01848 if( LMIC.dataLen == 0 ) { 01849 // Nothing received - timeout 01850 LMIC.opmode &= ~(OP_SCAN | OP_TRACK); 01851 reportEvent(EV_SCAN_TIMEOUT); 01852 return; 01853 } 01854 if( decodeBeacon() <= 0 ) { 01855 // Something is wrong with the beacon - continue scan 01856 LMIC.dataLen = 0; 01857 os_radio(RADIO_RXON); 01858 os_setTimedCallback(&LMIC.osjob, LMIC.bcninfo.txtime, FUNC_ADDR(onBcnRx)); 01859 return; 01860 } 01861 // Found our 1st beacon 01862 // We don't have a previous beacon to calc some drift - assume 01863 // an max error of 13ms = 128sec*100ppm which is roughly +/-100ppm 01864 calcBcnRxWindowFromMillis(13,1); 01865 LMIC.opmode &= ~OP_SCAN; // turn SCAN off 01866 LMIC.opmode |= OP_TRACK; // auto enable tracking 01867 reportEvent(EV_BEACON_FOUND); // can be disabled in callback 01868 } 01869 01870 01871 // Enable receiver to listen to incoming beacons 01872 // netid defines when scan stops (any or specific beacon) 01873 // This mode ends with events: EV_SCAN_TIMEOUT/EV_SCAN_BEACON 01874 // Implicitely cancels any pending TX/RX transaction. 01875 // Also cancels an onpoing joining procedure. 01876 static void startScan (void) 01877 { 01878 debug("LMIC startScan enter\r\n"); 01879 ASSERT(LMIC.devaddr!=0 && (LMIC.opmode & OP_JOINING)==0); 01880 if( (LMIC.opmode & OP_SHUTDOWN) != 0 ) 01881 return; 01882 // Cancel onging TX/RX transaction 01883 LMIC.txCnt = LMIC.dnConf = LMIC.bcninfo.flags = 0; 01884 LMIC.opmode = (LMIC.opmode | OP_SCAN) & ~(OP_TXRXPEND); 01885 setBcnRxParams(); 01886 LMIC.rxtime = LMIC.bcninfo.txtime = os_getTime() + sec2osticks(BCN_INTV_sec+1); 01887 os_setTimedCallback(&LMIC.osjob, LMIC.rxtime, FUNC_ADDR(onBcnRx)); 01888 os_radio(RADIO_RXON); 01889 } 01890 01891 01892 bit_t LMIC_enableTracking (u1_t tryBcnInfo) 01893 { 01894 debug("LMIC LMIC_enableTracking enter\r\n"); 01895 if( (LMIC.opmode & (OP_SCAN|OP_TRACK|OP_SHUTDOWN)) != 0 ) 01896 return 0; // already in progress or failed to enable 01897 // If BCN info requested from NWK then app has to take are 01898 // of sending data up so that MCMD_BCNI_REQ can be attached. 01899 if( (LMIC.bcninfoTries = tryBcnInfo) == 0 ) 01900 startScan(); 01901 return 1; // enabled 01902 } 01903 01904 01905 void LMIC_disableTracking (void) 01906 { 01907 debug("LMIC LMIC_disableTracking enter\r\n"); 01908 LMIC.opmode &= ~(OP_SCAN|OP_TRACK); 01909 LMIC.bcninfoTries = 0; 01910 engineUpdate(); 01911 } 01912 01913 01914 // ================================================================================ 01915 // 01916 // Join stuff 01917 // 01918 // ================================================================================ 01919 01920 static void buildJoinRequest (u1_t ftype) 01921 { 01922 debug("LMIC buildJoinRequest enter\r\n"); 01923 // Do not use pendTxData since we might have a pending 01924 // user level frame in there. Use RX holding area instead. 01925 xref2u1_t d = LMIC.frame; 01926 d[OFF_JR_HDR] = ftype; 01927 os_getArtEui(d + OFF_JR_ARTEUI); 01928 os_getDevEui(d + OFF_JR_DEVEUI); 01929 os_wlsbf2(d + OFF_JR_DEVNONCE, LMIC.devNonce); 01930 aes_appendMic0(d, OFF_JR_MIC); 01931 01932 EV(joininfo,INFO,(e_.deveui = MAIN::CDEV->getEui(), 01933 e_.arteui = MAIN::CDEV->getArtEui(), 01934 e_.nonce = LMIC.devNonce, 01935 e_.oldaddr = LMIC.devaddr, 01936 e_.mic = Base::lsbf4(&d[LORA::OFF_JR_MIC]), 01937 e_.reason = ((LMIC.opmode & OP_REJOIN) != 0 01938 ? EV::joininfo_t::REJOIN_REQUEST 01939 : EV::joininfo_t::REQUEST))); 01940 LMIC.dataLen = LEN_JR; 01941 LMIC.devNonce++; 01942 DO_DEVDB(LMIC.devNonce,devNonce); 01943 } 01944 01945 static void startJoining (xref2osjob_t osjob) 01946 { 01947 debug("LMIC startJoining enter\r\n"); 01948 reportEvent(EV_JOINING); 01949 } 01950 01951 // Start join procedure if not already joined. 01952 bit_t LMIC_startJoining (void) 01953 { 01954 debug("LMIC LMIC_startJoining enter\r\n"); 01955 if( LMIC.devaddr == 0 ) 01956 { 01957 // There should be no TX/RX going on 01958 ASSERT((LMIC.opmode & (OP_POLL|OP_TXRXPEND)) == 0); 01959 // Lift any previous duty limitation 01960 LMIC.globalDutyRate = 0; 01961 // Cancel scanning 01962 LMIC.opmode &= ~(OP_SCAN|OP_REJOIN|OP_LINKDEAD|OP_NEXTCHNL); 01963 // Setup state 01964 LMIC.rejoinCnt = LMIC.txCnt = LMIC.pendTxConf = 0; 01965 initJoinLoop(); 01966 LMIC.opmode |= OP_JOINING; 01967 // reportEvent will call engineUpdate which then starts sending JOIN REQUESTS 01968 os_setCallback(&LMIC.osjob, FUNC_ADDR(startJoining)); 01969 return 1; 01970 } 01971 return 0; // already joined 01972 } 01973 01974 01975 // ================================================================================ 01976 // 01977 // 01978 // 01979 // ================================================================================ 01980 01981 static void processPingRx (xref2osjob_t osjob) 01982 { 01983 debug("LMIC processPingRx enter\r\n"); 01984 if( LMIC.dataLen != 0 ) { 01985 LMIC.txrxFlags = TXRX_PING; 01986 if( decodeFrame() ) { 01987 reportEvent(EV_RXCOMPLETE); 01988 return; 01989 } 01990 } 01991 // Pick next ping slot 01992 engineUpdate(); 01993 } 01994 01995 01996 static bit_t processDnData (void) 01997 { 01998 debug("LMIC processDnData enter\r\n"); 01999 ASSERT((LMIC.opmode & OP_TXRXPEND)!=0); 02000 02001 if( LMIC.dataLen == 0 ) { 02002 norx: 02003 if( LMIC.txCnt != 0 ) { 02004 if( LMIC.txCnt < TXCONF_ATTEMPTS ) { 02005 LMIC.txCnt += 1; 02006 setDrTxpow(DRCHG_NOACK, lowerDR(LMIC.datarate, DRADJUST[LMIC.txCnt]), KEEP_TXPOW); 02007 // Schedule another retransmission 02008 txDelay(LMIC.rxtime, RETRY_PERIOD_secs); 02009 LMIC.opmode &= ~OP_TXRXPEND; 02010 engineUpdate(); 02011 return 1; 02012 } 02013 LMIC.txrxFlags = TXRX_NACK | TXRX_NOPORT; 02014 } else { 02015 // Nothing received - implies no port 02016 LMIC.txrxFlags = TXRX_NOPORT; 02017 } 02018 if( LMIC.adrAckReq != LINK_CHECK_OFF ) 02019 LMIC.adrAckReq += 1; 02020 LMIC.dataBeg = LMIC.dataLen = 0; 02021 txcomplete: 02022 LMIC.opmode &= ~(OP_TXDATA|OP_TXRXPEND); 02023 if( (LMIC.txrxFlags & (TXRX_DNW1|TXRX_DNW2|TXRX_PING)) != 0 && (LMIC.opmode & OP_LINKDEAD) != 0 ) { 02024 LMIC.opmode &= ~OP_LINKDEAD; 02025 reportEvent(EV_LINK_ALIVE); 02026 } 02027 reportEvent(EV_TXCOMPLETE); 02028 // If we haven't heard from NWK in a while although we asked for a sign 02029 // assume link is dead - notify application and keep going 02030 if( LMIC.adrAckReq > LINK_CHECK_DEAD ) { 02031 // We haven't heard from NWK for some time although we 02032 // asked for a response for some time - assume we're disconnected. Lower DR one notch. 02033 EV(devCond, ERR, (e_.reason = EV::devCond_t::LINK_DEAD, 02034 e_.eui = MAIN::CDEV->getEui(), 02035 e_.info = LMIC.adrAckReq)); 02036 setDrTxpow(DRCHG_NOADRACK, decDR((dr_t)LMIC.datarate), KEEP_TXPOW); 02037 LMIC.adrAckReq = LINK_CHECK_CONT; 02038 LMIC.opmode |= OP_REJOIN|OP_LINKDEAD; 02039 reportEvent(EV_LINK_DEAD); 02040 } 02041 // If this falls to zero the NWK did not answer our MCMD_BCNI_REQ commands - try full scan 02042 if( LMIC.bcninfoTries > 0 ) { 02043 if( (LMIC.opmode & OP_TRACK) != 0 ) { 02044 reportEvent(EV_BEACON_FOUND); 02045 LMIC.bcninfoTries = 0; 02046 } 02047 else if( --LMIC.bcninfoTries == 0 ) { 02048 startScan(); // NWK did not answer - try scan 02049 } 02050 } 02051 return 1; 02052 } 02053 if( !decodeFrame() ) { 02054 if( (LMIC.txrxFlags & TXRX_DNW1) != 0 ) 02055 return 0; 02056 goto norx; 02057 } 02058 goto txcomplete; 02059 } 02060 02061 02062 static void processBeacon (xref2osjob_t osjob) 02063 { 02064 debug("LMIC processBeacon enter\r\n"); 02065 ostime_t lasttx = LMIC.bcninfo.txtime; // save here - decodeBeacon might overwrite 02066 u1_t flags = LMIC.bcninfo.flags; 02067 ev_t ev; 02068 02069 if( LMIC.dataLen != 0 && decodeBeacon() >= 1 ) { 02070 ev = EV_BEACON_TRACKED; 02071 if( (flags & (BCN_PARTIAL|BCN_FULL)) == 0 ) { 02072 // We don't have a previous beacon to calc some drift - assume 02073 // an max error of 13ms = 128sec*100ppm which is roughly +/-100ppm 02074 calcBcnRxWindowFromMillis(13,0); 02075 goto rev; 02076 } 02077 // We have a previous BEACON to calculate some drift 02078 s2_t drift = BCN_INTV_osticks - (LMIC.bcninfo.txtime - lasttx); 02079 if( LMIC.missedBcns > 0 ) { 02080 drift = LMIC.drift + (drift - LMIC.drift) / (LMIC.missedBcns+1); 02081 } 02082 if( (LMIC.bcninfo.flags & BCN_NODRIFT) == 0 ) { 02083 s2_t diff = LMIC.drift - drift; 02084 if( diff < 0 ) diff = -diff; 02085 LMIC.lastDriftDiff = diff; 02086 if( LMIC.maxDriftDiff < diff ) 02087 LMIC.maxDriftDiff = diff; 02088 LMIC.bcninfo.flags &= ~BCN_NODDIFF; 02089 } 02090 LMIC.drift = drift; 02091 LMIC.missedBcns = LMIC.rejoinCnt = 0; 02092 LMIC.bcninfo.flags &= ~BCN_NODRIFT; 02093 EV(devCond,INFO,(e_.reason = EV::devCond_t::CLOCK_DRIFT, 02094 e_.eui = MAIN::CDEV->getEui(), 02095 e_.info = drift, 02096 e_.info2 = /*occasion BEACON*/0)); 02097 ASSERT((LMIC.bcninfo.flags & (BCN_PARTIAL|BCN_FULL)) != 0); 02098 } else { 02099 ev = EV_BEACON_MISSED; 02100 LMIC.bcninfo.txtime += BCN_INTV_osticks - LMIC.drift; 02101 LMIC.bcninfo.time += BCN_INTV_sec; 02102 LMIC.missedBcns++; 02103 // Delay any possible TX after surmised beacon - it's there although we missed it 02104 txDelay(LMIC.bcninfo.txtime + BCN_RESERVE_osticks, 4); 02105 if( LMIC.missedBcns > MAX_MISSED_BCNS ) 02106 LMIC.opmode |= OP_REJOIN; // try if we can roam to another network 02107 if( LMIC.bcnRxsyms > MAX_RXSYMS ) { 02108 LMIC.opmode &= ~(OP_TRACK|OP_PINGABLE|OP_PINGINI|OP_REJOIN); 02109 reportEvent(EV_LOST_TSYNC); 02110 return; 02111 } 02112 } 02113 LMIC.bcnRxtime = LMIC.bcninfo.txtime + BCN_INTV_osticks - calcRxWindow(0,DR_BCN); 02114 LMIC.bcnRxsyms = LMIC.rxsyms; 02115 rev: 02116 #ifdef CFG_us915 02117 LMIC.bcnChnl = (LMIC.bcnChnl+1) & 7; 02118 #endif 02119 if( (LMIC.opmode & OP_PINGINI) != 0 ) 02120 rxschedInit(&LMIC.ping); // note: reuses LMIC.frame buffer! 02121 reportEvent(ev); 02122 } 02123 02124 02125 static void startRxBcn (xref2osjob_t osjob) 02126 { 02127 debug("LMIC startRxBcn enter\r\n"); 02128 LMIC.osjob.func = FUNC_ADDR(processBeacon); 02129 os_radio(RADIO_RX); 02130 } 02131 02132 02133 static void startRxPing (xref2osjob_t osjob) 02134 { 02135 debug("LMIC startRxPing enter\r\n"); 02136 LMIC.osjob.func = FUNC_ADDR(processPingRx); 02137 os_radio(RADIO_RX); 02138 } 02139 02140 02141 // Decide what to do next for the MAC layer of a device 02142 static void engineUpdate (void) 02143 { 02144 debug("LMIC engineUpdate enter\r\n"); 02145 // Check for ongoing state: scan or TX/RX transaction 02146 if( (LMIC.opmode & (OP_SCAN|OP_TXRXPEND|OP_SHUTDOWN)) != 0 ) 02147 return; 02148 02149 if( LMIC.devaddr == 0 && (LMIC.opmode & OP_JOINING) == 0 ) { 02150 LMIC_startJoining(); 02151 return; 02152 } 02153 02154 ostime_t now = os_getTime(); 02155 ostime_t rxtime = 0; 02156 ostime_t txbeg = 0; 02157 02158 if( (LMIC.opmode & OP_TRACK) != 0 ) { 02159 // We are tracking a beacon 02160 ASSERT( now + RX_RAMPUP - LMIC.bcnRxtime <= 0 ); 02161 rxtime = LMIC.bcnRxtime - RX_RAMPUP; 02162 } 02163 02164 if( (LMIC.opmode & (OP_JOINING|OP_REJOIN|OP_TXDATA|OP_POLL)) != 0 ) { 02165 // Need to TX some data... 02166 // Assuming txChnl points to channel which first becomes available again. 02167 bit_t jacc = ((LMIC.opmode & (OP_JOINING|OP_REJOIN)) != 0 ? 1 : 0); 02168 // Find next suitable channel and return availability time 02169 if( (LMIC.opmode & OP_NEXTCHNL) != 0 ) { 02170 txbeg = LMIC.txend = nextTx(now); 02171 LMIC.opmode &= ~OP_NEXTCHNL; 02172 } else { 02173 txbeg = LMIC.txend; 02174 } 02175 // Delayed TX or waiting for duty cycle? 02176 if( (LMIC.globalDutyRate != 0 || (LMIC.opmode & OP_RNDTX) != 0) && (txbeg - LMIC.globalDutyAvail) < 0 ) 02177 txbeg = LMIC.globalDutyAvail; 02178 // If we're tracking a beacon... 02179 // then make sure TX-RX transaction is complete before beacon 02180 if( (LMIC.opmode & OP_TRACK) != 0 && 02181 txbeg + (jacc ? JOIN_GUARD_osticks : TXRX_GUARD_osticks) - rxtime > 0 ) { 02182 // Not enough time to complete TX-RX before beacon - postpone after beacon. 02183 // In order to avoid clustering of postponed TX right after beacon randomize start! 02184 txDelay(rxtime + BCN_RESERVE_osticks, 16); 02185 txbeg = 0; 02186 goto checkrx; 02187 } 02188 // Earliest possible time vs overhead to setup radio 02189 if( txbeg - (now + TX_RAMPUP) < 0 ) { 02190 // We could send right now! 02191 dr_t txdr = (dr_t)LMIC.datarate; 02192 txbeg = now; 02193 if( jacc ) { 02194 u1_t ftype; 02195 if( (LMIC.opmode & OP_REJOIN) != 0 ) { 02196 txdr = lowerDR(txdr, LMIC.rejoinCnt); 02197 //ftype = HDR_FTYPE_REJOIN; 02198 ftype = HDR_FTYPE_JREQ; 02199 } else { 02200 ftype = HDR_FTYPE_JREQ; 02201 } 02202 buildJoinRequest(ftype); 02203 LMIC.osjob.func = FUNC_ADDR(jreqDone); 02204 } else { 02205 if( LMIC.seqnoDn >= 0xFFFFFF80 ) { 02206 // Imminent roll over - proactively reset MAC 02207 EV(specCond, INFO, (e_.reason = EV::specCond_t::DNSEQNO_ROLL_OVER, 02208 e_.eui = MAIN::CDEV->getEui(), 02209 e_.info = LMIC.seqnoDn, 02210 e_.info2 = 0)); 02211 // Device has to react! NWK will not roll over and just stop sending. 02212 // Thus, we have N frames to detect a possible lock up. 02213 reset: 02214 os_setCallback(&LMIC.osjob, FUNC_ADDR(runReset)); 02215 return; 02216 } 02217 if( (LMIC.txCnt==0 && LMIC.seqnoUp == 0xFFFFFFFF) ) { 02218 // Roll over of up seq counter 02219 EV(specCond, ERR, (e_.reason = EV::specCond_t::UPSEQNO_ROLL_OVER, 02220 e_.eui = MAIN::CDEV->getEui(), 02221 e_.info2 = LMIC.seqnoUp)); 02222 // Do not run RESET event callback from here! 02223 // App code might do some stuff after send unaware of RESET. 02224 goto reset; 02225 } 02226 buildDataFrame(); 02227 LMIC.osjob.func = FUNC_ADDR(updataDone); 02228 } 02229 LMIC.rps = setCr(updr2rps(txdr), (cr_t)LMIC.errcr); 02230 LMIC.dndr = txdr; // carry TX datarate (can be != LMIC.datarate) over to txDone/setupRx1 02231 LMIC.opmode = (LMIC.opmode & ~(OP_POLL|OP_RNDTX)) | OP_TXRXPEND | OP_NEXTCHNL; 02232 updateTx(txbeg); 02233 os_radio(RADIO_TX); 02234 return; 02235 } 02236 // Cannot yet TX 02237 if( (LMIC.opmode & OP_TRACK) == 0 ) 02238 goto txdelay; // We don't track the beacon - nothing else to do - so wait for the time to TX 02239 // Consider RX tasks 02240 if( txbeg == 0 ) // zero indicates no TX pending 02241 txbeg += 1; // TX delayed by one tick (insignificant amount of time) 02242 } else { 02243 // No TX pending - no scheduled RX 02244 if( (LMIC.opmode & OP_TRACK) == 0 ) 02245 return; 02246 } 02247 02248 // Are we pingable? 02249 checkrx: 02250 if( (LMIC.opmode & OP_PINGINI) != 0 ) { 02251 // One more RX slot in this beacon period? 02252 if( rxschedNext(&LMIC.ping, now+RX_RAMPUP) ) { 02253 if( txbeg != 0 && (txbeg - LMIC.ping.rxtime) < 0 ) 02254 goto txdelay; 02255 LMIC.rxsyms = LMIC.ping.rxsyms; 02256 LMIC.rxtime = LMIC.ping.rxtime; 02257 LMIC.freq = LMIC.ping.freq; 02258 LMIC.rps = dndr2rps(LMIC.ping.dr); 02259 LMIC.dataLen = 0; 02260 ASSERT(LMIC.rxtime - now+RX_RAMPUP >= 0 ); 02261 os_setTimedCallback(&LMIC.osjob, LMIC.rxtime - RX_RAMPUP, FUNC_ADDR(startRxPing)); 02262 return; 02263 } 02264 // no - just wait for the beacon 02265 } 02266 02267 if( txbeg != 0 && (txbeg - rxtime) < 0 ) 02268 goto txdelay; 02269 02270 setBcnRxParams(); 02271 LMIC.rxsyms = LMIC.bcnRxsyms; 02272 LMIC.rxtime = LMIC.bcnRxtime; 02273 if( now - rxtime >= 0 ) { 02274 LMIC.osjob.func = FUNC_ADDR(processBeacon); 02275 os_radio(RADIO_RX); 02276 return; 02277 } 02278 os_setTimedCallback(&LMIC.osjob, rxtime, FUNC_ADDR(startRxBcn)); 02279 return; 02280 02281 txdelay: 02282 EV(devCond, INFO, (e_.reason = EV::devCond_t::TX_DELAY, 02283 e_.eui = MAIN::CDEV->getEui(), 02284 e_.info = osticks2ms(txbeg-now), 02285 e_.info2 = LMIC.seqnoUp-1)); 02286 os_setTimedCallback(&LMIC.osjob, txbeg-TX_RAMPUP, FUNC_ADDR(runEngineUpdate)); 02287 } 02288 02289 02290 void LMIC_setAdrMode (bit_t enabled) 02291 { 02292 debug("LMIC LMIC_setAdrMode enter\r\n"); 02293 LMIC.adrEnabled = enabled ? FCT_ADREN : 0; 02294 } 02295 02296 02297 // Should we have/need an ext. API like this? 02298 void LMIC_setDrTxpow (dr_t dr, s1_t txpow) 02299 { 02300 debug("LMIC LMIC_setDrTxpow enter\r\n"); 02301 setDrTxpow(DRCHG_SET, dr, txpow); 02302 } 02303 02304 02305 void LMIC_shutdown (void) 02306 { 02307 debug("LMIC LMIC_shutdown enter\r\n"); 02308 os_clearCallback(&LMIC.osjob); 02309 os_radio(RADIO_RST); 02310 LMIC.opmode |= OP_SHUTDOWN; 02311 } 02312 02313 02314 void LMIC_reset (void) 02315 { 02316 debug("LMIC LMIC_reset enter\r\n"); 02317 EV(devCond, INFO, (e_.reason = EV::devCond_t::LMIC_EV, 02318 e_.eui = MAIN::CDEV->getEui(), 02319 e_.info = EV_RESET)); 02320 os_radio(RADIO_RST); 02321 os_clearCallback(&LMIC.osjob); 02322 02323 os_clearMem((xref2u1_t)&LMIC,SIZEOFEXPR(LMIC)); 02324 LMIC.devaddr = 0; 02325 LMIC.devNonce = os_getRndU2(); 02326 LMIC.opmode = OP_NONE; 02327 LMIC.errcr = CR_4_5; 02328 LMIC.adrEnabled = FCT_ADREN; 02329 LMIC.dn2Dr = DR_DNW2; // we need this for 2nd DN window of join accept 02330 LMIC.dn2Freq = FREQ_DNW2; // ditto 02331 LMIC.ping.freq = FREQ_PING; // defaults for ping 02332 LMIC.ping.dr = DR_PING; // ditto 02333 LMIC.ping.intvExp = 0xFF; 02334 #if defined(CFG_us915) 02335 initDefaultChannels(); 02336 #endif 02337 DO_DEVDB(LMIC.devaddr, devaddr); 02338 DO_DEVDB(LMIC.devNonce, devNonce); 02339 DO_DEVDB(LMIC.dn2Dr, dn2Dr); 02340 DO_DEVDB(LMIC.dn2Freq, dn2Freq); 02341 DO_DEVDB(LMIC.ping.freq, pingFreq); 02342 DO_DEVDB(LMIC.ping.dr, pingDr); 02343 DO_DEVDB(LMIC.ping.intvExp, pingIntvExp); 02344 } 02345 02346 02347 void LMIC_init (void) { 02348 debug("LMIC_init enter\r\n"); 02349 LMIC.opmode = OP_SHUTDOWN; 02350 } 02351 02352 02353 void LMIC_clrTxData (void) 02354 { 02355 debug("LMIC LMIC_clrTxData enter\r\n"); 02356 LMIC.opmode &= ~(OP_TXDATA|OP_TXRXPEND|OP_POLL); 02357 LMIC.pendTxLen = 0; 02358 if( (LMIC.opmode & (OP_JOINING|OP_SCAN)) != 0 ) // do not interfere with JOINING 02359 return; 02360 os_clearCallback(&LMIC.osjob); 02361 os_radio(RADIO_RST); 02362 engineUpdate(); 02363 } 02364 02365 02366 void LMIC_setTxData (void) 02367 { 02368 debug("LMIC LMIC_setTxData enter\r\n"); 02369 LMIC.opmode |= OP_TXDATA; 02370 if( (LMIC.opmode & OP_JOINING) == 0 ) 02371 LMIC.txCnt = 0; // cancel any ongoing TX/RX retries 02372 engineUpdate(); 02373 } 02374 02375 02376 // 02377 int LMIC_setTxData2 (u1_t port, xref2u1_t data, u1_t dlen, u1_t confirmed) 02378 { 02379 debug("LMIC LMIC_setTxData2 enter\r\n"); 02380 if( dlen > SIZEOFEXPR(LMIC.pendTxData) ) 02381 return -2; 02382 if( data != (xref2u1_t)0 ) 02383 os_copyMem(LMIC.pendTxData, data, dlen); 02384 LMIC.pendTxConf = confirmed; 02385 LMIC.pendTxPort = port; 02386 LMIC.pendTxLen = dlen; 02387 LMIC_setTxData(); 02388 return 0; 02389 } 02390 02391 02392 // Send a payload-less message to signal device is alive 02393 void LMIC_sendAlive (void) 02394 { 02395 debug("LMIC LMIC_sendAlive enter\r\n"); 02396 LMIC.opmode |= OP_POLL; 02397 engineUpdate(); 02398 } 02399 02400 02401 // Check if other networks are around. 02402 void LMIC_tryRejoin (void) 02403 { 02404 debug("LMIC LMIC_tryRejoin enter\r\n"); 02405 LMIC.opmode |= OP_REJOIN; 02406 engineUpdate(); 02407 } 02408 02409 //! \brief Setup given session keys 02410 //! and put the MAC in a state as if 02411 //! a join request/accept would have negotiated just these keys. 02412 //! It is crucial that the combinations `devaddr/nwkkey` and `devaddr/artkey` 02413 //! are unique within the network identified by `netid`. 02414 //! NOTE: on Harvard architectures when session keys are in flash: 02415 //! Caller has to fill in LMIC.{nwk,art}Key before and pass {nwk,art}Key are NULL 02416 //! \param netid a 24 bit number describing the network id this device is using 02417 //! \param devaddr the 32 bit session address of the device. It is strongly recommended 02418 //! to ensure that different devices use different numbers with high probability. 02419 //! \param nwkKey the 16 byte network session key used for message integrity. 02420 //! If NULL the caller has copied the key into `LMIC.nwkKey` before. 02421 //! \param artKey the 16 byte application router session key used for message confidentiality. 02422 //! If NULL the caller has copied the key into `LMIC.artKey` before. 02423 void LMIC_setSession (u4_t netid, devaddr_t devaddr, xref2u1_t nwkKey, xref2u1_t artKey) 02424 { 02425 debug("LMIC LMIC_setSession enter\r\n"); 02426 LMIC.netid = netid; 02427 LMIC.devaddr = devaddr; 02428 if( nwkKey != (xref2u1_t)0 ) 02429 os_copyMem(LMIC.nwkKey, nwkKey, 16); 02430 if( artKey != (xref2u1_t)0 ) 02431 os_copyMem(LMIC.artKey, artKey, 16); 02432 02433 #if defined(CFG_eu868) 02434 initDefaultChannels(0); 02435 #endif 02436 02437 LMIC.opmode &= ~(OP_JOINING|OP_TRACK|OP_REJOIN|OP_TXRXPEND|OP_PINGINI); 02438 LMIC.opmode |= OP_NEXTCHNL; 02439 stateJustJoined(); 02440 } 02441 02442 // Enable/disable link check validation. 02443 // LMIC sets the ADRACKREQ bit in UP frames if there were no DN frames 02444 // for a while. It expects the network to provide a DN message to prove 02445 // connectivity with a span of UP frames. If this no such prove is coming 02446 // then the datarate is lowered and a LINK_DEAD event is generated. 02447 // This mode can be disabled and no connectivity prove (ADRACKREQ) is requested 02448 // nor is the datarate changed. 02449 // This must be called only if a session is established (e.g. after EV_JOINED) 02450 void LMIC_setLinkCheckMode (bit_t enabled) 02451 { 02452 debug("LMIC LMIC_setLinkCheckMode enter\r\n"); 02453 LMIC.adrChanged = 0; 02454 LMIC.adrAckReq = enabled ? LINK_CHECK_INIT : LINK_CHECK_OFF; 02455 } 02456 02457 void LMIC_reverse_memcpy(u1_t *dst, const u1_t *src, size_t n) 02458 { 02459 size_t i; 02460 02461 for (i=0; i < n; ++i) 02462 dst[n-1-i] = src[i]; 02463 }
Generated on Wed Jul 13 2022 02:38:28 by 1.7.2