first test

Dependents:   LoRaWAN-lmic-app_tjm

Fork of LMiC by Semtech

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lmic.cpp Source File

lmic.cpp

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