N4 Flight Software N4
Flight software used for the N4 flight computers
Loading...
Searching...
No Matches
main.cpp File Reference

This contains the main driver code for the flight computer. More...

#include <Arduino.h>
#include <Wire.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <TinyGPSPlus.h>
#include <SFE_BMP180.h>
#include <FS.h>
#include <SD.h>
#include <SPIFFS.h>
#include <CSV_Parser.h>
#include "defs.h"
#include "mpu.h"
#include "SerialFlash.h"
#include "logger.h"
#include "data_types.h"
#include "states.h"
#include "system_logger.h"
#include "system_log_levels.h"
#include "wifi-config.h"
#include "kalman_filter.h"
#include "ring_buffer.h"
#include "custom_test_states.h"

Macros

#define BMP_CHECK_BIT   0
 
#define IMU_CHECK_BIT   1
 
#define FLASH_CHECK_BIT   2
 
#define GPS_CHECK_BIT   3
 
#define SD_CHECK_BIT   4
 
#define SPIFFS_CHECK_BIT   5
 
#define TEST_HARDWARE_CHECK_BIT   6
 
#define BAUDRATE   115200
 
#define NAK_INTERVAL   4000
 
#define SOH   0x01
 
#define EOT   0x04
 
#define ACK   0x06
 
#define NAK   0x15
 
#define CAN   0x18
 
#define MAX_CMD_LENGTH   10
 
#define MAX_CSV_LENGTH   256
 
#define FORMAT_SPIFFS_IF_FAILED   1
 
#define ALTITUDE   1525.0
 

Enumerations

enum  OPERATION_MODE { SAFE_MODE = 0 , ARMED_MODE }
 
enum  DAQ_STATES { HANDSHAKE = 0 , RECEIVE_TEST_DATA , CONFIRM_TEST_DATA , FINISH_DATA_RECEIVE }
 This enum holds the states during flight computer test mode. More...
 
enum  TEST_STATES { DATA_CONSUME = 0 , DONE_TESTING }
 

Functions

void drogueChuteDeploy ()
 fires the pyro-charge to deploy the drogue chute Turn on the drogue chute ejection circuit by running the GPIO HIGH for a preset No. of seconds.
Default no. of seconds to remain HIGH is 5
 
void mainChuteDeploy ()
 fires the pyro-charge to deploy the main chute Turn on the main chute ejection circuit by running the GPIO HIGH for a preset No. of seconds Default no. of seconds to remain HIGH is 5
 
void initDynamicWIFI ()
 create dynamic WIFI
 
float kalmanFilter (float z)
 Kalman filter estimated value calculation.
 
char feedRowParser ()
 
bool rowParserFinished ()
 
void listDir (fs::FS &fs, const char *dirname, uint8_t levels)
 
uint8_t initTestGPIO ()
 Inititialize the GPIOs.
 
uint8_t InitSPIFFS ()
 
uint8_t initSD ()
 
void SwitchLEDs (uint8_t red_state, uint8_t green_state)
 Switch the LEDS states.
 
void InitXMODEM ()
 Initiate XMODEM protocol by sending a NAK command every 4 seconds until the transmitter returns an ACK signal.
 
void SerialEvent ()
 
void ParseSerial (char *)
 
void checkRunTestToggle ()
 Sample the RUN/TEST toggle pins to check whether the flight computer is in test-DAQ mode, TEST mode or FLIGHT mode. If in DAQ mode, set the DAQ flag If in TEST mode, define the TEST flag FLIGHT mode is activated by completely removing the jumper.
 
void checkSubSystems ()
 
void readFile (fs::FS &fs, const char *path)
 
void readStateFile (fs::FS &fs, const char *path)
 
void readSubSystemStateFile (fs::FS &fs, const char *path)
 
void writeFile (fs::FS &fs, const char *path, const char *message)
 
void appendFile (fs::FS &fs, const char *path, const char *message)
 
void deleteFile (fs::FS &fs, const char *path)
 
void readTestDataFile ()
 
void initDataFiles ()
 
void buzz ()
 Buzz the buzzer for a given buzz_interval This function is non-blocking.
 
void blink_200ms (uint8_t led_pin)
 implements non-blocking blink
 
void ParseSerialBuffer (char *buffer)
 
void ParseSerialNumeric (int value)
 Parse the received serial command if it is a digit We are only interested in numeric values being sent by the transmitter to us, the receiver.
 
void handshakeSerialEvent ()
 Receive serial message during handshake.
 
