RadioShuttle Lib for the STM32 L4 Heltec Board
Dependents: Turtle_RadioShuttle
examples/RadioTest.cpp
- Committer:
- Helmut Tschemernjak
- Date:
- 2019-04-14
- Revision:
- 13:591254bed18b
- Parent:
- 9:02766ad58bdd
File content as of revision 13:591254bed18b:
/* * The file is Licensed under the Apache License, Version 2.0 * (c) 2017 Helmut Tschemernjak * 30826 Garbsen (Hannover) Germany */ #include "mbed.h" #include "PinMap.h" #include "sx1276-mbed-hal.h" #include "RadioShuttle.h" #include "RadioStatus.h" #include "RadioSecurity.h" #include "main.h" #ifdef FEATURE_NVPROPERTY #include <NVPropertyProviderInterface.h> #include "NVProperty.h" #endif #if defined(FEATURE_LORA) && defined(FEATURE_RADIOTEST) #define CHECK_ERROR_RET(func, err) { \ if (err) { \ dprintf("Error in %s: %s", func, rs->StrError(err)); \ return err; \ } \ } #ifndef TARGET_STM32L4 #define RADIO_SERVER 1 #endif bool usePassword = false; // password the can used indepenend of AES bool server; // automatically being set if radioTypeMode RadioShuttle::RS_Station_Basic bool useAES = false; // AES needs the usePassword option on const char *appPassword; static const int myTempSensorApp = 0x0001; // Must be unique world wide. #ifdef RADIO_SERVER int myDeviceID = 1; int remoteDeviceID = 14; uint32_t myCode = 0; RadioShuttle::RadioType radioTypeMode = RadioShuttle::RS_Station_Basic; // 1 = RS_Node_Offline, 3 = RS_Node_Online, 4 = RS_Station_Basic #else int myDeviceID = 14; int remoteDeviceID = 1; uint32_t myCode = 0; RadioShuttle::RadioType radioTypeMode = RadioShuttle::RS_Node_Offline; // 1 = RS_Node_Offline, 3 = RS_Node_Online, 4 = RS_Station_Basic #endif /* * For details review: SX1276GenericLib/sx1276/sx1276.h * Supported spreading factors SF 7,8, 9, 10, 11, (12 does not work well) * Working frequencies using the 125000 bandwidth which leaves * sufficient distance to the neighbour channel * EU: 868.1, 868.3, 868.5 (Default LoRaWAN EU channels) * EU: 865.1, 865.3, 865.5, 865.7, 865.9 (additional channels) * EU: 866.1, 866.3, 866.5, 866.7, 866.9 (additional channels) * EU: 867.1, 867.3, 867.5, 867.7, 867.9 (additional channels) * Utilisation of these channels should not exceed 1% per hour per node * Bandwidth changes other than 125k requires different channels distances */ RadioShuttle::RadioProfile myProfile[] = { /* * Our default profile * frequency, bandwidth, TX power, spreading factor, frequency-offset */ { 868100000, 125000, 14, 7, 0 }, { 0, 0, 0, 0, 0 }, }; struct sensor { uint8_t version; uint8_t padding; uint16_t pm25; uint16_t pm10; uint16_t id; } PMAppData; void TempSensorRecvHandler(int AppID, RadioShuttle::devid_t stationID, int msgID, int status, void *buffer, int length) { switch(status) { case RadioShuttle::MS_SentCompleted: // A SendMsg has been sent. dprintf("MSG_SentCompleted: id=%d %d bytes", msgID, length); break; case RadioShuttle::MS_SentCompletedConfirmed:// A SendMsg has been sent and confirmed dprintf("MSG_SentCompletedConfirmed: id=%d %d bytes", msgID, length); break; case RadioShuttle::MS_SentTimeout: // A timeout occurred, number of retries exceeded dprintf("MSG_SentTimeout ID: %d", msgID); break; case RadioShuttle::MS_RecvData: // a simple input message dprintf("MSG_RecvData ID: %d, len=%d", msgID, length); // dump("MSG_RecvData", buffer, length); #ifdef PM_SENSOR { struct sensor *p = (sensor *)buffer; if (length == sizeof(struct sensor) && p->version == 1) { 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); } } #endif break; case RadioShuttle::MS_RecvDataConfirmed: // received a confirmed message dprintf("MSG_RecvDataConfirmed ID: %d, len=%d", msgID, length); // dump("MSG_RecvDataConfirmed", buffer, length); break; case RadioShuttle::MS_NoStationFound: dprintf("MSG_NoStationFound"); break; case RadioShuttle::MS_NoStationSupportsApp: dprintf("MSG_NoStationSupportsApp"); break; case RadioShuttle::MS_AuthenicationRequired: // the password does not match. dprintf("MSG_AuthenicationRequired"); break; case RadioShuttle::MS_StationConnected: // a confirmation that the connection was accepted dprintf("MSG_StationConnected"); break; case RadioShuttle::MS_StationDisconnected: // a confirmation that the disconnect was accepted dprintf("MSG_StationDisconnected"); break; default: break; } } Radio *radio; RadioShuttle *rs; RadioStatusInterface *statusIntf; RadioSecurityInterface *securityIntf; int InitRadio() { Radio *radio; RSCode err; #ifdef FEATURE_NVPROPERTY NVProperty prop; int value; myDeviceID = prop.GetProperty(prop.LORA_DEVICE_ID, 0); myCode = prop.GetProperty(prop.LORA_CODE_ID, 0); if ((value = prop.GetProperty(prop.LORA_RADIO_TYPE, 0)) != 0) radioTypeMode = (RadioShuttle::RadioType)value; remoteDeviceID = 1; if (myDeviceID == 0 || myCode == 0 || radioTypeMode == 0) { dprintf("LORA_DEVICE_ID or LORA_CODE_ID or LORA_RADIO_TYPE not set, use PropertyEditor to set this!"); return -1; } /* * Here are optional properties for custom settings */ if ((value = prop.GetProperty(prop.LORA_REMOTE_ID, 0)) != 0) remoteDeviceID = value; if ((value = prop.GetProperty(prop.LORA_FREQUENCY, 0)) != 0) myProfile[0].Frequency = value; if ((value = prop.GetProperty(prop.LORA_BANDWIDTH, 0)) != 0) myProfile[0].Bandwidth = value; if ((value = prop.GetProperty(prop.LORA_SPREADING_FACTOR, 0)) != 0) myProfile[0].SpreadingFaktor = value; if ((value = prop.GetProperty(prop.LORA_TXPOWER, 0)) != 0) myProfile[0].TXPower = value; if ((value = prop.GetProperty(prop.LORA_FREQUENCY_OFFSET, 0)) != 0) myProfile[0].FrequencyOffset = value; appPassword = prop.GetProperty(prop.LORA_APP_PWD, (const char *)NULL); #endif if (radioTypeMode >= RadioShuttle::RS_Station_Basic) server = true; #ifdef TARGET_DISCO_L072CZ_LRWAN1 radio = new SX1276Generic(NULL, MURATA_SX1276, LORA_SPI_MOSI, LORA_SPI_MISO, LORA_SPI_SCLK, LORA_CS, LORA_RESET, LORA_DIO0, LORA_DIO1, LORA_DIO2, LORA_DIO3, LORA_DIO4, LORA_DIO5, LORA_ANT_RX, LORA_ANT_TX, LORA_ANT_BOOST, LORA_TCXO); #elif defined(HELTECL432_REV1) radio = new SX1276Generic(NULL, HELTEC_L4_1276, LORA_SPI_MOSI, LORA_SPI_MISO, LORA_SPI_SCLK, LORA_CS, LORA_RESET, LORA_DIO0, LORA_DIO1, LORA_DIO2, LORA_DIO3, LORA_DIO4, LORA_DIO5, LORA_ANT_PWR); #else // RFM95 radio = new SX1276Generic(NULL, RFM95_SX1276, LORA_SPI_MOSI, LORA_SPI_MISO, LORA_SPI_SCLK, LORA_CS, LORA_RESET, LORA_DIO0, LORA_DIO1, LORA_DIO2, LORA_DIO3, LORA_DIO4, LORA_DIO5); #endif statusIntf = new MyRadioStatus(); securityIntf = new RadioSecurity(); rs = new RadioShuttle("MyRadioShuttle"); rs->EnablePacketTrace(RadioShuttle::DEV_ID_ANY, true, true); err = rs->AddLicense(myDeviceID, myCode); CHECK_ERROR_RET("AddLicense", err); err = rs->AddRadio(radio, MODEM_LORA, myProfile); CHECK_ERROR_RET("AddRadio", err); dprintf("Radio: %.1f MHz, SF%d, %.f kHz", (float)myProfile[0].Frequency/1000000.0, myProfile[0].SpreadingFaktor, (float)myProfile[0].Bandwidth/1000.0); rs->AddRadioStatus(statusIntf); CHECK_ERROR_RET("AddRadioStatus", err); rs->AddRadioSecurity(securityIntf); CHECK_ERROR_RET("AddRadioSecurity", err); /* * The password parameter can be NULL if no password is required */ err = rs->RegisterApplication(myTempSensorApp, &TempSensorRecvHandler, (void *)appPassword); CHECK_ERROR_RET("RegisterApplication", err); if (server) { // usually RadioShuttle::RS_Station_Basic, set via properties err = rs->Startup(radioTypeMode); dprintf("Startup as a Server: %s ID=%d", rs->GetRadioName(rs->GetRadioType()), myDeviceID); } else { // usually RadioShuttle::RS_Node_Online or RadioShuttle, set via properties err = rs->Startup(radioTypeMode); dprintf("Startup as a Node: %s ID=%d", rs->GetRadioName(rs->GetRadioType()), myDeviceID); if (!err && rs->AppRequiresAuthentication(myTempSensorApp) == RS_PasswordSet) { err = rs->Connect(myTempSensorApp, remoteDeviceID); } } CHECK_ERROR_RET("Startup", err); return 0; } void DeInitRadio() { if (securityIntf) { delete securityIntf; securityIntf = NULL; } if (statusIntf) { delete statusIntf; statusIntf = NULL; } if (rs) { delete rs; rs = NULL; } if (radio) { delete radio; radio = NULL; } } /* * this is a example basic loop for RadioShuttle */ int RadioTest() { extern volatile int pressedCount; if (InitRadio() != 0) return -1; for(;;) { static int cnt = 0; if (cnt != pressedCount) { if (cnt > 0) { int flags = 0; flags |= RadioShuttle::MF_NeedsConfirm; // optional if (useAES && appPassword) flags |= RadioShuttle::MF_Encrypted; if (server) { static char msg[] = "The server feels very good today"; rs->SendMsg(myTempSensorApp, msg, sizeof(msg), flags, remoteDeviceID); } else { static char msg[] = "Hello, the temperature is 26 celsius"; rs->SendMsg(myTempSensorApp, msg, sizeof(msg), flags, remoteDeviceID); } } cnt = pressedCount; } if (rs->Idle() && rs->GetRadioType() == RadioShuttle::RS_Node_Offline) { sleep(); // uses deepsleep() when idle lowest power mode; } else { sleep(); // timer and radio interrupts will wakeup us } rs->RunShuttle(); // process all pending events } return 0; } int RadioUpdate(bool keyPressed) { if (!rs) return 0; if (keyPressed) { int flags = 0; flags |= RadioShuttle::MF_NeedsConfirm; // optional if (usePassword && useAES) flags |= RadioShuttle::MF_Encrypted; if (server) { static char msg[] = "The server feels very good today"; rs->SendMsg(myTempSensorApp, msg, sizeof(msg), flags, remoteDeviceID); } else { static char msg[] = "Hello, the temperature is 26 celsius"; rs->SendMsg(myTempSensorApp, msg, sizeof(msg), flags, remoteDeviceID); } } rs->RunShuttle(); return 0; } bool RadioISIdle() { if (!rs) return true; return rs->Idle(); } void InitLoRaChipWithShutdown() { #ifdef LORA_CS if (LORA_CS == NC) return; #ifdef HELTECL432_REV1 Radio *radio = new SX1276Generic(NULL, HELTEC_L4_1276, LORA_SPI_MOSI, LORA_SPI_MISO, LORA_SPI_SCLK, LORA_CS, LORA_RESET, LORA_DIO0, LORA_DIO1, LORA_DIO2, LORA_DIO3, LORA_DIO4, LORA_DIO5, LORA_ANT_PWR); #else Radio *radio = new SX1276Generic(NULL, RFM95_SX1276, LORA_SPI_MOSI, LORA_SPI_MISO, LORA_SPI_SCLK, LORA_CS, LORA_RESET, LORA_DIO0, LORA_DIO1, LORA_DIO2, LORA_DIO3, LORA_DIO4, LORA_DIO5); #endif RadioEvents_t radioEvents; memset(&radioEvents, 0, sizeof(radioEvents)); if (radio->Init(&radioEvents)) { radio->Sleep(); delete radio; } #endif } void RadioContinuesTX(void) { Radio *radio; #ifdef FEATURE_NVPROPERTY NVProperty prop; int value; /* * Here are optional properties for custom settings */ if ((value = prop.GetProperty(prop.LORA_FREQUENCY, 0)) != 0) myProfile[0].Frequency = value; if ((value = prop.GetProperty(prop.LORA_TXPOWER, 0)) != 0) myProfile[0].TXPower = value; if ((value = prop.GetProperty(prop.LORA_SPREADING_FACTOR, 0)) != 0) myProfile[0].SpreadingFaktor = value; #endif #ifdef TARGET_DISCO_L072CZ_LRWAN1 radio = new SX1276Generic(NULL, MURATA_SX1276, LORA_SPI_MOSI, LORA_SPI_MISO, LORA_SPI_SCLK, LORA_CS, LORA_RESET, LORA_DIO0, LORA_DIO1, LORA_DIO2, LORA_DIO3, LORA_DIO4, LORA_DIO5, LORA_ANT_RX, LORA_ANT_TX, LORA_ANT_BOOST, LORA_TCXO); #elif defined(HELTECL432_REV1) radio = new SX1276Generic(NULL, HELTEC_L4_1276, LORA_SPI_MOSI, LORA_SPI_MISO, LORA_SPI_SCLK, LORA_CS, LORA_RESET, LORA_DIO0, LORA_DIO1, LORA_DIO2, LORA_DIO3, LORA_DIO4, LORA_DIO5, LORA_ANT_PWR); #else // RFM95 radio = new SX1276Generic(NULL, RFM95_SX1276, LORA_SPI_MOSI, LORA_SPI_MISO, LORA_SPI_SCLK, LORA_CS, LORA_RESET, LORA_DIO0, LORA_DIO1, LORA_DIO2, LORA_DIO3, LORA_DIO4, LORA_DIO5); #endif dprintf("RadioContinuesTX test, press reset to abort"); while(true) { int secs = 10; radio->SetTxContinuousWave(myProfile[0].Frequency, myProfile[0].TXPower, secs); wait_ms(secs * 1000); rprintf("."); } } #endif // FEATURE_LORA