From 7b7a7cd7732f7c051bfba768dcac8988cbf26d32 Mon Sep 17 00:00:00 2001 From: Joe Date: Mon, 30 Mar 2026 14:04:43 -0700 Subject: [PATCH 1/6] Initial Commit Boilerplate ahh --- blaze-lite/core/lib/IMU/LSM9DS1IMU.cpp | 0 blaze-lite/core/lib/IMU/LSM9DS1IMU.h | 0 blaze-lite/core/platformio.ini | 16 ++++++++-------- 3 files changed, 8 insertions(+), 8 deletions(-) create mode 100644 blaze-lite/core/lib/IMU/LSM9DS1IMU.cpp create mode 100644 blaze-lite/core/lib/IMU/LSM9DS1IMU.h diff --git a/blaze-lite/core/lib/IMU/LSM9DS1IMU.cpp b/blaze-lite/core/lib/IMU/LSM9DS1IMU.cpp new file mode 100644 index 0000000..e69de29 diff --git a/blaze-lite/core/lib/IMU/LSM9DS1IMU.h b/blaze-lite/core/lib/IMU/LSM9DS1IMU.h new file mode 100644 index 0000000..e69de29 diff --git a/blaze-lite/core/platformio.ini b/blaze-lite/core/platformio.ini index 037ace3..81b2366 100644 --- a/blaze-lite/core/platformio.ini +++ b/blaze-lite/core/platformio.ini @@ -13,14 +13,14 @@ platform = ststm32 board = blackpill_f411ce framework = arduino upload_protocol = dfu -build_flags = - -D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC - -D USBCON - -D ARDUINO_USB_CDC_ON_BOOTLOADER -lib_deps = - https://github.com/sparkfun/SparkFun_KX13X_Arduino_Library.git +build_flags = + -D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC + -D USBCON + -D ARDUINO_USB_CDC_ON_BOOTLOADER +lib_deps = + https://github.com/sparkfun/SparkFun_KX13X_Arduino_Library.git adafruit/Adafruit BMP280 Library - adafruit/Adafruit Unified Sensor adafruit/SdFat - Adafruit Fork@^2.3.102 arduino-libraries/SD@^1.3.0 - mikem/RadioHead@^1.120 + mikem/RadioHead@^1.120 + adafruit/Adafruit LSM9DS1 Library@^2.2.1 \ No newline at end of file From 9be7d35885f77579d9f7c4003cc9a6855a33fd14 Mon Sep 17 00:00:00 2001 From: Joe Date: Mon, 30 Mar 2026 15:25:35 -0700 Subject: [PATCH 2/6] library finished, pending HW test --- blaze-lite/core/lib/IMU/LSM9DS1IMU.cpp | 125 ++++++++++++++++++++++++ blaze-lite/core/lib/IMU/LSM9DS1IMU.h | 39 ++++++++ blaze-lite/core/platformio.ini | 3 +- blaze-lite/core/test/LSM9DS1IMUTest.cpp | 77 +++++++++++++++ blaze-lite/core/test/README.md | 1 - 5 files changed, 243 insertions(+), 2 deletions(-) create mode 100644 blaze-lite/core/test/LSM9DS1IMUTest.cpp delete mode 100644 blaze-lite/core/test/README.md diff --git a/blaze-lite/core/lib/IMU/LSM9DS1IMU.cpp b/blaze-lite/core/lib/IMU/LSM9DS1IMU.cpp index e69de29..17facd5 100644 --- a/blaze-lite/core/lib/IMU/LSM9DS1IMU.cpp +++ b/blaze-lite/core/lib/IMU/LSM9DS1IMU.cpp @@ -0,0 +1,125 @@ +/** + * @file LSM9DS1IMU.cpp + * @brief Implementation of LSM9DS1IMU class + */ + +#include + +#include "LSM9DS1IMU.h" + +LSM9DS1IMU::LSM9DS1IMU(SPIClass &spiPort, uint8_t accelGyroCsPin, uint8_t magCsPin) + : _lsm9ds1(accelGyroCsPin, magCsPin, &spiPort), + _hasSample(false), + _isReady(false) {} + +LSM9DS1IMU::~LSM9DS1IMU() {} + +void LSM9DS1IMU::setUp() { + Serial.println("Initializing LSM9DS1 IMU..."); + while (!_lsm9ds1.begin()) { + Serial.println("Failed to initialize LSM9DS1 IMU! Retrying..."); + delay(1000); + } + _isReady = true; + Serial.println("Setting sensor range"); + _lsm9ds1.setupAccel(_lsm9ds1.LSM9DS1_ACCELRANGE_16G, _lsm9ds1.LSM9DS1_ACCELDATARATE_952HZ); + _lsm9ds1.setupMag(_lsm9ds1.LSM9DS1_MAGGAIN_16GAUSS); + _lsm9ds1.setupGyro(_lsm9ds1.LSM9DS1_GYROSCALE_245DPS); +} + +void LSM9DS1IMU::pollSensors() { + if (!_isReady) { + _hasSample = false; + return; + } + + _lsm9ds1.read(); + _lsm9ds1.getEvent(&_accel, &_mag, &_gyro, &_temp); + _hasSample = true; +} + +bool LSM9DS1IMU::readAccel(float &x, float &y, float &z) { + if (!_isReady) { + x = 0.0f; + y = 0.0f; + z = 0.0f; + return false; + } + if (!_hasSample) { + pollSensors(); + } + if (!_hasSample) { + x = 0.0f; + y = 0.0f; + z = 0.0f; + return false; + } + + x = _accel.acceleration.x; + y = _accel.acceleration.y; + z = _accel.acceleration.z; + return true; +} + +bool LSM9DS1IMU::readGyro(float &x, float &y, float &z) { + if (!_isReady) { + x = 0.0f; + y = 0.0f; + z = 0.0f; + return false; + } + if (!_hasSample) { + pollSensors(); + } + if (!_hasSample) { + x = 0.0f; + y = 0.0f; + z = 0.0f; + return false; + } + + x = _gyro.gyro.x; + y = _gyro.gyro.y; + z = _gyro.gyro.z; + return true; +} + +bool LSM9DS1IMU::readMag(float &x, float &y, float &z) { + if (!_isReady) { + x = 0.0f; + y = 0.0f; + z = 0.0f; + return false; + } + if (!_hasSample) { + pollSensors(); + } + if (!_hasSample) { + x = 0.0f; + y = 0.0f; + z = 0.0f; + return false; + } + + x = _mag.magnetic.x; + y = _mag.magnetic.y; + z = _mag.magnetic.z; + return true; +} + +bool LSM9DS1IMU::readTemp(float &celsius) { + if (!_isReady) { + celsius = 0.0f; + return false; + } + if (!_hasSample) { + pollSensors(); + } + if (!_hasSample) { + celsius = 0.0f; + return false; + } + + celsius = _temp.temperature; + return true; +} \ No newline at end of file diff --git a/blaze-lite/core/lib/IMU/LSM9DS1IMU.h b/blaze-lite/core/lib/IMU/LSM9DS1IMU.h index e69de29..1a8311a 100644 --- a/blaze-lite/core/lib/IMU/LSM9DS1IMU.h +++ b/blaze-lite/core/lib/IMU/LSM9DS1IMU.h @@ -0,0 +1,39 @@ +/** + * @file LSM9DS1IMU.h + * @brief Wrapper class for Adafruit LSM9DS1 IMU using SPI communication + * + * This class provides a simplified interface for interacting with the LSM9DS1 + * IMU using SPI communication. It wraps the Adafruit_LSM9DS1 class + * from the Adafruit LSM9DS1 Library. + */ + +#ifndef LSM9DS1IMU_H +#define LSM9DS1IMU_H + +#include +#include +#include + +class LSM9DS1IMU { +public: + LSM9DS1IMU(SPIClass &spiPort, uint8_t accelGyroCsPin, uint8_t magCsPin); + ~LSM9DS1IMU(); + + void setUp(); + void pollSensors(); + bool readAccel(float &x, float &y, float &z); + bool readGyro(float &x, float &y, float &z); + bool readMag(float &x, float &y, float &z); + bool readTemp(float &celsius); + +private: + Adafruit_LSM9DS1 _lsm9ds1; + sensors_event_t _accel; + sensors_event_t _gyro; + sensors_event_t _mag; + sensors_event_t _temp; + bool _hasSample; + bool _isReady; +}; + +#endif \ No newline at end of file diff --git a/blaze-lite/core/platformio.ini b/blaze-lite/core/platformio.ini index 81b2366..ec58943 100644 --- a/blaze-lite/core/platformio.ini +++ b/blaze-lite/core/platformio.ini @@ -23,4 +23,5 @@ lib_deps = adafruit/SdFat - Adafruit Fork@^2.3.102 arduino-libraries/SD@^1.3.0 mikem/RadioHead@^1.120 - adafruit/Adafruit LSM9DS1 Library@^2.2.1 \ No newline at end of file + adafruit/Adafruit LSM9DS1 Library@^2.2.1 + adafruit/Adafruit Unified Sensor@^1.1.15 \ No newline at end of file diff --git a/blaze-lite/core/test/LSM9DS1IMUTest.cpp b/blaze-lite/core/test/LSM9DS1IMUTest.cpp new file mode 100644 index 0000000..23fc351 --- /dev/null +++ b/blaze-lite/core/test/LSM9DS1IMUTest.cpp @@ -0,0 +1,77 @@ +#include +#include + +#include "LSM9DS1IMU.h" + +#define LSM9DS1_XGCS_PIN PB12 +#define LSM9DS1_MCS_PIN PB13 + +LSM9DS1IMU imu(SPI, LSM9DS1_XGCS_PIN, LSM9DS1_MCS_PIN); + +void setup() { + Serial.begin(9600); + while (!Serial) { + delay(100); + } + + SPI.begin(); + + pinMode(LSM9DS1_XGCS_PIN, OUTPUT); + pinMode(LSM9DS1_MCS_PIN, OUTPUT); + digitalWrite(LSM9DS1_XGCS_PIN, HIGH); + digitalWrite(LSM9DS1_MCS_PIN, HIGH); + + imu.setUp(); +} + +void loop() { + float ax, ay, az; + float gx, gy, gz; + float mx, my, mz; + float tempC; + + imu.pollSensors(); + + if (imu.readAccel(ax, ay, az)) { + Serial.print("ACC (m/s^2): "); + Serial.print(ax, 4); + Serial.print(", "); + Serial.print(ay, 4); + Serial.print(", "); + Serial.println(az, 4); + } else { + Serial.println("ACC: read failed"); + } + + if (imu.readGyro(gx, gy, gz)) { + Serial.print("GYRO (dps): "); + Serial.print(gx, 4); + Serial.print(", "); + Serial.print(gy, 4); + Serial.print(", "); + Serial.println(gz, 4); + } else { + Serial.println("GYRO: read failed"); + } + + if (imu.readMag(mx, my, mz)) { + Serial.print("MAG (gauss): "); + Serial.print(mx, 4); + Serial.print(", "); + Serial.print(my, 4); + Serial.print(", "); + Serial.println(mz, 4); + } else { + Serial.println("MAG: read failed"); + } + + if (imu.readTemp(tempC)) { + Serial.print("TEMP (C): "); + Serial.println(tempC, 2); + } else { + Serial.println("TEMP: read failed"); + } + + Serial.println("---"); + delay(200); +} diff --git a/blaze-lite/core/test/README.md b/blaze-lite/core/test/README.md deleted file mode 100644 index 12a719a..0000000 --- a/blaze-lite/core/test/README.md +++ /dev/null @@ -1 +0,0 @@ -Example From 5dc8e61e151c12e64c34a555f120d230a541f6dc Mon Sep 17 00:00:00 2001 From: Joe Date: Tue, 31 Mar 2026 16:49:55 -0700 Subject: [PATCH 3/6] fixed construtor --- blaze-lite/core/lib/IMU/LSM9DS1IMU.cpp | 4 ++-- blaze-lite/core/lib/IMU/LSM9DS1IMU.h | 2 +- blaze-lite/core/test/LSM9DS1IMUTest.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/blaze-lite/core/lib/IMU/LSM9DS1IMU.cpp b/blaze-lite/core/lib/IMU/LSM9DS1IMU.cpp index 17facd5..5fc17a2 100644 --- a/blaze-lite/core/lib/IMU/LSM9DS1IMU.cpp +++ b/blaze-lite/core/lib/IMU/LSM9DS1IMU.cpp @@ -7,8 +7,8 @@ #include "LSM9DS1IMU.h" -LSM9DS1IMU::LSM9DS1IMU(SPIClass &spiPort, uint8_t accelGyroCsPin, uint8_t magCsPin) - : _lsm9ds1(accelGyroCsPin, magCsPin, &spiPort), +LSM9DS1IMU::LSM9DS1IMU(uint8_t accelGyroCsPin, uint8_t magCsPin) + : _lsm9ds1(accelGyroCsPin, magCsPin), _hasSample(false), _isReady(false) {} diff --git a/blaze-lite/core/lib/IMU/LSM9DS1IMU.h b/blaze-lite/core/lib/IMU/LSM9DS1IMU.h index 1a8311a..d8157c4 100644 --- a/blaze-lite/core/lib/IMU/LSM9DS1IMU.h +++ b/blaze-lite/core/lib/IMU/LSM9DS1IMU.h @@ -16,7 +16,7 @@ class LSM9DS1IMU { public: - LSM9DS1IMU(SPIClass &spiPort, uint8_t accelGyroCsPin, uint8_t magCsPin); + LSM9DS1IMU(uint8_t accelGyroCsPin, uint8_t magCsPin); ~LSM9DS1IMU(); void setUp(); diff --git a/blaze-lite/core/test/LSM9DS1IMUTest.cpp b/blaze-lite/core/test/LSM9DS1IMUTest.cpp index 23fc351..ff2035b 100644 --- a/blaze-lite/core/test/LSM9DS1IMUTest.cpp +++ b/blaze-lite/core/test/LSM9DS1IMUTest.cpp @@ -6,7 +6,7 @@ #define LSM9DS1_XGCS_PIN PB12 #define LSM9DS1_MCS_PIN PB13 -LSM9DS1IMU imu(SPI, LSM9DS1_XGCS_PIN, LSM9DS1_MCS_PIN); +LSM9DS1IMU imu(LSM9DS1_XGCS_PIN, LSM9DS1_MCS_PIN); void setup() { Serial.begin(9600); From 5d3ad474f6c6539a94c748068bcdf6bde15b6832 Mon Sep 17 00:00:00 2001 From: Joe Date: Fri, 10 Apr 2026 14:02:52 -0700 Subject: [PATCH 4/6] fixed pins for inhouse board --- blaze-lite/core/platformio.ini | 4 +- blaze-lite/core/src/main.cpp | 680 +++------------------------------ 2 files changed, 63 insertions(+), 621 deletions(-) diff --git a/blaze-lite/core/platformio.ini b/blaze-lite/core/platformio.ini index ec58943..6de8f25 100644 --- a/blaze-lite/core/platformio.ini +++ b/blaze-lite/core/platformio.ini @@ -8,9 +8,9 @@ ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html -[env:blackpill_f411ce] +[env:genericSTM32F411CE] platform = ststm32 -board = blackpill_f411ce +board = genericSTM32F411CE framework = arduino upload_protocol = dfu build_flags = diff --git a/blaze-lite/core/src/main.cpp b/blaze-lite/core/src/main.cpp index 33721cd..cbc52d2 100644 --- a/blaze-lite/core/src/main.cpp +++ b/blaze-lite/core/src/main.cpp @@ -1,644 +1,86 @@ -/** - * @file main.cpp - * @brief Main avionics system implementation - * - * Implements the high-level flight control system with: - * - Sensor polling and data aggregation - * - Flight state machine - * - Radio communication (uplink/downlink) - * - Data logging (SD card + SPI flash) - * - LED status indicators - */ - #include #include -#include -#include -#include -#include - -// Hardware libraries -#include "KX134Accelerometer.h" -#include "Radio.h" -#include "sdCard.h" -#include "dataPacket.h" //@Merrick, wat is dis? how is data packet a hardware library? - -// System libraries -#include "SensorData.h" -#include "FlightState.h" - -// ============================================================================ -// Pin Definitions -// ============================================================================ - - -// Radio (RF69 - SPI) -#define RADIO_CS_PIN PB6 //CS and Reset are swapped on the board, will fix in next revision -#define RADIO_INT_PIN PB4 -#define RADIO_RST_PIN PB7 - -// SD Card (SPI) -#define SD_CS_PIN PB15 - -// SPI Flash (W25Q128 - placeholder, adjust pin as needed) -#define SPI_FLASH_CS_PIN PB8 - -// ============================================================================ -// SPI Settings -// ============================================================================ - -// ============================================================================ -// Global Objects -// ============================================================================ +#include "LSM9DS1IMU.h" -// Sensors -KX134Accelerometer accelerometer; +#define LSM9DS1_XGCS_PIN PA1 //accel/gyro +#define LSM9DS1_MCS_PIN PA2 //magnetometer -// Communication -Radio radio(RADIO_CS_PIN, RADIO_INT_PIN, RADIO_RST_PIN); +#define SPI_SCK_PIN PA5 +#define SPI_MISO_PIN PA6 +#define SPI_MOSI_PIN PA7 -// Storage -sdCard card(SD_CS_PIN); - -// Data structures -SensorData sensorData; -FlightStateMachine stateMachine; - -// Data packet formatters for different sensor types -DataPacket accelPacket(StartByte::NO_RESPONSE); // High-G Accelerometer -DataPacket baroPacket(StartByte::NO_RESPONSE); // Barometer -DataPacket statusPacket(StartByte::NO_RESPONSE); // Status checks - - -static constexpr uint32_t RADIO_FREQUENCY = 433; // 433 MHz -static constexpr uint32_t SENSOR_READ_INTERVAL = 20; // ms (50 Hz) -static constexpr uint32_t RADIO_TX_INTERVAL = 100; // ms (10 Hz) -static constexpr uint32_t RADIO_RX_INTERVAL = 50; // ms (20 Hz) - -uint32_t lastSensorRead = 0; -uint32_t lastRadioTx = 0; -uint32_t lastRadioRx = 0; -uint32_t dataSequenceNumber = 0; - -// ============================================================================ -// Function Prototypes -// ============================================================================ - -void readSensors(); -void updateStateMachine(); -void handleRadio(); -bool formatAccelerometerPayload(uint8_t* payload); -bool formatBarometerPayload(uint8_t* payload); -bool formatStatusPayload(uint8_t* payload); -void parseRadioCommand(const DecodedPacket& decoded); -void writeLogEntry(); -void writeSystemLog(const char* format, ...); -void printReceivedPacket(const uint8_t* buffer, size_t length, const DecodedPacket* decoded); -// ============================================================================ -// Setup -// ============================================================================ +LSM9DS1IMU imu(LSM9DS1_XGCS_PIN, LSM9DS1_MCS_PIN); void setup() { - // Initialize Serial Serial.begin(9600); - while (!Serial && millis() < 5000) { - delay(50); + while (!Serial) { + delay(100); } - Serial.println("\n=== Blaze Avionics System ==="); - - // Initialize SPI - SPI.begin(); - delay(2000); - - // Initialize Accelerometer - Serial.println("Initializing KX134 accelerometer..."); - pinMode(KX134_CS_PIN, OUTPUT); - digitalWrite(KX134_CS_PIN, HIGH); - - if (!accelerometer.begin(SPI)) { - writeSystemLog("[%lu] ERROR: KX134 initialization failed!\r\n", millis()); - stateMachine.setError("KX134 init failed"); - } else { - Serial.println("KX134 initialized successfully"); - accelerometer.reset(); - delay(50); - accelerometer.enableDataEngine(true); - accelerometer.setRange(SFE_KX134_RANGE64G); - accelerometer.enable(true); - } - - // Initialize Radio - Serial.println("Initializing radio..."); - if (!radio.init(RADIO_FREQUENCY)) { - writeSystemLog("[%lu] ERROR: Radio initialization failed!\r\n", millis()); - stateMachine.setError("Radio init failed"); - } else { - Serial.println("Radio initialized successfully"); - radio.setCallSign("KO6JIZ"); - } - - // Initialize SD Card - Serial.println("Initializing SD card..."); - card.startUp(); - - // Initialize State Machine - stateMachine.init(); - Serial.println("State machine initialized - Starting in UNARMED state"); - - // Initialize Sensor Data - initSensorData(&sensorData); + delay(1000); // Allow time for serial monitor to connect + SPI.setSCLK(SPI_SCK_PIN); + SPI.setMISO(SPI_MISO_PIN); + SPI.setMOSI(SPI_MOSI_PIN); - stateMachine.setPhase(FlightPhase::UNARMED); - - Serial.println("=== System Ready ==="); - Serial.println("Waiting for ARM command..."); -} + SPI.begin(); + delay(100); // Allow time for SPI to initialize -// ============================================================================ -// Main Loop -// ============================================================================ + pinMode(LSM9DS1_XGCS_PIN, OUTPUT); + pinMode(LSM9DS1_MCS_PIN, OUTPUT); + digitalWrite(LSM9DS1_XGCS_PIN, HIGH); + digitalWrite(LSM9DS1_MCS_PIN, HIGH); -void loop() { - updateStateMachine(); // Flight logic - readSensors(); // All sensor polling (includes logging) - handleRadio(); // Uplink/downlink + imu.setUp(); } -// ============================================================================ -// Sensor Reading -// ============================================================================ - -void readSensors() { - uint32_t currentTime = millis(); - - // Throttle sensor reads to avoid overwhelming the system - if (currentTime - lastSensorRead < SENSOR_READ_INTERVAL) { - return; - } - lastSensorRead = currentTime; - - sensorData.systemTimestamp = currentTime; - sensorData.sequenceNumber = dataSequenceNumber++; - - // Read Accelerometer (KX134) - if (accelerometer.dataReady()) { - outputData accelData; - if (accelerometer.getAccelData(&accelData)) { - sensorData.accel.x = accelData.xData; - sensorData.accel.y = accelData.yData; - sensorData.accel.z = accelData.zData; - sensorData.accel.magnitude = calculateAccelMagnitude( - accelData.xData, accelData.yData, accelData.zData); - sensorData.accel.valid = true; - sensorData.accel.timestamp = currentTime; - } else { - sensorData.accel.valid = false; - } +void loop() { + float ax, ay, az; + float gx, gy, gz; + float mx, my, mz; + float tempC; + + imu.pollSensors(); + + if (imu.readAccel(ax, ay, az)) { + Serial.print("ACC (m/s^2): "); + Serial.print(ax, 4); + Serial.print(", "); + Serial.print(ay, 4); + Serial.print(", "); + Serial.println(az, 4); } else { - sensorData.accel.valid = false; - } - - // TODO: Read Gyroscope (LSM9DS1 or similar) - // sensorData.gyro.valid = false; // Placeholder - - // TODO: Read Magnetometer (LSM9DS1 or similar) - // sensorData.mag.valid = false; // Placeholder - - // TODO: Read Barometer (BMP280/MS5611) - // sensorData.baro.valid = false; // Placeholder - // For now, use a placeholder altitude based on accelerometer - // In a real system, this would come from barometric pressure sensor - sensorData.baro.altitude = 0.0f; // Placeholder - sensorData.baro.valid = false; - - // Log data every time sensors are read - writeLogEntry(); -} - -// ============================================================================ -// State Machine Update -// ============================================================================ - -void updateStateMachine() { - // Get current sensor data for state machine - float altitude = sensorData.baro.valid ? sensorData.baro.altitude : 0.0f; - float acceleration = sensorData.accel.valid ? sensorData.accel.magnitude : 0.0f; - - // Update state machine - bool stateChanged = stateMachine.update(altitude, acceleration); - - // Handle state changes - if (stateChanged) { - const FlightState& state = stateMachine.getState(); - Serial.print("State changed to: "); - char logMsg[256]; - - switch (state.phase) { - case FlightPhase::UNARMED: - writeSystemLog("[%lu] STATE: UNARMED\r\n", millis()); - // Disable logging and radio when entering UNARMED state - stateMachine.setLoggingEnabled(false); - stateMachine.setRadioFlag(false); - break; - case FlightPhase::ARMED: - writeSystemLog("[%lu] STATE: ARMED\r\n", millis()); - // Enable logging and radio when entering ARMED state - stateMachine.setLoggingEnabled(true); - stateMachine.setRadioFlag(true); - break; - case FlightPhase::LAUNCH: - writeSystemLog("[%lu] STATE: LAUNCH (time: %lu)\r\n", millis(), state.launchTime); - break; - case FlightPhase::APOGEE: - writeSystemLog("[%lu] STATE: APOGEE (max alt: %.2f m)\r\n", millis(), state.maxAltitude); - break; - case FlightPhase::DESCENT: - writeSystemLog("[%lu] STATE: DESCENT\r\n", millis()); - break; - case FlightPhase::LANDED: - writeSystemLog("[%lu] STATE: LANDED (time: %lu)\r\n", millis(), state.landedTime); - break; - case FlightPhase::ERROR: - writeSystemLog("[%lu] ERROR: %s\r\n", millis(), state.errorMessage); - break; - } - } - - // Check for ARM command (could be from radio or button) -} - -// ============================================================================ -// Radio Handling -// ============================================================================ - -void handleRadio() { - uint32_t currentTime = millis(); - const FlightState& state = stateMachine.getState(); - - // Receive radio commands during UNARMED and ARMED phases - // Check for incoming messages every 50ms - if ((currentTime - lastRadioRx >= RADIO_RX_INTERVAL)) { - lastRadioRx = currentTime; - - // Check for incoming radio messages (uplink) - if (radio.available()) { - uint8_t rxBuffer[64]; - size_t received = radio.recv(rxBuffer, sizeof(rxBuffer)); - - if (received > 0) { - // Try to decode as a DataPacket - DecodedPacket decoded; - if (received == DataPacket::PACKET_SIZE) { - DataPacket tempPacket(StartByte::NO_RESPONSE); - if (tempPacket.decodePacket(rxBuffer, received, decoded)) { - // Log received telemetry/command - writeSystemLog("[%lu] RX: ID=%c%c, Seq=%lu, TS=%lu\r\n", - millis(), decoded.idA, decoded.idB, decoded.sequenceID, decoded.timestamp); - - // Print full packet details to Serial for debugging - printReceivedPacket(rxBuffer, received, &decoded); - - parseRadioCommand(decoded); - } else { - writeSystemLog("[%lu] ERROR: Failed to decode packet\r\n", millis()); - } - } else { - // Debug-only: print raw bytes for non-DataPacket lengths - printReceivedPacket(rxBuffer, received, nullptr); - } - } - } + Serial.println("ACC: read failed"); } - - // Send telemetry (downlink) at regular intervals - // According to protocol: send sensor-specific packets - if (state.radioFlag && (currentTime - lastRadioTx >= RADIO_TX_INTERVAL)) { - lastRadioTx = currentTime; - - // Send High-G Accelerometer data (ID: "al") - if (sensorData.accel.valid) { - uint8_t payload[DataPacket::PAYLOAD_SIZE]; - if (!formatAccelerometerPayload(payload)) { - writeSystemLog("[%lu] ERROR: Failed to format accelerometer payload\r\n", millis()); - return; - } - accelPacket.encodePacket(payload, 'a', 'l'); - - uint8_t* packetBuffer = accelPacket.getBuffer(); - size_t packetSize = accelPacket.getLength(); - radio.send(packetBuffer, packetSize, false); - } - - // Send Barometer data (ID: "ba") if available - if (sensorData.baro.valid) { - uint8_t payload[DataPacket::PAYLOAD_SIZE]; - if (!formatBarometerPayload(payload)) { - writeSystemLog("[%lu] ERROR: Failed to format barometer payload\r\n", millis()); - return; - } - baroPacket.encodePacket(payload, 'b', 'a'); - - uint8_t* packetBuffer = baroPacket.getBuffer(); - size_t packetSize = baroPacket.getLength(); - radio.send(packetBuffer, packetSize, false); - } - - // Send Status checks (ID: "sc") - { - uint8_t payload[DataPacket::PAYLOAD_SIZE]; - if (!formatStatusPayload(payload)) { - writeSystemLog("[%lu] ERROR: Failed to format status payload\r\n", millis()); - return; - } - statusPacket.encodePacket(payload, 's', 'c'); - - uint8_t* packetBuffer = statusPacket.getBuffer(); - size_t packetSize = statusPacket.getLength(); - radio.send(packetBuffer, packetSize, false); - } - } -} - -// ============================================================================ -// Logging -// ============================================================================ - -void writeLogEntry() { - const FlightState& state = stateMachine.getState(); - - // Only log if logging is enabled - if (!state.loggingEnabled) { - return; - } - - float accelX = sensorData.accel.valid ? sensorData.accel.x : 0.0f; - float accelY = sensorData.accel.valid ? sensorData.accel.y : 0.0f; - float accelZ = sensorData.accel.valid ? sensorData.accel.z : 0.0f; - float accelMag = sensorData.accel.valid ? sensorData.accel.magnitude : 0.0f; - float baroAlt = sensorData.baro.valid ? sensorData.baro.altitude : 0.0f; - - char accelXStr[16]; - char accelYStr[16]; - char accelZStr[16]; - char accelMagStr[16]; - char baroAltStr[16]; - - dtostrf(accelX, 0, 3, accelXStr); - dtostrf(accelY, 0, 3, accelYStr); - dtostrf(accelZ, 0, 3, accelZStr); - dtostrf(accelMag, 0, 3, accelMagStr); - dtostrf(baroAlt, 0, 2, baroAltStr); - - // Format data for logging - char logBuffer[256]; - snprintf(logBuffer, sizeof(logBuffer), - "%lu,%u,%s,%s,%s,%s,%s,%u\r\n", - sensorData.systemTimestamp, - sensorData.sequenceNumber, - accelXStr, - accelYStr, - accelZStr, - accelMagStr, - baroAltStr, - static_cast(state.phase) - ); - - // Write to SD card - ssize_t written = card.writeData(strlen(logBuffer), logBuffer); - if (written < 0) { - writeSystemLog("[%lu] ERROR: SD data write failed\r\n", millis()); - } - - // TODO: Write to SPI Flash (W25Q128) - // This would require a SPI flash library - // For now, this is a placeholder -} - -/** - * Write system log entry to separate log file (Log.txt) - * Used for errors, state changes, and received telemetry/commands - */ -void writeSystemLog(const char* format, ...) { - if (format == nullptr) { - return; - } - Serial.println(format); - char message[256]; - va_list args; - va_start(args, format); - vsnprintf(message, sizeof(message), format, args); - va_end(args); - - Serial.print(message); - - // Write to log file using writeLog method - ssize_t written = card.writeLog(message, strlen(message)); - if (written < 0) { - // If log write fails, at least try to print to Serial - Serial.print("Log write failed: "); - Serial.println(message); - } -} - -/** - * Print received packet details to Serial. - * Includes raw bytes and decoded fields when available. - */ -void printReceivedPacket(const uint8_t* buffer, size_t length, const DecodedPacket* decoded) { - if (buffer == nullptr || length == 0) { - Serial.println("RX: "); - return; - } - - Serial.print("RX RAW ["); - Serial.print(length); - Serial.print("B]: "); - for (size_t i = 0; i < length; i++) { - if (buffer[i] < 0x10) { - Serial.print('0'); - } - Serial.print(buffer[i], HEX); - if (i + 1 < length) { - Serial.print(' '); - } - } - Serial.println(); - if (decoded != nullptr && decoded->isValid) { - Serial.print("RX DEC: ID="); - Serial.print(decoded->idA); - Serial.print(decoded->idB); - Serial.print(", Seq="); - Serial.print(decoded->sequenceID); - Serial.print(", TS="); - Serial.print(decoded->timestamp); - Serial.print(", Payload=\""); - for (size_t i = 0; i < DataPacket::PAYLOAD_SIZE; i++) { - char c = static_cast(decoded->payload[i]); - if (c >= 32 && c <= 126) { - Serial.print(c); - } else { - Serial.print('.'); - } - } - Serial.println("\""); - } -} - -// ============================================================================ -// Helper Functions -// ============================================================================ - -/** - * Format High-G Accelerometer payload (ID: "al") - * Payload: acceleration-x, acceleration-y, acceleration-z - * Format: ASCII string with leading zeros, 17 bytes total - * Example: "00000546789764783" (X=5467, Y=8976, Z=4783 with leading zeros) - */ -bool formatAccelerometerPayload(uint8_t* payload) { - if (payload == nullptr) { - writeSystemLog("[%lu] ERROR: Invalid packet received\r\n", millis()); - return false; - } - - float accelXVal = sensorData.accel.valid ? sensorData.accel.x : 0.0f; - float accelYVal = sensorData.accel.valid ? sensorData.accel.y : 0.0f; - float accelZVal = sensorData.accel.valid ? sensorData.accel.z : 0.0f; - - // Convert accelerometer values to integers (multiply by 1000 for precision) - // Then format as ASCII strings with leading zeros - int32_t accelX = (int32_t)(accelXVal * 1000.0f); - int32_t accelY = (int32_t)(accelYVal * 1000.0f); - int32_t accelZ = (int32_t)(accelZVal * 1000.0f); - - // Format: X(5 digits) + Y(6 digits) + Z(6 digits) = 17 bytes - // Using format: "XXXXXYYYYYYZZZZZZ" - char temp[18]; - snprintf(temp, sizeof(temp), "%05ld%06ld%06ld", - (long)accelX, (long)accelY, (long)accelZ); - - // Copy to payload (ensure exactly 17 bytes) - for (int i = 0; i < 17; i++) { - payload[i] = (i < strlen(temp)) ? temp[i] : '0'; - } - return true; -} - -/** - * Format Barometer payload (ID: "ba") - * Payload: pressure value - * Format: ASCII string with leading zeros, 17 bytes total - * Example: "00000000000000546" (pressure value with leading zeros) - */ -bool formatBarometerPayload(uint8_t* payload) { - if (payload == nullptr) { - return false; - } - - // Convert pressure to integer (Pa, multiply by 1 for integer representation) - // Format as ASCII string with leading zeros - int32_t pressure = (int32_t)sensorData.baro.pressure; - - char temp[18]; - snprintf(temp, sizeof(temp), "%017ld", (long)pressure); - - // Copy to payload (ensure exactly 17 bytes) - for (int i = 0; i < 17; i++) { - payload[i] = (i < strlen(temp)) ? temp[i] : '0'; + if (imu.readGyro(gx, gy, gz)) { + Serial.print("GYRO (dps): "); + Serial.print(gx, 4); + Serial.print(", "); + Serial.print(gy, 4); + Serial.print(", "); + Serial.println(gz, 4); + } else { + Serial.println("GYRO: read failed"); } - return true; -} -/** - * Format Status checks payload (ID: "sc") - * Payload: flight state and system status - * Format: ASCII string with leading zeros, 17 bytes total - */ -bool formatStatusPayload(uint8_t* payload) { - if (payload == nullptr) { - return false; - } - - const FlightState& state = stateMachine.getState(); - - // Format: phase(1) + altitude(8) + maxAltitude(8) = 17 bytes - // Example: "10000000000000000" (phase=1, altitude=0, maxAltitude=0) - char temp[18]; - int32_t altitude = (int32_t)(state.altitude * 100.0f); // cm precision - int32_t maxAltitude = (int32_t)(state.maxAltitude * 100.0f); - - snprintf(temp, sizeof(temp), "%01d%08ld%08ld", - static_cast(state.phase), (long)altitude, (long)maxAltitude); - - // Copy to payload (ensure exactly 17 bytes) - for (int i = 0; i < 17; i++) { - payload[i] = (i < strlen(temp)) ? temp[i] : '0'; + if (imu.readMag(mx, my, mz)) { + Serial.print("MAG (gauss): "); + Serial.print(mx, 4); + Serial.print(", "); + Serial.print(my, 4); + Serial.print(", "); + Serial.println(mz, 4); + } else { + Serial.println("MAG: read failed"); } - return true; -} -/** - * Parse incoming radio command using decoded packet - * Command IDs (Ground → Air): - * - "ss" (0x7373): System command (reboot, etc.) - * - "sm" (0x736D): State machine command (ARM/DISARM) - * - "pr" (0x7072): Ping request (status checks) - */ -void parseRadioCommand(const DecodedPacket& decoded) { - if (!decoded.isValid) { - writeSystemLog("[%lu] ERROR: Invalid packet received\r\n", millis()); - return; - } - - // Extract message ID - char idA = decoded.idA; - char idB = decoded.idB; - - // Check command type based on message ID - if (idA == 's' && idB == 's') { - // System command (ss) - writeSystemLog("[%lu] CMD: System command (ss) received\r\n", millis()); - // Payload could contain reboot command, etc. - // For now, just acknowledge - Serial.println("System command acknowledged"); - - } else if (idA == 's' && idB == 'm') { - // State machine command (sm) - ARM/DISARM - writeSystemLog("[%lu] CMD: State machine command (sm) received\r\n", millis()); - - // Parse payload for state command - // Assuming payload[0] contains command: 0=DISARM, 1=ARM - if (decoded.payload[0] == '1' || decoded.payload[0] == 1) { - writeSystemLog("[%lu] CMD: ARM command executed\r\n", millis()); - stateMachine.setPhase(FlightPhase::ARMED); - } else if (decoded.payload[0] == '0' || decoded.payload[0] == 0) { - writeSystemLog("[%lu] CMD: DISARM command executed\r\n", millis()); - stateMachine.setPhase(FlightPhase::UNARMED); - } - - } else if (idA == 'p' && idB == 'r') { - // Ping request (pr) - status checks - writeSystemLog("[%lu] CMD: Ping request (pr) received\r\n", millis()); - // Send a ping response packet - uint8_t payload[DataPacket::PAYLOAD_SIZE]; - const FlightState& state = stateMachine.getState(); - // Format ping response: "PingResp" + phase number + status - // Format: "PingResp" (8 chars) + phase (1 char) + "OK" (2 chars) + padding = 17 bytes - snprintf((char*)payload, sizeof(payload), "PingResp%01dOK ", static_cast(state.phase)); - statusPacket.encodePacket(payload, 'p', 'r'); - - // Send the ping response packet - uint8_t* packetBuffer = statusPacket.getBuffer(); - size_t packetSize = statusPacket.getLength(); - radio.send(packetBuffer, packetSize, false); + if (imu.readTemp(tempC)) { + Serial.print("TEMP (C): "); + Serial.println(tempC, 2); } else { - writeSystemLog("[%lu] WARN: Unknown command ID: %c%c\r\n", millis(), idA, idB); + Serial.println("TEMP: read failed"); } - - // Log received packet info - Serial.print("Sequence: "); - Serial.print(decoded.sequenceID); - Serial.print(", Timestamp: "); - Serial.println(decoded.timestamp); + + Serial.println("---"); + delay(200); } From a6f9de0252096992faa640ec09ce26d8b3965161 Mon Sep 17 00:00:00 2001 From: Joe Date: Fri, 10 Apr 2026 17:18:11 -0700 Subject: [PATCH 5/6] updated test file --- blaze-lite/core/test/LSM9DS1IMUTest.cpp | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/blaze-lite/core/test/LSM9DS1IMUTest.cpp b/blaze-lite/core/test/LSM9DS1IMUTest.cpp index ff2035b..5022376 100644 --- a/blaze-lite/core/test/LSM9DS1IMUTest.cpp +++ b/blaze-lite/core/test/LSM9DS1IMUTest.cpp @@ -3,8 +3,12 @@ #include "LSM9DS1IMU.h" -#define LSM9DS1_XGCS_PIN PB12 -#define LSM9DS1_MCS_PIN PB13 +#define LSM9DS1_XGCS_PIN PA1 //accel/gyro +#define LSM9DS1_MCS_PIN PA2 //magnetometer + +#define SPI_SCK_PIN PA5 +#define SPI_MISO_PIN PA6 +#define SPI_MOSI_PIN PA7 LSM9DS1IMU imu(LSM9DS1_XGCS_PIN, LSM9DS1_MCS_PIN); @@ -13,14 +17,16 @@ void setup() { while (!Serial) { delay(100); } + delay(1000); // Allow time for serial monitor to connect - SPI.begin(); - - pinMode(LSM9DS1_XGCS_PIN, OUTPUT); - pinMode(LSM9DS1_MCS_PIN, OUTPUT); - digitalWrite(LSM9DS1_XGCS_PIN, HIGH); - digitalWrite(LSM9DS1_MCS_PIN, HIGH); + Serial.println("Starting SPI"); + SPI.setSCLK(SPI_SCK_PIN); + SPI.setMISO(SPI_MISO_PIN); + SPI.setMOSI(SPI_MOSI_PIN); + SPI.begin(); + delay(100); // Allow time for SPI to initialize + Serial.println("Setting up IMU"); imu.setUp(); } From 04c2f9cc02b29f63b97828481188a86535fc08ec Mon Sep 17 00:00:00 2001 From: Joe Date: Tue, 28 Apr 2026 17:01:01 -0700 Subject: [PATCH 6/6] updated imu startup to "bool" type Co-authored-by: Copilot --- blaze-lite/core/lib/IMU/LSM9DS1IMU.cpp | 12 ++++++++---- blaze-lite/core/lib/IMU/LSM9DS1IMU.h | 2 +- blaze-lite/core/src/main.cpp | 5 ++++- blaze-lite/core/test/LSM9DS1IMUTest.cpp | 4 +++- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/blaze-lite/core/lib/IMU/LSM9DS1IMU.cpp b/blaze-lite/core/lib/IMU/LSM9DS1IMU.cpp index 5fc17a2..d48545b 100644 --- a/blaze-lite/core/lib/IMU/LSM9DS1IMU.cpp +++ b/blaze-lite/core/lib/IMU/LSM9DS1IMU.cpp @@ -14,17 +14,21 @@ LSM9DS1IMU::LSM9DS1IMU(uint8_t accelGyroCsPin, uint8_t magCsPin) LSM9DS1IMU::~LSM9DS1IMU() {} -void LSM9DS1IMU::setUp() { +bool LSM9DS1IMU::setUp() { Serial.println("Initializing LSM9DS1 IMU..."); - while (!_lsm9ds1.begin()) { - Serial.println("Failed to initialize LSM9DS1 IMU! Retrying..."); - delay(1000); + if (!_lsm9ds1.begin()) { + _isReady = false; + _hasSample = false; + Serial.println("Failed to initialize LSM9DS1 IMU!"); + return false; } + _isReady = true; Serial.println("Setting sensor range"); _lsm9ds1.setupAccel(_lsm9ds1.LSM9DS1_ACCELRANGE_16G, _lsm9ds1.LSM9DS1_ACCELDATARATE_952HZ); _lsm9ds1.setupMag(_lsm9ds1.LSM9DS1_MAGGAIN_16GAUSS); _lsm9ds1.setupGyro(_lsm9ds1.LSM9DS1_GYROSCALE_245DPS); + return true; } void LSM9DS1IMU::pollSensors() { diff --git a/blaze-lite/core/lib/IMU/LSM9DS1IMU.h b/blaze-lite/core/lib/IMU/LSM9DS1IMU.h index d8157c4..15394cc 100644 --- a/blaze-lite/core/lib/IMU/LSM9DS1IMU.h +++ b/blaze-lite/core/lib/IMU/LSM9DS1IMU.h @@ -19,7 +19,7 @@ class LSM9DS1IMU { LSM9DS1IMU(uint8_t accelGyroCsPin, uint8_t magCsPin); ~LSM9DS1IMU(); - void setUp(); + bool setUp(); void pollSensors(); bool readAccel(float &x, float &y, float &z); bool readGyro(float &x, float &y, float &z); diff --git a/blaze-lite/core/src/main.cpp b/blaze-lite/core/src/main.cpp index eab813b..31297b9 100644 --- a/blaze-lite/core/src/main.cpp +++ b/blaze-lite/core/src/main.cpp @@ -204,7 +204,10 @@ void setup() { } //initialize IMU - imu.setUp(); + if (!imu.setUp()) { + writeSystemLog("[%lu] ERROR: LSM9DS1 initialization failed!\r\n", millis()); + stateMachine.setError("IMU init failed"); + } // Initialize State Machine stateMachine.init(); diff --git a/blaze-lite/core/test/LSM9DS1IMUTest.cpp b/blaze-lite/core/test/LSM9DS1IMUTest.cpp index 5022376..ddabeb9 100644 --- a/blaze-lite/core/test/LSM9DS1IMUTest.cpp +++ b/blaze-lite/core/test/LSM9DS1IMUTest.cpp @@ -27,7 +27,9 @@ void setup() { SPI.begin(); delay(100); // Allow time for SPI to initialize Serial.println("Setting up IMU"); - imu.setUp(); + if (!imu.setUp()) { + Serial.println("IMU setup failed"); + } } void loop() {