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
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
Generated on Wed Jul 13 2022 12:02:31 by
1.7.2
Helmut Tschemernjak