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