void receiveTestDataSerialEvent ()
 Receive serial message during RECEIVE_TEST_DATA state Data received in this state is the actual test data. It is saved into the test flash memory.
 
void prepareForDataReceive ()
 this function prepares the flight computer to receive test data depending on the state, it tries to establich link between flight computer and sending PC receives the actual data confirm the actual data
 
PubSubClient client (wifi_client)
 
uint8_t MQTTInit (const char *broker_IP, uint16_t broker_port)
 
uint8_t BMPInit ()
 Initialize BMP180 barometric sensor.
 
uint8_t GPSInit ()
 Initialize the GPS connected on Serial2.
 
void readAccelerationTask (void *pvParameter)
 Read acceleration data from the accelerometer.
 
void readAltimeterTask (void *pvParameters)
 Read atm pressure data from the barometric sensor onboard.
 
void readGPSTask (void *pvParameters)
 Read the GPS location data and altitude and append to telemetry packet for transmission.
 
void kalmanFilterTask (void *pvParameters)
 Filter data using the Kalman Filter.
 
void checkFlightState (void *pvParameters)
 check various condition from flight data to change the flight state
 
void flightStateCallback (void *pvParameters)
 performs flight actions based on the current flight state
 
void debugToTerminalTask (void *pvParameters)
 debug flight/test data to terminal, this task is called if the DEBUG_TO_TERMINAL is set to 1 (see defs.h)
 
void logToMemory (void *pvParameter)
 log the data to the external flash memory
 
void MQTT_TransmitTelemetry (void *pvParameters)
 send flight data to ground
 
void MQTT_Reconnect ()
 Try reconnecting to MQTT if connection is lost.
 
void MQTTInit (const char *broker_IP, int broker_port)
 Initialize MQTT.
 
void customCheckState ()
 
void setup ()
 Setup - perform initialization of all hardware subsystems, create queues, create queue handles initialize system check table.
 
void loop ()
 Main loop.
 

Variables

uint8_t operation_mode = 0
 
uint8_t current_state = ARMED_FLIGHT_STATE::PRE_FLIGHT_GROUND
 
uint8_t STATE_BIT_MASK = 0
 
TinyGPSPlus gps
 
SystemLogger SYSTEM_LOGGER
 
const char * system_log_file = "/event_log.txt"
 
LOG_LEVEL level = INFO
 
const char * rocket_ID = "FC1"
 
uint8_t is_flight_mode = 0
 
char subsystems_state_buffer [10]
 
uint8_t SUBSYSTEM_INIT_MASK = 0b00000000
 
uint8_t DAQ_MODE = 0
 
uint8_t TEST_MODE = 0
 
uint8_t SOH_recvd_flag = 0
 
unsigned long last_NAK_time = 0
 
unsigned long current_NAK_time = 0
 
char SOH_CHR [6] = "SOH"
 
char serial_buffer [MAX_CMD_LENGTH]
 
int16_t serial_index = 0
 
char test_data_buffer [MAX_CSV_LENGTH]
 
char data_buffer_formatted [MAX_CSV_LENGTH]
 
int16_t test_data_serial_index = 0
 
uint8_t recv_data_led = 2
 
uint8_t red_led = 15
 
uint8_t green_led = 4
 
uint8_t buzzer = 33
 
uint8_t SET_DAQ_MODE_PIN = 14
 
uint8_t SET_TEST_MODE_PIN = 13
 
uint8_t SD_CS_PIN = 26
 
uint8_t current_DAQ_state = DAQ_STATES::HANDSHAKE
 
uint8_t sub_check_state
 
uint8_t current_test_state = TEST_STATES::DATA_CONSUME
 
const char * f_name = "/altitude_log.csv"
 
File test_file
 
const char * test_data_file = "/data.csv"
 
const char * run_state_file = "/state.txt"
 
char current_test_state_buffer [50] = ""
 
char subsystem_state_buffer [50]
 
unsigned long last_buzz = 0
 
unsigned long current_buzz = 0
 
unsigned long buzz_interval = 200
 
uint8_t buzzer_state = LOW
 
unsigned long last_blink = 0
 
unsigned long current_blink = 0
 
unsigned long blink_interval = 200
 
uint8_t led_state = LOW
 
int value = 0
 Parse the received serial command if it is a string.
 
WiFiClient wifi_client
 
WIFIConfig wifi_config
 
uint8_t drogue_pyro = 25
 
uint8_t main_pyro = 12
 
uint8_t flash_cs_pin = 5
 
