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