diff --git a/flight-computer.ino b/flight-computer.ino index 48af264..9c9c019 100644 --- a/flight-computer.ino +++ b/flight-computer.ino @@ -4,29 +4,30 @@ #include "mosfet_igniter.h" #include "adafruit_gps_api.h" #include "definitions.h" +#include "SD.h" -LSM9DS1_API imu_sensor = LSM9DS1_API::getInstance(); -BMP3XX_API altimeter = BMP3XX_API::getInstance(); -Telemetry telemetry = Telemetry::getInstance(); -MosfetIgniter igniter = MosfetIgniter::getInstance(); -Adafruit_GPS_API gps = Adafruit_GPS_API::getInstance(); -FSM *fsm; +static LSM9DS1_API* imu_sensor = nullptr; +static BMP3XX_API* altimeter = nullptr; +static Telemetry* telemetry = nullptr; +static MosfetIgniter* igniter = nullptr; +static Adafruit_GPS_API* gps = nullptr; +static FSM* fsm = nullptr; // TODO: improve buzzer code const int buzzer = 17; bool sound = false; uint8_t loop_frequency = 10; // Hz -void setup() { -#if SERIAL_DEBUG - Serial.begin(115200); -#endif +bool SetupSensorsAndCommunication(); -#if BUZZER - pinMode(buzzer, OUTPUT); - tone(buzzer, 500); -#endif +void setup() { + #if SERIAL_DEBUG + Serial.begin(115200); + #endif - fsm = new FSM(&telemetry, &imu_sensor, &altimeter, &gps, &igniter, &loop_frequency); + if (!SetupSensorsAndCommunication()) { + Serial.println("Did not initialize sensors"); + while(1); + } #if BUZZER noTone(buzzer); @@ -36,8 +37,8 @@ void setup() { void loop() { int timerStart = millis(); - if (telemetry.messageAvailable()) { - String message = telemetry.receiveMessage(); + if (telemetry->messageAvailable()) { + String message = telemetry->receiveMessage(); if (message.substring(0, 5).equals("SPCMD")) { int event; if (sscanf(message.c_str(), "SPCMD:%i--", &event) == 1) { @@ -69,3 +70,51 @@ void loop() { delay(max(0, delayTime)); } + +bool SetupSensorsAndCommunication() { +#if SD_LOGS + while(!SD.begin(SD_CS)) { +#if SERIAL_DEBUG + Serial.println("SD did not initialize"); +#endif + } +#endif + +#if BUZZER + pinMode(buzzer, OUTPUT); + tone(buzzer, 500); +#endif + + imu_sensor = static_cast(malloc(sizeof(LSM9DS1_API))); + if (imu_sensor == nullptr) { + return false; + } + *imu_sensor = LSM9DS1_API::getInstance(); + + altimeter = static_cast(malloc(sizeof(BMP3XX_API))); + if (altimeter == nullptr) { + return false; + } + *altimeter = BMP3XX_API::getInstance(); + + telemetry = static_cast(malloc(sizeof(Telemetry))); + if (telemetry == nullptr) { + return false; + } + *telemetry = Telemetry::getInstance(); + + igniter = static_cast(malloc(sizeof(MosfetIgniter))); + if (igniter == nullptr) { + return false; + } + *igniter = MosfetIgniter::getInstance(); + + gps = static_cast(malloc(sizeof(Adafruit_GPS_API))); + if (gps == nullptr) { + return false; + } + *gps = Adafruit_GPS_API::getInstance(); + + fsm = new FSM(telemetry, imu_sensor, altimeter, gps, igniter, &loop_frequency); + return fsm != nullptr; +} \ No newline at end of file diff --git a/libraries/adafruit_gps_api.cpp b/libraries/adafruit_gps_api.cpp index 2a1f00d..6e6376a 100644 --- a/libraries/adafruit_gps_api.cpp +++ b/libraries/adafruit_gps_api.cpp @@ -1,29 +1,35 @@ +#include #include "adafruit_gps_api.h" #define GPSSerial Serial1 -Adafruit_GPS_API::Adafruit_GPS_API() {}; +static Adafruit_GPS_API* instance = nullptr; +static Adafruit_GPS* receiver = nullptr; +static unsigned long last_read = 0; -Adafruit_GPS Adafruit_GPS_API::receiver(&GPSSerial); +Adafruit_GPS_API::Adafruit_GPS_API() {}; Adafruit_GPS_API& Adafruit_GPS_API::getInstance() { - static Adafruit_GPS_API instance; - return instance; + if (instance == nullptr) { + instance = new Adafruit_GPS_API(); + receiver = new Adafruit_GPS(&GPSSerial); + } + return *instance; } void Adafruit_GPS_API::setup() { last_read = 0; - receiver.begin(9600); + receiver->begin(9600); // turn on GPRMC and GGA. - receiver.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA); + receiver->sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA); // Update every 1Hz. - receiver.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ); + receiver->sendCommand(PMTK_SET_NMEA_UPDATE_1HZ); // Possition fix update every 1Hz. - receiver.sendCommand(PMTK_API_SET_FIX_CTL_1HZ); + receiver->sendCommand(PMTK_API_SET_FIX_CTL_1HZ); } void Adafruit_GPS_API::readData() { @@ -33,13 +39,13 @@ void Adafruit_GPS_API::readData() { } // Empty buffer. - while(receiver.read()); + while(receiver->read()); last_read = millis(); // Parse data. - if (receiver.newNMEAreceived()) { - receiver.parse(receiver.lastNMEA()); + if (receiver->newNMEAreceived()) { + receiver->parse(receiver->lastNMEA()); } } @@ -47,7 +53,7 @@ bool Adafruit_GPS_API::fix() { // Check if last data is updated. readData(); - return receiver.fix; + return receiver->fix; } int32_t Adafruit_GPS_API::latitude() { @@ -60,7 +66,7 @@ int32_t Adafruit_GPS_API::latitude() { return 0; } - return receiver.latitude_fixed; + return receiver->latitude_fixed; } int32_t Adafruit_GPS_API::longitude() { @@ -73,7 +79,7 @@ int32_t Adafruit_GPS_API::longitude() { return 0; } - return receiver.longitude_fixed; + return receiver->longitude_fixed; } float Adafruit_GPS_API::altitude() { @@ -86,12 +92,12 @@ float Adafruit_GPS_API::altitude() { return 0; } - return receiver.altitude; + return receiver->altitude; } int Adafruit_GPS_API::satellites() { // Check if last data is updated. readData(); - return receiver.satellites; -} + return receiver->satellites; +} \ No newline at end of file diff --git a/libraries/adafruit_gps_api.h b/libraries/adafruit_gps_api.h index f646b91..895ac4b 100644 --- a/libraries/adafruit_gps_api.h +++ b/libraries/adafruit_gps_api.h @@ -1,4 +1,3 @@ -#include #include "gps_receiver.h" class Adafruit_GPS_API: public GPSReceiver { @@ -87,15 +86,6 @@ class Adafruit_GPS_API: public GPSReceiver { */ Adafruit_GPS_API(); - static Adafruit_GPS receiver; - - /** - * @brief

