Adapted to LoRa Semtech + Nucleo
Dependencies: LMiC SX1276Lib cantcoap lwip mbed-rtos mbed
Fork of LoRaWAN-lmic-app by
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 ="<="; 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 }
Generated on Sun Jul 17 2022 22:01:57 by 1.7.2