LMIC transmit example for NAmote-72 with GPS

Dependencies:   lib_gps lib_mpl3115a2 lmic_MOTE_L152RC mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /*******************************************************************************
00002  * Copyright (c) 2014-2015 IBM Corporation.
00003  * All rights reserved. This program and the accompanying materials
00004  * are made available under the terms of the Eclipse Public License v1.0
00005  * which accompanies this distribution, and is available at
00006  * http://www.eclipse.org/legal/epl-v10.html
00007  *
00008  * Contributors:
00009  *    IBM Zurich Research Lab - initial API, implementation and documentation
00010  *******************************************************************************/
00011 
00012 #include "lmic.h"
00013 #include "debug.h"
00014 #include <mbed.h>
00015 #include "gps.h"
00016 #include "mpl3115a2.h"
00017 
00018 #define FHS_MAX_POW     30      /* Frequency Hopping Max Power */
00019 #define DMTS_MAX_POW    26      /* Digital Modulation Max Power */
00020 #define HS_MAX_POW      20      /* Hybrid System Max Power */
00021 
00022 bool joined;
00023 typedef enum {
00024     MOTE_NONE = 0,
00025     MOTE_V2,
00026     MOTE_V3
00027 } mote_version_e;
00028 mote_version_e mote_version = MOTE_NONE;
00029 
00030 DigitalOut gps_en(PB_11);   // dis/enables voltage divider on PA_1
00031 DigitalOut pc_7(PC_7);
00032 DigitalIn pc_1(PC_1);
00033 AnalogIn *bat;
00034 #define LOW_BAT_THRESHOLD   3.45
00035 #define AIN_VREF        3.3     // stm32 internal refernce
00036 #define AIN_VBAT_DIV    2       // resistor divider
00037 
00038 #define LED_ON          0
00039 #define LED_OFF         1
00040 static DigitalOut led_red(PB_1);
00041 static DigitalOut led_yellow(PB_10);
00042 //static DigitalOut led_green(PC_3);
00043 static DigitalOut led_usr(PA_5);
00044 
00045 
00046 GPS gps(PB_6, PB_7, PB_11);
00047 I2C i2c(I2C_SDA, I2C_SCL);
00048 DigitalIn i2c_int_pin(PB_4);
00049 MPL3115A2 mpl3115a2(i2c, i2c_int_pin);
00050 volatile bool AppLedStateOn = false;
00051 
00052 
00053 //////////////////////////////////////////////////
00054 // CONFIGURATION (FOR APPLICATION CALLBACKS BELOW)
00055 //////////////////////////////////////////////////
00056 
00057 static const u1_t app_eui[ 8] = { APPEUI };
00058 //static       u1_t dev_eui[ 8] = { OUI, 0x00, 0xff, 0xff, 0xff, 0xff };
00059 static       u1_t dev_eui[ 8] = { DEVEUI };
00060 static const u1_t dev_key[16] = { DEVKEY };
00061 
00062 
00063 //////////////////////////////////////////////////
00064 // APPLICATION CALLBACKS
00065 //////////////////////////////////////////////////
00066 
00067 // provide application router ID (8 bytes, LSBF)
00068 void os_getArtEui (u1_t* buf) {
00069     LMIC_reverse_memcpy(buf, app_eui, sizeof(app_eui));
00070 }
00071 
00072 // provide device ID (8 bytes, LSBF)
00073 void os_getDevEui (u1_t* buf) {
00074     LMIC_reverse_memcpy(buf, dev_eui, sizeof(dev_eui));
00075 }
00076 
00077 // provide device key (16 bytes)
00078 void os_getDevKey (u1_t* buf) {
00079     memcpy(buf, dev_key, sizeof(dev_key));
00080 }
00081 
00082 
00083 //////////////////////////////////////////////////
00084 // MAIN - INITIALIZATION AND STARTUP
00085 //////////////////////////////////////////////////
00086 void get_mote_version()
00087 {
00088     char first;
00089       
00090     pc_7 = 1;
00091     first = pc_1;
00092     pc_7 = 0;
00093     if (first && !pc_1) {
00094         gps.en_invert = 1;
00095         mote_version = MOTE_V2;
00096         bat = new AnalogIn(PA_0);       
00097     } else {
00098         mote_version = MOTE_V3;
00099         bat = new AnalogIn(PA_1);
00100         //gps.en_invert = 0;        
00101         gps_en = 0;
00102     }
00103 }
00104 
00105 //////////////////////////////////////////////////
00106 // Display network parameters (DevEUI, AppEUI etc)
00107 //////////////////////////////////////////////////
00108 void DisplayNetworkParam()
00109 {
00110     int i;
00111 
00112     if(mote_version == MOTE_V2)
00113         printf("\r\nNA Mote Ver. 2\r\n");
00114     else
00115         if(mote_version == MOTE_V3)
00116             printf("\r\nNA Mote Ver. 3\r\n");
00117         else
00118             printf("\r\nNA Mote Ver. NOT DEFINED\r\n");
00119         
00120     printf("DEVEUI:");
00121     for (i = 0; i < sizeof(dev_eui); i++) {
00122         printf("%02x", dev_eui[i]);
00123         if (i < sizeof(dev_eui)-1)
00124             printf("-");
00125     }
00126     printf("\r\n");
00127     
00128     printf("APPEUI:");
00129     for (i = 0; i < sizeof(app_eui); i++) {
00130         printf("%02x", app_eui[i]);
00131         if (i < sizeof(app_eui)-1)
00132             printf("-");        
00133     }
00134     printf("\r\n");
00135         
00136     printf("DEVKEY:");
00137     for (i = 0; i < sizeof(dev_key); i++) {
00138         printf("%02x ", dev_key[i]);
00139     }
00140     printf("\r\n"); 
00141 }
00142 
00143 void DisplayData(uint8_t *pData, int len)
00144 {
00145     int i;
00146 
00147     for(i = 0; i < len; i++)
00148         printf("%x ", pData[i]);
00149     printf("\r\n");
00150 }
00151 
00152 osjob_t nJoinedJob;
00153 
00154 static void on_not_joined(osjob_t* j)
00155 {   
00156     if (joined)
00157         return;
00158 
00159     DisplayNetworkParam();
00160     
00161     os_setTimedCallback( &nJoinedJob, os_getTime() + ms2osticks(7000), on_not_joined );
00162 }
00163 
00164 
00165 // initial job
00166 static void initfunc (osjob_t* j)
00167 {
00168     u4_t* id;
00169     u4_t* u4_ptr;
00170     
00171     u4_ptr = (u4_t*)&dev_eui[4];   // [4] to [7]
00172 
00173     if(*u4_ptr == 0)
00174     {
00175         id = (u4_t*)0x1ff800d0; // STM32L1xx Cat3
00176         *u4_ptr = *id;
00177         id = (u4_t*)0x1ff800d4;
00178         *u4_ptr ^= *id;
00179         id = (u4_t*)0x1ff800e4;
00180         *u4_ptr ^= *id;    
00181     }
00182     
00183     get_mote_version(); 
00184     gps.init();
00185         
00186     gps.enable(1);
00187     mpl3115a2.init();       
00188     
00189     // reset MAC state
00190     LMIC_reset();
00191     
00192     os_setTimedCallback( &nJoinedJob, os_getTime() + ms2osticks(3000), on_not_joined );
00193     joined = false;
00194     // start joining
00195     LMIC_startJoining();
00196     
00197     led_red = LED_ON;   // indicate joining
00198     led_yellow = LED_OFF;
00199     //led_green = LED_OFF;
00200     // init done - onEvent() callback will be invoked...
00201 }
00202 
00203 
00204 // application entry point
00205 int main () {
00206     osjob_t initjob;
00207 
00208     // initialize runtime env
00209     os_init();
00210     // initialize debug library
00211     debug_init();
00212     // setup initial job
00213     os_setCallback(&initjob, initfunc);
00214     // execute scheduled jobs and events
00215     os_runloop();
00216     // (not reached)
00217     return 0;
00218 }
00219 
00220 static void
00221 restore_hsi()
00222 {
00223     RCC_OscInitTypeDef osc_init;
00224     /* if HSI was shut off in deep sleep (needed for AnalogIn) */
00225     HAL_RCC_GetOscConfig(&osc_init);
00226     if (osc_init.HSIState != RCC_HSI_ON) {
00227         // Enable the HSI (to clock the ADC)
00228         osc_init.OscillatorType = RCC_OSCILLATORTYPE_HSI;
00229         osc_init.HSIState       = RCC_HSI_ON;
00230         osc_init.PLL.PLLState   = RCC_PLL_NONE;
00231         HAL_RCC_OscConfig(&osc_init);    
00232     }    
00233 }
00234 
00235 osjob_t sendFrameJob;
00236 osjob_t indicateJob;
00237 
00238 static void tx_ind_cb(osjob_t* j)
00239 {
00240     led_red = LED_OFF;    
00241 }
00242 
00243 static void onSendFrame (osjob_t* j)
00244 {
00245     uint16_t altitudeGps;
00246     
00247     if (LMIC.opmode & OP_TXRXPEND) {
00248         return;
00249     }
00250     
00251 #ifdef FIXED_DR
00252     LMIC.datarate = FIXED_DR;
00253 #endif
00254     
00255 #ifdef FIXED_TX_POWER
00256     LMIC.txpow = FIXED_TX_POWER;
00257 #endif
00258     
00259     restore_hsi();
00260     
00261     if(LMIC.datarate == DR_SF8C)
00262         LMIC.txpow_limit = DMTS_MAX_POW;
00263     else
00264 #ifdef CHNL_HYBRID
00265         LMIC.txpow_limit = HS_MAX_POW;
00266 #else
00267         LMIC.txpow_limit = FHS_MAX_POW;
00268 #endif
00269 
00270     if( LMIC.txpow > LMIC.txpow_limit)
00271         LMIC.txpow = LMIC.txpow_limit;
00272     
00273     float volts = bat->read()*AIN_VREF*AIN_VBAT_DIV;
00274     if (volts < LOW_BAT_THRESHOLD) {
00275         if (LMIC.txpow_limit > 20)
00276             LMIC.txpow_limit = 20;
00277         if (LMIC.txpow > 20)
00278             LMIC.txpow = 20;
00279     }
00280     
00281     ///////////////////////////////////////////////////////////////////    
00282     gps.service();
00283     mpl3115a2.ReadTemperature();    
00284 
00285     uint8_t tmpData[PAYLOAD_LENGTH] = {0};
00286 
00287     tmpData[0] = 15-(LMIC.txpow>>1);
00288     tmpData[0] <<= 4;
00289 #ifdef CHNL_HYBRID
00290     tmpData[0] |= 0x04;  // 8ch: set bit2
00291 #else
00292     tmpData[0] |= 0x08;  // 64ch: set bit3
00293 #endif
00294 
00295     tmpData[0] |= AppLedStateOn & 1; // (bit 0 == 1) => LED on
00296     tmpData[1] = (int)mpl3115a2.Temperature; // Signed degrees Celcius in half degree units. So,  +/-63 C
00297     tmpData[2] = (bat->read_u16() >> 8) + (bat->read_u16() >> 9) ; // per LoRaMAC spec; 0=Charging; 1...254 = level, 255 = N/A
00298     
00299     tmpData[3] = ( gps.LatitudeBinary >> 16 ) & 0xFF;
00300     tmpData[4] = ( gps.LatitudeBinary >> 8 ) & 0xFF;
00301     tmpData[5] = gps.LatitudeBinary & 0xFF;
00302     tmpData[6] = ( gps.LongitudeBinary >> 16 ) & 0xFF;
00303     tmpData[7] = ( gps.LongitudeBinary >> 8 ) & 0xFF;
00304     tmpData[8] = gps.LongitudeBinary & 0xFF;
00305 
00306     altitudeGps = atoi(gps.NmeaGpsData.NmeaAltitude);
00307     tmpData[9] = ( altitudeGps >> 8 ) & 0xFF;
00308     tmpData[10] = altitudeGps & 0xFF;
00309     if (PAYLOAD_LENGTH > 11) {
00310         for (int i = 11; i < PAYLOAD_LENGTH; i++)
00311             tmpData[i] = i - 10;
00312     }
00313 
00314     for(int i = 0; i < PAYLOAD_LENGTH; i++)
00315         LMIC.frame[i] = tmpData[i];
00316         
00317     // port, buffer, buffer length, need_ack
00318     LMIC_setTxData2(5, LMIC.frame, PAYLOAD_LENGTH, 0);
00319 
00320     led_red = LED_ON;
00321 
00322     // Display Info
00323 
00324     DisplayNetworkParam();
00325 
00326     printf("Seq# %d\r\n",LMIC.seqnoUp-1);
00327 
00328     printf("TX Data: ");
00329     DisplayData(tmpData, PAYLOAD_LENGTH);
00330 
00331     printf("TX Power: %d dBm\r\n",LMIC.txpow);
00332 
00333     printf("Battery: %f Volts\r\n",volts);
00334 
00335     os_setTimedCallback( &indicateJob, os_getTime() + ms2osticks(30), tx_ind_cb );  
00336     
00337 }
00338 
00339 
00340 //////////////////////////////////////////////////
00341 // LMIC EVENT CALLBACK
00342 //////////////////////////////////////////////////
00343 
00344 void onEvent (ev_t ev)
00345 {
00346     debug_event(ev);
00347     
00348     switch(ev) {
00349         case EV_JOINED:
00350             // network joined, session established
00351             debug_val("netid = ", LMIC.netid);
00352             joined = true;
00353             led_red = LED_OFF;   // indicate joined
00354             goto tx;
00355         case EV_TXCOMPLETE:
00356             // scheduled data sent (optionally data received)
00357             if(LMIC.dataLen) { // data received in rx slot after tx
00358                 led_yellow = led_yellow ? 0 : 1;
00359                 if (LMIC.dataLen == 1) { // set LED state if exactly one byte is received
00360                     led_usr = LMIC.frame[LMIC.dataBeg] & 0x01; 
00361                 }
00362                 debug_buf(LMIC.frame+LMIC.dataBeg, LMIC.dataLen);
00363             }
00364 tx:
00365             os_setTimedCallback( &sendFrameJob, os_getTime() + ms2osticks(MS_DELAY_NEXT_TX), onSendFrame );           
00366             break;
00367         default:
00368             led_red = LED_ON;   // indicate not joined
00369             break;
00370     } // ..switch(ev)
00371 }