Last read data time.

- * - * Ensure data is read every 100ms. - */ - unsigned long last_read; - /** * @brief

Reads the latest data from the serial.

* Clear the GPS buffer and read the last data available from the GPS module. diff --git a/libraries/bmp280_api.cpp b/libraries/bmp280_api.cpp index 59ee9ec..32d1c6b 100644 --- a/libraries/bmp280_api.cpp +++ b/libraries/bmp280_api.cpp @@ -1,3 +1,4 @@ +#include "Adafruit_BMP280.h" #include "bmp280_api.h" #define BMP_SCK (13) @@ -5,19 +6,24 @@ #define BMP_MOSI (11) // SD1 #define BMP_CS (10) -Adafruit_BMP280 BMP280_API::sensor; +static BMP280_API* instance = nullptr; +static Adafruit_BMP280* sensor = nullptr; +static int32_t ground_level = 0; BMP280_API& BMP280_API::getInstance() { - static BMP280_API instance; - return instance; + if (instance == nullptr) { + instance = new BMP280_API(); + sensor = new Adafruit_BMP280(); + } + return *instance; } int32_t BMP280_API::altitude_cm() { - return sensor.readAltitude() * 100; + return sensor->readAltitude() * 100; } int32_t BMP280_API::pressure() { - return sensor.readPressure(); + return sensor->readPressure(); } int32_t BMP280_API::aglCM() { @@ -33,13 +39,13 @@ int32_t BMP280_API::getGroundLevelCM() { } void BMP280_API::setup() { - if (!sensor.begin()) { + if (!sensor->begin()) { while(1); //Freeze } } void BMP280_API::calibrate() { - sensor.setSampling( + sensor->setSampling( Adafruit_BMP280::MODE_NORMAL, Adafruit_BMP280::SAMPLING_X16, Adafruit_BMP280::SAMPLING_X16, diff --git a/libraries/bmp280_api.h b/libraries/bmp280_api.h index b13cde7..067ef92 100644 --- a/libraries/bmp280_api.h +++ b/libraries/bmp280_api.h @@ -1,10 +1,7 @@ #include "altimeter.h" -#include "Adafruit_BMP280.h" #include class BMP280_API: public Altimeter { - static Adafruit_BMP280 sensor; - public: static BMP280_API& getInstance(); @@ -101,11 +98,6 @@ class BMP280_API: public Altimeter { * @author themicp */ BMP280_API(); - - /** - * @brief

Reference ground level.

- */ - int32_t ground_level = 0; void setGroundLevel(); }; diff --git a/libraries/bmp3xx_api.cpp b/libraries/bmp3xx_api.cpp index ef895bc..ff321c4 100644 --- a/libraries/bmp3xx_api.cpp +++ b/libraries/bmp3xx_api.cpp @@ -1,3 +1,4 @@ +#include "Adafruit_BMP3XX.h" #include "bmp3xx_api.h" #define BMP_SCK (13) @@ -8,11 +9,19 @@ #define BMP_REFRESH_RATE 50 // Hz #define MAX_ALTITUDE_STEP 100000 // cm -Adafruit_BMP3XX BMP3XX_API::sensor; +static BMP3XX_API* instance = nullptr; +static Adafruit_BMP3XX* sensor = nullptr; +static unsigned long last_sensor_read = 0; +static int32_t cached_altitude_cm; +static int32_t ground_level = 0; +static bool broken_connection; BMP3XX_API& BMP3XX_API::getInstance() { - static BMP3XX_API instance; - return instance; + if (instance == nullptr) { + instance = new BMP3XX_API(); + sensor = new Adafruit_BMP3XX(); + } + return *instance; } @@ -28,7 +37,7 @@ void BMP3XX_API::readSensorData() { return; } - int32_t reading = sensor.readAltitude(SEALEVELPRESSURE_HPA) * 100; + int32_t reading = sensor->readAltitude(SEALEVELPRESSURE_HPA) * 100; if (abs(reading - cached_altitude_cm) >= MAX_ALTITUDE_STEP) { // Ignore reading if difference is extreme. Probably problem with the sensor. return; @@ -43,11 +52,11 @@ int32_t BMP3XX_API::altitude_cm() { } int32_t BMP3XX_API::pressure() { - return sensor.pressure; + return sensor->pressure; } int16_t BMP3XX_API::temperature() { - return sensor.temperature * 100; + return sensor->temperature * 100; } int32_t BMP3XX_API::aglCM() { @@ -63,18 +72,18 @@ int32_t BMP3XX_API::getGroundLevelCM() { } void BMP3XX_API::setup() { - if (!sensor.begin()) { + if (!sensor->begin()) { while(1); //Freeze } } void BMP3XX_API::calibrate() { - sensor.setPressureOversampling(BMP3_OVERSAMPLING_16X); - sensor.setIIRFilterCoeff(BMP3_IIR_FILTER_COEFF_7); - sensor.setOutputDataRate(BMP3_ODR_100_HZ); + sensor->setPressureOversampling(BMP3_OVERSAMPLING_16X); + sensor->setIIRFilterCoeff(BMP3_IIR_FILTER_COEFF_7); + sensor->setOutputDataRate(BMP3_ODR_100_HZ); // TODO: use something better than a constant here - while (sensor.readAltitude(SEALEVELPRESSURE_HPA) > 1700) { + while (sensor->readAltitude(SEALEVELPRESSURE_HPA) > 1700) { delay(100); } delay(1000); // TODO: refine the value. New BMP needed more time diff --git a/libraries/bmp3xx_api.h b/libraries/bmp3xx_api.h index 942168a..9d10986 100644 --- a/libraries/bmp3xx_api.h +++ b/libraries/bmp3xx_api.h @@ -1,10 +1,6 @@ #include "altimeter.h" -#include "Adafruit_BMP3XX.h" - class BMP3XX_API: public Altimeter { - static Adafruit_BMP3XX sensor; - public: static BMP3XX_API& getInstance(); @@ -121,26 +117,6 @@ class BMP3XX_API: public Altimeter { */ BMP3XX_API(); - /** - * @brief

