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