LMIC lib Lora OTA device for Everynet

Fork of LMiC-10secs by Alcatel-Lucent IoT Development

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