RadioShuttle Lib for the STM32 L4 Heltec Board

Dependents:   Turtle_RadioShuttle

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers RadioTest.cpp Source File

RadioTest.cpp

00001 /*
00002  * The file is Licensed under the Apache License, Version 2.0
00003  * (c) 2017 Helmut Tschemernjak
00004  * 30826 Garbsen (Hannover) Germany
00005  */
00006 
00007 #include "mbed.h"
00008 #include "PinMap.h"
00009 #include "sx1276-mbed-hal.h"
00010 #include "RadioShuttle.h"
00011 #include "RadioStatus.h"
00012 #include "RadioSecurity.h"
00013 #include "main.h"
00014 #ifdef  FEATURE_NVPROPERTY
00015 #include <NVPropertyProviderInterface.h>
00016 #include "NVProperty.h"
00017 #endif
00018 
00019 
00020 #if defined(FEATURE_LORA) && defined(FEATURE_RADIOTEST)
00021 
00022 #define CHECK_ERROR_RET(func, err) { \
00023     if (err) { \
00024         dprintf("Error in %s: %s", func, rs->StrError(err)); \
00025         return err; \
00026     } \
00027 }
00028 
00029 #ifndef TARGET_STM32L4
00030  #define RADIO_SERVER   1
00031 #endif
00032 
00033 
00034 bool usePassword = false;   // password the can used indepenend of AES
00035 bool server;                // automatically being set if radioTypeMode RadioShuttle::RS_Station_Basic
00036 bool useAES = false;        // AES needs the usePassword option on
00037 const char *appPassword;
00038 
00039 static const int myTempSensorApp = 0x0001;  // Must be unique world wide.
00040 #ifdef RADIO_SERVER
00041 int myDeviceID = 1;
00042 int remoteDeviceID = 14;
00043 uint32_t myCode = 0;
00044 RadioShuttle::RadioType radioTypeMode = RadioShuttle::RS_Station_Basic;  // 1 = RS_Node_Offline, 3 = RS_Node_Online, 4 = RS_Station_Basic
00045 #else
00046 int myDeviceID = 14;
00047 int remoteDeviceID = 1;
00048 uint32_t myCode = 0;
00049 RadioShuttle::RadioType radioTypeMode = RadioShuttle::RS_Node_Offline;  // 1 = RS_Node_Offline, 3 = RS_Node_Online, 4 = RS_Station_Basic
00050 #endif
00051 
00052 
00053 /*
00054  * For details review: SX1276GenericLib/sx1276/sx1276.h
00055  * Supported spreading factors SF 7,8, 9, 10, 11, (12 does not work well)
00056  * Working frequencies using the 125000 bandwidth which leaves
00057  * sufficient distance to the neighbour channel
00058  * EU: 868.1, 868.3, 868.5 (Default LoRaWAN EU channels)
00059  * EU: 865.1, 865.3, 865.5, 865.7, 865.9 (additional channels)
00060  * EU: 866.1, 866.3, 866.5, 866.7, 866.9 (additional channels)
00061  * EU: 867.1, 867.3, 867.5, 867.7, 867.9 (additional channels)
00062  * Utilisation of these channels should not exceed 1% per hour per node
00063  * Bandwidth changes other than 125k requires different channels distances
00064  */
00065 RadioShuttle::RadioProfile myProfile[] =  {
00066     /*
00067      * Our default profile
00068      * frequency, bandwidth, TX power, spreading factor, frequency-offset
00069      */
00070     { 868100000, 125000, 14, 7, 0 },
00071     { 0, 0, 0, 0, 0 },
00072 };
00073 
00074 
00075 struct sensor {
00076     uint8_t  version;
00077     uint8_t  padding;
00078     uint16_t pm25;
00079     uint16_t pm10;
00080     uint16_t id;
00081 } PMAppData;
00082 
00083 
00084 void TempSensorRecvHandler(int AppID, RadioShuttle::devid_t stationID, int msgID, int status, void *buffer, int length)
00085 {
00086     switch(status) {
00087         case RadioShuttle::MS_SentCompleted:    // A SendMsg has been sent.
00088             dprintf("MSG_SentCompleted: id=%d  %d bytes", msgID, length);
00089             break;
00090         case RadioShuttle::MS_SentCompletedConfirmed:// A SendMsg has been sent and confirmed
00091             dprintf("MSG_SentCompletedConfirmed: id=%d %d bytes", msgID, length);
00092             break;
00093         case RadioShuttle::MS_SentTimeout:      // A timeout occurred, number of retries exceeded
00094             dprintf("MSG_SentTimeout ID: %d", msgID);
00095             break;
00096 
00097         case RadioShuttle::MS_RecvData:         // a simple input message
00098             dprintf("MSG_RecvData ID: %d, len=%d", msgID, length);
00099             // dump("MSG_RecvData", buffer, length);
00100 #ifdef PM_SENSOR
00101             {
00102                 struct sensor *p = (sensor *)buffer;
00103                 if (length == sizeof(struct sensor) && p->version == 1) {
00104                     dprintf("ParticalData: PM10: %.1f (μg/m3)   PM2.5: %.1f (μg/m3)    ID: %d", (float)p->pm10 / 10.0, (float)p->pm25 / 10.0, p->id);
00105                 }
00106             }
00107 #endif
00108             break;
00109         case RadioShuttle::MS_RecvDataConfirmed:    // received a confirmed message
00110             dprintf("MSG_RecvDataConfirmed ID: %d, len=%d", msgID, length);
00111             // dump("MSG_RecvDataConfirmed", buffer, length);
00112             break;
00113         case RadioShuttle::MS_NoStationFound:
00114             dprintf("MSG_NoStationFound");
00115             break;
00116         case RadioShuttle::MS_NoStationSupportsApp:
00117             dprintf("MSG_NoStationSupportsApp");
00118             break;
00119         case RadioShuttle::MS_AuthenicationRequired: // the password does not match.
00120             dprintf("MSG_AuthenicationRequired");
00121             break;
00122 
00123         case RadioShuttle::MS_StationConnected: // a confirmation that the connection was accepted
00124             dprintf("MSG_StationConnected");
00125             break;
00126         case RadioShuttle::MS_StationDisconnected:  // a confirmation that the disconnect was accepted
00127             dprintf("MSG_StationDisconnected");
00128             break;
00129         default:
00130             break;
00131     }
00132 }
00133 
00134 
00135 Radio *radio;
00136 RadioShuttle *rs;
00137 RadioStatusInterface *statusIntf;
00138 RadioSecurityInterface *securityIntf;
00139 
00140 int InitRadio()
00141 {
00142     Radio *radio;
00143     RSCode err;
00144     
00145 #ifdef  FEATURE_NVPROPERTY
00146     NVProperty prop;
00147     int value;
00148     
00149     myDeviceID = prop.GetProperty(prop.LORA_DEVICE_ID, 0);
00150     myCode = prop.GetProperty(prop.LORA_CODE_ID, 0);
00151     if ((value = prop.GetProperty(prop.LORA_RADIO_TYPE, 0)) != 0)
00152         radioTypeMode = (RadioShuttle::RadioType)value;
00153     remoteDeviceID = 1;
00154     
00155     if (myDeviceID == 0 || myCode == 0 || radioTypeMode == 0) {
00156         dprintf("LORA_DEVICE_ID or LORA_CODE_ID or LORA_RADIO_TYPE not set, use PropertyEditor to set this!");
00157         return -1;
00158     }
00159     /*
00160      * Here are optional properties for custom settings
00161      */
00162     if ((value = prop.GetProperty(prop.LORA_REMOTE_ID, 0)) != 0)
00163         remoteDeviceID = value;
00164     if ((value = prop.GetProperty(prop.LORA_FREQUENCY, 0)) != 0)
00165         myProfile[0].Frequency = value;
00166     if ((value = prop.GetProperty(prop.LORA_BANDWIDTH, 0)) != 0)
00167         myProfile[0].Bandwidth = value;
00168     if ((value = prop.GetProperty(prop.LORA_SPREADING_FACTOR, 0)) != 0)
00169         myProfile[0].SpreadingFaktor = value;
00170     if ((value = prop.GetProperty(prop.LORA_TXPOWER, 0)) != 0)
00171         myProfile[0].TXPower = value;
00172     if ((value = prop.GetProperty(prop.LORA_FREQUENCY_OFFSET, 0)) != 0)
00173         myProfile[0].FrequencyOffset = value;
00174     appPassword = prop.GetProperty(prop.LORA_APP_PWD, (const char *)NULL);
00175 #endif
00176 
00177   if (radioTypeMode >= RadioShuttle::RS_Station_Basic)
00178     server = true;
00179     
00180 #ifdef TARGET_DISCO_L072CZ_LRWAN1
00181     radio = new SX1276Generic(NULL, MURATA_SX1276,
00182                               LORA_SPI_MOSI, LORA_SPI_MISO, LORA_SPI_SCLK, LORA_CS, LORA_RESET,
00183                               LORA_DIO0, LORA_DIO1, LORA_DIO2, LORA_DIO3, LORA_DIO4, LORA_DIO5,
00184                               LORA_ANT_RX, LORA_ANT_TX, LORA_ANT_BOOST, LORA_TCXO);
00185 #elif defined(HELTECL432_REV1)
00186     radio = new SX1276Generic(NULL, HELTEC_L4_1276,
00187                               LORA_SPI_MOSI, LORA_SPI_MISO, LORA_SPI_SCLK, LORA_CS, LORA_RESET,
00188                               LORA_DIO0, LORA_DIO1, LORA_DIO2, LORA_DIO3, LORA_DIO4, LORA_DIO5,
00189                               LORA_ANT_PWR);
00190 #else // RFM95
00191     radio = new SX1276Generic(NULL, RFM95_SX1276,
00192                               LORA_SPI_MOSI, LORA_SPI_MISO, LORA_SPI_SCLK, LORA_CS, LORA_RESET,
00193                               LORA_DIO0, LORA_DIO1, LORA_DIO2, LORA_DIO3, LORA_DIO4, LORA_DIO5);
00194 #endif
00195     
00196 
00197     statusIntf = new MyRadioStatus();
00198     securityIntf = new RadioSecurity();
00199     
00200     rs = new RadioShuttle("MyRadioShuttle");
00201     
00202     rs->EnablePacketTrace(RadioShuttle::DEV_ID_ANY, true, true);
00203     
00204     err = rs->AddLicense(myDeviceID, myCode);
00205     CHECK_ERROR_RET("AddLicense", err);
00206     
00207     err = rs->AddRadio(radio, MODEM_LORA, myProfile);
00208     CHECK_ERROR_RET("AddRadio", err);
00209     dprintf("Radio: %.1f MHz, SF%d, %.f kHz", (float)myProfile[0].Frequency/1000000.0, myProfile[0].SpreadingFaktor, (float)myProfile[0].Bandwidth/1000.0);
00210     
00211     rs->AddRadioStatus(statusIntf);
00212     CHECK_ERROR_RET("AddRadioStatus", err);
00213     
00214     rs->AddRadioSecurity(securityIntf);
00215     CHECK_ERROR_RET("AddRadioSecurity", err);
00216     
00217     /*
00218      * The password parameter can be NULL if no password is required
00219      */
00220     err = rs->RegisterApplication(myTempSensorApp, &TempSensorRecvHandler,  (void *)appPassword);
00221     CHECK_ERROR_RET("RegisterApplication", err);
00222     
00223     if (server) {
00224         // usually RadioShuttle::RS_Station_Basic, set via properties
00225         err = rs->Startup(radioTypeMode);
00226         dprintf("Startup as a Server: %s ID=%d", rs->GetRadioName(rs->GetRadioType()), myDeviceID);
00227     } else {
00228         // usually RadioShuttle::RS_Node_Online or RadioShuttle, set via properties
00229         err = rs->Startup(radioTypeMode);
00230         dprintf("Startup as a Node: %s ID=%d", rs->GetRadioName(rs->GetRadioType()), myDeviceID);
00231         if (!err && rs->AppRequiresAuthentication(myTempSensorApp) == RS_PasswordSet) {
00232             err = rs->Connect(myTempSensorApp, remoteDeviceID);
00233         }
00234     }
00235     CHECK_ERROR_RET("Startup", err);
00236     return 0;
00237 }
00238 
00239 void DeInitRadio()
00240 {
00241     if (securityIntf) {
00242         delete securityIntf;
00243         securityIntf = NULL;
00244     }
00245     if (statusIntf) {
00246         delete statusIntf;
00247         statusIntf = NULL;
00248     }
00249     if (rs) {
00250         delete rs;
00251         rs = NULL;
00252     }
00253     if (radio) {
00254         delete radio;
00255         radio = NULL;
00256     }
00257 }
00258 
00259 /*
00260  * this is a example basic loop for RadioShuttle
00261  */
00262 int RadioTest()
00263 {
00264     extern volatile int pressedCount;
00265     
00266     if (InitRadio() != 0)
00267         return -1;
00268     
00269 
00270     for(;;) {
00271         static int cnt = 0;
00272         if (cnt != pressedCount) {
00273             if (cnt > 0) {
00274                 int flags = 0;
00275                 flags |= RadioShuttle::MF_NeedsConfirm;  // optional
00276                  if (useAES && appPassword)
00277                     flags |= RadioShuttle::MF_Encrypted;
00278                 if (server) {
00279                     static char msg[] = "The server feels very good today";
00280                     rs->SendMsg(myTempSensorApp, msg, sizeof(msg), flags, remoteDeviceID);
00281                 } else {
00282                     static char msg[] = "Hello, the temperature is 26 celsius";
00283                     rs->SendMsg(myTempSensorApp, msg, sizeof(msg), flags, remoteDeviceID);
00284                 }
00285             }
00286             cnt = pressedCount;
00287         }
00288         
00289         if (rs->Idle() && rs->GetRadioType() == RadioShuttle::RS_Node_Offline) {
00290             sleep(); // uses deepsleep() when idle lowest power mode;
00291         } else {
00292             sleep();  // timer and radio interrupts will wakeup us
00293         }
00294         rs->RunShuttle(); // process all pending events
00295     }
00296     return 0;
00297 }
00298 
00299 
00300 int RadioUpdate(bool keyPressed)
00301 {
00302     if (!rs)
00303         return 0;
00304         
00305     if (keyPressed) {
00306         int flags = 0;
00307         flags |= RadioShuttle::MF_NeedsConfirm;  // optional
00308         if (usePassword && useAES)
00309             flags |= RadioShuttle::MF_Encrypted;
00310         if (server) {
00311             static char msg[] = "The server feels very good today";
00312             rs->SendMsg(myTempSensorApp, msg, sizeof(msg), flags, remoteDeviceID);
00313         } else {
00314             static char msg[] = "Hello, the temperature is 26 celsius";
00315             rs->SendMsg(myTempSensorApp, msg, sizeof(msg), flags, remoteDeviceID);
00316         }
00317     }
00318     rs->RunShuttle();
00319     return 0;
00320 }
00321 
00322 bool RadioISIdle()
00323 {
00324     if (!rs)
00325         return true;
00326     return rs->Idle();
00327 }
00328 
00329 void InitLoRaChipWithShutdown()
00330 {
00331 #ifdef LORA_CS
00332     if (LORA_CS == NC)
00333       return;
00334 #ifdef HELTECL432_REV1
00335     Radio *radio = new SX1276Generic(NULL, HELTEC_L4_1276,
00336                             LORA_SPI_MOSI, LORA_SPI_MISO, LORA_SPI_SCLK, LORA_CS, LORA_RESET,
00337                             LORA_DIO0, LORA_DIO1, LORA_DIO2, LORA_DIO3, LORA_DIO4, LORA_DIO5, LORA_ANT_PWR);
00338 #else
00339     Radio *radio = new SX1276Generic(NULL, RFM95_SX1276,
00340                             LORA_SPI_MOSI, LORA_SPI_MISO, LORA_SPI_SCLK, LORA_CS, LORA_RESET,
00341                             LORA_DIO0, LORA_DIO1, LORA_DIO2, LORA_DIO3, LORA_DIO4, LORA_DIO5);
00342 #endif
00343     
00344     RadioEvents_t radioEvents;
00345     memset(&radioEvents, 0, sizeof(radioEvents));
00346     if (radio->Init(&radioEvents)) {
00347         radio->Sleep();
00348         delete radio;
00349     }
00350 #endif
00351 }
00352 
00353 void RadioContinuesTX(void)
00354 {
00355     Radio *radio;
00356     
00357 #ifdef  FEATURE_NVPROPERTY
00358     NVProperty prop;
00359     int value;
00360     
00361     /*
00362      * Here are optional properties for custom settings
00363      */
00364     if ((value = prop.GetProperty(prop.LORA_FREQUENCY, 0)) != 0)
00365         myProfile[0].Frequency = value;
00366     if ((value = prop.GetProperty(prop.LORA_TXPOWER, 0)) != 0)
00367         myProfile[0].TXPower = value;
00368     if ((value = prop.GetProperty(prop.LORA_SPREADING_FACTOR, 0)) != 0)
00369         myProfile[0].SpreadingFaktor = value;
00370 #endif
00371 
00372     
00373 #ifdef TARGET_DISCO_L072CZ_LRWAN1
00374     radio = new SX1276Generic(NULL, MURATA_SX1276,
00375                               LORA_SPI_MOSI, LORA_SPI_MISO, LORA_SPI_SCLK, LORA_CS, LORA_RESET,
00376                               LORA_DIO0, LORA_DIO1, LORA_DIO2, LORA_DIO3, LORA_DIO4, LORA_DIO5,
00377                               LORA_ANT_RX, LORA_ANT_TX, LORA_ANT_BOOST, LORA_TCXO);
00378 #elif defined(HELTECL432_REV1)
00379     radio = new SX1276Generic(NULL, HELTEC_L4_1276,
00380                               LORA_SPI_MOSI, LORA_SPI_MISO, LORA_SPI_SCLK, LORA_CS, LORA_RESET,
00381                               LORA_DIO0, LORA_DIO1, LORA_DIO2, LORA_DIO3, LORA_DIO4, LORA_DIO5,
00382                               LORA_ANT_PWR);
00383 #else // RFM95
00384     radio = new SX1276Generic(NULL, RFM95_SX1276,
00385                               LORA_SPI_MOSI, LORA_SPI_MISO, LORA_SPI_SCLK, LORA_CS, LORA_RESET,
00386                               LORA_DIO0, LORA_DIO1, LORA_DIO2, LORA_DIO3, LORA_DIO4, LORA_DIO5);
00387 #endif
00388     
00389     dprintf("RadioContinuesTX test, press reset to abort");
00390     while(true) {
00391         int secs = 10;
00392         radio->SetTxContinuousWave(myProfile[0].Frequency, myProfile[0].TXPower, secs);
00393         wait_ms(secs * 1000);
00394         rprintf(".");
00395     }
00396 }
00397 
00398 #endif // FEATURE_LORA