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