IBL LoRaWAN implementation

Dependents:   Simple-LoRaWAN

Fork of LMiC by Semtech

Revision:
2:974cafbfb159
Parent:
1:d3b7bde3995c
Child:
4:85b2b647cb64
--- a/lmic.cpp	Tue Mar 31 13:36:56 2015 +0000
+++ b/lmic.cpp	Wed Nov 25 02:49:45 2015 +0000
@@ -236,7 +236,7 @@
 #elif defined(CFG_us915) // ========================================
 
 #define maxFrameLen(dr) ((dr)<=DR_SF11CR ? maxFrameLens[(dr)] : 0xFF)
-const u1_t maxFrameLens [] = { 24,66,142,255,255,255,255,255,  66,142 };
+//const u1_t maxFrameLens [] = { 24,66,142,255,255,255,255,255,  66,142 };
 
 const u1_t _DR2RPS_CRC[] = {
     ILLEGAL_RPS,
@@ -315,10 +315,10 @@
     return (((ostime_t)tmp << sfx) * OSTICKS_PER_SEC + div/2) / div;
 }
 
-extern inline s1_t  rssi2s1 (int v);
+/*extern inline s1_t  rssi2s1 (int v);
 extern inline int   s12rssi (s1_t v);
 extern inline float  s12snr (s1_t v);
-extern inline s1_t   snr2s1 (double v);
+extern inline s1_t   snr2s1 (double v);*/
 
 extern inline rps_t updr2rps (dr_t dr);
 extern inline rps_t dndr2rps (dr_t dr);
@@ -501,8 +501,11 @@
                         e_.prevdr    = LMIC.datarate|DR_PAGE,
                         e_.prevtxpow = LMIC.adrTxPow));
     
