Adapted to LoRa Semtech + Nucleo

Dependencies:   LMiC SX1276Lib cantcoap lwip mbed-rtos mbed

Fork of LoRaWAN-lmic-app by Semtech

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /* 
00002  / _____)             _              | |
00003 ( (____  _____ ____ _| |_ _____  ____| |__
00004  \____ \| ___ |    (_   _) ___ |/ ___)  _ \
00005  _____) ) ____| | | || |_| ____( (___| | | |
00006 (______/|_____)_|_|_| \__)_____)\____)_| |_|
00007     (C)2015 Semtech
00008 
00009 Description: MBED LoRaWAN example application
00010 
00011 License: Revised BSD License, see LICENSE.TXT file include in the project
00012 
00013 Maintainer: Miguel Luis and Gregory Cristian
00014 */
00015 #include <cstdio>
00016 #include <string>
00017 #include <cassert>
00018 
00019 #include "mbed.h"
00020 #include "cantcoap.h"
00021 
00022 #include "lmic.h"
00023 #include "debug.h"
00024 
00025 const std::string REGISTRATION_SEGMENT ="/rd";
00026 const std::string ENDPOINT_SEGMENT     = "?ep=";
00027 const std::string LIFETIME             ="&lt=";
00028 const std::string BINDING              ="&b=";
00029 
00030 const std::string REGISTRATION_OPEN  =    "<";
00031 const std::string REGISTRATION_CLOSE =    ">";
00032 const std::string REGISTRATION_SEPARATOR ="/";
00033 
00034 int _node_Id=0;
00035 
00036 const std::string endPoint_Name = "loraDevice"; 
00037 const int lifeTime = 300;
00038 const std::string binding = "U";
00039 
00040 unsigned char * _payload;
00041 long _payload_size;
00042 
00043 /*!
00044  * When set to 1 the application uses the Over-the-Air activation procedure
00045  * When set to 0 the application uses the Personalization activation procedure
00046  */
00047 #define OVER_THE_AIR_ACTIVATION                     0
00048 
00049 #if( OVER_THE_AIR_ACTIVATION == 0 )
00050 
00051 /*!
00052  * Defines the network ID when using personalization activation procedure
00053  */
00054 #define LORAWAN_NET_ID                              ( uint32_t )0x00000000
00055 
00056 /*!
00057  * Defines the device address when using personalization activation procedure
00058  */
00059 #define LORAWAN_DEV_ADDR                            ( uint32_t )0x12345678
00060 
00061 #endif
00062 
00063 /*!
00064  * Defines the application data transmission duty cycle
00065  */
00066 #define APP_TX_DUTYCYCLE                            5000 // 5 [s] value in ms
00067 #define APP_TX_DUTYCYCLE_RND                        1000 // 1 [s] value in ms
00068 
00069 /*!
00070  * LoRaWAN Adaptative Data Rate
00071  */
00072 #define LORAWAN_ADR_ON                              1
00073 
00074 /*!
00075  * LoRaWAN confirmed messages
00076  */
00077 #define LORAWAN_CONFIRMED_MSG_ON                    1
00078 
00079 /*!
00080  * LoRaWAN application port
00081  */
00082 #define LORAWAN_APP_PORT                            15
00083 
00084 /*!
00085  * User application data buffer size
00086  */
00087 #if ( LORAWAN_CONFIRMED_MSG_ON == 1 )
00088 #define LORAWAN_APP_DATA_SIZE                       6
00089 
00090 #else
00091 #define LORAWAN_APP_DATA_SIZE                       1
00092 
00093 #endif
00094 
00095 #define UINT16_MAX (65535U)
00096 #define UINT64_MAX (18446744073709551615ULL)
00097 
00098 
00099 std::string to_string( int x ) {
00100   int length = snprintf( NULL, 0, "%d", x );
00101   assert( length >= 0 );
00102   char* buf = new char[length + 1];
00103   snprintf( buf, length + 1, "%d", x );
00104   std::string str( buf );
00105   delete[] buf;
00106   return str;
00107 }
00108 unsigned char * get_Registration_Payload(long *payload_size){
00109 
00110     string registration_Payload ="";
00111 
00112     string s="";
00113 
00114     s.append(REGISTRATION_OPEN);
00115     s.append(REGISTRATION_SEPARATOR);
00116     s.append("3/0/0");
00117     s.append(REGISTRATION_CLOSE);
00118     s.append(",");
00119     s.append(REGISTRATION_OPEN);
00120     s.append(REGISTRATION_SEPARATOR);
00121     s.append("3/0/1");
00122     s.append(REGISTRATION_CLOSE);
00123     s.append(",");
00124     s.append(REGISTRATION_OPEN);
00125     s.append(REGISTRATION_SEPARATOR);
00126     s.append("3/0/2");
00127     s.append(REGISTRATION_CLOSE);
00128 
00129     registration_Payload.append(s);
00130     
00131     unsigned char *c = new unsigned char[registration_Payload.size()+1];
00132     copy(registration_Payload.begin(),registration_Payload.end(),c);
00133     c[registration_Payload.size()]='\0';
00134     *payload_size=registration_Payload.size();
00135     
00136     return c;
00137 
00138 }
00139 uint8_t * get_Token(int * size){
00140     srand(time(0)+_node_Id);
00141     long test=0;
00142     bool exist=false;
00143     
00144     do{
00145         test=(rand() % UINT64_MAX);
00146         
00147     }while (exist==true);
00148     uint8_t ones = 0xFF;
00149     *size=1;
00150     for (int i=0; i<8; ++i) {
00151         if ( (test>>8*i & ones) =='\0' || i==8) {
00152             *size=i;
00153             break;
00154         }
00155     }
00156     uint8_t * token =new uint8_t[*size];
00157     for (int i=0; i<*size; ++i){
00158         token[*size-1-i]=test>>8*i & ones;
00159     }
00160     return token;
00161 }
00162 
00163 uint16_t get_Message_ID(){
00164     srand(time(0)+_node_Id);
00165     int test=0;
00166     bool exist=false;
00167     do{
00168         
00169         exist=false;
00170         test=(rand() % UINT16_MAX);
00171         
00172     }while (exist==true);
00173     
00174     
00175     return (uint16_t) test;
00176     
00177 }
00178 
00179 char * get_Registration_Query(){
00180     
00181     string buffer;
00182     buffer.append(REGISTRATION_SEGMENT);
00183     buffer.append(ENDPOINT_SEGMENT);
00184     buffer.append(endPoint_Name);
00185     buffer.append(LIFETIME);
00186     buffer.append(to_string(lifeTime));
00187     buffer.append(BINDING);
00188     buffer.append(binding);
00189     
00190     char *c = new char[buffer.size()+1];
00191     copy(buffer.begin(),buffer.end(),c);
00192     c[buffer.size()]='\0';
00193     return c;
00194     
00195 
00196 }
00197 
00198 //////////////////////////////////////////////////
00199 // CONFIGURATION (FOR APPLICATION CALLBACKS BELOW)
00200 //////////////////////////////////////////////////
00201 
00202 // application router ID (LSBF)
00203 static const uint8_t AppEui[8] =
00204 {
00205     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
00206 };
00207 
00208 // unique device ID (LSBF)
00209 static const u1_t DevEui[8] =
00210 {
00211     0x00, 0x00, 0x00, 0x00, 0x08, 0x06, 0x02, 0x48
00212 //    0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF
00213 //    0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x099, 0xF7
00214 };
00215 
00216 // device-specific AES key (derived from device EUI)
00217 static const uint8_t DevKey[16] = 
00218 {
00219     0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6,
00220     0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C
00221 };
00222 
00223 #if( OVER_THE_AIR_ACTIVATION == 0 )
00224 // network session key
00225 static uint8_t NwkSKey[] = 
00226 { 
00227     0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6,
00228     0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C
00229 };
00230 
00231 // application session key
00232 static uint8_t ArtSKey[] = 
00233 { 
00234     0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6,
00235     0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C
00236 };
00237 
00238 #endif
00239 
00240 // LEDs and Frame jobs
00241 osjob_t rxLedJob;
00242 osjob_t txLedJob;
00243 osjob_t sendFrameJob;
00244 
00245 // LED state
00246 static bool AppLedStateOn = false;
00247 
00248 //////////////////////////////////////////////////
00249 // Utility functions
00250 //////////////////////////////////////////////////
00251 /*!
00252  * \brief Computes a random number between min and max
00253  *
00254  * \param [IN] min range minimum value
00255  * \param [IN] max range maximum value
00256  * \retval random random value in range min..max
00257  */
00258 int32_t randr( int32_t min, int32_t max )
00259 {
00260     return ( int32_t )rand( ) % ( max - min + 1 ) + min;
00261 }
00262 
00263 //////////////////////////////////////////////////
00264 // APPLICATION CALLBACKS
00265 //////////////////////////////////////////////////
00266 
00267 // provide application router ID (8 bytes, LSBF)
00268 void os_getArtEui( uint8_t *buf )
00269 {
00270     memcpy( buf, AppEui, 8 );
00271 }
00272 
00273 // provide device ID (8 bytes, LSBF)
00274 void os_getDevEui( uint8_t *buf )
00275 {
00276     memcpy( buf, DevEui, 8 );
00277 }
00278 
00279 // provide device key (16 bytes)
00280 void os_getDevKey( uint8_t *buf )
00281 {
00282     memcpy( buf, DevKey, 16 );
00283 }
00284 
00285 //////////////////////////////////////////////////
00286 // MAIN - INITIALIZATION AND STARTUP
00287 //////////////////////////////////////////////////
00288 
00289 static void onRxLed( osjob_t* j )
00290 {
00291     debug_val("LED2 = ", 0 );
00292 }
00293 
00294 static void onTxLed( osjob_t* j )
00295 {
00296     debug_val("LED1 = ", 0 );
00297 }
00298 
00299 static void prepareTxFrame( void )
00300 {
00301     LMIC.frame[0] = AppLedStateOn;
00302 #if ( LORAWAN_CONFIRMED_MSG_ON == 1 )
00303     LMIC.frame[1] = LMIC.seqnoDn >> 8;
00304     LMIC.frame[2] = LMIC.seqnoDn;
00305     LMIC.frame[3] = LMIC.rssi >> 8;
00306     LMIC.frame[4] = LMIC.rssi;
00307     LMIC.frame[5] = LMIC.snr;
00308 #endif    
00309 /*    debug_str("Frame to be sent: ");
00310     debug_val("1: ", LMIC.frame[0]);
00311     debug_val("2: ", LMIC.frame[1]);
00312     debug_val("3: ", LMIC.frame[2]);
00313     debug_val("4: ", LMIC.frame[3]);
00314     debug_val("5: ", LMIC.frame[4]);
00315     debug_val("6: ", LMIC.frame[5]);
00316     debug_str("\r\n");*/
00317 }
00318 
00319 void processRxFrame( void )
00320 {
00321     debug_str("Data: ");
00322     debug_buf( LMIC.frame + LMIC.dataBeg, LMIC.dataLen );
00323 /*    debug_str("Data - command: ");
00324     debug_hex(LMIC.frame[0]);
00325     debug_str("\r\n");*/
00326 
00327     switch( LMIC.frame[LMIC.dataBeg - 1] ) // Check Rx port number
00328     {
00329         case 0:
00330 //            debug_str("Port 0!!!\r\n");
00331 //            debug_val("Data Len: ", LMIC.dataLen);
00332             
00333         case 1: // The application LED can be controlled on port 1 or 2
00334         case 2:
00335             if( LMIC.dataLen == 1 )
00336             {
00337                 debug_str("Data received on port 2: ");
00338                 debug_hex(LMIC.frame[LMIC.dataBeg]);
00339                 debug_str("\r\n");
00340                 AppLedStateOn = LMIC.frame[LMIC.dataBeg] & 0x01;
00341                 debug_val( "LED3 = ", AppLedStateOn );
00342             }
00343             break;
00344         default:
00345             break;
00346     }
00347 }
00348 
00349 static void onSendFrame( osjob_t* j )
00350 {
00351     prepareTxFrame( );
00352 
00353     // Create Registration PDU :
00354     
00355     CoapPDU *pdu = new CoapPDU();
00356     
00357     pdu->setCode(CoapPDU::COAP_POST);
00358     pdu->setType(CoapPDU::COAP_CONFIRMABLE);
00359     int size;
00360     uint8_t * token = get_Token(&size);
00361     pdu->setToken(token,size);
00362     pdu->setMessageID(get_Message_ID());
00363     pdu->setURI(get_Registration_Query());
00364     
00365     _payload=get_Registration_Payload(&_payload_size);
00366     pdu->setPayload(_payload, (int) _payload_size);
00367     
00368     int PDUlength = pdu->getPDULength();
00369     u1_t frame[PDUlength+6];
00370     
00371     memcpy(frame, pdu->getPDUPointer(), PDUlength * sizeof(uint8_t));
00372 
00373     frame[PDUlength] = LMIC.seqnoDn >> 8;
00374     frame[PDUlength+1] = LMIC.seqnoDn;
00375     frame[PDUlength+2] = LMIC.rssi >> 8;
00376     frame[PDUlength+3] = LMIC.rssi;
00377     frame[PDUlength+4] = LMIC.snr;
00378     frame[PDUlength+5] = '\0';
00379     /* debug_str("Frame: ");
00380     debug_str(pdu->getPDUPointer());
00381     debug_str("  <STOP>\r\n");
00382 
00383     debug_str("Frame: ");
00384     debug_str(frame);
00385     debug_str("  <STOP>\r\n");
00386     debug_val("Frame Length: ", PDUlength+5);*/
00387     
00388     //LMIC_setTxData2( LORAWAN_APP_PORT, frame, PDUlength+6, LORAWAN_CONFIRMED_MSG_ON );
00389     LMIC_setTxData2( LORAWAN_APP_PORT, LMIC.frame, LORAWAN_APP_DATA_SIZE, LORAWAN_CONFIRMED_MSG_ON );
00390 
00391     // Blink Tx LED
00392     debug_val( "LED1 = ", 1 );
00393     os_setTimedCallback( &txLedJob, os_getTime( ) + ms2osticks( 25 ), onTxLed );
00394 }
00395 
00396 // Initialization job
00397 static void onInit( osjob_t* j )
00398 {
00399     // reset MAC state
00400     LMIC_reset( );
00401     LMIC_setAdrMode( LORAWAN_ADR_ON );
00402     LMIC_setDrTxpow( DR_SF12, 14 );
00403 
00404     // start joining
00405 #if( OVER_THE_AIR_ACTIVATION != 0 )
00406     LMIC_startJoining( );
00407 #else
00408     LMIC_setSession( LORAWAN_NET_ID, LORAWAN_DEV_ADDR, NwkSKey, ArtSKey );
00409     onSendFrame( NULL );
00410 #endif
00411     // init done - onEvent( ) callback will be invoked...
00412 }
00413 
00414 int main( void )
00415 {
00416     debug_init();
00417     osjob_t initjob;
00418 
00419     // initialize runtime env
00420     os_init( );
00421     // setup initial job
00422     os_setCallback( &initjob, onInit );
00423     // execute scheduled jobs and events
00424     os_runloop( );
00425     // (not reached)
00426 }
00427 
00428 //////////////////////////////////////////////////
00429 // LMIC EVENT CALLBACK
00430 //////////////////////////////////////////////////
00431 void onEvent( ev_t ev )
00432 {
00433     bool txOn = false;
00434     debug_event( ev );
00435 
00436     switch( ev ) 
00437     {
00438     // network joined, session established
00439     case EV_JOINED:
00440         debug_val( "Net ID = ", LMIC.netid );
00441         txOn = true;
00442         break;
00443     // scheduled data sent (optionally data received)
00444     case EV_TXCOMPLETE:
00445         debug_val( "Datarate = ", LMIC.datarate );
00446         // Check if we have a downlink on either Rx1 or Rx2 windows
00447         if( ( LMIC.txrxFlags & ( TXRX_DNW1 | TXRX_DNW2 ) ) != 0 )
00448         {
00449             debug_val( "LED2 = ", 1 );
00450             os_setTimedCallback( &rxLedJob, os_getTime( ) + ms2osticks( 25 ), onRxLed );
00451 
00452             if( LMIC.dataLen != 0 )
00453             { // data received in rx slot after tx
00454                 //debug_buf( LMIC.frame + LMIC.dataBeg, LMIC.dataLen );
00455                 processRxFrame( );
00456             }
00457         }
00458         txOn = true;
00459         break;
00460     default:
00461         break;
00462     }
00463     if( txOn == true )
00464     {
00465         //Sends frame every APP_TX_DUTYCYCLE +/- APP_TX_DUTYCYCLE_RND random time (if not duty cycle limited)
00466         os_setTimedCallback( &sendFrameJob,
00467                              os_getTime( ) + ms2osticks( APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ) ),
00468                              onSendFrame );
00469         
00470         ////Sends frame as soon as possible (duty cylce limitations)
00471         //onSendFrame( NULL );
00472     }
00473 }