Adapted to LoRa Semtech + Nucleo

Dependencies:   LMiC SX1276Lib cantcoap lwip mbed-rtos mbed

Fork of LoRaWAN-lmic-app by Pascal Nysten

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