wayne roberts / Mbed OS LoRaWAN_singlechannel_endnode

Dependencies:   SX127x sx12xx_hal TSL2561

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers single_us915_main.cpp Source File

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 }