uint8_t remote_switch = 27
 
uint8_t flash_led_pin = 32
 
char filename [] = "flight.txt"
 
uint32_t FILE_SIZE_512K = 524288L
 
uint32_t FILE_SIZE_1M = 1048576L
 
uint32_t FILE_SIZE_4M = 4194304L
 
SerialFlashFile file
 
unsigned long long previous_log_time = 0
 
unsigned long long current_log_time = 0
 
uint16_t log_sample_interval = 10
 
DataLogger data_logger (flash_cs_pin, flash_led_pin, filename, file, FILE_SIZE_4M)
 
long long current_time = 0
 
long long previous_time = 0
 
char telemetry_packet_buffer [256]
 
ring_buffer altitude_ring_buffer
 
float curr_val
 
float oldest_val
 
uint8_t apogee_flag =0
 
uint8_t main_eject_flag = 0
 
TaskHandle_t readAccelerationTaskHandle
 
TaskHandle_t readAltimeterTaskHandle
 
TaskHandle_t readGPSTaskHandle
 
TaskHandle_t clearTelemetryQueueTaskHandle
 
TaskHandle_t checkFlightStateTaskHandle
 
TaskHandle_t flightStateCallbackTaskHandle
 
TaskHandle_t MQTT_TransmitTelemetryTaskHandle
 
TaskHandle_t kalmanFilterTaskHandle
 
TaskHandle_t debugToTerminalTaskHandle
 
TaskHandle_t logToMemoryTaskHandle
 
accel_type_t acc_data
 
gyro_type_t gyro_data
 
gps_type_t gps_data
 
altimeter_type_t altimeter_data
 
telemetry_type_t telemetry_packet
 
MPU6050 imu (0x68, 16, 1000)
 
SFE_BMP180 altimeter
 
char status
 
double T
 
double PRESSURE
 
double p0
 
double a
 
QueueHandle_t telemetry_data_queue_handle
 
QueueHandle_t log_to_mem_queue_handle
 
QueueHandle_t check_state_queue_handle
 
QueueHandle_t debug_to_term_queue_handle
 
QueueHandle_t kalman_filter_queue_handle
 

Detailed Description

This contains the main driver code for the flight computer.

Author
Edwin Mwiti
Version
N4
Date
July 15 2024

0x5765206D6179206D616B65206F757220706C616E73202C 0x62757420476F642068617320746865206C61737420776F7264

Macro Definition Documentation

◆ ACK

#define ACK   0x06

positive acknowledgement

◆ CAN

#define CAN   0x18

cancel

◆ EOT

#define EOT   0x04

end of transmission

◆ MAX_CMD_LENGTH

#define MAX_CMD_LENGTH   10

Maximum length of the XMODEM command string that can be received

◆ MAX_CSV_LENGTH

#define MAX_CSV_LENGTH   256

Maximum length of the csv string that can be received

◆ NAK

#define NAK   0x15

negative acknowledgement

◆ NAK_INTERVAL

#define NAK_INTERVAL   4000

Interval in which to send the NAK command to the transmitter

◆ SOH

#define SOH   0x01

start of header

Enumeration Type Documentation

◆ DAQ_STATES

enum DAQ_STATES

This enum holds the states during flight computer test mode.


Enumerator
HANDSHAKE 

state to establish initial communication with transmitter

RECEIVE_TEST_DATA 

sets the flight computer to receive test data over serial

◆ OPERATION_MODE

flight states these states are to be used for flight

◆ TEST_STATES

Holds the states used when consuming the test data in testing mode

Function Documentation

◆ blink_200ms()

void blink_200ms ( uint8_t led_pin)

implements non-blocking blink


◆ BMPInit()

uint8_t BMPInit ( )

Initialize BMP180 barometric sensor.


Returns
TODO: 1 if init OK, 0 otherwise

◆ buzz()

void buzz ( )

Buzz the buzzer for a given buzz_interval This function is non-blocking.


◆ checkFlightState()

void checkFlightState ( void * pvParameters)

check various condition from flight data to change the flight state


◆ checkRunTestToggle()

void checkRunTestToggle ( )

Sample the RUN/TEST toggle pins to check whether the flight computer is in test-DAQ mode, TEST mode or FLIGHT mode. If in DAQ mode, set the DAQ flag If in TEST mode, define the TEST flag FLIGHT mode is activated by completely removing the jumper.


TEST_MODE Pin and RUN_MODE pin are both pulled HIGH. When you set the jumper, you pull that pin to LOW.

