# -*- coding: utf-8 -*- """ @file tmtcc_tc_pdu2.py @brief PDU2 tests @details PDU2 is mounted on the X4 slot of the P60 dock @author J. Meier @date 17.12.2020 """ import enum from eive_tmtc.config.object_ids import PDU_2_HANDLER_ID from eive_tmtc.gomspace.gomspace_common import ( pack_reboot_command, pack_ping_command, pack_gnd_wdt_reset_command, pack_get_param_command, TableIds, pack_request_full_hk_table_command, ) from eive_tmtc.gomspace.gomspace_pdu_definitions import PduHkTable, PduConfigTable from eive_tmtc.tmtc.power.common_power import ( add_gomspace_nodes, pack_common_gomspace_cmds, req_hk_cmds, PowerOpCodes, generic_on_cmd, generic_off_cmd, add_gomspace_cmd_defs, pack_common_power_cmds, create_generic_on_cmd, create_generic_off_cmd, SetId, add_common_power_defs, ) from spacepackets.ecss import PusTelecommand from tmtccmd.config import CmdTreeNode, OpCodeEntry, TmtcDefinitionWrapper from tmtccmd.config.tmtc import tmtc_definitions_provider from tmtccmd.tmtc import DefaultPusQueueHelper from tmtccmd.util import ObjectIdU32 class Pdu2InfoBase: PL_PCDU_BAT_NOM = "Switch PL PCDU Nominal Battery Channel" RW = "Switch Reaction Wheel" HEATER = "Switch Heater" SUS_R = "Switch Sun Sensor Board Redundant" SOLAR_ARRAY_DEPL = "Switch Solar Array Deployment" PL_PCDU_BAT_RED = "Switch PL PCDU Redundant Battery Channel" ACS_B = "Switch ACS Board B-Side" PL_CAM = "Switch Payload Camera" class Pdu2ChIndex(enum.IntEnum): OBC = 0 PL_PCDU_BAT_NOM = 1 RW = 2 HEATER = 3 SUS_R = 4 SOLAR_ARRAY_DEPL = 5 PL_PCDU_BAT_RED = 6 ACS_B = 7 PL_CAM = 8 class PDU2TestProcedure: """ @brief Use this class to define the tests to perform for the PDU2. @details Setting all to True will run all tests. Setting all to False will only run the tests set to True. """ all = False reboot = False read_gnd_wdt = False gnd_wdt_reset = False ping = False channel_2_off = False # Reaction wheels 5V read_temperature = False read_channel_2_state = False # Reaction wheels 5V read_cur_lu_lim_0 = False # OBC channel_2_on = False # Reaction wheels 5V invalid_table_id_test = ( False # Test to check if software properly handles invalid table ids ) invalid_address_test = ( False # Test to check if software properly handles invalid addresses ) invalid_parameter_size_test = False request_hk_table = False def pack_pdu2_commands(object_id: ObjectIdU32, q: DefaultPusQueueHelper, cmd_str: str): q.add_log_cmd("Testing PDU2") objb = object_id.as_bytes pdu2_switch_cmds(q, cmd_str) pdu2_req_hk_cmds(q, cmd_str) pack_common_power_cmds("PDU2", object_id, q, cmd_str) pack_common_gomspace_cmds("PDU2", object_id, q, cmd_str) if PDU2TestProcedure.all or PDU2TestProcedure.reboot: q.add_log_cmd("PDU2: Reboot") q.add_pus_tc(pack_reboot_command(object_id)) if PDU2TestProcedure.all or PDU2TestProcedure.read_gnd_wdt: q.add_log_cmd("PDU2: Reading ground watchdog timer value") q.add_pus_tc( pack_get_param_command( objb, TableIds.HK, PduHkTable.wdt_gnd_left.parameter_address, PduHkTable.wdt_gnd_left.parameter_size, ) ) if PDU2TestProcedure.all or PDU2TestProcedure.gnd_wdt_reset: q.add_log_cmd("PDU2: Testing ground watchdog reset") q.add_pus_tc(pack_gnd_wdt_reset_command(object_id)) if PDU2TestProcedure.all or PDU2TestProcedure.ping: q.add_log_cmd("PDU2: Ping Test") ping_data = bytearray([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) q.add_pus_tc(pack_ping_command(object_id, ping_data)) if PDU2TestProcedure.all or PDU2TestProcedure.read_temperature: q.add_log_cmd("PDU2: Testing temperature reading") q.add_pus_tc( pack_get_param_command( objb, TableIds.HK, PduHkTable.temperature.parameter_address, PduHkTable.temperature.parameter_size, ) ) if PDU2TestProcedure.all or PDU2TestProcedure.read_channel_2_state: q.add_log_cmd("PDU2: Reading output channel 2 state (TCS Heater)") q.add_pus_tc( pack_get_param_command( objb, TableIds.CONFIG, PduConfigTable.out_en_2.parameter_address, PduConfigTable.out_en_2.parameter_size, ) ) if PDU2TestProcedure.all or PDU2TestProcedure.read_cur_lu_lim_0: q.add_log_cmd("PDU2: Reading current limit value of output channel 0 (OBC)") q.add_pus_tc( pack_get_param_command( objb, TableIds.CONFIG, PduConfigTable.cur_lu_lim_0.parameter_address, PduConfigTable.cur_lu_lim_0.parameter_size, ) ) if PDU2TestProcedure.all or PDU2TestProcedure.request_hk_table: q.add_log_cmd("PDU2: Requesting housekeeping table") q.add_pus_tc(pack_request_full_hk_table_command(object_id)) @tmtc_definitions_provider def add_pdu2_cmds(defs: TmtcDefinitionWrapper): oce = OpCodeEntry() add_pdu2_common_defs(oce) add_common_power_defs(oce) add_gomspace_cmd_defs(oce) oce.add( keys=PowerOpCodes.PRINT_SWITCH_V_I, info="PDU2: Print Switches, Voltages, Currents", ) oce.add( keys=PowerOpCodes.PRINT_LATCHUPS, info="PDU2: Print Latchups", ) defs.add_service( name="pdu2", info="PDU2 Device", op_code_entry=oce, ) def add_pdu2_subnodes(node: CmdTreeNode): node.add_child( CmdTreeNode(PowerOpCodes.ACS_B_ON[0], info_on_pdu2(Pdu2InfoBase.ACS_B)) ) node.add_child( CmdTreeNode(PowerOpCodes.ACS_B_OFF[0], info_off_pdu2(Pdu2InfoBase.ACS_B)) ) node.add_child( CmdTreeNode(PowerOpCodes.SUS_R_ON[0], info_on_pdu2(Pdu2InfoBase.SUS_R)) ) node.add_child( CmdTreeNode(PowerOpCodes.SUS_R_OFF[0], info_off_pdu2(Pdu2InfoBase.SUS_R)) ) node.add_child(CmdTreeNode(PowerOpCodes.RW_ON[0], info_on_pdu2(Pdu2InfoBase.RW))) node.add_child(CmdTreeNode(PowerOpCodes.RW_OFF[0], info_off_pdu2(Pdu2InfoBase.RW))) node.add_child( CmdTreeNode( PowerOpCodes.PL_PCDU_VBAT_NOM_ON[0], info_on_pdu2(Pdu2InfoBase.PL_PCDU_BAT_NOM), ) ) node.add_child( CmdTreeNode( PowerOpCodes.PL_PCDU_VBAT_NOM_OFF[0], info_off_pdu2(Pdu2InfoBase.PL_PCDU_BAT_NOM), ) ) node.add_child( CmdTreeNode( PowerOpCodes.PL_PCDU_VBAT_RED_ON[0], info_on_pdu2(Pdu2InfoBase.PL_PCDU_BAT_RED), ) ) node.add_child( CmdTreeNode( PowerOpCodes.PL_PCDU_VBAT_RED_OFF[0], info_off_pdu2(Pdu2InfoBase.PL_PCDU_BAT_RED), ) ) node.add_child( CmdTreeNode(PowerOpCodes.HEATER_ON[0], info_on_pdu2(Pdu2InfoBase.HEATER)) ) node.add_child( CmdTreeNode(PowerOpCodes.HEATER_OFF[0], info_off_pdu2(Pdu2InfoBase.HEATER)) ) node.add_child( CmdTreeNode( PowerOpCodes.SOLAR_ARRAY_DEPL_ON[0], info_on_pdu2(Pdu2InfoBase.SOLAR_ARRAY_DEPL), ) ) node.add_child( CmdTreeNode( PowerOpCodes.SOLAR_ARRAY_DEPL_OFF[0], info_off_pdu2(Pdu2InfoBase.SOLAR_ARRAY_DEPL), ) ) node.add_child( CmdTreeNode(PowerOpCodes.PL_CAM_ON[0], info_on_pdu2(Pdu2InfoBase.PL_CAM)) ) node.add_child( CmdTreeNode(PowerOpCodes.PL_CAM_OFF[0], info_off_pdu2(Pdu2InfoBase.PL_CAM)) ) def create_pdu2_node() -> CmdTreeNode: node = CmdTreeNode( "pdu2", "P60 PCDU PDU2 device", hide_children_which_are_leaves=True ) add_gomspace_nodes(node) add_pdu2_subnodes(node) node.add_child( CmdTreeNode( PowerOpCodes.PRINT_SWITCH_V_I[0], "PDU2: Print Switches, Voltages, Currents" ) ) return node def pdu2_switch_cmds(q: DefaultPusQueueHelper, op_code: str): # noqa C901 if op_code in PowerOpCodes.PL_PCDU_VBAT_NOM_ON: pl_pcdu_bat_nom_on_cmd(q) elif op_code in PowerOpCodes.PL_PCDU_VBAT_NOM_OFF: pl_pcdu_bat_nom_off_cmd(q) elif op_code in PowerOpCodes.RW_ON: reaction_wheel_on_cmd(q) elif op_code in PowerOpCodes.RW_OFF: reaction_wheel_off_cmd(q) elif op_code in PowerOpCodes.HEATER_ON: heater_on_cmd(q) elif op_code in PowerOpCodes.HEATER_OFF: heater_off_cmd(q) elif op_code in PowerOpCodes.SUS_R_ON: sus_red_on_cmd(q) elif op_code in PowerOpCodes.SUS_R_OFF: sus_red_off_cmd(q) elif op_code in PowerOpCodes.SOLAR_ARRAY_DEPL_ON: solar_array_deployment_on_cmd(q) elif op_code in PowerOpCodes.SOLAR_ARRAY_DEPL_OFF: solar_array_deployment_off_cmd(q) elif op_code in PowerOpCodes.PL_PCDU_VBAT_RED_ON: pl_pcdu_bat_red_on_cmd(q) elif op_code in PowerOpCodes.PL_PCDU_VBAT_RED_OFF: pl_pcdu_bat_nom_off_cmd(q) elif op_code in PowerOpCodes.ACS_B_ON: acs_board_b_side_on_cmd(q) elif op_code in PowerOpCodes.ACS_B_OFF: acs_board_b_side_off_cmd(q) elif op_code in PowerOpCodes.PL_CAM_ON: payload_camera_on_cmd(q) elif op_code in PowerOpCodes.PL_CAM_OFF: payload_camera_off_cmd(q) def info_on_pdu2(base: str) -> str: return "PDU2: " + base + " on" def info_off_pdu2(base: str) -> str: return "PDU2: " + base + " off" def add_pdu2_common_defs(oce: OpCodeEntry): oce.add(keys=PowerOpCodes.ACS_B_ON, info=info_on_pdu2(Pdu2InfoBase.ACS_B)) oce.add(keys=PowerOpCodes.ACS_B_OFF, info=info_off_pdu2(Pdu2InfoBase.ACS_B)) oce.add(keys=PowerOpCodes.SUS_R_ON, info=info_on_pdu2(Pdu2InfoBase.SUS_R)) oce.add(keys=PowerOpCodes.SUS_R_OFF, info=info_off_pdu2(Pdu2InfoBase.SUS_R)) oce.add(keys=PowerOpCodes.RW_ON, info=info_on_pdu2(Pdu2InfoBase.RW)) oce.add(keys=PowerOpCodes.RW_OFF, info=info_off_pdu2(Pdu2InfoBase.RW)) oce.add( keys=PowerOpCodes.PL_PCDU_VBAT_NOM_ON, info=info_on_pdu2(Pdu2InfoBase.PL_PCDU_BAT_NOM), ) oce.add( keys=PowerOpCodes.PL_PCDU_VBAT_NOM_OFF, info=info_off_pdu2(Pdu2InfoBase.PL_PCDU_BAT_NOM), ) oce.add( keys=PowerOpCodes.PL_PCDU_VBAT_RED_ON, info=info_on_pdu2(Pdu2InfoBase.PL_PCDU_BAT_RED), ) oce.add( keys=PowerOpCodes.PL_PCDU_VBAT_RED_OFF, info=info_off_pdu2(Pdu2InfoBase.PL_PCDU_BAT_RED), ) oce.add(keys=PowerOpCodes.HEATER_ON, info=info_on_pdu2(Pdu2InfoBase.HEATER)) oce.add(keys=PowerOpCodes.HEATER_OFF, info=info_off_pdu2(Pdu2InfoBase.HEATER)) oce.add( keys=PowerOpCodes.SOLAR_ARRAY_DEPL_ON, info=info_on_pdu2(Pdu2InfoBase.SOLAR_ARRAY_DEPL), ) oce.add( keys=PowerOpCodes.SOLAR_ARRAY_DEPL_OFF, info=info_off_pdu2(Pdu2InfoBase.SOLAR_ARRAY_DEPL), ) oce.add(keys=PowerOpCodes.PL_CAM_ON, info=info_on_pdu2(Pdu2InfoBase.PL_CAM)) oce.add(keys=PowerOpCodes.PL_CAM_OFF, info=info_off_pdu2(Pdu2InfoBase.PL_CAM)) def pdu2_req_hk_cmds(q: DefaultPusQueueHelper, op_code: str): req_hk_cmds("PDU2", q, op_code, PDU_2_HANDLER_ID, (SetId.CORE, SetId.AUX)) def pl_pcdu_bat_nom_on_cmd(q: DefaultPusQueueHelper): generic_on_cmd( PDU_2_HANDLER_ID, q, Pdu2InfoBase.PL_PCDU_BAT_NOM, Pdu2ChIndex.PL_PCDU_BAT_NOM ) def pl_pcdu_bat_nom_off_cmd(q: DefaultPusQueueHelper): generic_off_cmd( PDU_2_HANDLER_ID, q, Pdu2InfoBase.PL_PCDU_BAT_NOM, Pdu2ChIndex.PL_PCDU_BAT_NOM ) def reaction_wheel_on_cmd(q: DefaultPusQueueHelper): generic_on_cmd(PDU_2_HANDLER_ID, q, Pdu2InfoBase.RW, Pdu2ChIndex.RW) def create_reaction_wheel_on_cmd() -> PusTelecommand: return create_generic_on_cmd(PDU_2_HANDLER_ID, Pdu2ChIndex.RW) def reaction_wheel_off_cmd(q: DefaultPusQueueHelper): generic_off_cmd(PDU_2_HANDLER_ID, q, Pdu2InfoBase.RW, Pdu2ChIndex.RW) def create_reaction_wheel_off_cmd() -> PusTelecommand: return create_generic_off_cmd(PDU_2_HANDLER_ID, Pdu2ChIndex.RW) def heater_on_cmd(q: DefaultPusQueueHelper): generic_on_cmd(PDU_2_HANDLER_ID, q, Pdu2InfoBase.HEATER, Pdu2ChIndex.HEATER) def create_heater_on_cmd() -> PusTelecommand: return create_generic_on_cmd(PDU_2_HANDLER_ID, Pdu2ChIndex.HEATER) def heater_off_cmd(q: DefaultPusQueueHelper): generic_off_cmd(PDU_2_HANDLER_ID, q, Pdu2InfoBase.HEATER, Pdu2ChIndex.HEATER) def create_heater_off_cmd() -> PusTelecommand: return create_generic_off_cmd(PDU_2_HANDLER_ID, Pdu2ChIndex.HEATER) def sus_red_on_cmd(q: DefaultPusQueueHelper): generic_on_cmd(PDU_2_HANDLER_ID, q, Pdu2InfoBase.SUS_R, Pdu2ChIndex.SUS_R) def create_sus_red_on_cmd() -> PusTelecommand: return create_generic_on_cmd(PDU_2_HANDLER_ID, Pdu2ChIndex.SUS_R) def sus_red_off_cmd(q: DefaultPusQueueHelper): generic_off_cmd(PDU_2_HANDLER_ID, q, Pdu2InfoBase.SUS_R, Pdu2ChIndex.SUS_R) def create_sus_red_off_cmd() -> PusTelecommand: return create_generic_off_cmd(PDU_2_HANDLER_ID, Pdu2ChIndex.SUS_R) def solar_array_deployment_on_cmd(q: DefaultPusQueueHelper): generic_on_cmd( PDU_2_HANDLER_ID, q, Pdu2InfoBase.SOLAR_ARRAY_DEPL, Pdu2ChIndex.SOLAR_ARRAY_DEPL ) def create_solar_array_deployment_on_cmd() -> PusTelecommand: return create_generic_on_cmd(PDU_2_HANDLER_ID, Pdu2ChIndex.SOLAR_ARRAY_DEPL) def solar_array_deployment_off_cmd(q: DefaultPusQueueHelper): generic_off_cmd( PDU_2_HANDLER_ID, q, Pdu2InfoBase.SOLAR_ARRAY_DEPL, Pdu2ChIndex.SOLAR_ARRAY_DEPL ) def create_solar_array_deployment_off_cmd() -> PusTelecommand: return create_generic_off_cmd(PDU_2_HANDLER_ID, Pdu2ChIndex.SOLAR_ARRAY_DEPL) def pl_pcdu_bat_red_on_cmd(q: DefaultPusQueueHelper): generic_on_cmd( PDU_2_HANDLER_ID, q, Pdu2InfoBase.PL_PCDU_BAT_RED, Pdu2ChIndex.PL_PCDU_BAT_RED ) def create_pl_pcdu_bat_red_on_cmd() -> PusTelecommand: return create_generic_on_cmd(PDU_2_HANDLER_ID, Pdu2ChIndex.PL_PCDU_BAT_RED) def pl_pcdu_bat_red_off_cmd(q: DefaultPusQueueHelper): generic_off_cmd( PDU_2_HANDLER_ID, q, Pdu2InfoBase.PL_PCDU_BAT_RED, Pdu2ChIndex.PL_PCDU_BAT_RED ) def create_pl_pcdu_bat_red_off_cmd() -> PusTelecommand: return create_generic_off_cmd(PDU_2_HANDLER_ID, Pdu2ChIndex.PL_PCDU_BAT_RED) def acs_board_b_side_on_cmd(q: DefaultPusQueueHelper): generic_on_cmd(PDU_2_HANDLER_ID, q, Pdu2InfoBase.ACS_B, Pdu2ChIndex.ACS_B) def create_acs_board_b_side_on_cmd() -> PusTelecommand: return create_generic_on_cmd(PDU_2_HANDLER_ID, Pdu2ChIndex.ACS_B) def acs_board_b_side_off_cmd(q: DefaultPusQueueHelper): generic_off_cmd(PDU_2_HANDLER_ID, q, Pdu2InfoBase.ACS_B, Pdu2ChIndex.ACS_B) def create_acs_board_b_side_off_cmd() -> PusTelecommand: return create_generic_off_cmd(PDU_2_HANDLER_ID, Pdu2ChIndex.ACS_B) def payload_camera_on_cmd(q: DefaultPusQueueHelper): generic_on_cmd(PDU_2_HANDLER_ID, q, Pdu2InfoBase.PL_CAM, Pdu2ChIndex.PL_CAM) def create_payload_camera_on_cmd() -> PusTelecommand: return create_generic_on_cmd(PDU_2_HANDLER_ID, Pdu2ChIndex.PL_CAM) def payload_camera_off_cmd(q: DefaultPusQueueHelper): generic_off_cmd(PDU_2_HANDLER_ID, q, Pdu2InfoBase.PL_CAM, Pdu2ChIndex.PL_CAM) def create_payload_camera_off_cmd() -> PusTelecommand: return create_generic_off_cmd(PDU_2_HANDLER_ID, Pdu2ChIndex.PL_CAM)