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


