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