diff --git a/gomspace/gomspace_common.py b/gomspace/gomspace_common.py index e760849..571e28f 100644 --- a/gomspace/gomspace_common.py +++ b/gomspace/gomspace_common.py @@ -23,18 +23,20 @@ class GomspaceDeviceActionIds(enum.IntEnum): PARAM_SET = 255 WDT_RESET = 9 REQUEST_HK_TABLE = 16 + REQUEST_CONFIG_TABLE = 17 PRINT_SWITCH_V_I = 32 PRINT_LATCHUPS = 33 class GomspaceOpCodes: # Request HK - REQUEST_CORE_HK_ONCE = ["hk_core", "128"] - REQUEST_AUX_HK_ONCE = ["hk_aux", "129"] - PRINT_SWITCH_V_I = ["print-switch-vi", "130"] - PRINT_LATCHUPS = ["print-latchups", "131"] - GET_PARAM = ["get_param", "132"] - SET_PARAM = ["set_param", "133"] + REQUEST_CORE_HK_ONCE = ["hk_core"] + REQUEST_AUX_HK_ONCE = ["hk_aux"] + PRINT_SWITCH_V_I = ["print_switch_vi"] + PRINT_LATCHUPS = ["print_latchups"] + GET_PARAM = ["get_param"] + SET_PARAM = ["set_param"] + REQUEST_CONFIG_TABLE = ["cfg_table"] class GsInfo: @@ -44,6 +46,7 @@ class GsInfo: PRINT_LATCHUPS = "Print latchups" GET_PARAMETER = "Get parameter" SET_PARAMETER = "Set parameter" + REQUEST_CONFIG_TABLE = "Request Config Table" class SetIds: @@ -77,6 +80,12 @@ class Channel: off = 0 +def pack_request_config_command(object_id: bytes) -> PusTelecommand: + return make_fsfw_action_cmd( + object_id=object_id, action_id=GomspaceDeviceActionIds.REQUEST_CONFIG_TABLE + ) + + def pack_get_param_command( object_id: bytes, table_id: int, @@ -105,11 +114,7 @@ def pack_get_param_command( def pack_set_param_command( - object_id: bytes, - memory_address: bytes, - parameter_size: int, - parameter: int, - ssc: int = 0, + object_id: bytes, memory_address: bytes, parameter_size: int, parameter: int ) -> PusTelecommand: """Function to generate a command to set a parameter :param object_id: The object id of the gomspace device handler. @@ -117,7 +122,6 @@ def pack_set_param_command( :param parameter: The parameter value to set. :param parameter_size: Size of the value to set. There are uint8_t, uint16_t and uint32_t in the device tables. - :param ssc: :return: The command as bytearray. """ action_id = GomspaceDeviceActionIds.PARAM_SET diff --git a/pus_tc/devs/__init__.py b/pus_tc/devs/__init__.py index bc05547..8b13789 100644 --- a/pus_tc/devs/__init__.py +++ b/pus_tc/devs/__init__.py @@ -1 +1 @@ -from . import power + diff --git a/pus_tc/devs/common_power.py b/pus_tc/devs/common_power.py deleted file mode 100644 index cf49e81..0000000 --- a/pus_tc/devs/common_power.py +++ /dev/null @@ -1,472 +0,0 @@ -import enum -import struct - -from config.object_ids import PDU_1_HANDLER_ID, PDU_2_HANDLER_ID -from gomspace.gomspace_common import ( - pack_set_param_command, - Channel, - GomspaceOpCodes, - GsInfo, - SetIds, - GomspaceDeviceActionIds, -) -from gomspace.gomspace_pdu_definitions import PDU_CONFIG_LIST -from pus_tm.defs import PrintWrapper -from tmtccmd.config import OpCodeEntry -from tmtccmd.tc import DefaultPusQueueHelper -from tmtccmd.tc.pus_3_fsfw_hk import ( - make_sid, - generate_one_diag_command, - generate_one_hk_command, -) -from tmtccmd.util.tmtc_printer import FsfwTmTcPrinter - - -class Pdu1ChIndex(enum.IntEnum): - TCS = 0 - SYRLINKS = 1 - STR = 2 - MGT = 3 - SUS_N = 4 - SCEX = 5 - PLOC = 6 - ACS_A = 7 - - -class Pdu1InfoBase: - TCS = "Switch TCS Board" - SYRLINKS = "Switch Syrlinks (COM)" - STR = "Switch Startracker" - MGT = "Switch Magnetorquer" - SUS_N = "Switch Sun Sensor Board Nominal" - SCEX = "Switch Solar Cell Experiment" - PLOC = "Switch Payload On-Board Computer" - ACS_A = "Switch ACS Board A-Side" - - -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 PowerInfo: - INFO_CORE = "Core Information" - INFO_AUX = "Auxiliary Information" - INFO_ALL = "All Information" - - -class Pdu2ChIndex(enum.IntEnum): - 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 PowerOpCodes: - # PDU 1 - TCS_ON = ["tcs-on"] - TCS_OFF = ["tcs-off"] - SYRLINKS_ON = ["syrlinks-on"] - SYRLINKS_OFF = ["syrlinks-off"] - STAR_TRACKER_ON = ["str-on"] - STAR_TRACKER_OFF = ["str-off"] - MGT_ON = ["mgt-on"] - MGT_OFF = ["mgt-off"] - SUS_N_ON = ["sus-nom-on"] - SUS_N_OFF = ["sus-nom-off"] - SCEX_ON = ["scex-on"] - SCEX_OFF = ["scex-off"] - PLOC_ON = ["ploc-on"] - PLOC_OFF = ["ploc-off"] - ACS_A_ON = ["acs-a-on"] - ACS_A_OFF = ["acs-a-off"] - - # PDU 2 - PL_PCDU_VBAT_NOM_ON = ["plpcdu-vbat-nom-on"] - PL_PCDU_VBAT_NOM_OFF = ["plpcdu-vbat-nom-off"] - RW_ON = ["rw-on"] - RW_OFF = ["rw-off"] - HEATER_ON = ["heater-on"] - HEATER_OFF = ["heater-off"] - SUS_R_ON = ["sus-red-on"] - SUS_R_OFF = ["sus-red-off"] - SOLAR_ARRAY_DEPL_ON = ["sa-depl-on"] - SOLAR_ARRAY_DEPL_OFF = ["sa-depl-off"] - PL_PCDU_VBAT_RED_ON = ["plpcdu-vbat-red-on"] - PL_PCDU_VBAT_RED_OFF = ["plpcdu-vbat-red-off"] - ACS_B_ON = ["acs-b-on"] - ACS_B_OFF = ["acs-b-off"] - PL_CAM_ON = ["cam-on"] - PL_CAM_OFF = ["cam-off"] - - INFO_CORE = ["info"] - INFO_AUX = ["info-aux"] - INFO_ALL = ["info-all"] - - -def info_on_pdu1(base: str) -> str: - return "PDU1: " + base + " on" - - -def info_off_pdu1(base: str) -> str: - return "PDU1: " + base + " off" - - -def info_on_pdu2(base: str) -> str: - return "PDU2: " + base + " on" - - -def info_off_pdu2(base: str) -> str: - return "PDU2: " + base + " off" - - -def add_pdu1_common_defs(oce: OpCodeEntry): - oce.add(keys=PowerOpCodes.TCS_ON, info=info_on_pdu1(Pdu1InfoBase.TCS)) - oce.add(keys=PowerOpCodes.TCS_OFF, info=info_off_pdu1(Pdu1InfoBase.TCS)) - oce.add(keys=PowerOpCodes.STAR_TRACKER_ON, info=info_on_pdu1(Pdu1InfoBase.STR)) - oce.add(keys=PowerOpCodes.STAR_TRACKER_OFF, info=info_off_pdu1(Pdu1InfoBase.STR)) - oce.add(keys=PowerOpCodes.SUS_N_ON, info=info_on_pdu1(Pdu1InfoBase.SUS_N)) - oce.add(keys=PowerOpCodes.SUS_N_OFF, info=info_off_pdu1(Pdu1InfoBase.SUS_N)) - oce.add(keys=PowerOpCodes.ACS_A_ON, info=info_on_pdu1(Pdu1InfoBase.ACS_A)) - oce.add(keys=PowerOpCodes.ACS_A_OFF, info=info_off_pdu1(Pdu1InfoBase.ACS_A)) - oce.add(keys=PowerOpCodes.SYRLINKS_ON, info=info_on_pdu1(Pdu1InfoBase.SYRLINKS)) - oce.add(keys=PowerOpCodes.SYRLINKS_OFF, info=info_off_pdu1(Pdu1InfoBase.SYRLINKS)) - oce.add(keys=PowerOpCodes.MGT_ON, info=info_on_pdu1(Pdu1InfoBase.MGT)) - oce.add(keys=PowerOpCodes.MGT_OFF, info=info_off_pdu1(Pdu1InfoBase.MGT)) - oce.add(keys=PowerOpCodes.PLOC_ON, info=info_on_pdu1(Pdu1InfoBase.PLOC)) - oce.add(keys=PowerOpCodes.PLOC_OFF, info=info_off_pdu1(Pdu1InfoBase.PLOC)) - oce.add(keys=PowerOpCodes.SCEX_ON, info=info_on_pdu1(Pdu1InfoBase.SCEX)) - oce.add(keys=PowerOpCodes.SCEX_OFF, info=info_off_pdu1(Pdu1InfoBase.SCEX)) - - -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 pdu1_cmds(q: DefaultPusQueueHelper, op_code: str): - if op_code in PowerOpCodes.TCS_ON: - tcs_on_cmd(q) - elif op_code in PowerOpCodes.TCS_OFF: - tcs_off_cmd(q) - elif op_code in PowerOpCodes.SYRLINKS_ON: - syrlinks_on_cmd(q) - elif op_code in PowerOpCodes.SYRLINKS_OFF: - syrlinks_off_cmd(q) - elif op_code in PowerOpCodes.STAR_TRACKER_ON: - startracker_on_cmd(q) - elif op_code in PowerOpCodes.STAR_TRACKER_OFF: - startracker_off_cmd(q) - elif op_code in PowerOpCodes.MGT_ON: - mgt_on_cmd(q) - elif op_code in PowerOpCodes.MGT_OFF: - mgt_off_cmd(q) - elif op_code in PowerOpCodes.SUS_N_ON: - sun_sensor_nominal_on_cmd(q) - elif op_code in PowerOpCodes.SUS_N_OFF: - sun_sensor_nominal_off_cmd(q) - elif op_code in PowerOpCodes.SCEX_ON: - solar_cell_experiment_on_cmd(q) - elif op_code in PowerOpCodes.SCEX_OFF: - solar_cell_experiment_off_cmd(q) - elif op_code in PowerOpCodes.PLOC_ON: - ploc_on_cmd(q) - elif op_code in PowerOpCodes.PLOC_OFF: - ploc_off_cmd(q) - elif op_code in PowerOpCodes.ACS_A_ON: - acs_board_a_on_cmd(q) - elif op_code in PowerOpCodes.ACS_A_OFF: - acs_board_a_off_cmd(q) - - -def pdu2_cmds(q: DefaultPusQueueHelper, op_code: str): - 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 pdu1_req_hk_cmds(q: DefaultPusQueueHelper, op_code: str): - if op_code in GomspaceOpCodes.REQUEST_CORE_HK_ONCE: - q.add_log_cmd(f"PDU1: {GsInfo.REQUEST_CORE_HK_ONCE}") - hk_sid = make_sid(object_id=PDU_1_HANDLER_ID, set_id=SetIds.PDU_1_CORE) - q.add_pus_tc(generate_one_diag_command(sid=hk_sid)) - if op_code in GomspaceOpCodes.REQUEST_AUX_HK_ONCE: - q.add_log_cmd(f"PDU1: {GsInfo.REQUEST_AUX_HK_ONCE}") - hk_sid = make_sid(object_id=PDU_1_HANDLER_ID, set_id=SetIds.PDU_1_AUX) - q.add_pus_tc(generate_one_hk_command(sid=hk_sid)) - - -def pdu2_req_hk_cmds(q: DefaultPusQueueHelper, op_code: str): - if op_code in GomspaceOpCodes.REQUEST_CORE_HK_ONCE: - q.add_log_cmd(f"PDU2: {GsInfo.REQUEST_CORE_HK_ONCE}") - hk_sid = make_sid(object_id=PDU_2_HANDLER_ID, set_id=SetIds.PDU_2_CORE) - q.add_pus_tc(generate_one_diag_command(sid=hk_sid)) - if op_code in GomspaceOpCodes.REQUEST_AUX_HK_ONCE: - q.add_log_cmd(f"PDU2: {GsInfo.REQUEST_AUX_HK_ONCE}") - hk_sid = make_sid(object_id=PDU_2_HANDLER_ID, set_id=SetIds.PDU_2_AUX) - q.add_pus_tc(generate_one_hk_command(sid=hk_sid)) - - -def tcs_on_cmd(q: DefaultPusQueueHelper): - generic_on_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.TCS, Pdu1ChIndex.TCS) - - -def tcs_off_cmd(q: DefaultPusQueueHelper): - generic_off_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.TCS, Pdu1ChIndex.TCS) - - -def syrlinks_on_cmd(q: DefaultPusQueueHelper): - generic_on_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.SYRLINKS, Pdu1ChIndex.SYRLINKS) - - -def syrlinks_off_cmd(q: DefaultPusQueueHelper): - generic_off_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.SYRLINKS, Pdu1ChIndex.SYRLINKS) - - -def startracker_on_cmd(q: DefaultPusQueueHelper): - generic_on_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.STR, Pdu1ChIndex.STR) - - -def startracker_off_cmd(q: DefaultPusQueueHelper): - generic_off_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.STR, Pdu1ChIndex.STR) - - -def mgt_on_cmd(q: DefaultPusQueueHelper): - generic_on_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.MGT, Pdu1ChIndex.MGT) - - -def mgt_off_cmd(q: DefaultPusQueueHelper): - generic_off_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.MGT, Pdu1ChIndex.MGT) - - -def sun_sensor_nominal_on_cmd(q: DefaultPusQueueHelper): - generic_on_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.SUS_N, Pdu1ChIndex.SUS_N) - - -def sun_sensor_nominal_off_cmd(q: DefaultPusQueueHelper): - generic_off_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.SUS_N, Pdu1ChIndex.SUS_N) - - -def solar_cell_experiment_on_cmd(q: DefaultPusQueueHelper): - generic_on_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.SCEX, Pdu1ChIndex.SCEX) - - -def solar_cell_experiment_off_cmd(q: DefaultPusQueueHelper): - generic_off_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.SCEX, Pdu1ChIndex.SCEX) - - -def ploc_on_cmd(q: DefaultPusQueueHelper): - generic_on_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.PLOC, Pdu1ChIndex.PLOC) - - -def ploc_off_cmd(q: DefaultPusQueueHelper): - generic_off_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.PLOC, Pdu1ChIndex.PLOC) - - -def acs_board_a_on_cmd(q: DefaultPusQueueHelper): - generic_on_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.ACS_A, Pdu1ChIndex.ACS_A) - - -def acs_board_a_off_cmd(q: DefaultPusQueueHelper): - generic_on_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.ACS_A, Pdu1ChIndex.ACS_A) - - -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 reaction_wheel_off_cmd(q: DefaultPusQueueHelper): - generic_off_cmd(PDU_2_HANDLER_ID, q, Pdu2InfoBase.RW, Pdu2ChIndex.RW) - - -def heater_on_cmd(q: DefaultPusQueueHelper): - generic_on_cmd(PDU_2_HANDLER_ID, q, Pdu2InfoBase.HEATER, Pdu2ChIndex.HEATER) - - -def heater_off_cmd(q: DefaultPusQueueHelper): - generic_off_cmd(PDU_2_HANDLER_ID, q, Pdu2InfoBase.HEATER, Pdu2ChIndex.HEATER) - - -def sus_red_on_cmd(q: DefaultPusQueueHelper): - generic_on_cmd(PDU_2_HANDLER_ID, q, Pdu2InfoBase.SUS_R, 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 solar_array_deployment_on_cmd(q: DefaultPusQueueHelper): - generic_on_cmd( - PDU_2_HANDLER_ID, q, Pdu2InfoBase.SOLAR_ARRAY_DEPL, 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 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 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 acs_board_b_side_on_cmd(q: DefaultPusQueueHelper): - generic_on_cmd(PDU_2_HANDLER_ID, q, Pdu2InfoBase.ACS_B, 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 payload_camera_on_cmd(q: DefaultPusQueueHelper): - generic_on_cmd(PDU_2_HANDLER_ID, q, Pdu2InfoBase.PL_CAM, 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 generic_on_cmd( - object_id: bytes, q: DefaultPusQueueHelper, info_str: str, out_idx: int -): - q.add_log_cmd(info_str + " on") - q.add_pus_tc( - pack_set_param_command( - object_id, - PDU_CONFIG_LIST[out_idx].parameter_address, - PDU_CONFIG_LIST[out_idx].parameter_size, - Channel.on, - ) - ) - - -def generic_off_cmd( - object_id: bytes, q: DefaultPusQueueHelper, info_str: str, out_idx: int -): - q.add_log_cmd(info_str + " off") - q.add_pus_tc( - pack_set_param_command( - object_id, - PDU_CONFIG_LIST[out_idx].parameter_address, - PDU_CONFIG_LIST[out_idx].parameter_size, - Channel.off, - ) - ) - - -def handle_get_param_data_reply( - action_id: int, pw: PrintWrapper, custom_data: bytearray -): - if action_id == GomspaceDeviceActionIds.PARAM_GET: - header_list = [ - "Gomspace action ID", - "Table ID", - "Memory Address", - "Payload length", - "Payload", - ] - fmt_str = "!BBHH" - (action, table_id, address, payload_length) = struct.unpack( - fmt_str, custom_data[:6] - ) - content_list = [ - action, - table_id, - hex(address), - payload_length, - "0x" + custom_data[6:].hex(), - ] - pw.dlog(f"{header_list}") - pw.dlog(f"{content_list}") diff --git a/pus_tc/devs/pdu1.py b/pus_tc/devs/pdu1.py deleted file mode 100644 index 15d428b..0000000 --- a/pus_tc/devs/pdu1.py +++ /dev/null @@ -1,115 +0,0 @@ -# -*- coding: utf-8 -*- -"""PDU1 is mounted on the X2 slot of the P60 dock -@author J. Meier -@date 17.12.2020 -""" -import gomspace.gomspace_common as gs -from pus_tc.devs.common_power import pdu1_cmds, pdu1_req_hk_cmds - -from tmtccmd.tc import DefaultPusQueueHelper -from tmtccmd.tc.pus_3_fsfw_hk import ( - generate_one_hk_command, - make_sid, - generate_one_diag_command, -) -from gomspace.gomspace_common import * -from gomspace.gomspace_pdu_definitions import * -from config.object_ids import PDU_1_HANDLER_ID - - -class PDU1TestProcedure: - """ - @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 - ping = False - read_temperature = False - turn_channel_2_on = False # Star Tracker connected to this channel (5V) - turn_channel_2_off = False - turn_channel_3_on = False # MTQ connected to this channel (5V) - turn_channel_3_off = False - - -def pack_pdu1_commands(object_id: ObjectIdU32, q: DefaultPusQueueHelper, op_code: str): - q.add_log_cmd("Commanding PDU1") - objb = object_id.as_bytes - pdu1_cmds(q, op_code) - pdu1_req_hk_cmds(q, op_code) - if op_code in GomspaceOpCodes.PRINT_SWITCH_V_I: - q.add_log_cmd("PDU1: Print Switches, Voltages, Currents") - q.add_pus_tc( - make_fsfw_action_cmd( - object_id=objb, action_id=GomspaceDeviceActionIds.PRINT_SWITCH_V_I - ) - ) - if op_code in GomspaceOpCodes.PRINT_LATCHUPS: - q.add_log_cmd("PDU1: Print Latchups") - q.add_pus_tc( - make_fsfw_action_cmd( - object_id=objb, action_id=GomspaceDeviceActionIds.PRINT_LATCHUPS - ) - ) - if op_code in GomspaceOpCodes.SET_PARAM: - q.add_log_cmd(f"PDU1: {GsInfo.SET_PARAMETER}") - prompt_and_pack_set_param_command(q, object_id) - if op_code in GomspaceOpCodes.GET_PARAM: - q.add_log_cmd(f"PDU1: {GsInfo.GET_PARAMETER}") - gs.prompt_and_pack_get_param_command(q, object_id) - if PDU1TestProcedure.all or PDU1TestProcedure.ping: - q.add_log_cmd("PDU1: 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 PDU1TestProcedure.all or PDU1TestProcedure.read_temperature: - q.add_log_cmd("PDU1: Testing temperature reading") - q.add_pus_tc( - pack_get_param_command( - objb, - TableIds.hk, - PduHkTable.temperature.parameter_address, - PduHkTable.temperature.parameter_size, - ) - ) - if PDU1TestProcedure.all or PDU1TestProcedure.turn_channel_2_on: - q.add_log_cmd("PDU1: Turn channel 2 on (Star Tracker)") - q.add_pus_tc( - pack_set_param_command( - objb, - PduConfigTable.out_en_2.parameter_address, - PduConfigTable.out_en_2.parameter_size, - Channel.on, - ) - ) - if PDU1TestProcedure.all or PDU1TestProcedure.turn_channel_2_off: - q.add_log_cmd("PDU1: Turn channel 2 off (Star Tracker)") - q.add_pus_tc( - pack_set_param_command( - objb, - PduConfigTable.out_en_2.parameter_address, - PduConfigTable.out_en_2.parameter_size, - Channel.off, - ) - ) - if PDU1TestProcedure.all or PDU1TestProcedure.turn_channel_3_on: - q.add_log_cmd("PDU1: Turn channel 3 on (MTQ)") - q.add_pus_tc( - pack_set_param_command( - objb, - PduConfigTable.out_en_3.parameter_address, - PduConfigTable.out_en_3.parameter_size, - Channel.on, - ) - ) - if PDU1TestProcedure.all or PDU1TestProcedure.turn_channel_3_off: - q.add_log_cmd("PDU1: Turn channel 3 off (MTQ)") - q.add_pus_tc( - pack_set_param_command( - objb, - PduConfigTable.out_en_3.parameter_address, - PduConfigTable.out_en_3.parameter_size, - Channel.off, - ) - ) diff --git a/pus_tc/devs/pdu2.py b/pus_tc/devs/pdu2.py deleted file mode 100644 index 367b791..0000000 --- a/pus_tc/devs/pdu2.py +++ /dev/null @@ -1,138 +0,0 @@ -# -*- 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 -""" -from pus_tc.devs.common_power import pdu2_cmds, pdu2_req_hk_cmds -from gomspace.gomspace_common import * -from gomspace.gomspace_pdu_definitions import * - - -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, op_code: str): - q.add_log_cmd("Testing PDU2") - objb = object_id.as_bytes - pdu2_cmds(q, op_code) - pdu2_req_hk_cmds(q, op_code) - if op_code in GomspaceOpCodes.PRINT_SWITCH_V_I: - q.add_log_cmd(f"PDU2: {GsInfo.PRINT_SWITCH_V_I}") - q.add_pus_tc( - make_fsfw_action_cmd( - object_id=objb, action_id=GomspaceDeviceActionIds.PRINT_SWITCH_V_I - ) - ) - if op_code in GomspaceOpCodes.PRINT_LATCHUPS: - q.add_log_cmd("PDU2: Print Latchups") - q.add_pus_tc( - make_fsfw_action_cmd( - object_id=objb, action_id=GomspaceDeviceActionIds.PRINT_LATCHUPS - ) - ) - if op_code in GomspaceOpCodes.SET_PARAM: - q.add_log_cmd(f"PDU2: {GsInfo.SET_PARAMETER}") - prompt_and_pack_set_param_command(q, object_id) - if op_code in GomspaceOpCodes.GET_PARAM: - q.add_log_cmd(f"PDU2: {GsInfo.GET_PARAMETER}") - prompt_and_pack_get_param_command(q, object_id) - 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.channel_2_on: - q.add_log_cmd("PDU2: Testing setting output channel 2 on (TCS Heater)") - q.add_pus_tc( - pack_set_param_command( - objb, - PduConfigTable.out_en_2.parameter_address, - PduConfigTable.out_en_2.parameter_size, - Channel.on, - ) - ) - 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.channel_2_off: - q.add_log_cmd("PDU2: Testing setting output channel 2 off") - q.add_pus_tc( - pack_set_param_command( - objb, - PduConfigTable.out_en_2.parameter_address, - PduConfigTable.out_en_2.parameter_size, - Channel.off, - ) - ) - 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)) diff --git a/pus_tc/procedure_packer.py b/pus_tc/procedure_packer.py index 9fe7a06..5bf3bd7 100644 --- a/pus_tc/procedure_packer.py +++ b/pus_tc/procedure_packer.py @@ -2,7 +2,7 @@ """ from typing import cast -from pus_tc.devs.power import pack_power_commands +from tmtc.power.power import pack_power_commands from pus_tc.devs.rtd import pack_rtd_commands from pus_tc.devs.scex import pack_scex_cmds from pus_tc.system.controllers import ( @@ -23,14 +23,13 @@ from tmtccmd.tc.pus_5_event import ( from tmtccmd.pus.pus_17_test import pack_service_17_ping_command from pus_tc.service_200_mode import pack_service_200_test_into -from pus_tc.devs.p60dock import pack_p60dock_cmds -from pus_tc.devs.pdu2 import pack_pdu2_commands -from pus_tc.devs.pdu1 import pack_pdu1_commands -from pus_tc.devs.acu import pack_acu_commands +from tmtc.power.p60dock import pack_p60dock_cmds +from tmtc.power.pdu2 import pack_pdu2_commands +from tmtc.power.pdu1 import pack_pdu1_commands +from tmtc.power.acu import pack_acu_commands from pus_tc.devs.solar_array_deployment import pack_solar_array_deployment_test_into from pus_tc.devs.imtq import pack_imtq_test_into from pus_tc.devs.tmp1075 import pack_tmp1075_test_into -from tmtc.ploc_mpsoc import pack_ploc_mpsoc_commands from pus_tc.devs.heater import pack_heater_cmds from pus_tc.devs.reaction_wheels import pack_single_rw_test_into, pack_rw_ass_cmds from pus_tc.devs.rad_sensor import pack_rad_sensor_test_into @@ -55,7 +54,6 @@ from config.object_ids import ( TMP_1075_2_HANDLER_ID, HEATER_ID, IMTQ_HANDLER_ID, - PLOC_MPSOC_ID, RW1_ID, RW2_ID, RW3_ID, diff --git a/pus_tc/system/core.py b/pus_tc/system/core.py index 30a93c2..565f7e0 100644 --- a/pus_tc/system/core.py +++ b/pus_tc/system/core.py @@ -250,6 +250,6 @@ def perform_reboot_cmd( make_fsfw_action_cmd( object_id=CORE_CONTROLLER_ID, action_id=ActionIds.XSC_REBOOT, - user_data=tc_data + user_data=tc_data, ) ) diff --git a/pus_tm/action_reply_handler.py b/pus_tm/action_reply_handler.py index b7077b3..520ae26 100644 --- a/pus_tm/action_reply_handler.py +++ b/pus_tm/action_reply_handler.py @@ -1,11 +1,11 @@ import struct from config.object_ids import * -from pus_tc.devs.common_power import handle_get_param_data_reply from pus_tc.devs.imtq import ImtqActionIds from pus_tm.defs import PrintWrapper from tmtc.ploc_mpsoc import PlocReplyIds from tmtc.ploc_supervisor import SupvActionIds from pus_tc.devs.star_tracker import StarTrackerActionIds +from tmtc.power.tm import handle_get_param_data_reply from tmtccmd.logging import get_console_logger from tmtccmd.tm import Service8FsfwTm from tmtccmd.util.tmtc_printer import FsfwTmTcPrinter @@ -43,7 +43,7 @@ def handle_action_reply( PDU_2_HANDLER_ID, P60_DOCK_HANDLER, ]: - return handle_get_param_data_reply(action_id, pw, custom_data) + return handle_get_param_data_reply(object_id, action_id, pw, custom_data) else: pw.dlog(f"No dedicated action reply handler found for reply from {object_id}") pw.dlog(f"Raw Data: {tm_packet.custom_data.hex(sep=',')}") diff --git a/pus_tm/hk_handling.py b/pus_tm/hk_handling.py index 395f274..b84e430 100644 --- a/pus_tm/hk_handling.py +++ b/pus_tm/hk_handling.py @@ -23,7 +23,7 @@ from pus_tm.devs.imtq_mgt import ( handle_calibrated_mtm_measurement, handle_raw_mtm_measurement, ) -from pus_tm.system.power import handle_pdu_data, handle_p60_hk_data, handle_acu_hk_data +from tmtc.power.tm import handle_pdu_data, handle_p60_hk_data, handle_acu_hk_data from pus_tm.devs.syrlinks import handle_syrlinks_hk_data from pus_tc.devs.imtq import ImtqSetIds from pus_tm.devs.reaction_wheels import handle_rw_hk_data diff --git a/tmtc/power/__init__.py b/tmtc/power/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pus_tc/devs/acu.py b/tmtc/power/acu.py similarity index 78% rename from pus_tc/devs/acu.py rename to tmtc/power/acu.py index 1070598..12fe28b 100644 --- a/pus_tc/devs/acu.py +++ b/tmtc/power/acu.py @@ -3,9 +3,13 @@ @author J. Meier, R. Mueller @date 21.12.2020 """ -import struct from config.definitions import CustomServiceList +from tmtc.power.common_power import ( + add_gomspace_cmds, + add_gomspace_cmd_defs, + req_hk_cmds, +) from tmtccmd.config import TmtcDefinitionWrapper, OpCodeEntry from tmtccmd.config.tmtc import tmtc_definitions_provider @@ -19,7 +23,7 @@ import gomspace.gomspace_common as gs from gomspace.gomspace_common import GomspaceOpCodes from gomspace.gomspace_common import GsInfo as GsInfo from config.object_ids import ACU_HANDLER_ID -from pus_tc.devs.p60dock import P60DockConfigTable +from tmtc.power.p60dock import P60DockConfigTable from tmtccmd.tc.pus_8_funccmd import make_fsfw_action_cmd from tmtccmd.util import ObjectIdU32 @@ -52,26 +56,8 @@ class Info: @tmtc_definitions_provider def add_acu_cmds(defs: TmtcDefinitionWrapper): oce = OpCodeEntry() - oce.add( - keys=GomspaceOpCodes.REQUEST_CORE_HK_ONCE, - info=GsInfo.REQUEST_CORE_HK_ONCE, - ) - oce.add( - keys=GomspaceOpCodes.REQUEST_AUX_HK_ONCE, - info=GsInfo.REQUEST_AUX_HK_ONCE, - ) - oce.add( - keys=GomspaceOpCodes.REQUEST_AUX_HK_ONCE, - info=GsInfo.REQUEST_AUX_HK_ONCE, - ) - oce.add( - keys=GomspaceOpCodes.GET_PARAM, - info=GsInfo.GET_PARAMETER, - ) - oce.add( - keys=GomspaceOpCodes.SET_PARAM, - info=GsInfo.SET_PARAMETER, - ) + add_gomspace_cmd_defs(oce) + oce.add(keys=OpCodes.TEST, info=Info.TEST) defs.add_service( name=CustomServiceList.ACU.value, @@ -82,31 +68,17 @@ def add_acu_cmds(defs: TmtcDefinitionWrapper): def pack_acu_commands(object_id: ObjectIdU32, q: DefaultPusQueueHelper, op_code: str): q.add_log_cmd("Handling ACU command") - if op_code in GomspaceOpCodes.PRINT_SWITCH_V_I: - q.add_log_cmd("ACU: Print channel stats") - q.add_pus_tc( - make_fsfw_action_cmd( - object_id=object_id.as_bytes, - action_id=gs.GomspaceDeviceActionIds.PRINT_SWITCH_V_I, - ) - ) - if op_code in GomspaceOpCodes.REQUEST_CORE_HK_ONCE: - q.add_log_cmd(f"ACU: {GsInfo.REQUEST_CORE_HK_ONCE}") - hk_sid = make_sid(object_id=object_id.as_bytes, set_id=gs.SetIds.ACU_CORE) - q.add_pus_tc(generate_one_diag_command(sid=hk_sid)) - if op_code in GomspaceOpCodes.REQUEST_AUX_HK_ONCE: - q.add_log_cmd(f"ACU: {GsInfo.REQUEST_AUX_HK_ONCE}") - hk_sid = make_sid(object_id=object_id.as_bytes, set_id=gs.SetIds.ACU_AUX) - q.add_pus_tc(generate_one_hk_command(sid=hk_sid)) - if op_code in GomspaceOpCodes.GET_PARAM: - q.add_log_cmd(f"ACU: {GsInfo.GET_PARAMETER}") - gs.prompt_and_pack_get_param_command(q, object_id) - if op_code in GomspaceOpCodes.SET_PARAM: - q.add_log_cmd(f"ACU: {GsInfo.SET_PARAMETER}") - gs.prompt_and_pack_set_param_command(q, object_id) + add_gomspace_cmds("ACU", object_id, q, op_code) + acu_req_hk_cmds(q, op_code) pack_test_cmds(object_id=object_id, q=q) +def acu_req_hk_cmds(q: DefaultPusQueueHelper, op_code: str): + req_hk_cmds( + "ACU", q, op_code, ACU_HANDLER_ID, [gs.SetIds.ACU_CORE, gs.SetIds.ACU_AUX] + ) + + class ACUTestProcedure: """ @brief Use this class to define the tests to perform for the ACU. diff --git a/tmtc/power/common_power.py b/tmtc/power/common_power.py new file mode 100644 index 0000000..3b45874 --- /dev/null +++ b/tmtc/power/common_power.py @@ -0,0 +1,157 @@ +from gomspace.gomspace_common import ( + pack_set_param_command, + Channel, + GomspaceOpCodes, + GsInfo, + GomspaceDeviceActionIds, + prompt_and_pack_set_param_command, + prompt_and_pack_get_param_command, + pack_request_config_command, +) +from gomspace.gomspace_pdu_definitions import PDU_CONFIG_LIST +from tmtccmd.config import OpCodeEntry +from tmtccmd.tc import DefaultPusQueueHelper +from tmtccmd.tc.pus_3_fsfw_hk import ( + make_sid, + generate_one_diag_command, + generate_one_hk_command, +) +from tmtccmd.tc.pus_8_funccmd import make_fsfw_action_cmd +from tmtccmd.util import ObjectIdU32 + + +class PowerInfo: + INFO_CORE = "Core Information" + INFO_AUX = "Auxiliary Information" + INFO_ALL = "All Information" + + +class PowerOpCodes: + # PDU 1 + TCS_ON = ["tcs-on"] + TCS_OFF = ["tcs-off"] + SYRLINKS_ON = ["syrlinks-on"] + SYRLINKS_OFF = ["syrlinks-off"] + STAR_TRACKER_ON = ["str-on"] + STAR_TRACKER_OFF = ["str-off"] + MGT_ON = ["mgt-on"] + MGT_OFF = ["mgt-off"] + SUS_N_ON = ["sus-nom-on"] + SUS_N_OFF = ["sus-nom-off"] + SCEX_ON = ["scex-on"] + SCEX_OFF = ["scex-off"] + PLOC_ON = ["ploc-on"] + PLOC_OFF = ["ploc-off"] + ACS_A_ON = ["acs-a-on"] + ACS_A_OFF = ["acs-a-off"] + + # PDU 2 + PL_PCDU_VBAT_NOM_ON = ["plpcdu-vbat-nom-on"] + PL_PCDU_VBAT_NOM_OFF = ["plpcdu-vbat-nom-off"] + RW_ON = ["rw-on"] + RW_OFF = ["rw-off"] + HEATER_ON = ["heater-on"] + HEATER_OFF = ["heater-off"] + SUS_R_ON = ["sus-red-on"] + SUS_R_OFF = ["sus-red-off"] + SOLAR_ARRAY_DEPL_ON = ["sa-depl-on"] + SOLAR_ARRAY_DEPL_OFF = ["sa-depl-off"] + PL_PCDU_VBAT_RED_ON = ["plpcdu-vbat-red-on"] + PL_PCDU_VBAT_RED_OFF = ["plpcdu-vbat-red-off"] + ACS_B_ON = ["acs-b-on"] + ACS_B_OFF = ["acs-b-off"] + PL_CAM_ON = ["cam-on"] + PL_CAM_OFF = ["cam-off"] + + INFO_CORE = ["info"] + INFO_AUX = ["info-aux"] + INFO_ALL = ["info-all"] + + +def add_gomspace_cmds( + prefix: str, object_id: ObjectIdU32, q: DefaultPusQueueHelper, op_code: str +): + objb = object_id.as_bytes + if op_code in GomspaceOpCodes.PRINT_SWITCH_V_I: + q.add_log_cmd(f"{prefix}: {GsInfo.PRINT_SWITCH_V_I}") + q.add_pus_tc( + make_fsfw_action_cmd( + object_id=objb, action_id=GomspaceDeviceActionIds.PRINT_SWITCH_V_I + ) + ) + if op_code in GomspaceOpCodes.PRINT_LATCHUPS: + q.add_log_cmd(f"{prefix}: {GsInfo.PRINT_LATCHUPS}") + q.add_pus_tc( + make_fsfw_action_cmd( + object_id=objb, action_id=GomspaceDeviceActionIds.PRINT_LATCHUPS + ) + ) + if op_code in GomspaceOpCodes.SET_PARAM: + q.add_log_cmd(f"{prefix}: {GsInfo.SET_PARAMETER}") + prompt_and_pack_set_param_command(q, object_id) + if op_code in GomspaceOpCodes.GET_PARAM: + q.add_log_cmd(f"{prefix}: {GsInfo.GET_PARAMETER}") + prompt_and_pack_get_param_command(q, object_id) + if op_code in GomspaceOpCodes.REQUEST_CONFIG_TABLE: + q.add_log_cmd(f"{prefix}: {GsInfo.REQUEST_CONFIG_TABLE}") + q.add_pus_tc(pack_request_config_command(object_id.as_bytes)) + + +def req_hk_cmds( + prefix: str, + q: DefaultPusQueueHelper, + op_code: str, + obj_id: bytes, + set_id_pair: [int, int], +): + if op_code in GomspaceOpCodes.REQUEST_CORE_HK_ONCE: + q.add_log_cmd(f"{prefix}: {GsInfo.REQUEST_CORE_HK_ONCE}") + hk_sid = make_sid(object_id=obj_id, set_id=set_id_pair[0]) + q.add_pus_tc(generate_one_diag_command(sid=hk_sid)) + if op_code in GomspaceOpCodes.REQUEST_AUX_HK_ONCE: + q.add_log_cmd(f"{prefix}: {GsInfo.REQUEST_AUX_HK_ONCE}") + hk_sid = make_sid(object_id=obj_id, set_id=set_id_pair[1]) + q.add_pus_tc(generate_one_hk_command(sid=hk_sid)) + + +def generic_on_cmd( + object_id: bytes, q: DefaultPusQueueHelper, info_str: str, out_idx: int +): + q.add_log_cmd(info_str + " on") + q.add_pus_tc( + pack_set_param_command( + object_id, + PDU_CONFIG_LIST[out_idx].parameter_address, + PDU_CONFIG_LIST[out_idx].parameter_size, + Channel.on, + ) + ) + + +def generic_off_cmd( + object_id: bytes, q: DefaultPusQueueHelper, info_str: str, out_idx: int +): + q.add_log_cmd(info_str + " off") + q.add_pus_tc( + pack_set_param_command( + object_id, + PDU_CONFIG_LIST[out_idx].parameter_address, + PDU_CONFIG_LIST[out_idx].parameter_size, + Channel.off, + ) + ) + + +def add_gomspace_cmd_defs(oce: OpCodeEntry): + oce.add( + keys=GomspaceOpCodes.REQUEST_CORE_HK_ONCE, + info=GsInfo.REQUEST_CORE_HK_ONCE, + ) + oce.add( + keys=GomspaceOpCodes.REQUEST_AUX_HK_ONCE, + info=GsInfo.REQUEST_AUX_HK_ONCE, + ) + oce.add(keys=GomspaceOpCodes.GET_PARAM, info=GsInfo.GET_PARAMETER) + oce.add(keys=GomspaceOpCodes.PRINT_LATCHUPS, info=GsInfo.PRINT_LATCHUPS) + oce.add(keys=GomspaceOpCodes.SET_PARAM, info=GsInfo.SET_PARAMETER) + oce.add(keys=GomspaceOpCodes.REQUEST_CONFIG_TABLE, info=GsInfo.REQUEST_CONFIG_TABLE) diff --git a/pus_tc/devs/p60dock.py b/tmtc/power/p60dock.py similarity index 88% rename from pus_tc/devs/p60dock.py rename to tmtc/power/p60dock.py index e460862..d4bcc01 100644 --- a/pus_tc/devs/p60dock.py +++ b/tmtc/power/p60dock.py @@ -5,11 +5,9 @@ @author J. Meier @date 13.12.2020 """ +from tmtc.power.common_power import add_gomspace_cmds, req_hk_cmds from tmtccmd.tc import DefaultPusQueueHelper -from tmtccmd.tc.pus_3_fsfw_hk import generate_one_hk_command, make_sid from gomspace.gomspace_common import ( - GsInfo, - GomspaceOpCodes, TableEntry, Channel, pack_set_param_command, @@ -17,12 +15,10 @@ from gomspace.gomspace_common import ( pack_get_param_command, pack_gnd_wdt_reset_command, pack_ping_command, - GomspaceDeviceActionIds, pack_reboot_command, SetIds, ) from config.object_ids import P60_DOCK_HANDLER -from tmtccmd.tc.pus_8_funccmd import make_fsfw_action_cmd from tmtccmd.util import ObjectIdU32 @@ -99,6 +95,8 @@ class P60DockHkTable: def pack_p60dock_cmds(object_id: ObjectIdU32, q: DefaultPusQueueHelper, op_code: str): objb = object_id.as_bytes + add_gomspace_cmds("P60 Dock", object_id, q, op_code) + p60_dock_req_hk_cmds(q, op_code) if op_code in P60OpCodes.STACK_3V3_ON: q.add_log_cmd(P60Info.STACK_3V3_ON) q.add_pus_tc( @@ -139,28 +137,6 @@ def pack_p60dock_cmds(object_id: ObjectIdU32, q: DefaultPusQueueHelper, op_code: Channel.off, ) ) - if op_code in GomspaceOpCodes.REQUEST_CORE_HK_ONCE: - q.add_log_cmd("P60 Dock: Requesting HK Core HK Once") - hk_sid = make_sid(object_id=P60_DOCK_HANDLER, set_id=SetIds.P60_CORE) - q.add_pus_tc(generate_one_hk_command(sid=hk_sid)) - if op_code in GomspaceOpCodes.REQUEST_AUX_HK_ONCE: - q.add_log_cmd("P60 Dock: Requesting HK Aux HK Once") - hk_sid = make_sid(object_id=P60_DOCK_HANDLER, set_id=SetIds.P60_AUX) - q.add_pus_tc(generate_one_hk_command(sid=hk_sid)) - if op_code in GomspaceOpCodes.PRINT_SWITCH_V_I: - q.add_log_cmd("P60 Dock: Print Switches, Voltages, Currents") - q.add_pus_tc( - make_fsfw_action_cmd( - object_id=objb, action_id=GomspaceDeviceActionIds.PRINT_SWITCH_V_I - ) - ) - if op_code in GomspaceOpCodes.PRINT_LATCHUPS: - q.add_log_cmd("P60 Dock: Print Latchups") - q.add_pus_tc( - make_fsfw_action_cmd( - object_id=objb, action_id=GomspaceDeviceActionIds.PRINT_LATCHUPS - ) - ) if P60DockTestProcedure.all or P60DockTestProcedure.reboot: q.add_log_cmd("P60 Dock: Reboot") q.add_pus_tc(pack_reboot_command(object_id)) @@ -287,3 +263,9 @@ def pack_p60dock_cmds(object_id: ObjectIdU32, q: DefaultPusQueueHelper, op_code: parameter, ) ) + + +def p60_dock_req_hk_cmds(q: DefaultPusQueueHelper, op_code: str): + req_hk_cmds( + "P60 Dock", q, op_code, P60_DOCK_HANDLER, [SetIds.P60_CORE, SetIds.P60_AUX] + ) diff --git a/tmtc/power/pdu1.py b/tmtc/power/pdu1.py new file mode 100644 index 0000000..c846a1c --- /dev/null +++ b/tmtc/power/pdu1.py @@ -0,0 +1,250 @@ +# -*- coding: utf-8 -*- +"""PDU1 is mounted on the X2 slot of the P60 dock +@author J. Meier +@date 17.12.2020 +""" +from config.object_ids import PDU_1_HANDLER_ID +from tmtc.power.common_power import ( + add_gomspace_cmds, + req_hk_cmds, + PowerOpCodes, + generic_on_cmd, + generic_off_cmd, +) + +from gomspace.gomspace_common import * +from gomspace.gomspace_pdu_definitions import * +from tmtccmd.config import OpCodeEntry + + +class Pdu1InfoBase: + TCS = "Switch TCS Board" + SYRLINKS = "Switch Syrlinks (COM)" + STR = "Switch Startracker" + MGT = "Switch Magnetorquer" + SUS_N = "Switch Sun Sensor Board Nominal" + SCEX = "Switch Solar Cell Experiment" + PLOC = "Switch Payload On-Board Computer" + ACS_A = "Switch ACS Board A-Side" + + +class Pdu1ChIndex(enum.IntEnum): + TCS = 0 + SYRLINKS = 1 + STR = 2 + MGT = 3 + SUS_N = 4 + SCEX = 5 + PLOC = 6 + ACS_A = 7 + + +class PDU1TestProcedure: + """ + @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 + ping = False + read_temperature = False + turn_channel_2_on = False # Star Tracker connected to this channel (5V) + turn_channel_2_off = False + turn_channel_3_on = False # MTQ connected to this channel (5V) + turn_channel_3_off = False + + +def pack_pdu1_commands(object_id: ObjectIdU32, q: DefaultPusQueueHelper, op_code: str): + q.add_log_cmd("Commanding PDU1") + objb = object_id.as_bytes + pdu1_cmds(q, op_code) + pdu1_req_hk_cmds(q, op_code) + add_gomspace_cmds("PDU1", object_id, q, op_code) + if PDU1TestProcedure.all or PDU1TestProcedure.ping: + q.add_log_cmd("PDU1: 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 PDU1TestProcedure.all or PDU1TestProcedure.read_temperature: + q.add_log_cmd("PDU1: Testing temperature reading") + q.add_pus_tc( + pack_get_param_command( + objb, + TableIds.hk, + PduHkTable.temperature.parameter_address, + PduHkTable.temperature.parameter_size, + ) + ) + if PDU1TestProcedure.all or PDU1TestProcedure.turn_channel_2_on: + q.add_log_cmd("PDU1: Turn channel 2 on (Star Tracker)") + q.add_pus_tc( + pack_set_param_command( + objb, + PduConfigTable.out_en_2.parameter_address, + PduConfigTable.out_en_2.parameter_size, + Channel.on, + ) + ) + if PDU1TestProcedure.all or PDU1TestProcedure.turn_channel_2_off: + q.add_log_cmd("PDU1: Turn channel 2 off (Star Tracker)") + q.add_pus_tc( + pack_set_param_command( + objb, + PduConfigTable.out_en_2.parameter_address, + PduConfigTable.out_en_2.parameter_size, + Channel.off, + ) + ) + if PDU1TestProcedure.all or PDU1TestProcedure.turn_channel_3_on: + q.add_log_cmd("PDU1: Turn channel 3 on (MTQ)") + q.add_pus_tc( + pack_set_param_command( + objb, + PduConfigTable.out_en_3.parameter_address, + PduConfigTable.out_en_3.parameter_size, + Channel.on, + ) + ) + if PDU1TestProcedure.all or PDU1TestProcedure.turn_channel_3_off: + q.add_log_cmd("PDU1: Turn channel 3 off (MTQ)") + q.add_pus_tc( + pack_set_param_command( + objb, + PduConfigTable.out_en_3.parameter_address, + PduConfigTable.out_en_3.parameter_size, + Channel.off, + ) + ) + + +def pdu1_req_hk_cmds(q: DefaultPusQueueHelper, op_code: str): + req_hk_cmds( + "PDU1", q, op_code, PDU_1_HANDLER_ID, [SetIds.PDU_1_CORE, SetIds.PDU_1_AUX] + ) + + +def info_on_pdu1(base: str) -> str: + return "PDU1: " + base + " on" + + +def info_off_pdu1(base: str) -> str: + return "PDU1: " + base + " off" + + +def pdu1_cmds(q: DefaultPusQueueHelper, op_code: str): + if op_code in PowerOpCodes.TCS_ON: + tcs_on_cmd(q) + elif op_code in PowerOpCodes.TCS_OFF: + tcs_off_cmd(q) + elif op_code in PowerOpCodes.SYRLINKS_ON: + syrlinks_on_cmd(q) + elif op_code in PowerOpCodes.SYRLINKS_OFF: + syrlinks_off_cmd(q) + elif op_code in PowerOpCodes.STAR_TRACKER_ON: + startracker_on_cmd(q) + elif op_code in PowerOpCodes.STAR_TRACKER_OFF: + startracker_off_cmd(q) + elif op_code in PowerOpCodes.MGT_ON: + mgt_on_cmd(q) + elif op_code in PowerOpCodes.MGT_OFF: + mgt_off_cmd(q) + elif op_code in PowerOpCodes.SUS_N_ON: + sun_sensor_nominal_on_cmd(q) + elif op_code in PowerOpCodes.SUS_N_OFF: + sun_sensor_nominal_off_cmd(q) + elif op_code in PowerOpCodes.SCEX_ON: + solar_cell_experiment_on_cmd(q) + elif op_code in PowerOpCodes.SCEX_OFF: + solar_cell_experiment_off_cmd(q) + elif op_code in PowerOpCodes.PLOC_ON: + ploc_on_cmd(q) + elif op_code in PowerOpCodes.PLOC_OFF: + ploc_off_cmd(q) + elif op_code in PowerOpCodes.ACS_A_ON: + acs_board_a_on_cmd(q) + elif op_code in PowerOpCodes.ACS_A_OFF: + acs_board_a_off_cmd(q) + + +def add_pdu1_common_defs(oce: OpCodeEntry): + oce.add(keys=PowerOpCodes.TCS_ON, info=info_on_pdu1(Pdu1InfoBase.TCS)) + oce.add(keys=PowerOpCodes.TCS_OFF, info=info_off_pdu1(Pdu1InfoBase.TCS)) + oce.add(keys=PowerOpCodes.STAR_TRACKER_ON, info=info_on_pdu1(Pdu1InfoBase.STR)) + oce.add(keys=PowerOpCodes.STAR_TRACKER_OFF, info=info_off_pdu1(Pdu1InfoBase.STR)) + oce.add(keys=PowerOpCodes.SUS_N_ON, info=info_on_pdu1(Pdu1InfoBase.SUS_N)) + oce.add(keys=PowerOpCodes.SUS_N_OFF, info=info_off_pdu1(Pdu1InfoBase.SUS_N)) + oce.add(keys=PowerOpCodes.ACS_A_ON, info=info_on_pdu1(Pdu1InfoBase.ACS_A)) + oce.add(keys=PowerOpCodes.ACS_A_OFF, info=info_off_pdu1(Pdu1InfoBase.ACS_A)) + oce.add(keys=PowerOpCodes.SYRLINKS_ON, info=info_on_pdu1(Pdu1InfoBase.SYRLINKS)) + oce.add(keys=PowerOpCodes.SYRLINKS_OFF, info=info_off_pdu1(Pdu1InfoBase.SYRLINKS)) + oce.add(keys=PowerOpCodes.MGT_ON, info=info_on_pdu1(Pdu1InfoBase.MGT)) + oce.add(keys=PowerOpCodes.MGT_OFF, info=info_off_pdu1(Pdu1InfoBase.MGT)) + oce.add(keys=PowerOpCodes.PLOC_ON, info=info_on_pdu1(Pdu1InfoBase.PLOC)) + oce.add(keys=PowerOpCodes.PLOC_OFF, info=info_off_pdu1(Pdu1InfoBase.PLOC)) + oce.add(keys=PowerOpCodes.SCEX_ON, info=info_on_pdu1(Pdu1InfoBase.SCEX)) + oce.add(keys=PowerOpCodes.SCEX_OFF, info=info_off_pdu1(Pdu1InfoBase.SCEX)) + + +def tcs_on_cmd(q: DefaultPusQueueHelper): + generic_on_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.TCS, Pdu1ChIndex.TCS) + + +def tcs_off_cmd(q: DefaultPusQueueHelper): + generic_off_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.TCS, Pdu1ChIndex.TCS) + + +def syrlinks_on_cmd(q: DefaultPusQueueHelper): + generic_on_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.SYRLINKS, Pdu1ChIndex.SYRLINKS) + + +def syrlinks_off_cmd(q: DefaultPusQueueHelper): + generic_off_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.SYRLINKS, Pdu1ChIndex.SYRLINKS) + + +def startracker_on_cmd(q: DefaultPusQueueHelper): + generic_on_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.STR, Pdu1ChIndex.STR) + + +def startracker_off_cmd(q: DefaultPusQueueHelper): + generic_off_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.STR, Pdu1ChIndex.STR) + + +def mgt_on_cmd(q: DefaultPusQueueHelper): + generic_on_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.MGT, Pdu1ChIndex.MGT) + + +def mgt_off_cmd(q: DefaultPusQueueHelper): + generic_off_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.MGT, Pdu1ChIndex.MGT) + + +def sun_sensor_nominal_on_cmd(q: DefaultPusQueueHelper): + generic_on_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.SUS_N, Pdu1ChIndex.SUS_N) + + +def sun_sensor_nominal_off_cmd(q: DefaultPusQueueHelper): + generic_off_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.SUS_N, Pdu1ChIndex.SUS_N) + + +def solar_cell_experiment_on_cmd(q: DefaultPusQueueHelper): + generic_on_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.SCEX, Pdu1ChIndex.SCEX) + + +def solar_cell_experiment_off_cmd(q: DefaultPusQueueHelper): + generic_off_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.SCEX, Pdu1ChIndex.SCEX) + + +def ploc_on_cmd(q: DefaultPusQueueHelper): + generic_on_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.PLOC, Pdu1ChIndex.PLOC) + + +def ploc_off_cmd(q: DefaultPusQueueHelper): + generic_off_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.PLOC, Pdu1ChIndex.PLOC) + + +def acs_board_a_on_cmd(q: DefaultPusQueueHelper): + generic_on_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.ACS_A, Pdu1ChIndex.ACS_A) + + +def acs_board_a_off_cmd(q: DefaultPusQueueHelper): + generic_on_cmd(PDU_1_HANDLER_ID, q, Pdu1InfoBase.ACS_A, Pdu1ChIndex.ACS_A) diff --git a/tmtc/power/pdu2.py b/tmtc/power/pdu2.py new file mode 100644 index 0000000..ef90352 --- /dev/null +++ b/tmtc/power/pdu2.py @@ -0,0 +1,311 @@ +# -*- 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 +""" +from config.object_ids import PDU_2_HANDLER_ID +from tmtc.power.common_power import ( + add_gomspace_cmds, + req_hk_cmds, + PowerOpCodes, + generic_on_cmd, + generic_off_cmd, +) +from gomspace.gomspace_common import * +from gomspace.gomspace_pdu_definitions import * +from tmtccmd.config import OpCodeEntry + + +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): + 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, op_code: str): + q.add_log_cmd("Testing PDU2") + objb = object_id.as_bytes + pdu2_cmds(q, op_code) + pdu2_req_hk_cmds(q, op_code) + add_gomspace_cmds("PDU2", object_id, q, op_code) + 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.channel_2_on: + q.add_log_cmd("PDU2: Testing setting output channel 2 on (TCS Heater)") + q.add_pus_tc( + pack_set_param_command( + objb, + PduConfigTable.out_en_2.parameter_address, + PduConfigTable.out_en_2.parameter_size, + Channel.on, + ) + ) + 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.channel_2_off: + q.add_log_cmd("PDU2: Testing setting output channel 2 off") + q.add_pus_tc( + pack_set_param_command( + objb, + PduConfigTable.out_en_2.parameter_address, + PduConfigTable.out_en_2.parameter_size, + Channel.off, + ) + ) + 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)) + + +def pdu2_cmds(q: DefaultPusQueueHelper, op_code: str): + 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, [SetIds.PDU_2_CORE, SetIds.PDU_2_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 reaction_wheel_off_cmd(q: DefaultPusQueueHelper): + generic_off_cmd(PDU_2_HANDLER_ID, q, Pdu2InfoBase.RW, Pdu2ChIndex.RW) + + +def heater_on_cmd(q: DefaultPusQueueHelper): + generic_on_cmd(PDU_2_HANDLER_ID, q, Pdu2InfoBase.HEATER, Pdu2ChIndex.HEATER) + + +def heater_off_cmd(q: DefaultPusQueueHelper): + generic_off_cmd(PDU_2_HANDLER_ID, q, Pdu2InfoBase.HEATER, Pdu2ChIndex.HEATER) + + +def sus_red_on_cmd(q: DefaultPusQueueHelper): + generic_on_cmd(PDU_2_HANDLER_ID, q, Pdu2InfoBase.SUS_R, 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 solar_array_deployment_on_cmd(q: DefaultPusQueueHelper): + generic_on_cmd( + PDU_2_HANDLER_ID, q, Pdu2InfoBase.SOLAR_ARRAY_DEPL, 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 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 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 acs_board_b_side_on_cmd(q: DefaultPusQueueHelper): + generic_on_cmd(PDU_2_HANDLER_ID, q, Pdu2InfoBase.ACS_B, 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 payload_camera_on_cmd(q: DefaultPusQueueHelper): + generic_on_cmd(PDU_2_HANDLER_ID, q, Pdu2InfoBase.PL_CAM, Pdu2ChIndex.PL_CAM) + + +def payload_camera_off_cmd(q: DefaultPusQueueHelper): + generic_off_cmd(PDU_2_HANDLER_ID, q, Pdu2InfoBase.PL_CAM, Pdu2ChIndex.PL_CAM) diff --git a/pus_tc/devs/power.py b/tmtc/power/power.py similarity index 80% rename from pus_tc/devs/power.py rename to tmtc/power/power.py index a05c0d2..2ce9643 100644 --- a/pus_tc/devs/power.py +++ b/tmtc/power/power.py @@ -1,20 +1,17 @@ -from gomspace.gomspace_common import GsInfo -from pus_tc.devs.common_power import ( +from gomspace.gomspace_common import GsInfo, GomspaceOpCodes +from tmtc.power.common_power import ( PowerOpCodes, - add_pdu1_common_defs, - add_pdu2_common_defs, PowerInfo, - pdu1_cmds, - pdu2_cmds, - pdu1_req_hk_cmds, - pdu2_req_hk_cmds, + add_gomspace_cmd_defs, ) from config.definitions import CustomServiceList +from tmtc.power.pdu1 import pdu1_req_hk_cmds, pdu1_cmds, add_pdu1_common_defs +from tmtc.power.pdu2 import pdu2_req_hk_cmds, add_pdu2_common_defs, pdu2_cmds from tmtccmd import get_console_logger from tmtccmd.config import TmtcDefinitionWrapper, OpCodeEntry -from pus_tc.devs.p60dock import P60OpCodes, GomspaceOpCodes, P60Info -from pus_tc.devs.acu import add_acu_cmds +from tmtc.power.p60dock import P60OpCodes, P60Info +from tmtc.power.acu import add_acu_cmds from tmtccmd.config.tmtc import tmtc_definitions_provider from tmtccmd.tc import DefaultPusQueueHelper @@ -50,7 +47,7 @@ def add_p60_cmds(defs: TmtcDefinitionWrapper): oce.add(keys=P60OpCodes.STACK_3V3_OFF, info=P60Info.STACK_3V3_OFF) oce.add(keys=P60OpCodes.STACK_5V_ON, info=P60Info.STACK_5V_ON) oce.add(keys=P60OpCodes.STACK_5V_OFF, info=P60Info.STACK_5V_OFF) - add_gomspace_cmds(oce) + add_gomspace_cmd_defs(oce) oce.add(keys=P60OpCodes.TEST, info="P60 Tests") defs.add_service( name=CustomServiceList.P60DOCK.value, info="P60 Device", op_code_entry=oce @@ -76,7 +73,7 @@ def add_power_cmd_defs(defs: TmtcDefinitionWrapper): def add_pdu1_cmds(defs: TmtcDefinitionWrapper): oce = OpCodeEntry() add_pdu1_common_defs(oce) - add_gomspace_cmds(oce) + add_gomspace_cmd_defs(oce) oce.add(keys=GomspaceOpCodes.REQUEST_CORE_HK_ONCE, info=GsInfo.REQUEST_CORE_HK_ONCE) oce.add(keys=GomspaceOpCodes.REQUEST_AUX_HK_ONCE, info=GsInfo.REQUEST_AUX_HK_ONCE) oce.add( @@ -96,7 +93,7 @@ def add_pdu1_cmds(defs: TmtcDefinitionWrapper): def add_pdu2_cmds(defs: TmtcDefinitionWrapper): oce = OpCodeEntry() add_pdu2_common_defs(oce) - add_gomspace_cmds(oce) + add_gomspace_cmd_defs(oce) oce.add( keys=GomspaceOpCodes.PRINT_SWITCH_V_I, info="PDU2: Print Switches, Voltages, Currents", @@ -112,20 +109,6 @@ def add_pdu2_cmds(defs: TmtcDefinitionWrapper): ) -def add_gomspace_cmds(oce: OpCodeEntry): - oce.add( - keys=GomspaceOpCodes.REQUEST_CORE_HK_ONCE, - info=GsInfo.REQUEST_CORE_HK_ONCE, - ) - oce.add( - keys=GomspaceOpCodes.REQUEST_AUX_HK_ONCE, - info=GsInfo.REQUEST_AUX_HK_ONCE, - ) - oce.add(keys=GomspaceOpCodes.GET_PARAM, info=GsInfo.GET_PARAMETER) - oce.add(keys=GomspaceOpCodes.PRINT_LATCHUPS, info=GsInfo.PRINT_LATCHUPS) - oce.add(keys=GomspaceOpCodes.SET_PARAM, info=GsInfo.SET_PARAMETER) - - def add_pcdu_cmds(defs: TmtcDefinitionWrapper): add_p60_cmds(defs) add_pdu1_cmds(defs) diff --git a/pus_tm/system/power.py b/tmtc/power/tm.py similarity index 70% rename from pus_tm/system/power.py rename to tmtc/power/tm.py index dd5f8e4..e48d7e4 100644 --- a/pus_tm/system/power.py +++ b/tmtc/power/tm.py @@ -1,9 +1,16 @@ import struct from typing import List, Tuple +from tmtccmd.util import ObjectIdBase from tmtccmd.util.tmtc_printer import FsfwTmTcPrinter from pus_tm.defs import PrintWrapper -from gomspace.gomspace_common import SetIds +from gomspace.gomspace_common import SetIds, GomspaceDeviceActionIds +from config.object_ids import ( + PDU_1_HANDLER_ID, + PDU_2_HANDLER_ID, + P60_DOCK_HANDLER, + ACU_HANDLER_ID, +) P60_INDEX_LIST = [ "ACU VCC", @@ -244,7 +251,7 @@ def handle_p60_hk_data(printer: FsfwTmTcPrinter, set_id: int, hk_data: bytes): f"{voltage_list[idx]:05} | {current_list[idx]:04}" ) pw.dlog(content_line) - fmt_str = "!IBhHhh" + fmt_str = "!IBhHff" inc_len = struct.calcsize(fmt_str) ( boot_count, @@ -259,7 +266,7 @@ def handle_p60_hk_data(printer: FsfwTmTcPrinter, set_id: int, hk_data: bytes): f"Batt: Mode {batt_mode} | Boot Count {boot_count} | " f"Charge current {batt_current} | Voltage {batt_voltage}" ) - temps = f"In C: Temp 0 {temp_0 / 10.0} | Temp 1 {temp_1 / 10.0} | " + temps = f"In C: Temp 0 {temp_0} | Temp 1 {temp_1} | " pw.dlog(temps) pw.dlog(batt_info) printer.print_validity_buffer(validity_buffer=hk_data[current_idx:], num_vars=9) @@ -361,7 +368,7 @@ def handle_acu_hk_data(printer: FsfwTmTcPrinter, set_id: int, hk_data: bytes): current_idx, powers = gen_six_entry_u16_list( hk_data=hk_data, current_idx=current_idx ) - fmt_str = "!HHHIIHH" + fmt_str = "!fffIIHH" inc_len = struct.calcsize(fmt_str) (tmp0, tmp1, tmp2, bootcnt, uptime, mppt_time, mppt_period) = struct.unpack( fmt_str, hk_data[current_idx : current_idx + inc_len] @@ -378,9 +385,7 @@ def handle_acu_hk_data(printer: FsfwTmTcPrinter, set_id: int, hk_data: bytes): f"{i} | {str(voltages[i]).ljust(4)} | {str(currents[i]).ljust(4)} | " f"{str(vboosts[i]).ljust(4)} | {str(powers[i]).ljust(2)}" ) - pw.dlog( - f"Temperatures in C: Ch0 {tmp0/10.0} | Ch1 {tmp1/10.0} | Ch2 {tmp2/10.0}" - ) + pw.dlog(f"Temperatures in C: Ch0 {tmp0} | Ch1 {tmp1} | Ch2 {tmp2}") pw.dlog( f"Boot Count {bootcnt} | Uptime {uptime} sec | " f"MPPT Time {mppt_time} msec | MPPT Period {mppt_period} msec" @@ -423,3 +428,135 @@ def handle_acu_hk_data(printer: FsfwTmTcPrinter, set_id: int, hk_data: bytes): ) dev_parser.print(pw=pw) printer.print_validity_buffer(validity_buffer=hk_data[current_idx:], num_vars=8) + + +OBC_ENDIANNESS = "<" + + +def handle_get_param_data_reply( + obj_id: ObjectIdBase, action_id: int, pw: PrintWrapper, custom_data: bytearray +): + if action_id == GomspaceDeviceActionIds.PARAM_GET: + pw.dlog(f"Parameter Get Request received for object {obj_id}") + header_list = [ + "Gomspace Request Code", + "Table ID", + "Memory Address", + "Payload length", + "Payload", + ] + fmt_str = "!BBHH" + (gs_request_code, table_id, address, payload_length) = struct.unpack( + fmt_str, custom_data[:6] + ) + content_list = [ + hex(gs_request_code), + table_id, + hex(address), + payload_length, + f"0x[{custom_data[6:].hex(sep=',')}]", + ] + pw.dlog(f"{header_list}") + pw.dlog(f"{content_list}") + elif action_id == GomspaceDeviceActionIds.REQUEST_CONFIG_TABLE: + print(f"Received config table with size {len(custom_data)} for object {obj_id}") + if obj_id.as_bytes == PDU_1_HANDLER_ID or obj_id.as_bytes == PDU_2_HANDLER_ID: + pdu_config_table_handler(pw, custom_data) + elif obj_id.as_bytes == ACU_HANDLER_ID: + acu_config_table_handler(pw, custom_data) + elif obj_id.as_bytes == P60_DOCK_HANDLER: + p60_dock_config_table_handler(pw, custom_data) + + +def pdu_config_table_handler(pw: PrintWrapper, custom_data: bytes): + out_on_cnt = unpack_array_in_data(custom_data, 0x52, 2, 9, "H") + out_off_cnt = unpack_array_in_data(custom_data, 0x64, 2, 9, "H") + init_out_norm = unpack_array_in_data(custom_data, 0x76, 1, 9, "B") + init_out_safe = unpack_array_in_data(custom_data, 0x80, 1, 9, "B") + init_on_dly = unpack_array_in_data(custom_data, 0x8A, 2, 9, "H") + init_off_dly = unpack_array_in_data(custom_data, 0x9C, 2, 9, "H") + safe_off_dly = unpack_array_in_data(custom_data, 0xAE, 1, 9, "B") + batt_hwmax = struct.unpack(f"{OBC_ENDIANNESS}H", custom_data[0x11C : 0x11C + 2])[0] + batt_max = struct.unpack(f"{OBC_ENDIANNESS}H", custom_data[0x11E : 0x11E + 2])[0] + batt_norm = struct.unpack(f"{OBC_ENDIANNESS}H", custom_data[0x120 : 0x120 + 2])[0] + batt_safe = struct.unpack(f"{OBC_ENDIANNESS}H", custom_data[0x122 : 0x122 + 2])[0] + batt_crit = struct.unpack(f"{OBC_ENDIANNESS}H", custom_data[0x124 : 0x124 + 2])[0] + pw.dlog(f"{'out_on_cnt'.ljust(15)}: {out_on_cnt}") + pw.dlog(f"{'out_off_cnt'.ljust(15)}: {out_off_cnt}") + pw.dlog(f"{'init_out_norm'.ljust(15)}: {init_out_norm}") + pw.dlog(f"{'init_out_safe'.ljust(15)}: {init_out_safe}") + pw.dlog(f"{'init_on_dly'.ljust(15)}: {init_on_dly}") + pw.dlog(f"{'init_off_dly'.ljust(15)}: {init_off_dly}") + pw.dlog(f"{'safe_off_dly'.ljust(15)}: {safe_off_dly}") + pw.dlog(f"{'batt_hwmax'.ljust(15)}: {batt_hwmax}") + pw.dlog(f"{'batt_max'.ljust(15)}: {batt_max}") + pw.dlog(f"{'batt_norm'.ljust(15)}: {batt_norm}") + pw.dlog(f"{'batt_safe'.ljust(15)}: {batt_safe}") + pw.dlog(f"{'batt_crit'.ljust(15)}: {batt_crit}") + + +def acu_config_table_handler(pw: PrintWrapper, custom_data: bytes): + mppt_mode = custom_data[0] + mppt_delta_mode = custom_data[1] + vboost_list = unpack_array_in_data(custom_data, 0x02, 2, 6, "H") + vbat_max_hi = struct.unpack(f"{OBC_ENDIANNESS}H", custom_data[0x10 : 0x10 + 2])[0] + vbat_max_lo = struct.unpack(f"{OBC_ENDIANNESS}H", custom_data[0x12 : 0x12 + 2])[0] + mppt_period = struct.unpack(f"{OBC_ENDIANNESS}I", custom_data[0x14 : 0x14 + 4])[0] + max_dv = struct.unpack(f"{OBC_ENDIANNESS}H", custom_data[0x18 : 0x18 + 2])[0] + ov_mode = custom_data[0x1A] + pw.dlog(f"{'mppt_mode'.ljust(15)}: {mppt_mode}") + pw.dlog(f"{'mppt_delta_mode'.ljust(15)}: {mppt_delta_mode}") + pw.dlog(f"{'vboost_list'.ljust(15)}: {vboost_list}") + pw.dlog(f"{'vbat_max_hi'.ljust(15)}: {vbat_max_hi}") + pw.dlog(f"{'vbat_max_lo'.ljust(15)}: {vbat_max_lo}") + pw.dlog(f"{'mppt_period'.ljust(15)}: {mppt_period}") + pw.dlog(f"{'max_dv'.ljust(15)}: {max_dv}") + pw.dlog(f"{'ov_mode'.ljust(15)}: {ov_mode}") + + +def p60_dock_config_table_handler(pw: PrintWrapper, custom_data: bytes): + ch_names = parse_name_list(custom_data[0:0x68], 13) + out_on_cnt = unpack_array_in_data(custom_data, 0x76, 2, 13, "H") + out_off_cnt = unpack_array_in_data(custom_data, 0x90, 2, 13, "H") + init_out_norm = unpack_array_in_data(custom_data, 0xAA, 1, 13, "B") + init_out_safe = unpack_array_in_data(custom_data, 0xB7, 1, 13, "B") + init_on_dly = unpack_array_in_data(custom_data, 0xC4, 2, 13, "H") + init_off_dly = unpack_array_in_data(custom_data, 0xDE, 2, 13, "H") + pw.dlog(f"Ch Names: {ch_names}") + pw.dlog(f"{'out_on_cnt'.ljust(15)}: {out_on_cnt}") + pw.dlog(f"{'out_off_cnt'.ljust(15)}: {out_off_cnt}") + pw.dlog(f"{'init_out_norm'.ljust(15)}: {init_out_norm}") + pw.dlog(f"{'init_out_safe'.ljust(15)}: {init_out_safe}") + pw.dlog(f"{'init_on_dly'.ljust(15)}: {init_on_dly}") + pw.dlog(f"{'init_off_dly'.ljust(15)}: {init_off_dly}") + + +def parse_name_list(data: bytes, name_len: int): + ch_list = [] + idx = 0 + while len(ch_list) < name_len: + next_byte = data[idx] + if next_byte != 0: + string_end_found = False + string_end_idx = idx + while not string_end_found: + string_end_idx += 1 + if data[string_end_idx] == 0: + string_end_found = True + name = data[idx:string_end_idx].decode() + ch_list.append(name) + idx += len(name) + idx += 1 + return ch_list + + +def unpack_array_in_data( + data: bytes, start_addr: int, width: int, entries: int, struct_spec: str +) -> List: + return [ + struct.unpack( + f"{OBC_ENDIANNESS}{struct_spec}", + data[start_addr + (i * width) : start_addr + ((i + 1) * width)], + )[0] + for i in range(entries) + ]