-    if( pow != KEEP_TXPOW )
-        LMIC.adrTxPow = pow;
+    if( pow != KEEP_TXPOW ) {
+         LMIC.adrTxPow = pow;
+        if (pow < LMIC.txpow_limit)
+            LMIC.txpow = pow;
+    }
     if( LMIC.datarate != dr ) {
         LMIC.datarate = dr;
         DO_DEVDB(LMIC.datarate,datarate);
@@ -548,7 +551,7 @@
     os_clearMem(&LMIC.channelDrMap, sizeof(LMIC.channelDrMap));
     os_clearMem(&LMIC.bands, sizeof(LMIC.bands));
 
-    LMIC.channelMap = 0x1F;
+    LMIC.channelMap = 0x3;
     u1_t su = join ? 0 : 6;
     for( u1_t fu=0; fu<6; fu++,su++ ) {
         LMIC.channelFreq[fu]  = iniChannelFreq[su];
@@ -680,7 +683,7 @@
 
 #define setRx1Params() /*LMIC.freq/rps remain unchanged*/
 
-static void initJoinLoop (void) {
+static void initJoinLoop (void) {   // eu868
     LMIC.txChnl = os_getRndU1() % 6;
     LMIC.adrTxPow = 14;
     setDrJoin(DRCHG_SET, DR_SF7);
@@ -732,16 +735,36 @@
 // BEG: US915 related stuff
 //
 
-
-static void initDefaultChannels (void) {
+static void initDefaultChannels (void)
+{
+#ifdef CHNL_HYBRID
+        int idx = CHNL_HYBRID >> 1;
+        LMIC.channelMap[0] = 0x0000;
+        LMIC.channelMap[1] = 0x0000;
+        LMIC.channelMap[2] = 0x0000;
+        LMIC.channelMap[3] = 0x0000;
+        if (CHNL_HYBRID & 1)
+            LMIC.channelMap[idx] = 0xff00;
+        else
+            LMIC.channelMap[idx] = 0x00ff;
+            
+        LMIC.channelMap[4] = 1 << CHNL_HYBRID;
+        LMIC.txpow_limit = 20;
+#else
     for( u1_t i=0; i<4; i++ )
         LMIC.channelMap[i] = 0xFFFF;
     LMIC.channelMap[4] = 0x00FF;
+    
+    LMIC.txpow_limit = 30;
+#endif
+
+    LMIC.txpow = LMIC.txpow_limit;
+    LMIC.adrTxPow = LMIC.txpow_limit;
 }
 
 static u4_t convFreq (xref2u1_t ptr) {
     u4_t freq = (os_rlsbf4(ptr-1) >> 8) * 100;
-    if( freq >= US915_FREQ_MIN && freq <= US915_FREQ_MAX )
+    if( freq < US915_FREQ_MIN || freq > US915_FREQ_MAX )
         freq = 0;
     return freq;
 }
@@ -777,17 +800,41 @@
 
 static void updateTx (ostime_t txbeg) {
     u1_t chnl = LMIC.txChnl;
+#ifdef JOIN_REQ_DEBUG    
+    printf("chnl%d ", chnl);
+#endif /* JOIN_REQ_DEBUG */  
     if( chnl < 64 ) {
         LMIC.freq = US915_125kHz_UPFBASE + chnl*US915_125kHz_UPFSTEP;
-        LMIC.txpow = 30;
+
+        if (LMIC.opmode & OP_JOINING) {
+            /* use max allowed power for joining */
+            if (LMIC.txpow <  LMIC.txpow_limit)
+                LMIC.txpow = LMIC.txpow_limit;
+        }
+
+#ifdef JOIN_REQ_DEBUG
+    printf("%d (125khz)\r\n", LMIC.freq);
+#endif /* JOIN_REQ_DEBUG */    
         return;
     }
-    LMIC.txpow = 26;
+    
+    /* using 500KHz channel */
+    if (LMIC.txpow_limit >= 26)
+        LMIC.txpow = 26;
+    else
+        LMIC.txpow = LMIC.txpow_limit;
+        
     if( chnl < 64+8 ) {
         LMIC.freq = US915_500kHz_UPFBASE + (chnl-64)*US915_500kHz_UPFSTEP;
+#ifdef JOIN_REQ_DEBUG
+    printf("%d (500k)\r\n", LMIC.freq);
+#endif /* JOIN_REQ_DEBUG */            
     } else {
         ASSERT(chnl < 64+8+MAX_XCHANNELS);
         LMIC.freq = LMIC.xchFreq[chnl-72];
+#ifdef JOIN_REQ_DEBUG
+    printf("%d (x)\r\n", LMIC.freq);
+#endif /* JOIN_REQ_DEBUG */           
     }
 
     // Update global duty cycle stats
@@ -797,29 +844,72 @@
     }
 }
 
+int count_bits(u2_t v)
+{
+    int c;
+    
+    for (c = 0; v; c++) {
+        v &= v - 1; // clear the last significant bit set
+    }
+
+    return c;
+}
+
 // US does not have duty cycling - return now as earliest TX time
 #define nextTx(now) (_nextTx(),(now))
 static void _nextTx (void) {
-    if( LMIC.chRnd==0 )
-        LMIC.chRnd = os_getRndU1() & 0x3F;
+    u1_t prev_ch = LMIC.txChnl;
+    u1_t tries = 0;
+    u1_t en_cnt;
+    
     if( LMIC.datarate >= DR_SF8C ) { // 500kHz
-        u1_t map = LMIC.channelMap[64/16]&0xFF;
-        for( u1_t i=0; i<8; i++ ) {
-            if( (map & (1<<(++LMIC.chRnd & 7))) != 0 ) {
-                LMIC.txChnl = 64 + (LMIC.chRnd & 7);
-                return;
-            }
-        }
+#ifdef CHNL_HYBRID
+        LMIC.txChnl = 1 << CHNL_HYBRID; // only one channel possible
+#else
+        en_cnt = count_bits(LMIC.channelMap[4]);
+        do {
+            do {
+                LMIC.chRnd = os_getRndU1() & 7;
+                if (++tries > 48)
+                    return;
+            } while ( !(LMIC.channelMap[4] & (1 << LMIC.chRnd)) );
+            LMIC.txChnl = 64 + LMIC.chRnd;
+            if (en_cnt < 2)
+                prev_ch = LMIC.txChnl + 1;  // not enough enabled, skip the following test
+                
+        } while (prev_ch == LMIC.txChnl);
+#endif
     } else { // 125kHz
-        for( u1_t i=0; i<64; i++ ) {
-            u1_t chnl = ++LMIC.chRnd & 0x3F;
-            if( (LMIC.channelMap[(chnl >> 4)] & (1<<(chnl & 0xF))) != 0 ) {
-                LMIC.txChnl = chnl;
-                return;
-            }
-        }
+#ifdef CHNL_HYBRID
+        u1_t idx = CHNL_HYBRID >> 1;
+        en_cnt = count_bits(LMIC.channelMap[idx]);
+        do {
+            do {
+                LMIC.chRnd = os_getRndU1() & 15;
+                if (++tries > 96)
+                    return;
+            } while ( !(LMIC.channelMap[idx] & (1 << LMIC.chRnd)) );
+            LMIC.txChnl = (idx << 4) + LMIC.chRnd;
+            if (en_cnt < 2)
+                prev_ch = LMIC.txChnl + 1;  // not enough enabled, skip the following test
+                            
+        } while (prev_ch == LMIC.txChnl);
+#else
+        en_cnt = count_bits(LMIC.channelMap[0]);
+        en_cnt += count_bits(LMIC.channelMap[1]);
+        en_cnt += count_bits(LMIC.channelMap[2]);
+        en_cnt += count_bits(LMIC.channelMap[3]);
+        do {
+            do {
+                LMIC.chRnd = os_getRndU1() & 63;
+            } while ( !(LMIC.channelMap[LMIC.chRnd >> 4] & (1 << (LMIC.chRnd & 15))) );
+            LMIC.txChnl = LMIC.chRnd;
+            if (en_cnt < 2)
+                prev_ch = LMIC.txChnl + 1;  // not enough enabled, skip the following test
+                
+        } while (prev_ch == LMIC.txChnl);
+#endif
     }
-    // No feasible channel  found! Keep old one.
 }
 
 static void setBcnRxParams (void) {
@@ -839,31 +929,43 @@
 
 static void initJoinLoop (void) {
     LMIC.chRnd = 0;
+#ifdef CHNL_HYBRID
+    LMIC.joinBlockChnl = 0;
+    LMIC.joinBlock = CHNL_HYBRID;
+    LMIC.txChnl = LMIC.joinBlock << 3;
+#else
     LMIC.txChnl = 0;
-    LMIC.adrTxPow = 20;
+    LMIC.joinBlockChnl = 0;
+    LMIC.joinBlock = 0;
+#endif
+    LMIC.datarate = DR_SF10;
+    LMIC.adrTxPow = LMIC.txpow_limit;
     ASSERT((LMIC.opmode & OP_NEXTCHNL)==0);
     LMIC.txend = os_getTime();
     setDrJoin(DRCHG_SET, DR_SF7);
 }
 
 static ostime_t nextJoinState (void) {
-    // Try the following:
-    //   SF7/8/9/10  on a random channel 0..63
-    //   SF8C        on a random channel 64..71
-    //
     u1_t failed = 0;
-    if( LMIC.datarate != DR_SF8C ) {
-        LMIC.txChnl = 64+(LMIC.txChnl&7);
-        setDrJoin(DRCHG_SET, DR_SF8C);
+    
+    if( LMIC.datarate == DR_SF8C ) {
+        // attempted 500khz channel, try 125khz channel in next block
+        LMIC.datarate = DR_SF10;
+        if (++LMIC.joinBlock == 8) {
+            LMIC.joinBlock = 0;
+            if (++LMIC.joinBlockChnl == 8)
+                LMIC.joinBlockChnl = 0;
+        }
+        LMIC.txChnl = (LMIC.joinBlock << 3) + LMIC.joinBlockChnl;
     } else {
-        LMIC.txChnl = os_getRndU1() & 0x3F;
-        s1_t dr = DR_SF7 - ++LMIC.txCnt;
-        if( dr < DR_SF10 ) {
-            dr = DR_SF10;
-            failed = 1; // All DR exhausted - signal failed
-        }
-        setDrJoin(DRCHG_SET, dr);
+        // attempted 125khz channel, try 500khz channel
+        LMIC.datarate = DR_SF8C;
+        LMIC.txChnl = LMIC.joinBlock + 64;
     }
+#ifdef JOIN_REQ_DEBUG
+    printf("njs blk%d, dr%d, txChnl%d ", LMIC.joinBlock, LMIC.datarate, LMIC.txChnl); // crlf in updateTx()
+#endif /* JOIN_REQ_DEBUG */
+    
     LMIC.opmode &= ~OP_NEXTCHNL;
     LMIC.txend = os_getTime() +
         (isTESTMODE()
@@ -931,9 +1033,9 @@
     ASSERT(LMIC.dataLen == LEN_BCN); // implicit header RX guarantees this
     xref2u1_t d = LMIC.frame;
     if(
-#if CFG_eu868
+#ifdef CFG_eu868
         d[OFF_BCN_CRC1] != (u1_t)os_crc16(d,OFF_BCN_CRC1)
-#elif CFG_us915
+#elif defined(CFG_us915)
         os_rlsbf2(&d[OFF_BCN_CRC1]) != os_crc16(d,OFF_BCN_CRC1)
 #endif
         )
@@ -1322,7 +1424,7 @@
 
     if( LMIC.dataLen == 0 ) {
       nojoinframe:
-        if( (LMIC.opmode & OP_JOINING) == 0 ) {
+        /* keep retrying -- if( (LMIC.opmode & OP_JOINING) == 0 ) {
             ASSERT((LMIC.opmode & OP_REJOIN) != 0);
             // REJOIN attempt for roaming
             LMIC.opmode &= ~(OP_REJOIN|OP_TXRXPEND);
@@ -1330,7 +1432,7 @@
                 LMIC.rejoinCnt++;
             reportEvent(EV_REJOIN_FAILED);
             return 1;
-        }
+        }*/
         LMIC.opmode &= ~OP_TXRXPEND;
         ostime_t delay = nextJoinState();
         EV(devCond, DEBUG, (e_.reason = EV::devCond_t::NO_JACC,
@@ -1860,7 +1962,7 @@
     LMIC.bcnRxtime = LMIC.bcninfo.txtime + BCN_INTV_osticks - calcRxWindow(0,DR_BCN);
     LMIC.bcnRxsyms = LMIC.rxsyms;    
   rev:
-#if CFG_us915
+#ifdef CFG_us915
     LMIC.bcnChnl = (LMIC.bcnChnl+1) & 7;
 #endif
     if( (LMIC.opmode & OP_PINGINI) != 0 )
@@ -1930,11 +2032,13 @@
         if( txbeg - (now + TX_RAMPUP) < 0 ) {
             // We could send right now!
             dr_t txdr = (dr_t)LMIC.datarate;
+            txbeg = now;
             if( jacc ) {
                 u1_t ftype;
                 if( (LMIC.opmode & OP_REJOIN) != 0 ) {
                     txdr = lowerDR(txdr, LMIC.rejoinCnt);
-                    ftype = HDR_FTYPE_REJOIN;
+                    //ftype = HDR_FTYPE_REJOIN;
+                    ftype = HDR_FTYPE_JREQ;
                 } else {
                     ftype = HDR_FTYPE_JREQ;
                 }
@@ -2170,4 +2274,10 @@
     LMIC.adrAckReq = enabled ? LINK_CHECK_INIT : LINK_CHECK_OFF;
 }
 
- 
+void LMIC_reverse_memcpy(u1_t *dst, const u1_t *src, size_t n)
+{
+    size_t i;
+
+    for (i=0; i < n; ++i)
+        dst[n-1-i] = src[i];    
+}