Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of lmic_MOTE_L152RC by
lmic.cpp
00001 /******************************************************************************* 00002 * Copyright (c) 2014-2015 IBM Corporation. 00003 * All rights reserved. This program and the accompanying materials 00004 * are made available under the terms of the Eclipse Public License v1.0 00005 * which accompanies this distribution, and is available at 00006 * http://www.eclipse.org/legal/epl-v10.html 00007 * 00008 * Contributors: 00009 * IBM Zurich Research Lab - initial API, implementation and documentation 00010 *******************************************************************************/ 00011 00012 //! \file 00013 #include "lmic.h" 00014 #include "debug.h" 00015 00016 #if !defined(MINRX_SYMS) 00017 #define MINRX_SYMS 5 00018 #endif // !defined(MINRX_SYMS) 00019 #define PAMBL_SYMS 8 00020 #define PAMBL_FSK 5 00021 #define PRERX_FSK 1 00022 #define RXLEN_FSK (1+5+2) 00023 00024 #define BCN_INTV_osticks sec2osticks(BCN_INTV_sec) 00025 #define TXRX_GUARD_osticks ms2osticks(TXRX_GUARD_ms) 00026 #define JOIN_GUARD_osticks ms2osticks(JOIN_GUARD_ms) 00027 #define DELAY_DNW1_osticks sec2osticks(DELAY_DNW1) 00028 #define DELAY_DNW2_osticks sec2osticks(DELAY_DNW2) 00029 #define DELAY_JACC1_osticks sec2osticks(DELAY_JACC1) 00030 #define DELAY_JACC2_osticks sec2osticks(DELAY_JACC2) 00031 #define DELAY_EXTDNW2_osticks sec2osticks(DELAY_EXTDNW2) 00032 #define BCN_RESERVE_osticks ms2osticks(BCN_RESERVE_ms) 00033 #define BCN_GUARD_osticks ms2osticks(BCN_GUARD_ms) 00034 #define BCN_WINDOW_osticks ms2osticks(BCN_WINDOW_ms) 00035 #define AIRTIME_BCN_osticks us2osticks(AIRTIME_BCN) 00036 #if defined(CFG_eu868) 00037 #define DNW2_SAFETY_ZONE ms2osticks(3000) 00038 #endif 00039 #if defined(CFG_us915) 00040 #define DNW2_SAFETY_ZONE ms2osticks(750) 00041 #endif 00042 00043 // Special APIs - for development or testing 00044 #define isTESTMODE() 0 00045 00046 DEFINE_LMIC; 00047 DECL_ON_LMIC_EVENT; 00048 00049 00050 // Fwd decls. 00051 static void engineUpdate(void); 00052 static void startScan (void); 00053 00054 00055 // ================================================================================ 00056 // BEG OS - default implementations for certain OS suport functions 00057 00058 #if !defined(HAS_os_calls) 00059 00060 #if !defined(os_rlsbf2) 00061 u2_t os_rlsbf2 (xref2cu1_t buf) { 00062 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
