Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: SX127x sx12xx_hal TSL2561
single_us915_main.cpp
00001 /* 00002 / _____) _ | | 00003 ( (____ _____ ____ _| |_ _____ ____| |__ 00004 \____ \| ___ | (_ _) ___ |/ ___) _ \ 00005 _____) ) ____| | | || |_| ____( (___| | | | 00006 (______/|_____)_|_|_| \__)_____)\____)_| |_| 00007 (C)2015 Semtech 00008 00009 Description: LoRaMac classA device implementation 00010 00011 License: Revised BSD License, see LICENSE.TXT file include in the project 00012 */ 00013 #include "mbed.h" 00014 #include "board.h" 00015 00016 #include "LoRaMacSingle.h" 00017 #include "Commissioning.h" 00018 #include "commands.h" 00019 00020 #ifdef ENABLE_LUMINOSITY 00021 #include "TSL2561.h" 00022 //TSL2561 tsl2561(TSL2561_ADDR_FLOAT); // https://developer.mbed.org/components/Grove-Digital-Light-Sensor/ 00023 TSL2561 tsl2561(TSL2561_ADDR_LOW); 00024 #endif 00025 00026 #ifdef ENABLE_RGB 00027 #include "ChainableLED.h" 00028 ChainableLED rgb(D6, D7, 1); // https://developer.mbed.org/components/Grove-Chainable-RGB-LED/ 00029 #endif 00030 00031 #ifdef TYPE_ABZ 00032 InterruptIn user_button(PB_2); 00033 #else 00034 InterruptIn user_button(USER_BUTTON); 00035 #endif 00036 00037 #ifdef SENSORS 00038 #ifdef TYPE_ABZ /* DISCO_L072CZ_LRWAN1 */ 00039 PwmOut pwm(PB_5); 00040 DigitalIn pc8_in(PB_13); 00041 DigitalOut pc6_out(PB_14); 00042 AnalogIn a0(PA_0); 00043 AnalogIn a2(PA_4); 00044 #else 00045 PwmOut pwm(PB_11); 00046 DigitalIn pc8_in(PC_8); 00047 DigitalOut pc6_out(PC_6); 00048 AnalogIn a1(A1); // https://developer.mbed.org/teams/Seeed/wiki/Potentiometer 00049 AnalogIn a3(A3); // https://developer.mbed.org/teams/Seeed/wiki/Potentiometer 00050 #endif 00051 00052 #define N_SAMPLES 4 00053 struct sens { 00054 uint16_t seq; 00055 uint16_t ain_A, ain_B; 00056 uint8_t pins; 00057 } sensor[N_SAMPLES]; 00058 uint8_t sensor_in_idx, sensor_out_idx; 00059 uint16_t sample_seqnum; 00060 bool sensor_overflow; 00061 #define POLL_RATE 1.0 00062 00063 void sensor_poll() 00064 { 00065 sensor[sensor_in_idx].seq = sample_seqnum++; 00066 #ifdef TYPE_ABZ 00067 sensor[sensor_in_idx].ain_A = a0.read_u16(); 00068 sensor[sensor_in_idx].ain_B = a2.read_u16(); 00069 #else 00070 sensor[sensor_in_idx].ain_A = a1.read_u16(); 00071 sensor[sensor_in_idx].ain_B = a3.read_u16(); 00072 #endif 00073 sensor[sensor_in_idx].pins = pc8_in.read(); 00074 sensor[sensor_in_idx].pins <<= 1; 00075 sensor[sensor_in_idx].pins = pc6_out.read(); 00076 if (++sensor_in_idx == N_SAMPLES) 00077 sensor_in_idx = 0; 00078 00079 if (sensor_in_idx == sensor_out_idx) 00080 sensor_overflow = true; 00081 } 00082 LowPowerTicker sensor_ticker; 00083 #endif /* SENSORS */ 00084 00085 #if defined(TARGET_DISCO_L072CZ_LRWAN1) || ( defined(TARGET_NUCLEO_L073RZ) && defined(TYPE_ABZ) ) 00086 DigitalOut jumper_out(PA_11); 00087 InterruptIn jumper_in(PA_12); 00088 #else 00089 DigitalOut jumper_out(PC_10); 00090 InterruptIn jumper_in(PC_12); 00091 #endif /* murata */ 00092 00093 char pcbuf[128]; 00094 int pcbuf_len; 00095 00096 /*! 00097 * Defines the application data transmission duty cycle. 5s, value in [ms]. 00098 */ 00099 #define APP_TX_DUTYCYCLE 5000 00100 00101 /*! 00102 * Defines a random delay for application data transmission duty cycle. 1s, 00103 * value in [ms]. 00104 */ 00105 #define APP_TX_DUTYCYCLE_RND 1000 00106 00107 /*! 00108 * LoRaWAN confirmed messages 00109 */ 00110 #define LORAWAN_CONFIRMED_MSG_ON true 00111 00112 /*! 00113 * LoRaWAN application port 00114 */ 00115 #define LORAWAN_APP_PORT 15 00116 00117 /*! 00118 * User application data buffer size 00119 */ 00120 #if ( LORAWAN_CONFIRMED_MSG_ON == 1 ) 00121 #define LORAWAN_APP_DATA_SIZE 6 00122 00123 #else 00124 #define LORAWAN_APP_DATA_SIZE 1 00125 00126 #endif 00127 00128 static uint8_t DevEui[] = LORAWAN_DEVICE_EUI; 00129 static uint8_t AppEui[] = LORAWAN_APPLICATION_EUI; 00130 static uint8_t AppKey[] = LORAWAN_APPLICATION_KEY; 00131 00132 #if( OVER_THE_AIR_ACTIVATION == 0 ) 00133 00134 static uint8_t NwkSKey[] = LORAWAN_NWKSKEY; 00135 static uint8_t AppSKey[] = LORAWAN_APPSKEY; 00136 00137 /*! 00138 * Device address 00139 */ 00140 static uint32_t DevAddr = LORAWAN_DEVICE_ADDRESS; 00141 00142 #endif 00143 00144 /*! 00145 * Application port 00146 */ 00147 #if defined(SENSORS) 00148 static uint8_t AppPort = SENSOR_PORT; 00149 #else 00150 static uint8_t AppPort = LORAWAN_APP_PORT; 00151 #endif 00152 00153 /*! 00154 * User application data size 00155 */ 00156 static uint8_t AppDataSize = LORAWAN_APP_DATA_SIZE; 00157 static unsigned int uplink_length; // user assigned 00158 00159 /*! 00160 * User application data buffer size 00161 */ 00162 #define LORAWAN_APP_DATA_MAX_SIZE 128 00163 00164 /*! 00165 * User application data 00166 */ 00167 static uint8_t AppData[LORAWAN_APP_DATA_MAX_SIZE]; 00168 00169 /*! 00170 * Indicates if the node is sending confirmed or unconfirmed messages 00171 */ 00172 static uint8_t IsTxConfirmed = LORAWAN_CONFIRMED_MSG_ON; 00173 00174 /*! 00175 * Defines the application data transmission duty cycle 00176 */ 00177 static uint32_t TxDutyCycleTime; 00178 00179 /*! 00180 * Timer to handle the application data transmission duty cycle 00181 */ 00182 LowPowerTimeout TxNextPacketTimeout; 00183 00184 volatile bool send_at_beacon; 00185 volatile bool awaiting_mcps_indic; 00186 bool join_retry; 00187 /*! 00188 * Specifies the state of the application LED 00189 */ 00190 static bool AppLedStateOn = false; 00191 00192 /*! 00193 * Device states 00194 */ 00195 static enum eDeviceState 00196 { 00197 DEVICE_STATE_INIT, 00198 DEVICE_STATE_JOIN, 00199 DEVICE_STATE_CYCLE, 00200 DEVICE_STATE_SLEEP, 00201 DEVICE_STATE_REJOIN, 00202 DEVICE_STATE_UPLINK 00203 }DeviceState; 00204 00205 /*! 00206 * Strucure containing the Uplink status 00207 */ 00208 struct sLoRaMacUplinkStatus 00209 { 00210 uint8_t Acked; 00211 //int8_t Datarate; 00212 uint16_t UplinkCounter; 00213 uint8_t Port; 00214 uint8_t *Buffer; 00215 uint8_t BufferSize; 00216 }LoRaMacUplinkStatus; 00217 00218 /*! 00219 * Strucure containing the Downlink status 00220 */ 00221 struct sLoRaMacDownlinkStatus 00222 { 00223 int16_t Rssi; 00224 int8_t Snr; 00225 uint16_t DownlinkCounter; 00226 bool RxData; 00227 uint8_t Port; 00228 uint8_t *Buffer; 00229 uint8_t BufferSize; 00230 }LoRaMacDownlinkStatus; 00231 00232 static uint8_t missed_count; 00233 00234 00235 /*! 00236 * \brief Prepares the payload of the frame 00237 */ 00238 static void PrepareTxFrame( uint8_t port ) 00239 { 00240 switch( port ) 00241 { 00242 case 15: 00243 { 00244 AppData[0] = AppLedStateOn; 00245 if( IsTxConfirmed == true ) 00246 { 00247 AppData[1] = LoRaMacDownlinkStatus.DownlinkCounter >> 8; 00248 AppData[2] = LoRaMacDownlinkStatus.DownlinkCounter; 00249 AppData[3] = LoRaMacDownlinkStatus.Rssi >> 8; 00250 AppData[4] = LoRaMacDownlinkStatus.Rssi; 00251 AppData[5] = LoRaMacDownlinkStatus.Snr; 00252 } 00253 } 00254 break; 00255 #if defined(SENSORS) 00256 case SENSOR_PORT: 00257 { 00258 uint16_t x = 0xffff; 00259 #ifdef ENABLE_LUMINOSITY 00260 x = tsl2561.getLuminosity(TSL2561_VISIBLE); 00261 #endif 00262 if (sensor_overflow) { 00263 app_printf("sensor_overflow\r\n"); 00264 sensor_overflow = false; 00265 } 00266 AppDataSize = 0; 00267 AppData[AppDataSize++] = x >> 8; 00268 AppData[AppDataSize++] = x & 0xff; 00269 while (sensor_in_idx != sensor_out_idx) { 00270 AppData[AppDataSize++] = sensor[sensor_out_idx].seq >> 8; 00271 AppData[AppDataSize++] = sensor[sensor_out_idx].seq & 0xff; 00272 AppData[AppDataSize++] = sensor[sensor_out_idx].ain_A >> 8; 00273 AppData[AppDataSize++] = sensor[sensor_out_idx].ain_A & 0xff; 00274 AppData[AppDataSize++] = sensor[sensor_out_idx].ain_B >> 8; 00275 AppData[AppDataSize++] = sensor[sensor_out_idx].ain_B & 0xff; 00276 AppData[AppDataSize++] = sensor[sensor_out_idx].pins; 00277 if (++sensor_out_idx == N_SAMPLES) 00278 sensor_out_idx = 0; 00279 } 00280 } 00281 break; 00282 #endif /* SENSORS */ 00283 default: 00284 break; 00285 } 00286 } 00287 00288 void 00289 LoRaMacEventInfoStatus_to_string(LoRaMacEventInfoStatus_t status, char* dst) 00290 { 00291 const char* ptr = NULL; 00292 00293 switch (status) { 00294 case LORAMAC_EVENT_INFO_STATUS_RX_ERROR: ptr = "RX_ERROR"; break; 00295 case LORAMAC_EVENT_INFO_STATUS_OK: ptr = "OK"; break; 00296 case LORAMAC_EVENT_INFO_STATUS_ERROR_RX_MTYPE: ptr = "ERROR_RX_MTYPE"; break; 00297 case LORAMAC_EVENT_INFO_STATUS_ERROR_SEND: ptr = "ERROR_SEND"; break; 00298 case LORAMAC_EVENT_INFO_STATUS_ERROR_JOIN_ACCEPT: ptr = "ERROR_JOIN_ACCEPT"; break; 00299 case LORAMAC_EVENT_INFO_STATUS_ERROR_MLMEREQ: ptr = "ERROR_MLMEREQ"; break; 00300 case LORAMAC_EVENT_INFO_STATUS_ERROR_MCPSREQ: ptr = "ERROR_MCPSREQ"; break; 00301 //case LORAMAC_EVENT_INFO_STATUS_ERROR: ptr = "ERROR"; break; 00302 00303 case LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT: ptr = "TX_TIMEOUT"; break; 00304 case LORAMAC_EVENT_INFO_STATUS_RX_TIMEOUT: ptr = "RX_TIMEOUT"; break; 00305 case LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL: ptr = "JOIN_FAIL"; break; 00306 case LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED: ptr = "DOWNLINK_REPEATED"; break; 00307 case LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR: ptr = "TX_DR_PAYLOAD_SIZE_ERROR"; break; 00308 case LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS: ptr = "DOWNLINK_TOO_MANY_FRAMES_LOSS"; break; 00309 case LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL: ptr = "ADDRESS_FAIL"; break; 00310 case LORAMAC_EVENT_INFO_STATUS_MIC_FAIL: ptr = "MIC_FAIL"; break; 00311 case LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED: ptr = "BEACON_LOCKED"; break; 00312 case LORAMAC_EVENT_INFO_STATUS_BEACON_LOST: ptr = "BEACON_LOST"; break; 00313 case LORAMAC_EVENT_INFO_STATUS_BEACON_NOT_FOUND: ptr = "BEACON_NOT_FOUND"; break; 00314 case LORAMAC_EVENT_INFO_STATUS_STOP: ptr = "STOP"; break; 00315 } 00316 00317 if (ptr != NULL) 00318 strcpy(dst, ptr); 00319 } 00320 00321 void 00322 LoRaMacStatus_to_string(LoRaMacStatus_t status, char* dst) 00323 { 00324 const char* ptr = NULL; 00325 00326 switch (status) { 00327 case LORAMAC_STATUS_OK: ptr = "OK"; break; 00328 case LORAMAC_STATUS_BUSY: ptr = "BUSY"; break; 00329 case LORAMAC_STATUS_SERVICE_UNKNOWN: ptr = "SERVICE_UNKNOWN"; break; 00330 case LORAMAC_STATUS_PARAMETER_INVALID: ptr = "PARAMETER_INVALID"; break; 00331 case LORAMAC_STATUS_FREQUENCY_INVALID: ptr = "FREQUENCY_INVALID"; break; 00332 case LORAMAC_STATUS_DATARATE_INVALID: ptr = "DATARATE_INVALID"; break; 00333 case LORAMAC_STATUS_FREQ_AND_DR_INVALID: ptr = "FREQ_AND_DR_INVALID"; break; 00334 case LORAMAC_STATUS_NO_NETWORK_JOINED: ptr = "NO_NETWORK_JOINED"; break; 00335 case LORAMAC_STATUS_LENGTH_ERROR: ptr = "LENGTH_ERROR"; break; 00336 case LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR: ptr = "MAC_CMD_LENGTH_ERROR"; break; 00337 case LORAMAC_STATUS_DEVICE_OFF: ptr = "DEVICE_OFF"; break; 00338 } 00339 if (ptr != NULL) 00340 strcpy(dst, ptr); 00341 } 00342 00343 static void OnTxNextPacketTimerEvent( void ); 00344 00345 /*! 00346 * \brief Prepares the payload of the frame 00347 * 00348 * \retval [0: frame could be send, 1: error] 00349 */ 00350 static bool SendFrame(uint8_t port) 00351 { 00352 McpsReq_t mcpsReq; 00353 LoRaMacTxInfo_t txInfo; 00354 LoRaMacStatus_t status; 00355 char str[64]; 00356 00357 if( LoRaMacQueryTxPossible( AppDataSize, &txInfo ) != LORAMAC_STATUS_OK ) 00358 { 00359 // Send empty frame in order to flush MAC commands 00360 mcpsReq.Type = MCPS_UNCONFIRMED; 00361 mcpsReq.Req.Unconfirmed .fBuffer = NULL; 00362 mcpsReq.Req.Unconfirmed .fBufferSize = 0; 00363 00364 LoRaMacUplinkStatus.Acked = false; 00365 LoRaMacUplinkStatus.Port = 0; 00366 LoRaMacUplinkStatus.Buffer = NULL; 00367 LoRaMacUplinkStatus.BufferSize = 0; 00368 } 00369 else 00370 { 00371 LoRaMacUplinkStatus.Acked = false; 00372 LoRaMacUplinkStatus.Port = port; 00373 LoRaMacUplinkStatus.Buffer = AppData; 00374 LoRaMacUplinkStatus.BufferSize = AppDataSize; 00375 00376 if( IsTxConfirmed == false ) 00377 { 00378 mcpsReq.Type = MCPS_UNCONFIRMED; 00379 mcpsReq.Req.Unconfirmed .fPort = port; 00380 mcpsReq.Req.Unconfirmed .fBuffer = AppData; 00381 mcpsReq.Req.Unconfirmed .fBufferSize = AppDataSize; 00382 } 00383 else 00384 { 00385 mcpsReq.Type = MCPS_CONFIRMED; 00386 mcpsReq.Req.Confirmed .fPort = port; 00387 mcpsReq.Req.Confirmed .fBuffer = AppData; 00388 mcpsReq.Req.Confirmed .fBufferSize = AppDataSize; 00389 mcpsReq.Req.Confirmed .NbTrials = 8; 00390 } 00391 } 00392 00393 status = LoRaMacMcpsRequest( &mcpsReq ); 00394 if( status == LORAMAC_STATUS_OK ) 00395 { 00396 awaiting_mcps_indic = true; 00397 app_printf("send ok\r\n"); 00398 return false; 00399 } 00400 LoRaMacStatus_to_string(status, str); 00401 app_printf("send failed:%s\r\n", str); 00402 00403 if (status == LORAMAC_STATUS_NO_NETWORK_JOINED) { 00404 join_retry = true; 00405 #ifdef SENSORS 00406 sensor_ticker.detach(); 00407 #endif 00408 } else { 00409 AppPort = port; 00410 TxNextPacketTimeout.attach(&OnTxNextPacketTimerEvent, microseconds(randr(1000000, 5000000) + 1000000)); 00411 if (status == LORAMAC_STATUS_BUSY) 00412 send_at_beacon = true; 00413 } 00414 00415 return true; 00416 } 00417 00418 /*! 00419 * \brief Function executed on TxNextPacket Timeout event 00420 */ 00421 static void OnTxNextPacketTimerEvent( void ) 00422 { 00423 MibRequestConfirm_t mibReq; 00424 LoRaMacStatus_t status; 00425 00426 if (DeviceState == DEVICE_STATE_REJOIN) { 00427 app_printf("unjoin\r\n"); 00428 mibReq.Type = MIB_NETWORK_JOINED; 00429 mibReq.Param .IsNetworkJoined = false; 00430 #ifdef SENSORS 00431 sensor_ticker.detach(); 00432 #endif 00433 if (LoRaMacMibSetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK) { 00434 TxNextPacketTimeout.attach(&OnTxNextPacketTimerEvent, 500ms); 00435 return; 00436 } 00437 } 00438 00439 mibReq.Type = MIB_NETWORK_JOINED; 00440 status = LoRaMacMibGetRequestConfirm( &mibReq ); 00441 00442 app_printf("OnTxNextPacketTimerEvent() "); 00443 if( status == LORAMAC_STATUS_OK ) 00444 { 00445 if( mibReq.Param .IsNetworkJoined == true ) 00446 { 00447 app_printf("send"); 00448 DeviceState = DEVICE_STATE_UPLINK; 00449 } 00450 else 00451 { 00452 app_printf("join"); 00453 DeviceState = DEVICE_STATE_JOIN; 00454 } 00455 } 00456 app_printf("\r\n"); 00457 } 00458 00459 void 00460 send_uplink() 00461 { 00462 AppDataSize = uplink_length; 00463 DeviceState = DEVICE_STATE_UPLINK; 00464 } 00465 00466 /*! 00467 * \brief MCPS-Confirm event function 00468 * 00469 * \param [IN] mcpsConfirm - Pointer to the confirm structure, 00470 * containing confirm attributes. 00471 */ 00472 static void McpsConfirm( McpsConfirm_t *mcpsConfirm ) 00473 { 00474 static uint8_t fail_count = 0; 00475 char str[64]; 00476 00477 app_printf("McpsConfirm "); 00478 if( mcpsConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK ) 00479 { 00480 fail_count = 0; 00481 app_printf("OK "); 00482 switch( mcpsConfirm->McpsRequest ) 00483 { 00484 case MCPS_UNCONFIRMED: 00485 { 00486 app_printf("UNCONFIRMED"); 00487 // Check Datarate 00488 // Check TxPower 00489 break; 00490 } 00491 case MCPS_CONFIRMED: 00492 { 00493 app_printf("CONFIRMED"); 00494 // Check Datarate 00495 // Check TxPower 00496 // Check AckReceived 00497 // Check NbTrials 00498 LoRaMacUplinkStatus.Acked = mcpsConfirm->AckReceived ; 00499 break; 00500 } 00501 case MCPS_PROPRIETARY: 00502 { 00503 break; 00504 } 00505 default: 00506 break; 00507 } 00508 LoRaMacUplinkStatus.UplinkCounter = mcpsConfirm->UpLinkCounter ; 00509 00510 } else { 00511 LoRaMacEventInfoStatus_to_string(mcpsConfirm->Status , str); 00512 app_printf("%s ", str); 00513 00514 /* mcpsIndication may not come. last uplink done, send another uplink */ 00515 if (jumper_in.read()) { /* jumper installed: auto uplink */ 00516 TxNextPacketTimeout.attach(&send_uplink, 100ms); 00517 } 00518 00519 if (++fail_count > 10) { 00520 /* cause re-join */ 00521 MibRequestConfirm_t mibReq; 00522 mibReq.Type = MIB_NETWORK_JOINED; 00523 mibReq.Param .IsNetworkJoined = false; 00524 LoRaMacMibSetRequestConfirm( &mibReq ); 00525 fail_count = 0; 00526 #ifdef SENSORS 00527 sensor_ticker.detach(); 00528 #endif 00529 } 00530 } 00531 00532 app_printf("\r\n"); 00533 } 00534 00535 /*! 00536 * \brief MCPS-Indication event function 00537 * 00538 * \param [IN] mcpsIndication - Pointer to the indication structure, 00539 * containing indication attributes. 00540 */ 00541 static void McpsIndication( McpsIndication_t *mcpsIndication ) 00542 { 00543 char str[64]; 00544 MibRequestConfirm_t mibReq; 00545 00546 app_printf("McpsIndication "); 00547 00548 /* last uplink done, send another uplink */ 00549 if (jumper_in.read() && mcpsIndication->Status != LORAMAC_EVENT_INFO_STATUS_STOP) { 00550 /* jumper installed: auto uplink */ 00551 TxNextPacketTimeout.attach(&send_uplink, 100ms); 00552 } 00553 00554 if( mcpsIndication->Status != LORAMAC_EVENT_INFO_STATUS_OK ) 00555 { 00556 LoRaMacEventInfoStatus_to_string(mcpsIndication->Status , str); 00557 app_printf("%s\r\n", str); 00558 return; 00559 } 00560 00561 awaiting_mcps_indic = false; 00562 00563 switch( mcpsIndication->McpsIndication ) 00564 { 00565 /* this refers to the downlink from gateway, not the uplink that was sent to it */ 00566 case MCPS_UNCONFIRMED: 00567 { 00568 app_printf("UNCONFIRMED "); 00569 break; 00570 } 00571 case MCPS_CONFIRMED: 00572 { 00573 /* downlink has requested Ack */ 00574 app_printf("CONFIRMED "); 00575 break; 00576 } 00577 case MCPS_PROPRIETARY: 00578 { 00579 break; 00580 } 00581 case MCPS_MULTICAST: 00582 { 00583 app_printf("MCPS_MULTICAST "); 00584 /*if (mcpsIndication->RxData) { 00585 }*/ 00586 break; 00587 } 00588 default: 00589 break; 00590 } 00591 00592 // Check Multicast 00593 // Check Port 00594 // Check Datarate 00595 // Check FramePending 00596 // Check Buffer 00597 // Check BufferSize 00598 // Check Rssi 00599 // Check Snr 00600 // Check RxSlot 00601 LoRaMacDownlinkStatus.Rssi = mcpsIndication->Rssi ; 00602 if( mcpsIndication->Snr & 0x80 ) // The SNR sign bit is 1 00603 { 00604 // Invert and divide by 4 00605 LoRaMacDownlinkStatus.Snr = ( ( ~mcpsIndication->Snr + 1 ) & 0xFF ) >> 2; 00606 LoRaMacDownlinkStatus.Snr = -LoRaMacDownlinkStatus.Snr; 00607 } 00608 else 00609 { 00610 // Divide by 4 00611 LoRaMacDownlinkStatus.Snr = ( mcpsIndication->Snr & 0xFF ) >> 2; 00612 } 00613 LoRaMacDownlinkStatus.DownlinkCounter++; 00614 LoRaMacDownlinkStatus.RxData = mcpsIndication->RxData ; 00615 LoRaMacDownlinkStatus.Port = mcpsIndication->Port ; 00616 LoRaMacDownlinkStatus.Buffer = mcpsIndication->Buffer ; 00617 LoRaMacDownlinkStatus.BufferSize = mcpsIndication->BufferSize ; 00618 00619 if( mcpsIndication->RxData == true ) 00620 { 00621 int i; 00622 app_printf("RxData %u ", mcpsIndication->BufferSize ); 00623 for (i = 0; i < mcpsIndication->BufferSize ; i++) { 00624 app_printf("%02x ", mcpsIndication->Buffer [i]); 00625 } 00626 app_printf("\r\n"); 00627 00628 switch (mcpsIndication->Buffer [0]) { 00629 default: 00630 case CMD_NONE: break; 00631 #if defined (ENABLE_RGB) 00632 case CMD_LED_RGB: 00633 rgb.setColorRGB(0, 00634 mcpsIndication->Buffer [1], // R 00635 mcpsIndication->Buffer [2], // G 00636 mcpsIndication->Buffer [3] // B 00637 ); 00638 app_printf("rgb %u %u %u\r\n", 00639 mcpsIndication->Buffer [1], 00640 mcpsIndication->Buffer [2], 00641 mcpsIndication->Buffer [3] 00642 ); 00643 break; 00644 #endif /* ENABLE_RGB */ 00645 #if defined(SENSORS) 00646 case CMD_GPIO_OUT: 00647 pc6_out = mcpsIndication->Buffer [1]; 00648 app_printf("gpo %d\r\n", mcpsIndication->Buffer [1]); 00649 break; 00650 case CMD_PWM: 00651 pwm.period(1.0 / mcpsIndication->Buffer [1]); 00652 pwm.write(mcpsIndication->Buffer [2] / 255.0); 00653 app_printf("pwm %u %u\r\n", mcpsIndication->Buffer [1], mcpsIndication->Buffer [2]); 00654 break; 00655 #endif /* SENSORS */ 00656 case CMD_TX_POWER: 00657 app_printf("txp %u\r\n", mcpsIndication->Buffer [1]); 00658 mibReq.Type = MIB_CHANNELS_TX_POWER; 00659 mibReq.Param .ChannelsTxPower = mcpsIndication->Buffer [1]; 00660 LoRaMacMibSetRequestConfirm( &mibReq ); 00661 break; 00662 } // ..switch (mcpsIndication->Buffer[3]) 00663 00664 switch( mcpsIndication->Port ) 00665 { 00666 case 1: // The application LED can be controlled on port 1 or 2 00667 case 2: 00668 if( mcpsIndication->BufferSize == 1 ) 00669 { 00670 AppLedStateOn = mcpsIndication->Buffer [0] & 0x01; 00671 } 00672 break; 00673 default: 00674 break; 00675 } 00676 } 00677 00678 if (mcpsIndication->Status == LORAMAC_EVENT_INFO_STATUS_STOP) { 00679 app_printf(" STOP-SCC"); 00680 TxNextPacketTimeout.detach(); 00681 DeviceState = DEVICE_STATE_SLEEP; 00682 } 00683 00684 app_printf("\r\n"); 00685 } 00686 00687 /*! 00688 * \brief MLME-Confirm event function 00689 * 00690 * \param [IN] mlmeConfirm - Pointer to the confirm structure, 00691 * containing confirm attributes. 00692 */ 00693 static void MlmeConfirm( MlmeConfirm_t *mlmeConfirm ) 00694 { 00695 char str[64]; 00696 LoRaMacEventInfoStatus_to_string(mlmeConfirm->Status , str); 00697 app_printf("MlmeConfirm %s ", str); 00698 00699 switch( mlmeConfirm->MlmeRequest ) 00700 { 00701 case MLME_JOIN: 00702 { 00703 app_printf("MLME_JOIN "); 00704 if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK ) 00705 { 00706 // Status is OK, node has joined the network 00707 DeviceState = DEVICE_STATE_SLEEP; 00708 #ifdef SENSORS 00709 sensor_ticker.attach(&sensor_poll, POLL_RATE); 00710 sensor_in_idx = 0; 00711 sensor_out_idx = 0; 00712 sample_seqnum = 0; 00713 #endif 00714 missed_count = 0; 00715 if (jumper_in.read()) /* jumper installed: auto uplink */ 00716 TxNextPacketTimeout.attach(&send_uplink, 100ms); 00717 } 00718 else 00719 { 00720 // Join was not successful. Try to join again 00721 DeviceState = DEVICE_STATE_JOIN; 00722 } 00723 break; 00724 } 00725 case MLME_LINK_CHECK: 00726 { 00727 app_printf("LINK_CHECK"); 00728 if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK ) 00729 { 00730 // Check DemodMargin 00731 //mlmeConfirm->DemodMargin; 00732 // Check NbGateways 00733 //mlmeConfirm->NbGateways; 00734 } 00735 break; 00736 } 00737 default: 00738 break; 00739 } 00740 00741 app_printf("\r\n"); 00742 } 00743 00744 00745 static void MlmeIndication( MlmeIndication_t *MlmeIndication ) 00746 { 00747 char str[64]; 00748 00749 app_printf("MlmeIndication "); 00750 switch( MlmeIndication->MlmeIndication ) 00751 { 00752 case MLME_BEACON: 00753 { 00754 app_printf("BEACON ", missed_count); 00755 if (missed_count) 00756 app_printf("missed:%u ", missed_count); 00757 00758 LoRaMacEventInfoStatus_to_string(MlmeIndication->Status, str); 00759 app_printf("%s ", str); 00760 00761 if (send_at_beacon) { 00762 TxNextPacketTimeout.attach(&send_uplink, 100ms); 00763 send_at_beacon = false; 00764 } 00765 00766 if (LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED == MlmeIndication->Status) { 00767 missed_count = 0; 00768 #if defined(ENABLE_RGB) 00769 rgb.setColorRGB(0, 0, 0, 0); // off 00770 #endif /* ENABLE_RGB */ 00771 } else { 00772 #if defined(ENABLE_RGB) 00773 rgb.setColorRGB(0, 255, 64, 0); // orange 00774 #endif /* ENABLE_RGB */ 00775 if (++missed_count > 4) { 00776 /* cause re-join */ 00777 LoRaMacStatus_t status; 00778 MibRequestConfirm_t mibReq; 00779 #ifdef SENSORS 00780 sensor_ticker.detach(); 00781 #endif 00782 mibReq.Type = MIB_NETWORK_JOINED; 00783 mibReq.Param .IsNetworkJoined = false; 00784 status = LoRaMacMibSetRequestConfirm(&mibReq); 00785 if (status != LORAMAC_STATUS_OK) 00786 DeviceState = DEVICE_STATE_REJOIN; 00787 00788 LoRaMacStatus_to_string(status, str); 00789 app_printf("app-rejoin %s\r\n", str); 00790 TxNextPacketTimeout.attach(&OnTxNextPacketTimerEvent, microseconds(randr(1000000, 5000000) + 1000000)); 00791 } 00792 } 00793 break; 00794 00795 } 00796 case MLME_TXDONE: 00797 app_printf("MLME_TXDONE "); 00798 break; 00799 default: 00800 app_printf("<%d> ", MlmeIndication->MlmeIndication); 00801 break; 00802 } 00803 00804 app_printf("\r\n"); 00805 } 00806 00807 void 00808 send_pcbuf_uplink() 00809 { 00810 bool ret; 00811 memcpy(AppData, pcbuf, pcbuf_len); 00812 AppDataSize = pcbuf_len; 00813 00814 ret = SendFrame(TEXT_PORT); 00815 app_printf("%d = SendFrame()\r\n", ret); 00816 } 00817 00818 00819 void cmd_status(uint8_t idx) 00820 { 00821 MibRequestConfirm_t mibReq; 00822 00823 app_printf("DevEUI "); 00824 for (int i = 0; i < 8; i++) 00825 app_printf("%02x ", DevEui[i]); 00826 mibReq.Type = MIB_DEV_ADDR; 00827 LoRaMacMibGetRequestConfirm( &mibReq ); 00828 app_printf(", DevAddr:%lx\r\n", mibReq.Param .DevAddr ); 00829 00830 #if defined(SENSORS) 00831 #ifdef TYPE_ABZ 00832 app_printf("a0:%u a2:%u\r\n", a0.read_u16(), a2.read_u16()); 00833 #else 00834 app_printf("a1:%u a3:%u\r\n", a1.read_u16(), a3.read_u16()); 00835 #endif 00836 app_printf("button:%d ", user_button.read()); 00837 #endif 00838 app_printf("DEVICE_STATE_"); 00839 switch (DeviceState) { 00840 case DEVICE_STATE_JOIN: printf("JOIN"); break; 00841 case DEVICE_STATE_CYCLE: printf("CYCLE"); break; 00842 case DEVICE_STATE_SLEEP: printf("SLEEP"); break; 00843 case DEVICE_STATE_REJOIN: printf("REJOIN"); break; 00844 case DEVICE_STATE_INIT: printf("INIT"); break; 00845 case DEVICE_STATE_UPLINK: printf("UPLINK"); break; 00846 } 00847 app_printf(" send_at_beacon:%d\r\n", send_at_beacon); 00848 app_printf("awaiting_mcps_indic:%d\r\n", awaiting_mcps_indic); 00849 00850 loramac_print_status(); 00851 00852 } 00853 00854 void cmd_uplink_length(uint8_t idx) 00855 { 00856 if (pcbuf[idx] >= '0' && pcbuf[idx] <= '9') { 00857 sscanf(pcbuf+idx, "%u", &uplink_length); 00858 } 00859 app_printf("uplink_length:%u\r\n", uplink_length); 00860 } 00861 00862 #if defined(ENABLE_RGB) 00863 void cmd_rgb(uint8_t idx) 00864 { 00865 int r, g, b; 00866 sscanf(pcbuf+idx, "%d %d %d", &r, &g, &b); 00867 rgb.setColorRGB(0, r, g, b); 00868 app_printf("\r\nrgb: %d %d %d\r\n", r, g, b); 00869 } 00870 #endif /* ENABLE_RGB */ 00871 00872 #if defined(SENSORS) 00873 void cmd_pwm(uint8_t idx) 00874 { 00875 float period, duty; 00876 unsigned p, d; 00877 00878 if (sscanf(pcbuf+idx, "%u %u", &p, &d) == 2) { 00879 period = 1.0 / p; 00880 duty = d / 255.0; 00881 pwm.period(period); 00882 pwm.write(duty); 00883 printf("pwm period:%f, duty:%f\r\n", period, duty); 00884 } else 00885 printf("pwm parse fail\r\n"); 00886 } 00887 00888 #endif /* SENSORS */ 00889 00890 void cmd_ChannelsTxPower(uint8_t idx) 00891 { 00892 MibRequestConfirm_t mibReq; 00893 unsigned int i; 00894 00895 if (pcbuf[idx] >= '0' && pcbuf[idx] <= '9') { 00896 sscanf(pcbuf+idx, "%u", &i); 00897 mibReq.Type = MIB_CHANNELS_TX_POWER; 00898 mibReq.Param .ChannelsTxPower = i; 00899 LoRaMacMibSetRequestConfirm( &mibReq ); 00900 } 00901 00902 mibReq.Type = MIB_CHANNELS_TX_POWER; 00903 LoRaMacMibGetRequestConfirm( &mibReq ); 00904 app_printf("ChannelsTxPower:%u\r\n", mibReq.Param .ChannelsTxPower ); 00905 } 00906 00907 typedef struct { 00908 const char* const cmd; 00909 void (*handler)(uint8_t args_at); 00910 const char* const arg_descr; 00911 const char* const description; 00912 } menu_item_t; 00913 00914 void cmd_help(uint8_t args_at); 00915 00916 const menu_item_t menu_items[] = 00917 { /* after first character, command names must be [A-Za-z] */ 00918 { "?", cmd_help, "","show available commands"}, 00919 { ".", cmd_status, "","print status"}, 00920 { "ul", cmd_uplink_length, "%u","set uplink payload length"}, 00921 { "ctxp", cmd_ChannelsTxPower, "%u","get/set ChannelsTxPower"}, 00922 #if defined(ENABLE_RGB) 00923 { "rgb", cmd_rgb, "%d %d %d", "set led R G B"}, 00924 #endif 00925 #if defined(SENSORS) 00926 { "p", cmd_pwm, "%u %u", "set pwm period, duty"}, 00927 #endif /* SENSORS */ 00928 { NULL, NULL, NULL, NULL } 00929 }; 00930 00931 void cmd_help(uint8_t args_at) 00932 { 00933 int i; 00934 00935 for (i = 0; menu_items[i].cmd != NULL ; i++) { 00936 app_printf("%s%s\t%s\r\n", menu_items[i].cmd, menu_items[i].arg_descr, menu_items[i].description); 00937 } 00938 00939 } 00940 00941 void 00942 console() 00943 { 00944 bool parsed; 00945 int i; 00946 uint8_t user_cmd_len; 00947 00948 if (pcbuf_len < 0) { // ctrl-C 00949 return; 00950 } 00951 if (pcbuf_len == 0) 00952 return; 00953 00954 app_printf("\r\n"); 00955 00956 /* get end of user-entered command */ 00957 user_cmd_len = 1; // first character can be any character 00958 for (i = 1; i <= pcbuf_len; i++) { 00959 if (pcbuf[i] < 'A' || (pcbuf[i] > 'Z' && pcbuf[i] < 'a') || pcbuf[i] > 'z') { 00960 user_cmd_len = i; 00961 break; 00962 } 00963 } 00964 00965 parsed = false; 00966 for (i = 0; menu_items[i].cmd != NULL ; i++) { 00967 int mi_len = strlen(menu_items[i].cmd); 00968 00969 if (menu_items[i].handler && user_cmd_len == mi_len && (strncmp(pcbuf, menu_items[i].cmd, mi_len) == 0)) { 00970 while (pcbuf[mi_len] == ' ') // skip past spaces 00971 mi_len++; 00972 menu_items[i].handler(mi_len); 00973 parsed = true; 00974 break; 00975 } 00976 } 00977 00978 if (!parsed) 00979 send_pcbuf_uplink(); 00980 00981 pcbuf_len = 0; 00982 app_printf("> "); 00983 fflush(stdout); 00984 } 00985 00986 void rx_callback() 00987 { 00988 static uint8_t pcbuf_idx = 0; 00989 static uint8_t prev_len = 0;; 00990 //char c = pc.getc(); 00991 char c; 00992 pc.read(&c, 1); 00993 00994 if (c == 8) { 00995 if (pcbuf_idx > 0) { 00996 uint8_t buf[3] = {8, ' ', 8}; 00997 pc.write(buf, 3); 00998 pcbuf_idx--; 00999 } 01000 } else if (c == 3) { // ctrl-C 01001 pcbuf_len = -1; 01002 } else if (c == '\r') { 01003 if (pcbuf_idx == 0) { 01004 pcbuf_len = prev_len; 01005 } else { 01006 pcbuf[pcbuf_idx] = 0; // null terminate 01007 prev_len = pcbuf_idx; 01008 pcbuf_idx = 0; 01009 pcbuf_len = prev_len; 01010 } 01011 } else if (pcbuf_idx < sizeof(pcbuf)) { 01012 pcbuf[pcbuf_idx++] = c; 01013 pc.write(&c, 1); 01014 } 01015 } 01016 01017 void button_isr() 01018 { 01019 app_printf("button_isr\r\n"); 01020 01021 AppPort = SENSOR_PORT; 01022 send_uplink(); 01023 } 01024 01025 /** 01026 * Main application entry point. 01027 */ 01028 int main( void ) 01029 { 01030 LoRaMacPrimitives_t LoRaMacPrimitives; 01031 LoRaMacCallback_t LoRaMacCallbacks; 01032 MibRequestConfirm_t mibReq; 01033 01034 pc.baud(115200); 01035 pc.attach(&rx_callback); 01036 app_printf("\r\nreset %s\r\n", FW_VERS); 01037 01038 BoardInit( ); 01039 01040 DeviceState = DEVICE_STATE_INIT; 01041 01042 while (!user_button) { 01043 printf("button-lo\r\n"); 01044 ThisThread::sleep_for(10ms);//wait(0.01); 01045 } 01046 user_button.fall(&button_isr); 01047 01048 #ifdef ENABLE_LUMINOSITY 01049 app_printf("TSL2561 Sensor "); 01050 if (tsl2561.begin()) { 01051 app_printf("Found\r\n"); 01052 } else { 01053 app_printf("not-found\r\n"); 01054 } 01055 01056 // You can change the gain on the fly, to adapt to brighter/dimmer tsl2561 situations 01057 tsl2561.setGain(TSL2561_GAIN_0X); // set no gain (for bright situtations) 01058 //tsl2561.setGain(TSL2561_GAIN_16X); // set 16x gain (for dim situations) 01059 01060 // Changing the integration time gives you a longer time over which to sense tsl2561 01061 // longer timelines are slower, but are good in very low tsl2561 situtations! 01062 //tsl2561.setTiming(TSL2561_INTEGRATIONTIME_13MS); // shortest integration time (bright tsl2561) 01063 //tsl2561.setTiming(TSL2561_INTEGRATIONTIME_101MS); // medium integration time (medium tsl2561) 01064 tsl2561.setTiming(TSL2561_INTEGRATIONTIME_402MS); // longest integration time (dim tsl2561) 01065 #endif /* ENABLE_LUMINOSITY */ 01066 01067 jumper_out = 1; 01068 jumper_in.mode(PullDown); 01069 01070 while( 1 ) 01071 { 01072 console(); 01073 01074 switch( DeviceState ) 01075 { 01076 case DEVICE_STATE_INIT: 01077 { 01078 app_printf("DEVICE_STATE_INIT\r\n"); 01079 #if defined(SENSORS) 01080 uplink_length = 7; 01081 #else 01082 uplink_length = 2; 01083 #endif 01084 LoRaMacPrimitives.MacMcpsConfirm = McpsConfirm; 01085 LoRaMacPrimitives.MacMcpsIndication = McpsIndication; 01086 LoRaMacPrimitives.MacMlmeConfirm = MlmeConfirm; 01087 LoRaMacPrimitives.MacMlmeIndication = MlmeIndication; 01088 LoRaMacCallbacks.GetBatteryLevel = BoardGetBatteryLevel; 01089 if (LORAMAC_STATUS_OK != LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks )) { 01090 app_printf("LoRaMacInitialization() failed\r\n"); 01091 for (;;) ; 01092 } 01093 app_printf("INIT-ok\r\n"); 01094 01095 mibReq.Type = MIB_PUBLIC_NETWORK; 01096 mibReq.Param .EnablePublicNetwork = LORAWAN_PUBLIC_NETWORK; 01097 LoRaMacMibSetRequestConfirm( &mibReq ); 01098 01099 LoRaMacDownlinkStatus.DownlinkCounter = 0; 01100 01101 DeviceState = DEVICE_STATE_JOIN; 01102 break; 01103 } 01104 case DEVICE_STATE_JOIN: 01105 { 01106 if (jumper_in.read()) /* if jumper installed: auto uplink */ 01107 send_at_beacon = true; 01108 #if( OVER_THE_AIR_ACTIVATION != 0 ) 01109 MlmeReq_t mlmeReq; 01110 // override software definition with hardware value 01111 BoardGetUniqueId(DevEui); 01112 app_printf("DevEUI "); 01113 for (int i = 0; i < 8; i++) 01114 app_printf("%02x ", DevEui[i]); 01115 app_printf("\r\n"); 01116 01117 mlmeReq.Type = MLME_JOIN; 01118 01119 mlmeReq.Req.Join .DevEui = DevEui; 01120 mlmeReq.Req.Join .AppEui = AppEui; 01121 mlmeReq.Req.Join .AppKey = AppKey; 01122 mlmeReq.Req.Join .NbTrials = 255; 01123 01124 LoRaMacStatus_t status = LoRaMacMlmeRequest( &mlmeReq ); 01125 if (status != LORAMAC_STATUS_OK) { 01126 char str[48]; 01127 LoRaMacStatus_to_string(status, str); 01128 app_printf("join-req-failed:%s\r\n", str); 01129 } 01130 DeviceState = DEVICE_STATE_SLEEP; 01131 #else 01132 mibReq.Type = MIB_NET_ID; 01133 mibReq.Param .NetID = LORAWAN_NETWORK_ID; 01134 LoRaMacMibSetRequestConfirm( &mibReq ); 01135 01136 mibReq.Type = MIB_DEV_ADDR; 01137 mibReq.Param .DevAddr = DevAddr; 01138 LoRaMacMibSetRequestConfirm( &mibReq ); 01139 01140 mibReq.Type = MIB_NWK_SKEY; 01141 mibReq.Param .NwkSKey = NwkSKey; 01142 LoRaMacMibSetRequestConfirm( &mibReq ); 01143 01144 mibReq.Type = MIB_APP_SKEY; 01145 mibReq.Param .AppSKey = AppSKey; 01146 LoRaMacMibSetRequestConfirm( &mibReq ); 01147 01148 mibReq.Type = MIB_NETWORK_JOINED; 01149 mibReq.Param .IsNetworkJoined = true; 01150 LoRaMacMibSetRequestConfirm( &mibReq ); 01151 #endif 01152 join_retry = false; 01153 break; 01154 } 01155 case DEVICE_STATE_CYCLE: 01156 { 01157 DeviceState = DEVICE_STATE_SLEEP; 01158 01159 // Schedule next packet transmission 01160 { 01161 milliseconds ms(TxDutyCycleTime * 1000); 01162 TxNextPacketTimeout.attach(&OnTxNextPacketTimerEvent, ms); 01163 } 01164 break; 01165 } 01166 case DEVICE_STATE_SLEEP: 01167 { 01168 //bottom_half(); 01169 LoRaMacBottomHalf(); 01170 // Wake up through events 01171 sleep(); 01172 break; 01173 } 01174 case DEVICE_STATE_UPLINK: 01175 app_printf("DEVICE_STATE_UPLINK\r\n"); 01176 PrepareTxFrame(AppPort); 01177 SendFrame(AppPort); 01178 DeviceState = DEVICE_STATE_SLEEP; 01179 break; 01180 default: 01181 { 01182 DeviceState = DEVICE_STATE_INIT; 01183 break; 01184 } 01185 } 01186 01187 LoRaMacBottomHalf(); 01188 01189 if (join_retry) { 01190 app_printf("join_retry\r\n"); 01191 DeviceState = DEVICE_STATE_JOIN; 01192 join_retry = false; 01193 } 01194 01195 } // ..while( 1 ) 01196 }
Generated on Wed Jul 13 2022 01:56:42 by
1.7.2