Last read data time.

- * - * Ensure data is read every (1000/BMP_REFRESH_RATE)s. - */ - unsigned long last_sensor_read = 0; - - - int32_t cached_altitude_cm; - - /** - * @brief

Reference ground level.

- */ - int32_t ground_level = 0; - - /** - * @brief

Checks if communication protocol failed.

- */ - bool broken_connection; - void setGroundLevel(); /** diff --git a/libraries/bno055_api.cpp b/libraries/bno055_api.cpp index bfcc348..ce2bee2 100644 --- a/libraries/bno055_api.cpp +++ b/libraries/bno055_api.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include "bno055_api.h" @@ -7,11 +7,17 @@ #define READ_INTERVAL (10) -Adafruit_BNO055 BNO055_API::sensor(55, 0x28); +static BNO055_API* instance = nullptr; +static Adafruit_BNO055* sensor = nullptr; +static unsigned long last_read = 0; +static imu::Vector<3> euler, acc, gyro, mag; BNO055_API& BNO055_API::getInstance() { - static BNO055_API instance; - return instance; + if (instance == nullptr) { + instance = new BNO055_API(); + sensor = new Adafruit_BNO055(55, 0x28); + } + return *instance; } void BNO055_API::readSensorData() { @@ -20,10 +26,10 @@ void BNO055_API::readSensorData() { return; } - euler = sensor.getVector(Adafruit_BNO055::VECTOR_EULER); - acc = sensor.getVector(Adafruit_BNO055::VECTOR_ACCELEROMETER); - gyro = sensor.getVector(Adafruit_BNO055::VECTOR_GYROSCOPE); - mag = sensor.getVector(Adafruit_BNO055::VECTOR_MAGNETOMETER); + euler = sensor->getVector(Adafruit_BNO055::VECTOR_EULER); + acc = sensor->getVector(Adafruit_BNO055::VECTOR_ACCELEROMETER); + gyro = sensor->getVector(Adafruit_BNO055::VECTOR_GYROSCOPE); + mag = sensor->getVector(Adafruit_BNO055::VECTOR_MAGNETOMETER); last_read = millis(); } @@ -92,20 +98,20 @@ void BNO055_API::calibrate() { uint8_t system, gyro, accel, mag; system = gyro = accel = mag = 0; - while (sensor.isFullyCalibrated()) {} + while (sensor->isFullyCalibrated()) {} } void BNO055_API::setup() { // Relative heading -- no magnetometer - if(!sensor.begin(Adafruit_BNO055::OPERATION_MODE_ACCGYRO)) { + if(!sensor->begin(Adafruit_BNO055::OPERATION_MODE_ACCGYRO)) { while(1); } // 2G = 0, 4G = 1, 8G = 2, 16G = 3 - sensor.setAccelRange(3); + sensor->setAccelRange(3); // TODO: do we need this? - sensor.setExtCrystalUse(true); + sensor->setExtCrystalUse(true); } BNO055_API::BNO055_API() {} diff --git a/libraries/bno055_api.h b/libraries/bno055_api.h index a9ed73b..97c43a8 100644 --- a/libraries/bno055_api.h +++ b/libraries/bno055_api.h @@ -1,9 +1,6 @@ -#include #include "imu.h" class BNO055_API: public IMU { - static Adafruit_BNO055 sensor; - public: static BNO055_API& getInstance(); float pitch(); @@ -28,7 +25,5 @@ class BNO055_API: public IMU { private: BNO055_API(); - unsigned long last_read = 0; void readSensorData(); - imu::Vector<3> euler, acc, gyro, mag; }; diff --git a/libraries/definitions.h b/libraries/definitions.h index 183dc2a..de566c6 100644 --- a/libraries/definitions.h +++ b/libraries/definitions.h @@ -3,3 +3,4 @@ #define IGN_DEBUG true #define IGNITER 1 // 1 or 2 #define BUZZER true +#define SD_CS 10 diff --git a/libraries/lsm9ds1_api.cpp b/libraries/lsm9ds1_api.cpp index 28b8972..9dff971 100644 --- a/libraries/lsm9ds1_api.cpp +++ b/libraries/lsm9ds1_api.cpp @@ -4,11 +4,18 @@ #define IMU_REFRESH_RATE 100 // Hz -Adafruit_LSM9DS1 LSM9DS1_API::sensor; +static LSM9DS1_API* instance = nullptr; +static Adafruit_LSM9DS1* sensor = nullptr; +static bool broken_connection = false; +static unsigned long last_read = 0; +static sensors_event_t acc, mag, gyro, temp; LSM9DS1_API& LSM9DS1_API::getInstance() { - static LSM9DS1_API instance; - return instance; + if (instance == nullptr) { + instance = new LSM9DS1_API(); + sensor = new Adafruit_LSM9DS1(); + } + return *instance; } void LSM9DS1_API::readSensorData() { @@ -24,8 +31,8 @@ void LSM9DS1_API::readSensorData() { return; } - sensor.read(); - sensor.getEvent(&acc, &mag, &gyro, &temp); + sensor->read(); + sensor->getEvent(&acc, &mag, &gyro, &temp); last_read = millis(); } @@ -93,13 +100,13 @@ void LSM9DS1_API::calibrate() { void LSM9DS1_API::setup() { // Relative heading -- no magnetometer - if (!sensor.begin()) { + if (!sensor->begin()) { while(1); } - sensor.setupAccel(sensor.LSM9DS1_ACCELRANGE_16G, sensor.LSM9DS1_ACCELDATARATE_119HZ); - sensor.setupMag(sensor.LSM9DS1_MAGGAIN_4GAUSS); - sensor.setupGyro(sensor.LSM9DS1_GYROSCALE_500DPS); + sensor->setupAccel(sensor->LSM9DS1_ACCELRANGE_16G, sensor->LSM9DS1_ACCELDATARATE_119HZ); + sensor->setupMag(sensor->LSM9DS1_MAGGAIN_4GAUSS); + sensor->setupGyro(sensor->LSM9DS1_GYROSCALE_500DPS); } LSM9DS1_API::LSM9DS1_API() {} diff --git a/libraries/lsm9ds1_api.h b/libraries/lsm9ds1_api.h index 535a0ab..a84f539 100644 --- a/libraries/lsm9ds1_api.h +++ b/libraries/lsm9ds1_api.h @@ -1,11 +1,7 @@ -#include -#include #include "imu.h" #include class LSM9DS1_API: public IMU { - static Adafruit_LSM9DS1 sensor; - public: static LSM9DS1_API& getInstance(); float pitch(); @@ -29,8 +25,5 @@ class LSM9DS1_API: public IMU { private: LSM9DS1_API(); - unsigned long last_read = 0; void readSensorData(); - sensors_event_t acc, mag, gyro, temp; - bool broken_connection = false; -}; +}; \ No newline at end of file diff --git a/libraries/mosfet_igniter.cpp b/libraries/mosfet_igniter.cpp index 941531f..3fcca92 100644 --- a/libraries/mosfet_igniter.cpp +++ b/libraries/mosfet_igniter.cpp @@ -7,13 +7,17 @@ struct IgniterOptions { int led_pin; }; -IgniterOptions igniters[2] = { - {5, 16}, {6, 15} +static IgniterOptions igniters[2] = { + {5, 16}, + {6, 15} }; +static MosfetIgniter* instance = nullptr; MosfetIgniter& MosfetIgniter::getInstance() { - static MosfetIgniter instance; - return instance; + if (instance == nullptr) { + instance = new MosfetIgniter(); + } + return *instance; } void MosfetIgniter::setup() { diff --git a/libraries/telemetry.cpp b/libraries/telemetry.cpp index 14af95b..617bd17 100644 --- a/libraries/telemetry.cpp +++ b/libraries/telemetry.cpp @@ -1,24 +1,41 @@ +#include "Arduino.h" +#include "SPI.h" +#include "RH_RF95.h" +#include "RHReliableDatagram.h" +#include "SD.h" + #include "definitions.h" #include "telemetry.h" #define CLIENT_ADDRESS 1 #define SERVER_ADDRESS 2 -#define SD_CS 10 #define SD_OFFLOAD_INTERVAL 1000 // ms +static Telemetry* instance = nullptr; // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on -RH_RF95 Telemetry::rf95(8, 3); -RHReliableDatagram Telemetry::rf_manager(Telemetry::rf95, SERVER_ADDRESS); +static RH_RF95* rf95 = nullptr; +static RHReliableDatagram* rf_manager = nullptr; +static bool rfInit = false; +static uint32_t message_count; +static String logs_filename = "flight.log"; +static File logs_file; +static unsigned long last_sd_sync = 0; +static unsigned long last_radio_message_time = 0; +static uint16_t radio_throttle_ms = 0; Telemetry& Telemetry::getInstance() { - static Telemetry instance; - return instance; + if (instance == nullptr) { + instance = new Telemetry(); + rf95 = new RH_RF95(8, 3); + rf_manager = new RHReliableDatagram(*rf95, SERVER_ADDRESS); + } + return *instance; } void Telemetry::send(TelemetryMessage message) { ++message_count; message.count = message_count; - if (!init) { + if (!rfInit) { return; } @@ -52,15 +69,15 @@ void Telemetry::send(TelemetryMessage message) { #endif if (millis() - last_radio_message_time > radio_throttle_ms) { - rf95.send(stream, message_size); - rf95.waitPacketSent(); - rf95.setModeRx(); // continue listening + rf95->send(stream, message_size); + rf95->waitPacketSent(); + rf95->setModeRx(); // continue listening last_radio_message_time = millis(); } } void Telemetry::send(String debug_message) { - if (!init) { + if (!rfInit) { return; } TelemetryMessage message; @@ -70,14 +87,14 @@ void Telemetry::send(String debug_message) { } void Telemetry::setup() { - if (!rf_manager.init()) { + if (!rf_manager->init()) { while(1); } - rf95.setFrequency(432.25); - rf95.setSignalBandwidth(500000); - rf95.setSpreadingFactor(8); - rf95.setTxPower(18); + rf95->setFrequency(432.25); + rf95->setSignalBandwidth(500000); + rf95->setSpreadingFactor(8); + rf95->setTxPower(18); #if SD_LOGS if (!SD.begin(SD_CS)) { @@ -93,11 +110,11 @@ void Telemetry::setup() { #endif message_count = 0; - init = true; + rfInit = true; } bool Telemetry::messageAvailable() { - return rf_manager.available(); + return rf_manager->available(); } String Telemetry::receiveMessage() { @@ -105,12 +122,12 @@ String Telemetry::receiveMessage() { uint8_t len = sizeof(buf); uint8_t from; - rf_manager.recvfromAck(buf, &len, &from); + rf_manager->recvfromAck(buf, &len, &from); return String((char*)buf); } -void Telemetry::setRadioThrottle(uint16_t radio_throttle_ms) { - this->radio_throttle_ms = radio_throttle_ms; +void Telemetry::setRadioThrottle(uint16_t new_radio_throttle_ms) { + radio_throttle_ms = new_radio_throttle_ms; } Telemetry::Telemetry() {} diff --git a/libraries/telemetry.h b/libraries/telemetry.h index 6d8a2d8..2649926 100644 --- a/libraries/telemetry.h +++ b/libraries/telemetry.h @@ -1,8 +1,3 @@ -#include "Arduino.h" -#include "SPI.h" -#include "RH_RF95.h" -#include "RHReliableDatagram.h" -#include "SD.h" #include "types.h" class Telemetry { @@ -11,20 +6,10 @@ class Telemetry { void send(TelemetryMessage message); void send(String data); void setup(); - void setRadioThrottle(uint16_t radio_throttle_ms); + void setRadioThrottle(uint16_t new_radio_throttle_ms); bool messageAvailable(); String receiveMessage(); private: - bool init = false; - uint32_t message_count; - static RH_RF95 rf95; - static RHReliableDatagram rf_manager; - String logs_filename = "flight.log"; // max length: 8.3 - File logs_file; - unsigned long last_sd_sync = 0; - unsigned long last_radio_message_time = 0; - uint16_t radio_throttle_ms = 0; // no throttling - Telemetry(); };