An example project for the Heltec Turtle LoRa board (STM32L4 and SX1276 chips). The projects is only supported for the Nucleo-L432KC board platform in the mbed online and offline compiler environment. Visit www.radioshuttle.de (choose Turtle board) for instructions. Note that most source files and libraries are open source, however some files especially the RadioShuttle core protocol is copyrighted work. Check header for details.

Dependencies:   mbed BufferedSerial SX1276GenericLib OLED_SSD1306 HELIOS_Si7021 NVProperty RadioShuttle-STM32L4 USBDeviceHT

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers RadioTestSample.cpp Source File

RadioTestSample.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 
00010 #if defined(FEATURE_LORA) && defined(FEATURE_RADIOTESTSAMPLE)
00011 
00012 #include "sx1276-mbed-hal.h"
00013 #include "RadioShuttle.h"
00014 #include "RadioStatus.h"
00015 #include "RadioSecurity.h"
00016 #include "main.h"
00017 #ifdef  FEATURE_NVPROPERTY
00018 #include <NVPropertyProviderInterface.h>
00019 #include "NVProperty.h"
00020 #endif
00021 
00022 
00023 
00024 #define CHECK_ERROR_RET(func, err) { \
00025     if (err) { \
00026         dprintf("Error in %s: %s", func, rs->StrError(err)); \
00027         return err; \
00028     } \
00029 }
00030 
00031 // #define RADIO_SERVER 1
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;    // the AES password
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             break;
00101         case RadioShuttle::MS_RecvDataConfirmed:    // received a confirmed message
00102             dprintf("MSG_RecvDataConfirmed ID: %d, len=%d", msgID, length);
00103             // dump("MSG_RecvDataConfirmed", buffer, length);
00104             break;
00105         case RadioShuttle::MS_NoStationFound:
00106             dprintf("MSG_NoStationFound");
00107             break;
00108         case RadioShuttle::MS_NoStationSupportsApp:
00109             dprintf("MSG_NoStationSupportsApp");
00110             break;
00111         case RadioShuttle::MS_AuthenicationRequired: // the password does not match.
00112             dprintf("MSG_AuthenicationRequired");
00113             break;
00114 
00115         case RadioShuttle::MS_StationConnected: // a confirmation that the connection was accepted
00116             dprintf("MSG_StationConnected");
00117             break;
00118         case RadioShuttle::MS_StationDisconnected:  // a confirmation that the disconnect was accepted
00119             dprintf("MSG_StationDisconnected");
00120             break;
00121         default:
00122             break;
00123     }
00124 }
00125 
00126 
00127 Radio *radio;
00128 RadioShuttle *rs;
00129 RadioStatusInterface *statusIntf;
00130 RadioSecurityInterface *securityIntf;
00131 
00132 int InitRadio()
00133 {
00134     Radio *radio;
00135     RSCode err;
00136     
00137 #ifdef  FEATURE_NVPROPERTY
00138     NVProperty prop;
00139     int value;
00140     
00141     myDeviceID = prop.GetProperty(prop.LORA_DEVICE_ID, 0);
00142     myCode = prop.GetProperty(prop.LORA_CODE_ID, 0);
00143     if ((value = prop.GetProperty(prop.LORA_RADIO_TYPE, 0)) != 0)
00144         radioTypeMode = (RadioShuttle::RadioType)value;
00145     
00146     if (myDeviceID == 0 || myCode == 0 || radioTypeMode == 0) {
00147         dprintf("LORA_DEVICE_ID or LORA_CODE_ID or LORA_RADIO_TYPE not set, use PropertyEditor to set this!");
00148         return -1;
00149     }
00150     /*
00151      * Here are optional properties for custom settings
00152      */
00153     if ((value = prop.GetProperty(prop.LORA_REMOTE_ID, 0)) != 0)
00154         remoteDeviceID = value;
00155     if ((value = prop.GetProperty(prop.LORA_FREQUENCY, 0)) != 0)
00156         myProfile[0].Frequency = value;
00157     if ((value = prop.GetProperty(prop.LORA_BANDWIDTH, 0)) != 0)
00158         myProfile[0].Bandwidth = value;
00159     if ((value = prop.GetProperty(prop.LORA_SPREADING_FACTOR, 0)) != 0)
00160         myProfile[0].SpreadingFaktor = value;
00161     if ((value = prop.GetProperty(prop.LORA_TXPOWER, 0)) != 0)
00162         myProfile[0].TXPower = value;
00163     if ((value = prop.GetProperty(prop.LORA_FREQUENCY_OFFSET, 0)) != 0)
00164         myProfile[0].FrequencyOffset = value;
00165     appPassword = prop.GetProperty(prop.LORA_APP_PWD, (const char *)NULL);
00166 #endif
00167 
00168   if (radioTypeMode >= RadioShuttle::RS_Station_Basic)
00169     server = true;
00170     
00171 #ifdef TARGET_DISCO_L072CZ_LRWAN1
00172     radio = new SX1276Generic(NULL, MURATA_SX1276,
00173                               LORA_SPI_MOSI, LORA_SPI_MISO, LORA_SPI_SCLK, LORA_CS, LORA_RESET,
00174                               LORA_DIO0, LORA_DIO1, LORA_DIO2, LORA_DIO3, LORA_DIO4, LORA_DIO5,
00175                               LORA_ANT_RX, LORA_ANT_TX, LORA_ANT_BOOST, LORA_TCXO);
00176 #elif defined(HELTECL432_REV1)
00177     radio = new SX1276Generic(NULL, HELTEC_L4_1276,
00178                               LORA_SPI_MOSI, LORA_SPI_MISO, LORA_SPI_SCLK, LORA_CS, LORA_RESET,
00179                               LORA_DIO0, LORA_DIO1, LORA_DIO2, LORA_DIO3, LORA_DIO4, LORA_DIO5,
00180                               LORA_ANT_PWR);
00181 #else // RFM95
00182     radio = new SX1276Generic(NULL, RFM95_SX1276,
00183                               LORA_SPI_MOSI, LORA_SPI_MISO, LORA_SPI_SCLK, LORA_CS, LORA_RESET,
00184                               LORA_DIO0, LORA_DIO1, LORA_DIO2, LORA_DIO3, LORA_DIO4, LORA_DIO5);
00185 #endif
00186     
00187 
00188     statusIntf = new MyRadioStatus();
00189     securityIntf = new RadioSecurity();
00190     
00191     rs = new RadioShuttle("MyRadioShuttle");
00192     
00193     rs->EnablePacketTrace(RadioShuttle::DEV_ID_ANY, true, true);
00194     
00195     err = rs->AddLicense(myDeviceID, myCode);
00196     CHECK_ERROR_RET("AddLicense", err);
00197     
00198     err = rs->AddRadio(radio, MODEM_LORA, myProfile);
00199     CHECK_ERROR_RET("AddRadio", err);
00200     dprintf("Radio: %.1f MHz, SF%d, %.f kHz", (float)myProfile[0].Frequency/1000000.0, myProfile[0].SpreadingFaktor, (float)myProfile[0].Bandwidth/1000.0);
00201     
00202     rs->AddRadioStatus(statusIntf);
00203     CHECK_ERROR_RET("AddRadioStatus", err);
00204     
00205     rs->AddRadioSecurity(securityIntf);
00206     CHECK_ERROR_RET("AddRadioSecurity", err);
00207     
00208     /*
00209      * The password parameter can be NULL if no password is required
00210      */
00211     err = rs->RegisterApplication(myTempSensorApp, &TempSensorRecvHandler,  (void *)appPassword);
00212     CHECK_ERROR_RET("RegisterApplication", err);
00213     
00214     if (server) {
00215         // usually RadioShuttle::RS_Station_Basic, set via properties
00216         err = rs->Startup(radioTypeMode);
00217         dprintf("Startup as a Server: %s ID=%d", rs->GetRadioName(rs->GetRadioType()), myDeviceID);
00218     } else {
00219         // usually RadioShuttle::RS_Node_Online or RadioShuttle, set via properties
00220         err = rs->Startup(radioTypeMode);
00221         dprintf("Startup as a Node: %s ID=%d", rs->GetRadioName(rs->GetRadioType()), myDeviceID);
00222         if (!err && rs->AppRequiresAuthentication(myTempSensorApp) == RS_PasswordSet) {
00223             err = rs->Connect(myTempSensorApp, remoteDeviceID);
00224         }
00225     }
00226     CHECK_ERROR_RET("Startup", err);
00227     return 0;
00228 }
00229 
00230 void DeInitRadio()
00231 {
00232     if (securityIntf) {
00233         delete securityIntf;
00234         securityIntf = NULL;
00235     }
00236     if (statusIntf) {
00237         delete statusIntf;
00238         statusIntf = NULL;
00239     }
00240     if (rs) {
00241         delete rs;
00242         rs = NULL;
00243     }
00244     if (radio) {
00245         delete radio;
00246         radio = NULL;
00247     }
00248 }
00249 
00250 
00251 int RadioUpdate(bool keyPressed)
00252 {
00253     if (!rs)
00254         return 0;
00255         
00256     if (keyPressed) {
00257         int flags = 0;
00258         flags |= RadioShuttle::MF_NeedsConfirm;  // optional
00259         if (usePassword && useAES)
00260             flags |= RadioShuttle::MF_Encrypted;
00261         if (server) {
00262             static char msg[] = "The server feels very good today";
00263             rs->SendMsg(myTempSensorApp, msg, sizeof(msg), flags, remoteDeviceID);
00264         } else {
00265             static char msg[] = "Hello, the temperature is 26 celsius";
00266             rs->SendMsg(myTempSensorApp, msg, sizeof(msg), flags, remoteDeviceID);
00267         }
00268     }
00269     rs->RunShuttle();
00270     return 0;
00271 }
00272 
00273 bool RadioISIdle()
00274 {
00275     if (!rs)
00276         return true;
00277     return rs->Idle();
00278 }
00279 
00280 void InitLoRaChipWithShutdown()
00281 {
00282 #ifdef LORA_CS
00283     if (LORA_CS == NC)
00284       return;
00285 #ifdef HELTECL432_REV1
00286     Radio *radio = new SX1276Generic(NULL, HELTEC_L4_1276,
00287                             LORA_SPI_MOSI, LORA_SPI_MISO, LORA_SPI_SCLK, LORA_CS, LORA_RESET,
00288                             LORA_DIO0, LORA_DIO1, LORA_DIO2, LORA_DIO3, LORA_DIO4, LORA_DIO5, LORA_ANT_PWR);
00289 #else
00290     Radio *radio = new SX1276Generic(NULL, RFM95_SX1276,
00291                             LORA_SPI_MOSI, LORA_SPI_MISO, LORA_SPI_SCLK, LORA_CS, LORA_RESET,
00292                             LORA_DIO0, LORA_DIO1, LORA_DIO2, LORA_DIO3, LORA_DIO4, LORA_DIO5);
00293 #endif
00294     
00295     RadioEvents_t radioEvents;
00296     memset(&radioEvents, 0, sizeof(radioEvents));
00297     if (radio->Init(&radioEvents)) {
00298         radio->Sleep();
00299         delete radio;
00300     }
00301 #endif
00302 }
00303 
00304 
00305 void RadioContinuesTX(void)
00306 {
00307     Radio *radio;
00308     
00309 #ifdef  FEATURE_NVPROPERTY
00310     NVProperty prop;
00311     int value;
00312     
00313     /*
00314      * Here are optional properties for custom settings
00315      */
00316     if ((value = prop.GetProperty(prop.LORA_FREQUENCY, 0)) != 0)
00317         myProfile[0].Frequency = value;
00318     if ((value = prop.GetProperty(prop.LORA_TXPOWER, 0)) != 0)
00319         myProfile[0].TXPower = value;
00320     if ((value = prop.GetProperty(prop.LORA_SPREADING_FACTOR, 0)) != 0)
00321         myProfile[0].SpreadingFaktor = value;
00322 #endif
00323 
00324     
00325 #ifdef TARGET_DISCO_L072CZ_LRWAN1
00326     radio = new SX1276Generic(NULL, MURATA_SX1276,
00327                               LORA_SPI_MOSI, LORA_SPI_MISO, LORA_SPI_SCLK, LORA_CS, LORA_RESET,
00328                               LORA_DIO0, LORA_DIO1, LORA_DIO2, LORA_DIO3, LORA_DIO4, LORA_DIO5,
00329                               LORA_ANT_RX, LORA_ANT_TX, LORA_ANT_BOOST, LORA_TCXO);
00330 #elif defined(HELTECL432_REV1)
00331     radio = new SX1276Generic(NULL, HELTEC_L4_1276,
00332                               LORA_SPI_MOSI, LORA_SPI_MISO, LORA_SPI_SCLK, LORA_CS, LORA_RESET,
00333                               LORA_DIO0, LORA_DIO1, LORA_DIO2, LORA_DIO3, LORA_DIO4, LORA_DIO5,
00334                               LORA_ANT_PWR);
00335 #else // RFM95
00336     radio = new SX1276Generic(NULL, RFM95_SX1276,
00337                               LORA_SPI_MOSI, LORA_SPI_MISO, LORA_SPI_SCLK, LORA_CS, LORA_RESET,
00338                               LORA_DIO0, LORA_DIO1, LORA_DIO2, LORA_DIO3, LORA_DIO4, LORA_DIO5);
00339 #endif
00340     
00341     dprintf("RadioContinuesTX test, press reset to abort");
00342     while(true) {
00343         int secs = 10;
00344         radio->SetTxContinuousWave(myProfile[0].Frequency, myProfile[0].TXPower, secs);
00345         wait_ms(secs * 1000);
00346         rprintf(".");
00347     }
00348 }
00349 
00350 #endif // FEATURE_LORA