◆ debugToTerminalTask()

void debugToTerminalTask ( void * pvParameters)

debug flight/test data to terminal, this task is called if the DEBUG_TO_TERMINAL is set to 1 (see defs.h)


Parameters
pvParameter- A value that is passed as the parameter to the created task. If pvParameter is set to the address of a variable then the variable must still exist when the created task executes - so it is not valid to pass the address of a stack variable.

record number operation_mode state ax ay az pitch roll gx gy gz latitude longitude gps_altitude pressure temperature altitude_agl velocity

◆ drogueChuteDeploy()

void drogueChuteDeploy ( )

fires the pyro-charge to deploy the drogue chute Turn on the drogue chute ejection circuit by running the GPIO HIGH for a preset No. of seconds.
Default no. of seconds to remain HIGH is 5


◆ feedRowParser()

char feedRowParser ( )
Returns

◆ flightStateCallback()

void flightStateCallback ( void * pvParameters)

performs flight actions based on the current flight state


If the flight state requires an action, we perform it here For example if the flight state is apogee, we perform MAIN_CHUTE ejection

◆ GPSInit()

uint8_t GPSInit ( )

Initialize the GPS connected on Serial2.


Returns
1 if init OK, 0 otherwise

FIXME: Proper GPS init check! Look into if the GPS has acquired a LOCK on satelites Only if it has a lock then can we return a 1

GPS is low priority at the time of writing this but make it work!

◆ handshakeSerialEvent()

void handshakeSerialEvent ( )

Receive serial message during handshake.


◆ initTestGPIO()

uint8_t initTestGPIO ( )

Inititialize the GPIOs.


◆ InitXMODEM()

void InitXMODEM ( )

Initiate XMODEM protocol by sending a NAK command every 4 seconds until the transmitter returns an ACK signal.

XMODEM serial function definition


Parameters
none

◆ kalmanFilterTask()

void kalmanFilterTask ( void * pvParameters)

Filter data using the Kalman Filter.


◆ listDir()

void listDir ( fs::FS & fs,
const char * dirname,
uint8_t levels )

XMODEM serial function prototypes

◆ logToMemory()

void logToMemory ( void * pvParameter)

log the data to the external flash memory


Parameters
pvParameter- A value that is passed as the paramater to the created task. If pvParameter is set to the address of a variable then the variable must still exist when the created task executes - so it is not valid to pass the address of a stack variable.

◆ loop()

void loop ( )

Main loop.


Here is where we consume the test data stored in the data.txt file

◆ mainChuteDeploy()

void mainChuteDeploy ( )

fires the pyro-charge to deploy the main chute Turn on the main chute ejection circuit by running the GPIO HIGH for a preset No. of seconds Default no. of seconds to remain HIGH is 5


◆ MQTT_TransmitTelemetry()

void MQTT_TransmitTelemetry ( void * pvParameters)

send flight data to ground


Parameters
pvParameter- A value that is passed as the paramater to the created task. If pvParameter is set to the address of a variable then the variable must still exist when the created task executes - so it is not valid to pass the address of a stack variable.

PACKAGE TELEMETRY PACKET

record number operation_mode state ax ay az pitch roll gx gy gz latitude longitude gps_altitude gps_time pressure temperature altitude_agl velocity pyro1_state // not used pyro2_state // not used battery_voltage // not used

◆ MQTTInit()

void MQTTInit ( const char * broker_IP,
int broker_port )

Initialize MQTT.


◆ ParseSerialNumeric()

void ParseSerialNumeric ( int value)

Parse the received serial command if it is a digit We are only interested in numeric values being sent by the transmitter to us, the receiver.


◆ readAccelerationTask()

void readAccelerationTask ( void * pvParameter)

Read acceleration data from the accelerometer.


Parameters
pvParameters- A value that is passed as the paramater to the created task. If pvParameters is set to the address of a variable then the variable must still exist when the created task executes - so it is not valid to pass the address of a stack variable.
Returns
Updates accelerometer data struct on the telemetry queue

◆ readAltimeterTask()

void readAltimeterTask ( void * pvParameters)

Read atm pressure data from the barometric sensor onboard.


◆ readGPSTask()

void readGPSTask ( void * pvParameters)

Read the GPS location data and altitude and append to telemetry packet for transmission.


Parameters
pvParameters- A value that is passed as the paramater to the created task. If pvParameters is set to the address of a variable then the variable must still exist when the created task executes - so it is not valid to pass the address of a stack variable.

