From c8e8827584fa5fc0481c57ea730b10b8e588beb3 Mon Sep 17 00:00:00 2001 From: tmf97 Date: Thu, 8 Apr 2021 11:31:35 -0400 Subject: [PATCH 01/10] Add ignore low batter command, prep for FnF Signed-off-by: tmf97 --- communications/command_definitions.py | 6 ++++ flight_modes/flight_mode.py | 52 +++++++++++++-------------- utils/constants.py | 4 +++ 3 files changed, 36 insertions(+), 26 deletions(-) diff --git a/communications/command_definitions.py b/communications/command_definitions.py index 864d8068..62b9c0d6 100644 --- a/communications/command_definitions.py +++ b/communications/command_definitions.py @@ -338,8 +338,14 @@ def electrolysis(self, **kwargs): state = kwargs[STATE] delay = kwargs.get(DELAY, 0) assert type(state) is bool + params.WANT_TO_ELECTROLYZE = state self.parent.gom.set_electrolysis(state, delay=delay) + def ignore_low_battery(self, **kwargs): + """This is obviously a very dangerous command. It's mainly meant for testing on the ground""" + ignore = kwargs[IGNORE] + params.IGNORE_LOW_BATTERY = ignore + # def burn(self, **kwargs): # time_burn = kwargs['time'] # absolute = kwargs['absolute'] diff --git a/flight_modes/flight_mode.py b/flight_modes/flight_mode.py index 2d9330a2..f744b145 100644 --- a/flight_modes/flight_mode.py +++ b/flight_modes/flight_mode.py @@ -224,12 +224,12 @@ def run_mode(self): TestCommandEnum.CommsDriver.value: ([], 0), TestCommandEnum.PiShutdown.value: ([], 0), TestCommandEnum.RTCTest.value: ([], 0), - TestCommandEnum.LongString.value: (['some_number', 'long_string'],180) + TestCommandEnum.LongString.value: (['some_number', 'long_string'], 180) } command_arg_types = { 'some_number': 'float', - 'long_string':'string' + 'long_string': 'string' } downlink_codecs = {TestCommandEnum.CommsDriver.value: (['gyro1', 'gyro2', 'gyro3'], 12)} @@ -429,24 +429,24 @@ def register_commands(cls): NormalCommandEnum.NemoWriteRegister.value: ([REG_ADDRESS, REG_VALUE], 2), NormalCommandEnum.NemoReadRegister.value: ([REG_ADDRESS, REG_SIZE], 2), NormalCommandEnum.NemoSetConfig.value: ([ - DET_ENABLE_UINT8, - DET0_BIAS_UINT8, - DET1_BIAS_UINT8, - DET0_THRESHOLD_UINT8, - DET1_THRESHOLD_UINT8, - RATE_WIDTH_MIN, - RATE_WIDTH_MAX, - BIN_WIDTH, - BIN_0_MIN_WIDTH, - RATE_INTERVAL, - VETO_THRESHOLD_MIN, - VETO_THRESHOLD_MAX, - CONFIG_WRITE_PERIOD, - CONFIG_ROTATE_PERIOD, - DATE_WRITE_PERIOD, - RATE_DATA_ROTATE_PERIOD, - HISTOGRAM_ROTATE_PERIOD, - ], 32), + DET_ENABLE_UINT8, + DET0_BIAS_UINT8, + DET1_BIAS_UINT8, + DET0_THRESHOLD_UINT8, + DET1_THRESHOLD_UINT8, + RATE_WIDTH_MIN, + RATE_WIDTH_MAX, + BIN_WIDTH, + BIN_0_MIN_WIDTH, + RATE_INTERVAL, + VETO_THRESHOLD_MIN, + VETO_THRESHOLD_MAX, + CONFIG_WRITE_PERIOD, + CONFIG_ROTATE_PERIOD, + DATE_WRITE_PERIOD, + RATE_DATA_ROTATE_PERIOD, + HISTOGRAM_ROTATE_PERIOD, + ], 32), NormalCommandEnum.NemoPowerOff.value: ([], 0), NormalCommandEnum.NemoPowerOn.value: ([], 0), NormalCommandEnum.NemoReboot.value: ([], 0), @@ -463,6 +463,7 @@ def register_commands(cls): NormalCommandEnum.ShellCommand.value: ([CMD], 24), NormalCommandEnum.SudoCommand.value: ([CMD], 24), NormalCommandEnum.Picberry.value: ([CMD], 24), + NormalCommandEnum.IgnoreLowBatt.value: ([IGNORE], 1) } command_arg_types = { @@ -526,7 +527,7 @@ def register_commands(cls): OUTPUT_SAFE8: "bool", OUTPUT_ON_DELAY: "short", OUTPUT_OFF_DELAY: "short", VBOOST1: "short", VBOOST2: "short", VBOOST3: "short", - CMD: 'string' + CMD: 'string', IGNORE: 'bool', } downlink_codecs = { @@ -641,12 +642,11 @@ class CommandMode(PauseBackgroundMode): flight_mode_id = FMEnum.Command.value - command_codecs = { - CommandCommandEnum.AddFileBlock.value:([FILE_PATH,BLOCK_NUMBER,BLOCK_TEXT],195 - MIN_COMMAND_SIZE), + CommandCommandEnum.AddFileBlock.value: ([FILE_PATH, BLOCK_NUMBER, BLOCK_TEXT], 195 - MIN_COMMAND_SIZE), CommandCommandEnum.GetFileBlocksInfo.value: ([FILE_PATH, TOTAL_BLOCKS], 52), - CommandCommandEnum.ActivateFile.value:([FILE_PATH,TOTAL_BLOCKS],52) - } + CommandCommandEnum.ActivateFile.value: ([FILE_PATH, TOTAL_BLOCKS], 52) + } command_arg_types = { FILE_PATH: 'string', @@ -656,7 +656,7 @@ class CommandMode(PauseBackgroundMode): } downlink_codecs = { - CommandCommandEnum.AddFileBlock.value: ([SUCCESSFUL,BLOCK_NUMBER],3), + CommandCommandEnum.AddFileBlock.value: ([SUCCESSFUL, BLOCK_NUMBER], 3), CommandCommandEnum.GetFileBlocksInfo.value: ([CHECKSUM, MISSING_BLOCKS], 80 - MIN_COMMAND_SIZE) } diff --git a/utils/constants.py b/utils/constants.py index c970a22b..86ab3b43 100644 --- a/utils/constants.py +++ b/utils/constants.py @@ -189,6 +189,8 @@ CMD = 'cmd' RETURN_CODE = 'return_code' +IGNORE = 'ignore' + # GOMspace Channel designations: # TODO: re-evaluate and double check before flight for each satellite half @@ -267,6 +269,8 @@ class NormalCommandEnum(IntEnum): SudoCommand = 51 Picberry = 52 + IgnoreLowBatt = 60 + CommandStatus = 99 From 76290ffe5ea9acf0de63237df720ea3eda1a9d5d Mon Sep 17 00:00:00 2001 From: tmf97 Date: Sat, 17 Apr 2021 10:01:13 -0400 Subject: [PATCH 02/10] Log relevant fill and fire data into csv in normal mode Signed-off-by: tmf97 --- flight_modes/flight_mode.py | 19 ++++++++++++++++++- utils/parameters.py | 5 ++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/flight_modes/flight_mode.py b/flight_modes/flight_mode.py index f744b145..6ce7a6b8 100644 --- a/flight_modes/flight_mode.py +++ b/flight_modes/flight_mode.py @@ -156,7 +156,6 @@ def execute_commands(self): self.parent.commands_to_execute.remove(finished_command) def poll_inputs(self): - if self.parent.gom is not None: self.parent.gom.tick_wdt() self.parent.telemetry.poll() @@ -595,6 +594,9 @@ def register_commands(cls): def __init__(self, parent): super().__init__(parent) + def poll_inputs(self): + super().poll_inputs() + def update_state(self): super_fm = super().update_state() @@ -608,6 +610,9 @@ def update_state(self): # if we don't want to electrolyze (per GS command), set need_to_electrolyze to false need_to_electrolyze = need_to_electrolyze and params.WANT_TO_ELECTROLYZE + # if we don't want to run opnav (per GS command), set time_for_opnav to false + time_for_opnav = time_for_opnav and params.WANT_TO_OPNAV + # if currently electrolyzing and over pressure, stop electrolyzing if currently_electrolyzing and not need_to_electrolyze: self.parent.gom.set_electrolysis(False) @@ -634,6 +639,18 @@ def update_state(self): def run_mode(self): logger.info(f"In NORMAL flight mode") + if not params.FOR_FLIGHT: + # log relevant data + gom_voltage = self.parent.tlm.gom.hk.vbatt + current_in = self.parent.tlm.gom.hk.cursun + current_out = self.parent.tlm.gom.hk.cursys + pressure = self.parent.tlm.prs.pressure + poll_time = self.parent.tlm.poll_time + data = [poll_time, gom_voltage, current_in, current_out, pressure] + data_str = ','.join([str(elem) for elem in data]) + with open("fill_and_fire.csv", 'a') as ff: + ff.write(data_str) + self.completed_task() diff --git a/utils/parameters.py b/utils/parameters.py index fd83dd85..ba508a68 100644 --- a/utils/parameters.py +++ b/utils/parameters.py @@ -1,7 +1,9 @@ +FOR_FLIGHT = False + DOWNLINK_BUFFER_TIME = 3 TELEM_DOWNLINK_TIME = 60 - + BOOTUP_SEPARATION_DELAY = 30.0 # seconds ENTER_LOW_BATTERY_MODE_THRESHOLD = 0.3 @@ -30,5 +32,6 @@ ACS_SPIKE_DURATION = 15 # milliseconds WANT_TO_ELECTROLYZE = False +WANT_TO_OPNAV = False DEFAULT_ELECTROLYSIS_DELAY = 1 From c8c7ed336233d91d772053829a23c08e2538f2a7 Mon Sep 17 00:00:00 2001 From: tmf97 Date: Sat, 24 Apr 2021 18:13:31 -0400 Subject: [PATCH 03/10] Add mission mode id Signed-off-by: tmf97 --- flight_modes/flight_mode.py | 20 +++++++++++++++++++- utils/constants.py | 6 ++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/flight_modes/flight_mode.py b/flight_modes/flight_mode.py index 50bf552d..99e14432 100644 --- a/flight_modes/flight_mode.py +++ b/flight_modes/flight_mode.py @@ -13,6 +13,7 @@ from multiprocessing import Process import subprocess from queue import Empty +from traceback import format_tb from utils.constants import * @@ -169,6 +170,23 @@ def automatic_actions(self): def write_telemetry(self): pass + @staticmethod + def update_mission_mode(cls, mission_mode_id): + """Sets the behavior of flight modes. Acts like a meta-flight mode.""" + if mission_mode_id == MissionModeEnum.Boot.value: + # set parameters for boot + params.CURRENT_MISSION_MODE = 0 + params.WANT_TO_ELECTROLYZE = False + params.WANT_TO_OPNAV = False + params.TELEM_DOWNLINK_TIME = 10 + + if mission_mode_id == MissionModeEnum.Normal.value: + # set parameters for normal mission mode + params.CURRENT_MISSION_MODE = 1 + params.WANT_TO_ELECTROLYZE = True + params.WANT_TO_OPNAV = True + params.TELEM_DOWNLINK_TIME = 60 + def __enter__(self): logger.debug(f"Starting flight mode {self.flight_mode_id}") return self @@ -177,7 +195,7 @@ def __exit__(self, exc_type, exc_value, tb): logger.debug(f"Finishing flight mode {self.flight_mode_id}") if exc_type is not None: logger.error(f"Flight Mode failed with error type {exc_type} and value {exc_value}") - logger.error(f"Failed with traceback:\n {tb}") + logger.error(f"Failed with traceback:\n {format_tb(tb)}") # Model for FlightModes that require precise timing diff --git a/utils/constants.py b/utils/constants.py index b468c329..e76cebc1 100644 --- a/utils/constants.py +++ b/utils/constants.py @@ -362,3 +362,9 @@ class CommandCommandEnum(IntEnum): ActivateFile = 11 ShellCommand = 50 CeaseComms = 170 + + +@unique +class MissionModeEnum(IntEnum): + Boot = 0 + Normal = 1 From a95fc6b902699cd88968cb86371d11fbc427c3fd Mon Sep 17 00:00:00 2001 From: tmf97 Date: Sat, 24 Apr 2021 18:35:03 -0400 Subject: [PATCH 04/10] Added relevant parameters where needed Signed-off-by: tmf97 --- communications/command_definitions.py | 1 + flight_modes/flight_mode.py | 2 +- tests/commands_flight_mode_test.py | 2 +- tests/parameters_test.py | 5 ++++- utils/parameters.json | 4 +++- 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/communications/command_definitions.py b/communications/command_definitions.py index 57590a51..831274f6 100644 --- a/communications/command_definitions.py +++ b/communications/command_definitions.py @@ -106,6 +106,7 @@ def __init__(self, parent: MainSatelliteThread): NormalCommandEnum.SudoCommand.value: self.sudo_command, NormalCommandEnum.Picberry.value: self.picberry, NormalCommandEnum.ExecPyFile.value: self.exec_py_file, + NormalCommandEnum.IgnoreLowBatt.value: self.ignore_low_battery, } self.low_battery_commands = { diff --git a/flight_modes/flight_mode.py b/flight_modes/flight_mode.py index acf37614..f95b005b 100644 --- a/flight_modes/flight_mode.py +++ b/flight_modes/flight_mode.py @@ -482,7 +482,7 @@ def register_commands(cls): NormalCommandEnum.GomConf1Get.value: ([], 0), NormalCommandEnum.GomConf2Set.value: ([MAX_VOLTAGE, NORM_VOLTAGE, SAFE_VOLTAGE, CRIT_VOLTAGE], 8), NormalCommandEnum.GomConf2Get.value: ([], 0), - NormalCommandEnum.ExecPyFile.value: ([FNAME], 36) + NormalCommandEnum.ExecPyFile.value: ([FNAME], 36), NormalCommandEnum.IgnoreLowBatt.value: ([IGNORE], 1) } diff --git a/tests/commands_flight_mode_test.py b/tests/commands_flight_mode_test.py index 0a5084ff..e311cba7 100644 --- a/tests/commands_flight_mode_test.py +++ b/tests/commands_flight_mode_test.py @@ -27,7 +27,7 @@ def testFlightCommands(): assert all_enum_commands == all_command_ids except AssertionError: commands_not_in_both = set(all_enum_commands).symmetric_difference(all_command_ids) - error_msg += f"Commands defined in {enum} not consistent with utils.constants: {commands_not_in_both}\n" + error_msg += f"command_definition.py's {str(enum)[6:-1]} command dict not consistent with utils.constants: {commands_not_in_both}\n " if error_msg != "": raise AssertionError(error_msg) diff --git a/tests/parameters_test.py b/tests/parameters_test.py index fee5b9ca..98eb765d 100644 --- a/tests/parameters_test.py +++ b/tests/parameters_test.py @@ -2,11 +2,14 @@ from utils.exceptions import CislunarException from json import load import os +debug = False def test_parameters(): """Copied from main.py's init_parameters""" - print(os.getcwd()) + + if debug: + print(os.getcwd()) if 'FlightSoftware/FlightSoftware/' not in os.getcwd(): # checks if running pytest filepath = 'utils/parameters.json' else: diff --git a/utils/parameters.json b/utils/parameters.json index c0ca5d9d..080e517f 100644 --- a/utils/parameters.json +++ b/utils/parameters.json @@ -27,5 +27,7 @@ "GYRO_BIAS_TEMPERATURE": 0, "GYRO_BIAS_DXDT": 0, "GYRO_BIAS_DYDT": 0, - "GYRO_BIAS_DZDT": 0 + "GYRO_BIAS_DZDT": 0, + "FOR_FLIGHT": false, + "WANT_TO_OPNAV": false } \ No newline at end of file From 902ef022d4b6e41ab5f025e6e50f97c26d838d8c Mon Sep 17 00:00:00 2001 From: tmf97 Date: Sat, 24 Apr 2021 20:31:34 -0400 Subject: [PATCH 05/10] Add 'unit' test for FM command codecs and arg types, fixed up all issues Signed-off-by: tmf97 --- communications/command_definitions.py | 28 +++++---- flight_modes/attitude_adjustment.py | 2 +- flight_modes/flight_mode.py | 81 +++++++++++++++++++++------ flight_modes/restart_reboot.py | 11 +++- tests/commands_flight_mode_test.py | 37 +++++++++++- utils/constants.py | 17 ++++-- 6 files changed, 137 insertions(+), 39 deletions(-) diff --git a/communications/command_definitions.py b/communications/command_definitions.py index 831274f6..26648af2 100644 --- a/communications/command_definitions.py +++ b/communications/command_definitions.py @@ -132,11 +132,8 @@ def __init__(self, parent: MainSatelliteThread): self.sensor_commands = {} self.test_commands = { - 2: self.split, - 3: self.run_opnav, TestCommandEnum.ADCTest.value: self.adc_test, TestCommandEnum.SeparationTest.value: self.separation_test, - 6: self.gom_outputs, 7: self.comms_driver_test, TestCommandEnum.LongString.value: self.print_long_string, TestCommandEnum.PiShutdown.value: self.pi_shutdown, @@ -161,6 +158,8 @@ def __init__(self, parent: MainSatelliteThread): CommandCommandEnum.ShellCommand.value: self.shell_command } + self.attitude_commands = {} + self.COMMAND_DICT = { FMEnum.Boot.value: self.bootup_commands, FMEnum.Restart.value: self.restart_commands, @@ -172,7 +171,8 @@ def __init__(self, parent: MainSatelliteThread): FMEnum.SensorMode.value: self.sensor_commands, FMEnum.TestMode.value: self.test_commands, FMEnum.CommsMode: self.comms_commands, - FMEnum.Command.value: self.command_commands + FMEnum.Command.value: self.command_commands, + FMEnum.AttitudeAdjustment.value: self.attitude_commands } for value in self.COMMAND_DICT.values(): @@ -278,13 +278,9 @@ def set_parameter(self, **kwargs): def set_exit_lowbatt_threshold(self, **kwargs): """Does the same thing as set_parameter, but only for the EXIT_LOW_BATTERY_MODE_THRESHOLD parameter. Only requires one kwarg and does some basic sanity checks on the passed value""" - value = kwargs['value'] + value = kwargs['vbatt'] try: - assert 0 < value < 1.0 and float(value) is float - if value >= params.ENTER_LOW_BATTERY_MODE_THRESHOLD: - self.parent.logger.error( - f"New value for Exit LB thresh must be less than current Enter LB thresh value") - assert False + assert 4 < value < 8.5 and float(value) is float self.set_parameter(name="EXIT_LOW_BATTERY_MODE_THRESHOLD", value=value) except AssertionError: self.parent.logger.error(f"Incompatible value {value} for EXIT_LOW_BATTERY_MODE_THRESHOLD") @@ -377,11 +373,13 @@ def reboot_pi(): os.system("reboot") # add something here that adds to the restarts db that this restart was commanded - def cease_comms(self): - # I'm actually unsure of how to do this. Maybe do something with the GPIO pins so that the pi can't transmit - self.parent.logger.critical("Ceasing all communications") - # definitely should implement some sort of password and double verification to prevent accidental triggering - raise NotImplementedError + def cease_comms(self, **kwargs): + pword = kwargs[PASSWORD] + if pword == 123: # TODO, change + # I'm actually unsure of how to do this. Maybe do something with the GPIO pins so that the pi can't transmit + self.parent.logger.critical("Ceasing all communications") + # definitely should implement some sort of password and double verification to prevent accidental triggering + raise NotImplementedError def set_system_clock(self, **kwargs): # Needs validation (talk to Viraj) # need to validate this works, and need to integrate updating RTC diff --git a/flight_modes/attitude_adjustment.py b/flight_modes/attitude_adjustment.py index d66b8c4a..9d188a9d 100644 --- a/flight_modes/attitude_adjustment.py +++ b/flight_modes/attitude_adjustment.py @@ -38,7 +38,7 @@ def C3(theta): """ class AAMode(PauseBackgroundMode): - """Attitude adjustment flight mode""" + """FMID 11: Attitude adjustment flight mode""" flight_mode_id = FMEnum.AttitudeAdjustment.value command_codecs = {} diff --git a/flight_modes/flight_mode.py b/flight_modes/flight_mode.py index f95b005b..ccbe96db 100644 --- a/flight_modes/flight_mode.py +++ b/flight_modes/flight_mode.py @@ -32,6 +32,8 @@ logger = get_log() +NONE = ([], 0) + class FlightMode: # Override in Subclasses to tell CommandHandler the functions and arguments this flight mode takes @@ -224,6 +226,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): class TestMode(PauseBackgroundMode): + """FMID 8""" flight_mode_id = FMEnum.TestMode.value def __init__(self, parent): @@ -235,11 +238,12 @@ def update_state(self): def run_mode(self): pass - command_codecs = {TestCommandEnum.SeparationTest.value: ([], 0), - TestCommandEnum.ADCTest.value: ([], 0), - TestCommandEnum.CommsDriver.value: ([], 0), - TestCommandEnum.PiShutdown.value: ([], 0), - TestCommandEnum.RTCTest.value: ([], 0), + command_codecs = {TestCommandEnum.Switch.value: NONE, + TestCommandEnum.SeparationTest.value: NONE, + TestCommandEnum.ADCTest.value: NONE, + TestCommandEnum.CommsDriver.value: NONE, + TestCommandEnum.PiShutdown.value: NONE, + TestCommandEnum.RTCTest.value: NONE, TestCommandEnum.LongString.value: (['some_number', 'long_string'], 180) } @@ -258,7 +262,9 @@ def run_mode(self): class CommsMode(FlightMode): + """FMID 9""" flight_mode_id = FMEnum.CommsMode.value + command_codecs = {CommsCommandEnum.Switch.value: NONE} def __init__(self, parent): super().__init__(parent) @@ -322,7 +328,9 @@ def run_mode(self): class OpNavMode(FlightMode): + """FMID 5""" flight_mode_id = FMEnum.OpNav.value + command_codecs = {OpNavCommandEnum.Switch.value: NONE} def __init__(self, parent): super().__init__(parent) @@ -355,7 +363,9 @@ def opnav_subprocess(self, q): class SensorMode(FlightMode): + """FMID 7""" flight_mode_id = FMEnum.SensorMode.value + command_codecs = {SensorsCommandEnum.Switch.value: NONE} def __init__(self, parent): super().__init__(parent) @@ -366,7 +376,18 @@ def update_state(self): class LowBatterySafetyMode(FlightMode): + """FMID 3""" flight_mode_id = FMEnum.LowBatterySafety.value + command_codecs = {LowBatterySafetyCommandEnum.Switch.value: NONE, + LowBatterySafetyCommandEnum.BasicTelem.value: NONE, + LowBatterySafetyCommandEnum.CritTelem.value: NONE, + LowBatterySafetyCommandEnum.DetailedTelem.value: NONE, + LowBatterySafetyCommandEnum.ExitLBSafetyMode: NONE, + LowBatterySafetyCommandEnum.SetExitLBSafetyMode: ([VBATT], 2), + LowBatterySafetyCommandEnum.SetParam: ([NAME, VALUE, HARD_SET], 33) + } + + command_arg_types = {VBATT: 'short'} def __init__(self, parent): super().__init__(parent) @@ -388,8 +409,9 @@ def __enter__(self): class ManeuverMode(PauseBackgroundMode): + """FMID 6""" flight_mode_id = FMEnum.Maneuver.value - command_codecs = {} + command_codecs = {ManeuverCommandEnum.Switch.value: NONE} command_arg_unpackers = {} def __init__(self, parent): @@ -414,8 +436,16 @@ def run_mode(self): # TODO class SafeMode(FlightMode): + """FMID 4""" flight_mode_id = FMEnum.Safety.value + command_codecs = {SafetyCommandEnum.Switch.value: NONE, + SafetyCommandEnum.DetailedTelem.value: NONE, + SafetyCommandEnum.CritTelem.value: NONE, + SafetyCommandEnum.BasicTelem.value: NONE, + SafetyCommandEnum.ExitSafetyMode.value: NONE, + SafetyCommandEnum.SetParameter.value: ([NAME, VALUE, HARD_SET], 33), } + def __init__(self, parent): super().__init__(parent) @@ -431,15 +461,19 @@ def register_commands(cls): flight_mode_id = FMEnum.Normal.value command_codecs = { - NormalCommandEnum.Switch.value: ([], 0), - NormalCommandEnum.RunOpNav.value: ([], 0), + NormalCommandEnum.Switch.value: NONE, + NormalCommandEnum.RunOpNav.value: NONE, # NormalCommandEnum.SetDesiredAttitude.value: ([AZIMUTH, ELEVATION], 8), # NormalCommandEnum.SetAccelerate.value: ([ACCELERATE], 1), - # NormalCommandEnum.SetBreakpoint.value: ([], 0), # TODO define exact parameters + # NormalCommandEnum.SetBreakpoint.value: NONE, # TODO define exact parameters NormalCommandEnum.SetParam.value: ([NAME, VALUE, HARD_SET], 33), + NormalCommandEnum.CritTelem.value: NONE, + NormalCommandEnum.BasicTelem.value: NONE, + NormalCommandEnum.DetailedTelem.value: NONE, NormalCommandEnum.SetElectrolysis.value: ([STATE, DELAY], 5), NormalCommandEnum.SetOpnavInterval.value: ([INTERVAL], 4), NormalCommandEnum.Verification.value: ([NUM_BLOCKS], 2), + NormalCommandEnum.GetParam.value: ([INDEX], 2), NormalCommandEnum.ScheduleManeuver.value: ([TIME], 4), NormalCommandEnum.ACSPulsing.value: ([START, PULSE_DURATION, PULSE_NUM, PULSE_DT], 14), NormalCommandEnum.NemoWriteRegister.value: ([REG_ADDRESS, REG_VALUE], 2), @@ -463,9 +497,9 @@ def register_commands(cls): RATE_DATA_ROTATE_PERIOD, HISTOGRAM_ROTATE_PERIOD, ], 32), - NormalCommandEnum.NemoPowerOff.value: ([], 0), - NormalCommandEnum.NemoPowerOn.value: ([], 0), - NormalCommandEnum.NemoReboot.value: ([], 0), + NormalCommandEnum.NemoPowerOff.value: NONE, + NormalCommandEnum.NemoPowerOn.value: NONE, + NormalCommandEnum.NemoReboot.value: NONE, NormalCommandEnum.NemoProcessRateData.value: ([T_START, T_STOP, DECIMATION_FACTOR], 9), NormalCommandEnum.NemoProcessHistograms.value: ([T_START, T_STOP, DECIMATION_FACTOR], 9), NormalCommandEnum.GomConf1Set.value: ([PPT_MODE, BATTHEATERMODE, BATTHEATERLOW, BATTHEATERHIGH, OUTPUT_NORMAL1, @@ -479,9 +513,9 @@ def register_commands(cls): NormalCommandEnum.ShellCommand.value: ([CMD], 24), NormalCommandEnum.SudoCommand.value: ([CMD], 24), NormalCommandEnum.Picberry.value: ([CMD], 24), - NormalCommandEnum.GomConf1Get.value: ([], 0), + NormalCommandEnum.GomConf1Get.value: NONE, NormalCommandEnum.GomConf2Set.value: ([MAX_VOLTAGE, NORM_VOLTAGE, SAFE_VOLTAGE, CRIT_VOLTAGE], 8), - NormalCommandEnum.GomConf2Get.value: ([], 0), + NormalCommandEnum.GomConf2Get.value: NONE, NormalCommandEnum.ExecPyFile.value: ([FNAME], 36), NormalCommandEnum.IgnoreLowBatt.value: ([IGNORE], 1) } @@ -690,17 +724,32 @@ class CommandMode(PauseBackgroundMode): flight_mode_id = FMEnum.Command.value command_codecs = { + CommandCommandEnum.Switch.value: NONE, + CommandCommandEnum.SetParam.value: ([NAME, VALUE, HARD_SET], 33), + CommandCommandEnum.SetSystemTime: ([TIME], 8), + CommandCommandEnum.RebootPi: NONE, + CommandCommandEnum.RebootGom: NONE, + CommandCommandEnum.PowerCycle: NONE, + CommandCommandEnum.GomPin: ([OUTPUT_CHANNEL, STATE, DELAY], 4), CommandCommandEnum.AddFileBlock.value: ([FILE_PATH, BLOCK_NUMBER, BLOCK_TEXT], 195 - MIN_COMMAND_SIZE), CommandCommandEnum.GetFileBlocksInfo.value: ([FILE_PATH, TOTAL_BLOCKS], 52), CommandCommandEnum.ActivateFile.value: ([FILE_PATH, TOTAL_BLOCKS], 52), - CommandCommandEnum.ShellCommand.value: ([CMD], 24) + CommandCommandEnum.ShellCommand.value: ([CMD], 24), + CommandCommandEnum.GeneralCmd.value: ([CMD], 24), # TODO + CommandCommandEnum.GomGeneralCmd.value: ([CMD], 24), # TODO + CommandCommandEnum.CeaseComms.value: ([PASSWORD], 8) } command_arg_types = { FILE_PATH: 'string', BLOCK_NUMBER: 'short', BLOCK_TEXT: 'string', - TOTAL_BLOCKS: 'short' + TOTAL_BLOCKS: 'short', + SYS_TIME: 'double', + GOM_PIN_STATE: 'bool', + GOM_PIN_DELAY: 'short', + OUTPUT_CHANNEL: 'uint8', + PASSWORD: 'long' } downlink_codecs = { diff --git a/flight_modes/restart_reboot.py b/flight_modes/restart_reboot.py index 753fc82f..132d5a7d 100644 --- a/flight_modes/restart_reboot.py +++ b/flight_modes/restart_reboot.py @@ -10,9 +10,15 @@ logger = get_log() + class BootUpMode(FlightMode): + """FMID 0""" flight_mode_id = FMEnum.Boot.value - command_codecs = {BootCommandEnum.Split.value: ([], 0)} + command_codecs = { + BootCommandEnum.Switch.value: ([], 0), + BootCommandEnum.Split.value: ([], 0) + } + command_arg_unpackers = {} def __init__(self, parent): @@ -51,7 +57,8 @@ def update_state(self) -> int: class RestartMode(FlightMode): - command_codecs = {} + """FMID 1""" + command_codecs = {RestartCommandEnum.Switch.value: ([], 0)} command_arg_unpackers = {} flight_mode_id = FMEnum.Restart.value diff --git a/tests/commands_flight_mode_test.py b/tests/commands_flight_mode_test.py index e311cba7..66f15ccf 100644 --- a/tests/commands_flight_mode_test.py +++ b/tests/commands_flight_mode_test.py @@ -3,9 +3,11 @@ SafetyCommandEnum, OpNavCommandEnum, ManeuverCommandEnum, SensorsCommandEnum, CommsCommandEnum, TestCommandEnum, \ CommandCommandEnum +from flight_modes.flight_mode_factory import FLIGHT_MODE_DICT + command_enums = [BootCommandEnum, RestartCommandEnum, NormalCommandEnum, LowBatterySafetyCommandEnum, SafetyCommandEnum, OpNavCommandEnum, ManeuverCommandEnum, SensorsCommandEnum, TestCommandEnum, - CommsCommandEnum, CommandCommandEnum, TestCommandEnum, CommandCommandEnum] + CommsCommandEnum, CommandCommandEnum] def testFlightCommands(): @@ -33,5 +35,38 @@ def testFlightCommands(): raise AssertionError(error_msg) +def testFlightCodecs(): + flight_mode_objs = list(FLIGHT_MODE_DICT.values()) + fm_enums_zipped = list(zip(flight_mode_objs, command_enums)) + # print(fm_enums_zipped) + error_msg = "" + for fm_obj, command_enum in fm_enums_zipped: + command_enum_list = list(map(int, command_enum)) + command_codecs_list = list(fm_obj.command_codecs.keys()) + + command_enum_list = sorted(command_enum_list) + command_codecs_list = sorted(command_codecs_list) + try: + commands_not_in_both = set(command_enum_list).symmetric_difference(command_codecs_list) + assert len(commands_not_in_both) == 0 + except AssertionError: + error_msg += f"Command codec definition inconsistency. Check FM and constants: FMID: {fm_obj.flight_mode_id}, CID: {commands_not_in_both}\n" + + if error_msg != '': + raise AssertionError(error_msg) + + +def testFlightArgTypes(): + flight_mode_objs = list(FLIGHT_MODE_DICT.values()) + all_command_arg_types = [] + for fm_obj in flight_mode_objs: + all_command_arg_types.extend(list(fm_obj.command_arg_types.keys())) + all_arg_type_set = set(all_command_arg_types) + + assert len(all_command_arg_types) == len(all_arg_type_set) + + if __name__ == '__main__': testFlightCommands() + testFlightCodecs() + testFlightArgTypes() diff --git a/utils/constants.py b/utils/constants.py index 6a09070f..02153edf 100644 --- a/utils/constants.py +++ b/utils/constants.py @@ -60,9 +60,12 @@ NUM_BLOCKS = "num_blocks" TIME = "time" +SYS_TIME = 'sys_time' HARD_SET = "hard_set" +GOM_PIN_STATE = 'gom_pin_state' +GOM_PIN_DELAY = 'gom_pin_delay' FILE_PATH = "file_path" BLOCK_NUMBER = "block_number" @@ -95,6 +98,9 @@ DECIMATION_FACTOR = "decimation_factor" +INDEX = 'index' +VBATT = 'vbatt' + # Keyword argument definitions for downlink RTC_TIME = "rtc_time" @@ -190,12 +196,14 @@ NORM_VOLTAGE = 'norm_voltage' SAFE_VOLTAGE = 'safe_voltage' CRIT_VOLTAGE = 'crit_voltage' +OUTPUT_CHANNEL = 'output_channel' CMD = 'cmd' RETURN_CODE = 'return_code' FNAME = 'filename' IGNORE = 'ignore' +PASSWORD = 'password' # GOMspace Channel designations: @@ -331,18 +339,14 @@ class SensorsCommandEnum(IntEnum): class TestCommandEnum(IntEnum): Switch = 0 # command for switching flightmode without executing any other commands # SetTestMode = 1 # no args - TriggerBurnWire = 2 # no args - RunOpNav = 3 # no args ADCTest = 4 SeparationTest = 5 - GomPin = 6 CommsDriver = 7 RTCTest = 8 LongString = 9 PiShutdown = 11 - @unique class CommsCommandEnum(IntEnum): Switch = 0 # command for switching flightmode without executing any other commands @@ -368,6 +372,11 @@ class CommandCommandEnum(IntEnum): CeaseComms = 170 +@unique +class AttitudeCommandEnum(IntEnum): + Switch = 0 + + @unique class MissionModeEnum(IntEnum): Boot = 0 From f18d2f99adfc96785573c23f0a1f9a8f5e853830 Mon Sep 17 00:00:00 2001 From: tmf97 Date: Sun, 25 Apr 2021 01:04:08 -0400 Subject: [PATCH 06/10] Add spacecraft name check Signed-off-by: tmf97 --- communications/command_definitions.py | 16 ++++----- flight_modes/flight_mode.py | 47 +++++++++++++++++---------- flight_modes/restart_reboot.py | 41 ++++++++++++++++++++--- utils/constants.py | 3 +- utils/parameters.json | 4 ++- utils/parameters.py | 4 +-- 6 files changed, 81 insertions(+), 34 deletions(-) diff --git a/communications/command_definitions.py b/communications/command_definitions.py index 26648af2..8b478916 100644 --- a/communications/command_definitions.py +++ b/communications/command_definitions.py @@ -107,6 +107,7 @@ def __init__(self, parent: MainSatelliteThread): NormalCommandEnum.Picberry.value: self.picberry, NormalCommandEnum.ExecPyFile.value: self.exec_py_file, NormalCommandEnum.IgnoreLowBatt.value: self.ignore_low_battery, + NormalCommandEnum.MissionMode.value: self.set_mission_mode, } self.low_battery_commands = { @@ -666,14 +667,6 @@ def get_gom_conf2(self, **kwargs): # **current_config2_dict) # self.parent.downlink_queue.put(acknowledgement) - def get_gom_conf1(self, **kwargs): - raise NotImplementedError - - def set_gom_conf2(self, **kwargs): - raise NotImplementedError - - def get_gom_conf2(self, **kwargs): - raise NotImplementedError def shell_command(self, **kwargs): cmd: str = kwargs.get(CMD) @@ -703,6 +696,13 @@ def exec_py_file(self, **kwargs): self.parent.logger.debug(f"CWD: {os.getcwd()}") exec(open(filename).read()) + def set_mission_mode(self, **kwargs): + mission_mode = kwargs[MISSION_MODE] + self.set_parameter(name='CURRENT_MISSION_MODE', value=mission_mode, hard_set=True) + self.parent.flight_mode.update_mission_mode(mission_mode) + + return {MISSION_MODE: params.CURRENT_MISSION_MODE} + def dict_from_eps_config(config: ps.eps_config_t) -> dict: return {PPT_MODE: config.ppt_mode, diff --git a/flight_modes/flight_mode.py b/flight_modes/flight_mode.py index ccbe96db..9e57e287 100644 --- a/flight_modes/flight_mode.py +++ b/flight_modes/flight_mode.py @@ -172,22 +172,34 @@ def automatic_actions(self): def write_telemetry(self): pass - @staticmethod - def update_mission_mode(cls, mission_mode_id): + def update_mission_mode(self, mission_mode_id: int): """Sets the behavior of flight modes. Acts like a meta-flight mode.""" - if mission_mode_id == MissionModeEnum.Boot.value: - # set parameters for boot - params.CURRENT_MISSION_MODE = 0 - params.WANT_TO_ELECTROLYZE = False - params.WANT_TO_OPNAV = False - params.TELEM_DOWNLINK_TIME = 10 - - if mission_mode_id == MissionModeEnum.Normal.value: - # set parameters for normal mission mode - params.CURRENT_MISSION_MODE = 1 - params.WANT_TO_ELECTROLYZE = True - params.WANT_TO_OPNAV = True - params.TELEM_DOWNLINK_TIME = 60 + if mission_mode_id != params.CURRENT_MISSION_MODE: + self.parent.command_definitions.set_parameter(name='CURRENT_MISSION_MODE', value=mission_mode_id, + hard_set=True) + if mission_mode_id == MissionModeEnum.Boot.value: + # set parameters for boot + # TODO bulk parameters hard set? + self.parent.command_definitions.set_parameter(name='WANT_TO_ELECTROLYZE', value=False, + hard_set=True) + self.parent.command_definitions.set_parameter(name='WANT_TO_OPNAV', value=False, + hard_set=True) + self.parent.command_definitions.set_parameter(name='TELEM_DOWNLINK_TIME', value=10, + hard_set=True) + # self.parent.command_definitions.set_parameter(name='CURRENT_MISSION_MODE', value=mission_mode_id, + # hard_set=True) + + if mission_mode_id == MissionModeEnum.Normal.value: + # set parameters for normal mission mode + # TODO bulk parameters hard set? + self.parent.command_definitions.set_parameter(name='WANT_TO_ELECTROLYZE', value=True, + hard_set=True) + self.parent.command_definitions.set_parameter(name='WANT_TO_OPNAV', value=True, + hard_set=True) + self.parent.command_definitions.set_parameter(name='TELEM_DOWNLINK_TIME', value=60, + hard_set=True) + # self.parent.command_definitions.set_parameter(name='CURRENT_MISSION_MODE', value=mission_mode_id, + # hard_set=True) def __enter__(self): logger.debug(f"Starting flight mode {self.flight_mode_id}") @@ -517,7 +529,8 @@ def register_commands(cls): NormalCommandEnum.GomConf2Set.value: ([MAX_VOLTAGE, NORM_VOLTAGE, SAFE_VOLTAGE, CRIT_VOLTAGE], 8), NormalCommandEnum.GomConf2Get.value: NONE, NormalCommandEnum.ExecPyFile.value: ([FNAME], 36), - NormalCommandEnum.IgnoreLowBatt.value: ([IGNORE], 1) + NormalCommandEnum.IgnoreLowBatt.value: ([IGNORE], 1), + NormalCommandEnum.MissionMode.value: ([MISSION_MODE], 1) } command_arg_types = { @@ -586,7 +599,7 @@ def register_commands(cls): SAFE_VOLTAGE: 'short', CRIT_VOLTAGE: 'short', FNAME: 'string', - CMD: 'string', IGNORE: 'bool', + CMD: 'string', IGNORE: 'bool', MISSION_MODE: 'uint8' } downlink_codecs = { diff --git a/flight_modes/restart_reboot.py b/flight_modes/restart_reboot.py index 132d5a7d..2fcfe5d4 100644 --- a/flight_modes/restart_reboot.py +++ b/flight_modes/restart_reboot.py @@ -5,8 +5,10 @@ from flight_modes.flight_mode import FlightMode import os from utils.log import get_log -from utils.constants import FMEnum, BootCommandEnum, RestartCommandEnum +from utils.constants import FMEnum, BootCommandEnum, RestartCommandEnum, MissionModeEnum import psutil +import utils.parameters as params +import glob logger = get_log() @@ -32,11 +34,12 @@ def run_mode(self): self.session = create_session() self.log() + self.set_parameters() - # deploy antennae - # FIXME: differentiate between Hydrogen and Oxygen. Each satellite now has different required Bootup behaviors - logger.info("Antennae deploy...") - self.parent.gom.burnwire1(5) + if params.SPACECRAFT_NAME == 'HYDROGEN': + # deploy antennae + logger.info("Deploying antennae") + self.parent.gom.burnwire1(5) if self.parent.need_to_reboot: # TODO: double check the boot db history to make sure we aren't going into a boot loop @@ -55,6 +58,10 @@ def log(self): def update_state(self) -> int: return NO_FM_CHANGE + def set_parameters(self): + self.parent.command_definitions.set_parameter(name="SPACECRAFT_NAME", value=determine_name(), hard_set=True) + self.update_mission_mode(MissionModeEnum.Boot.value) + class RestartMode(FlightMode): """FMID 1""" @@ -91,3 +98,27 @@ def run_mode(self): def update_state(self) -> int: return super().update_state() + + +def get_hostname(): + # thank you https://stackoverflow.com/questions/4271740/how-can-i-use-python-to-get-the-system-hostname + # Does not work on windows + return os.uname()[1] + + +def determine_name(): + """Checks if Hydrogen or oxygen""" + filenames = glob.glob('../utils/*_parameters.py') + if 'hydrogen' in ','.join(filenames): + space_name = 'HYDROGEN' + else: + space_name = 'OXYGEN' + + # if in flight, double check the hostname + # Want to assume oxygen in worst case scenario (don't want to split prematurely!) + if params.FOR_FLIGHT: + hostname = get_hostname() + if 'oxygen' in hostname and space_name == 'HYDROGEN': + space_name = 'OXYGEN' + + return space_name diff --git a/utils/constants.py b/utils/constants.py index 02153edf..ee52d49c 100644 --- a/utils/constants.py +++ b/utils/constants.py @@ -204,7 +204,7 @@ FNAME = 'filename' IGNORE = 'ignore' PASSWORD = 'password' - +MISSION_MODE = 'mission_mode' # GOMspace Channel designations: # TODO: re-evaluate and double check before flight for each satellite half @@ -283,6 +283,7 @@ class NormalCommandEnum(IntEnum): SudoCommand = 51 Picberry = 52 ExecPyFile = 53 + MissionMode = 54 IgnoreLowBatt = 60 diff --git a/utils/parameters.json b/utils/parameters.json index 080e517f..62a73511 100644 --- a/utils/parameters.json +++ b/utils/parameters.json @@ -29,5 +29,7 @@ "GYRO_BIAS_DYDT": 0, "GYRO_BIAS_DZDT": 0, "FOR_FLIGHT": false, - "WANT_TO_OPNAV": false + "WANT_TO_OPNAV": false, + "SPACECRAFT_NAME": "", + "CURRENT_MISSION_MODE": 0 } \ No newline at end of file diff --git a/utils/parameters.py b/utils/parameters.py index b3b77e1f..56576e50 100644 --- a/utils/parameters.py +++ b/utils/parameters.py @@ -1,7 +1,7 @@ FOR_FLIGHT = False - +SPACECRAFT_NAME = '' DOWNLINK_BUFFER_TIME = 3 - +CURRENT_MISSION_MODE = 0 TELEM_DOWNLINK_TIME = 60 BOOTUP_SEPARATION_DELAY = 30.0 # seconds From a62cd0f4cf35dce1abfe85f4f97dd11af6db5592 Mon Sep 17 00:00:00 2001 From: tmf97 Date: Sun, 25 Apr 2021 01:23:09 -0400 Subject: [PATCH 07/10] Fix db Signed-off-by: tmf97 --- tests/db_test.py | 1 + utils/db.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/db_test.py b/tests/db_test.py index 3587787d..58fd298d 100644 --- a/tests/db_test.py +++ b/tests/db_test.py @@ -88,6 +88,7 @@ def test_telemetry_model(): session.add(new_measurement) session.commit() + telemetry_measurements = session.query(TelemetryModel).all() assert 1 == len(telemetry_measurements) entries = session.query(TelemetryModel).all() diff --git a/utils/db.py b/utils/db.py index abcb0961..0f53d6a5 100644 --- a/utils/db.py +++ b/utils/db.py @@ -545,7 +545,7 @@ class TelemetryModel(SQLAlchemyTableBase): __tablename__ = "Telemetry" id = Column(Integer, primary_key=True) - time_polled = Column(DateTime) # FIXME + time_polled = Column(Float) # GOM DATA GOM_vboost1 = Column(Integer) From 79a38cef1cafb14ad763e1cde14a506345c0361d Mon Sep 17 00:00:00 2001 From: tmf97 Date: Sun, 25 Apr 2021 11:27:32 -0400 Subject: [PATCH 08/10] Add automatic actions (burnwires after 3 hours, LNA turning off), opnav init parameters skeleton, comms off skeleton Signed-off-by: tmf97 --- communications/command_definitions.py | 21 ++++++++++++ flight_modes/flight_mode.py | 48 ++++++++++++--------------- flight_modes/restart_reboot.py | 6 ++-- main.py | 16 +++++---- utils/constants.py | 7 ++++ utils/parameters.json | 6 +++- utils/parameters.py | 6 ++++ 7 files changed, 73 insertions(+), 37 deletions(-) diff --git a/communications/command_definitions.py b/communications/command_definitions.py index 8b478916..36aa0b75 100644 --- a/communications/command_definitions.py +++ b/communications/command_definitions.py @@ -108,6 +108,8 @@ def __init__(self, parent: MainSatelliteThread): NormalCommandEnum.ExecPyFile.value: self.exec_py_file, NormalCommandEnum.IgnoreLowBatt.value: self.ignore_low_battery, NormalCommandEnum.MissionMode.value: self.set_mission_mode, + NormalCommandEnum.InitOpnav.value: self.init_opnav_parameters, + NormalCommandEnum.SetCommsOffTimes: self.set_comms_off_times } self.low_battery_commands = { @@ -703,6 +705,25 @@ def set_mission_mode(self, **kwargs): return {MISSION_MODE: params.CURRENT_MISSION_MODE} + def init_opnav_parameters(self, **kwargs): + pos_x = kwargs[POSITION_X] + pos_y = kwargs[POSITION_Y] + pos_z = kwargs[POSITION_Z] + pos_t = kwargs[NASA_PROVIDED_TIME] + + # TODO write above values to opnav db + + self.set_parameter(name="WANT_TO_OPNAV", value=True, hard_set=True) + + def set_comms_off_times(self, **kwargs): + comms_off_start = kwargs[COMMS_OFF_START] + comms_off_end = kwargs[COMMS_OFF_END] + + self.set_parameter(name="COMMS_OFF_TIME_START", value=comms_off_start, hard_set=True) + self.set_parameter(name="COMMS_OFF_TIME_END", value=comms_off_end, hard_set=True) + + return {COMMS_OFF_START: comms_off_start, COMMS_OFF_END: comms_off_end} + def dict_from_eps_config(config: ps.eps_config_t) -> dict: return {PPT_MODE: config.ppt_mode, diff --git a/flight_modes/flight_mode.py b/flight_modes/flight_mode.py index 9e57e287..59574a71 100644 --- a/flight_modes/flight_mode.py +++ b/flight_modes/flight_mode.py @@ -118,7 +118,6 @@ def run_mode(self): raise NotImplementedError("Only implemented in specific flight mode subclasses") def execute_commands(self): - bogus = bool() if len(self.parent.commands_to_execute) == 0: pass # If I have no commands to execute do nothing else: @@ -167,7 +166,15 @@ def completed_task(self): # Autonomous actions to maintain safety def automatic_actions(self): - pass + if not params.BURNWIRES_FIRED and self.parent.telemetry.rtc.rtc_time - params.INITIAL_TIME > (3600 * 3): + self.parent.logger.info("Actuating burnwires after 3 hours now.") + self.parent.gom.burnwire1(params.SPLIT_BURNWIRE_DURATION) + self.parent.command_definitions.set_parameter(name="BURNWIRES_FIRED", value=True, hard_set=True) + + if self.parent.telemetry.gom.hk.outputs[GomOutputs.comms.value] == 0 and \ + not (params.COMMS_OFF_TIME_START < time() < params.COMMS_OFF_TIME_END): + self.parent.logger.info("Autonomously Turning on LNA to receive commands") + self.parent.gom.lna(True) def write_telemetry(self): pass @@ -530,13 +537,13 @@ def register_commands(cls): NormalCommandEnum.GomConf2Get.value: NONE, NormalCommandEnum.ExecPyFile.value: ([FNAME], 36), NormalCommandEnum.IgnoreLowBatt.value: ([IGNORE], 1), - NormalCommandEnum.MissionMode.value: ([MISSION_MODE], 1) + NormalCommandEnum.MissionMode.value: ([MISSION_MODE], 1), + NormalCommandEnum.InitOpnav.value: ([POSITION_X, POSITION_Y, POSITION_Z, NASA_PROVIDED_TIME], 32), + NormalCommandEnum.SetCommsOffTimes.value: ([COMMS_OFF_START, COMMS_OFF_END], 8) } command_arg_types = { - AZIMUTH: 'float', - ELEVATION: 'float', - ACCELERATE: 'bool', + AZIMUTH: 'float', ELEVATION: 'float', ACCELERATE: 'bool', NAME: 'string', VALUE: 'double', STATE: 'bool', @@ -576,30 +583,17 @@ def register_commands(cls): BATTHEATERMODE: "bool", BATTHEATERLOW: "uint8", BATTHEATERHIGH: "uint8", - OUTPUT_NORMAL1: "bool", - OUTPUT_NORMAL2: "bool", - OUTPUT_NORMAL3: "bool", - OUTPUT_NORMAL4: "bool", - OUTPUT_NORMAL5: "bool", - OUTPUT_NORMAL6: "bool", - OUTPUT_NORMAL7: "bool", - OUTPUT_NORMAL8: "bool", - OUTPUT_SAFE1: "bool", - OUTPUT_SAFE2: "bool", - OUTPUT_SAFE3: "bool", - OUTPUT_SAFE4: "bool", - OUTPUT_SAFE5: "bool", - OUTPUT_SAFE6: "bool", - OUTPUT_SAFE7: "bool", - OUTPUT_SAFE8: "bool", + OUTPUT_NORMAL1: "bool", OUTPUT_NORMAL2: "bool", OUTPUT_NORMAL3: "bool", OUTPUT_NORMAL4: "bool", + OUTPUT_NORMAL5: "bool", OUTPUT_NORMAL6: "bool", OUTPUT_NORMAL7: "bool", OUTPUT_NORMAL8: "bool", + OUTPUT_SAFE1: "bool", OUTPUT_SAFE2: "bool", OUTPUT_SAFE3: "bool", OUTPUT_SAFE4: "bool", + OUTPUT_SAFE5: "bool", OUTPUT_SAFE6: "bool", OUTPUT_SAFE7: "bool", OUTPUT_SAFE8: "bool", OUTPUT_ON_DELAY: "short", OUTPUT_OFF_DELAY: "short", VBOOST1: "short", VBOOST2: "short", VBOOST3: "short", - MAX_VOLTAGE: 'short', - NORM_VOLTAGE: 'short', - SAFE_VOLTAGE: 'short', - CRIT_VOLTAGE: 'short', + MAX_VOLTAGE: 'short', NORM_VOLTAGE: 'short', SAFE_VOLTAGE: 'short', CRIT_VOLTAGE: 'short', FNAME: 'string', - CMD: 'string', IGNORE: 'bool', MISSION_MODE: 'uint8' + CMD: 'string', IGNORE: 'bool', MISSION_MODE: 'uint8', + POSITION_X: 'double', POSITION_Y: 'double', POSITION_Z: 'double', NASA_PROVIDED_TIME: 'double', + COMMS_OFF_START: 'int', COMMS_OFF_END: 'int' } downlink_codecs = { diff --git a/flight_modes/restart_reboot.py b/flight_modes/restart_reboot.py index 2fcfe5d4..9c1db8da 100644 --- a/flight_modes/restart_reboot.py +++ b/flight_modes/restart_reboot.py @@ -38,8 +38,9 @@ def run_mode(self): if params.SPACECRAFT_NAME == 'HYDROGEN': # deploy antennae - logger.info("Deploying antennae") - self.parent.gom.burnwire1(5) + logger.info("Deploying antennae on Hydrogen") + self.parent.gom.burnwire1(params.SPLIT_BURNWIRE_DURATION) + self.parent.command_definitions.set_parameter(name="BURNWIRES_FIRED", value=True, hard_set=True) if self.parent.need_to_reboot: # TODO: double check the boot db history to make sure we aren't going into a boot loop @@ -60,6 +61,7 @@ def update_state(self) -> int: def set_parameters(self): self.parent.command_definitions.set_parameter(name="SPACECRAFT_NAME", value=determine_name(), hard_set=True) + self.parent.logger.info(f"Spacecraft is {params.SPACECRAFT_NAME}") self.update_mission_mode(MissionModeEnum.Boot.value) diff --git a/main.py b/main.py index 2ae2887b..a5137113 100644 --- a/main.py +++ b/main.py @@ -71,13 +71,14 @@ def __init__(self): self.file_block_bank = {} self.need_to_reboot = False - self.gom = None - self.gyro = None - self.adc = None - self.rtc = None - self.radio = None - self.mux = None - self.camera = None + self.gom = Gomspace + self.gyro = GyroSensor + self.adc = ADC + self.rtc = RTC + self.radio = Radio + self.mux = camera.CameraMux + self.camera = camera.Camera + self.nemo_manager = NemoManager self.init_sensors() # Telemetry @@ -311,6 +312,7 @@ def run(self): self.read_command_queue_from_file() self.execute_commands() # Set goal or execute command immediately self.run_mode() + self.flight_mode.automatic_actions() finally: # TODO handle failure gracefully if FOR_FLIGHT is True: diff --git a/utils/constants.py b/utils/constants.py index ee52d49c..9738ffac 100644 --- a/utils/constants.py +++ b/utils/constants.py @@ -205,6 +205,11 @@ IGNORE = 'ignore' PASSWORD = 'password' MISSION_MODE = 'mission_mode' +NASA_PROVIDED_TIME = 'nasa_start_time' + +COMMS_OFF_START = 'comms_off_start' +COMMS_OFF_END = 'comms_off_end' + # GOMspace Channel designations: # TODO: re-evaluate and double check before flight for each satellite half @@ -278,6 +283,8 @@ class NormalCommandEnum(IntEnum): GomConf1Get = 31 GomConf2Set = 32 GomConf2Get = 33 + InitOpnav = 34 + SetCommsOffTimes = 35 ShellCommand = 50 SudoCommand = 51 diff --git a/utils/parameters.json b/utils/parameters.json index 62a73511..d30071ae 100644 --- a/utils/parameters.json +++ b/utils/parameters.json @@ -31,5 +31,9 @@ "FOR_FLIGHT": false, "WANT_TO_OPNAV": false, "SPACECRAFT_NAME": "", - "CURRENT_MISSION_MODE": 0 + "CURRENT_MISSION_MODE": 0, + "BURNWIRES_FIRED": false, + "INITIAL_TIME": 1893456000, + "COMMS_OFF_TIME_START": -1, + "COMMS_OFF_TIME_END": -1 } \ No newline at end of file diff --git a/utils/parameters.py b/utils/parameters.py index 56576e50..986fd553 100644 --- a/utils/parameters.py +++ b/utils/parameters.py @@ -46,3 +46,9 @@ GYRO_BIAS_DXDT = 0 GYRO_BIAS_DYDT = 0 GYRO_BIAS_DZDT = 0 + +BURNWIRES_FIRED = False +INITIAL_TIME = 1893456000 # Jan 1, 2030 + +COMMS_OFF_TIME_START = -1 +COMMS_OFF_TIME_END = -1 From 1df8d2df9069d98f91540425564c3a68adc30e4d Mon Sep 17 00:00:00 2001 From: tmf97 Date: Sun, 25 Apr 2021 16:22:07 -0400 Subject: [PATCH 09/10] Add sigterm handler Signed-off-by: tmf97 --- flight_modes/flight_mode.py | 3 ++- main.py | 11 ++++++++++- utils/constants.py | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/flight_modes/flight_mode.py b/flight_modes/flight_mode.py index 59574a71..ba576f89 100644 --- a/flight_modes/flight_mode.py +++ b/flight_modes/flight_mode.py @@ -166,7 +166,8 @@ def completed_task(self): # Autonomous actions to maintain safety def automatic_actions(self): - if not params.BURNWIRES_FIRED and self.parent.telemetry.rtc.rtc_time - params.INITIAL_TIME > (3600 * 3): + if not params.BURNWIRES_FIRED and self.parent.telemetry.rtc.rtc_time - params.INITIAL_TIME > ( + 3600 * BURNWIRE_WAITTIME): self.parent.logger.info("Actuating burnwires after 3 hours now.") self.parent.gom.burnwire1(params.SPLIT_BURNWIRE_DURATION) self.parent.command_definitions.set_parameter(name="BURNWIRES_FIRED", value=True, hard_set=True) diff --git a/main.py b/main.py index a5137113..d1d93368 100644 --- a/main.py +++ b/main.py @@ -68,6 +68,7 @@ def __init__(self): self.log_dir = LOG_DIR self.logger = get_log() self.attach_sigint_handler() # FIXME + self.attach_sigterm_handler() self.file_block_bank = {} self.need_to_reboot = False @@ -219,6 +220,14 @@ def handle_sigint(self, signal, frame): def attach_sigint_handler(self): signal.signal(signal.SIGINT, self.handle_sigint) + def handle_sigterm(self, signal, frame): + self.shutdown() + sys.exit(0) + + def attach_sigterm_handler(self): + self.logger.critical("SIGTERM received") + signal.signal(signal.SIGTERM, self.handle_sigterm) + def poll_inputs(self): self.flight_mode.poll_inputs() @@ -333,4 +342,4 @@ def shutdown(self): if __name__ == "__main__": FOR_FLIGHT = False main = MainSatelliteThread() - main.run() \ No newline at end of file + main.run() diff --git a/utils/constants.py b/utils/constants.py index 9738ffac..6530aa10 100644 --- a/utils/constants.py +++ b/utils/constants.py @@ -3,12 +3,12 @@ import hashlib # unit conversions - DEG2RAD = 3.14159265359 / 180 # Delay to wait on BootUp # TODO change back to 30.0 BOOTUP_SEPARATION_DELAY = 5.0 +BURNWIRE_WAITIME = 3 # hours, defined by NASA # Verification Key Parameters MAC_LENGTH = 4 From 36c3d77583f099fb067c0ecca7679fae2f9cdbca Mon Sep 17 00:00:00 2001 From: tmf97 Date: Wed, 5 May 2021 13:37:11 -0400 Subject: [PATCH 10/10] Fix minor typos and reorganization Signed-off-by: tmf97 --- flight_modes/flight_mode.py | 7 ++++--- main.py | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/flight_modes/flight_mode.py b/flight_modes/flight_mode.py index ba576f89..9e419a37 100644 --- a/flight_modes/flight_mode.py +++ b/flight_modes/flight_mode.py @@ -167,7 +167,7 @@ def completed_task(self): # Autonomous actions to maintain safety def automatic_actions(self): if not params.BURNWIRES_FIRED and self.parent.telemetry.rtc.rtc_time - params.INITIAL_TIME > ( - 3600 * BURNWIRE_WAITTIME): + 3600 * BURNWIRE_WAITIME): self.parent.logger.info("Actuating burnwires after 3 hours now.") self.parent.gom.burnwire1(params.SPLIT_BURNWIRE_DURATION) self.parent.command_definitions.set_parameter(name="BURNWIRES_FIRED", value=True, hard_set=True) @@ -202,8 +202,9 @@ def update_mission_mode(self, mission_mode_id: int): # TODO bulk parameters hard set? self.parent.command_definitions.set_parameter(name='WANT_TO_ELECTROLYZE', value=True, hard_set=True) - self.parent.command_definitions.set_parameter(name='WANT_TO_OPNAV', value=True, - hard_set=True) + # self.parent.command_definitions.set_parameter(name='WANT_TO_OPNAV', value=True, + # hard_set=True) + # Only want to run opnav once we get initial position and time update command self.parent.command_definitions.set_parameter(name='TELEM_DOWNLINK_TIME', value=60, hard_set=True) # self.parent.command_definitions.set_parameter(name='CURRENT_MISSION_MODE', value=mission_mode_id, diff --git a/main.py b/main.py index d1d93368..cc735888 100644 --- a/main.py +++ b/main.py @@ -221,11 +221,11 @@ def attach_sigint_handler(self): signal.signal(signal.SIGINT, self.handle_sigint) def handle_sigterm(self, signal, frame): + self.logger.critical("SIGTERM received") self.shutdown() sys.exit(0) def attach_sigterm_handler(self): - self.logger.critical("SIGTERM received") signal.signal(signal.SIGTERM, self.handle_sigterm) def poll_inputs(self):