◆ receiveTestDataSerialEvent()

void receiveTestDataSerialEvent ( )

Receive serial message during RECEIVE_TEST_DATA state Data received in this state is the actual test data. It is saved into the test flash memory.


◆ rowParserFinished()

bool rowParserFinished ( )
Returns

◆ setup()

void setup ( )

Setup - perform initialization of all hardware subsystems, create queues, create queue handles initialize system check table.


We need to read the TEST state from a file in the SD card This file stores the state we are in permanently, so that next time we reset while in run mode, we have a reference state to use

This file will be updated in the loop once we are done consuming the test data

check what state we are in while in the test state. If we are in the data consume state, set the current state to DATA_CONSUME The state is got from the SD card state.txt file

◆ SwitchLEDs()

void SwitchLEDs ( uint8_t red_state,
uint8_t green_state )

Switch the LEDS states.


Variable Documentation

◆ acc_data

accel_type_t acc_data

///////////////////////// DATA TYPES /////////////////////////

◆ current_DAQ_state

uint8_t current_DAQ_state = DAQ_STATES::HANDSHAKE

Define current data consume state the flight computer is in

◆ current_log_time

unsigned long long current_log_time = 0

What is the processor time right now?

◆ current_state

uint8_t current_state = ARMED_FLIGHT_STATE::PRE_FLIGHT_GROUND

The starting state - we start at PRE_FLIGHT_GROUND state

◆ file

SerialFlashFile file

object representing file object for flash memory

◆ FILE_SIZE_1M

uint32_t FILE_SIZE_1M = 1048576L

1MB

◆ FILE_SIZE_4M

uint32_t FILE_SIZE_4M = 4194304L

4MB

◆ FILE_SIZE_512K

uint32_t FILE_SIZE_512K = 524288L

512KB

◆ filename

char filename[] = "flight.txt"

data log filename - Filename must be less than 20 chars, including the file extension

◆ flash_cs_pin

uint8_t flash_cs_pin = 5

External flash memory chip select pin

◆ flash_led_pin

uint8_t flash_led_pin = 32

LED pin connected to indicate flash memory formatting

◆ green_led

uint8_t green_led = 4

Green LED pin

◆ imu

MPU6050 imu(0x68, 16, 1000) ( 0x68 ,
16 ,
1000  )

///////////////////////// END OF DATA VARIABLES ///////////////////////// create an MPU6050 object 0x68 is the address of the MPU set gyro to max deg to 1000 deg/sec set accel fs reading to 16g

◆ log_sample_interval

uint16_t log_sample_interval = 10

After how long should we sample and log data to flash memory?

◆ operation_mode

uint8_t operation_mode = 0

Tells whether software is in safe or flight mode - FLIGHT_MODE=1, SAFE_MODE=0

◆ previous_log_time

unsigned long long previous_log_time = 0

The last time we logged data to memory

◆ readAccelerationTaskHandle

TaskHandle_t readAccelerationTaskHandle

Task creation handles

◆ recv_data_led

uint8_t recv_data_led = 2

External flash memory chip select pin

◆ red_led

uint8_t red_led = 15

Red LED pin

◆ rocket_ID

const char* rocket_ID = "FC1"

Unique ID of the rocket. Change to the needed rocket name before uploading

◆ SD_CS_PIN

uint8_t SD_CS_PIN = 26

Chip select pin for SD card

◆ SET_DAQ_MODE_PIN

uint8_t SET_DAQ_MODE_PIN = 14

Pin to set the flight computer to DAQ mode

◆ SET_TEST_MODE_PIN

uint8_t SET_TEST_MODE_PIN = 13

Pin to set the flight computer to TEST mode

◆ SOH_recvd_flag

uint8_t SOH_recvd_flag = 0

Transmitter acknowledged?

◆ SUBSYSTEM_INIT_MASK

uint8_t SUBSYSTEM_INIT_MASK = 0b00000000

Holds the status of the subsystems. 1 if Init OK, 0 if init failed

◆ subsystems_state_buffer

char subsystems_state_buffer[10]

Holds the status of the subsystems. 1 if Init OK, 0 if init failed

◆ telemetry_data_queue_handle

QueueHandle_t telemetry_data_queue_handle

///////////////////////// END OF PERIPHERALS INIT /////////////////////////

◆ value

int value = 0

Parse the received serial command if it is a string.


◆ wifi_client

WiFiClient wifi_client

MQTT helper instances, if using MQTT to transmit telemetry