diff --git a/config/definitions.py b/config/definitions.py index c98e7da..7d88116 100644 --- a/config/definitions.py +++ b/config/definitions.py @@ -47,3 +47,4 @@ class CustomServiceList(enum.Enum): SUS_ASS = "sus-ass" TCS_ASS = "tcs-ass" TIME = "time" + CONTROLLERS = "controllers" diff --git a/config/object_ids.py b/config/object_ids.py index 7242c20..b7c605c 100644 --- a/config/object_ids.py +++ b/config/object_ids.py @@ -27,6 +27,7 @@ ACU_HANDLER_ID = bytes([0x44, 0x25, 0x00, 0x03]) BPX_HANDLER_ID = bytes([0x44, 0x26, 0x00, 0x00]) # Thermal Object IDs +THERMAL_CONTROLLER_ID = bytes([0x43, 0x40, 0x00, 0x01]) HEATER_ID = bytes([0x44, 0x41, 0x00, 0xA4]) TMP_1075_1_HANDLER_ID = bytes([0x44, 0x42, 0x00, 0x04]) TMP_1075_2_HANDLER_ID = bytes([0x44, 0x42, 0x00, 0x05]) diff --git a/pus_tc/cmd_definitions.py b/pus_tc/cmd_definitions.py index 94f3e82..c3dd7e8 100644 --- a/pus_tc/cmd_definitions.py +++ b/pus_tc/cmd_definitions.py @@ -949,6 +949,7 @@ def add_ploc_supv_cmds(cmd_dict: ServiceOpCodeDictT): def add_system_cmds(cmd_dict: ServiceOpCodeDictT): from pus_tc.system.acs import AcsOpCodes, SusOpCodes import pus_tc.system.tcs as tcs + import pus_tc.system.controllers as controllers default_opts = generate_op_code_options( enter_listener_mode=False, custom_timeout=8.0 @@ -1054,3 +1055,23 @@ def add_system_cmds(cmd_dict: ServiceOpCodeDictT): info="TCS Board Assembly", op_code_entry=op_code_dict, ) + + op_code_dict = dict() + add_op_code_entry( + op_code_dict=op_code_dict, + keys=controllers.OpCodes.THERMAL_CONTROLLER, + info=controllers.Info.THERMAL_CONTROLLER, + options=default_opts, + ) + add_op_code_entry( + op_code_dict=op_code_dict, + keys=controllers.OpCodes.CORE_CONTROLLER, + info=controllers.Info.CORE_CONTROLLER, + options=default_opts, + ) + add_service_op_code_entry( + srv_op_code_dict=cmd_dict, + name=CustomServiceList.CONTROLLERS.value, + info="Controllers", + op_code_entry=op_code_dict, + ) diff --git a/pus_tc/system/acs.py b/pus_tc/system/acs.py index ea97734..7d3eb48 100644 --- a/pus_tc/system/acs.py +++ b/pus_tc/system/acs.py @@ -3,8 +3,7 @@ from tmtccmd.tc.definitions import TcQueueT from tmtccmd.tc.pus_200_fsfw_modes import Modes from config.object_ids import ACS_BOARD_ASS_ID, SUS_BOARD_ASS_ID -from .common import command_assembly - +from .common import command_mode class AcsOpCodes: ACS_ASS_A_SIDE = ["0", "acs-a"] @@ -31,7 +30,7 @@ class DualSideSubmodes(enum.IntEnum): def pack_acs_command(tc_queue: TcQueueT, op_code: str): if op_code in AcsOpCodes.ACS_ASS_A_SIDE: - command_assembly( + command_mode( object_id=ACS_BOARD_ASS_ID, mode=Modes.NORMAL, submode=DualSideSubmodes.A_SIDE, @@ -39,7 +38,7 @@ def pack_acs_command(tc_queue: TcQueueT, op_code: str): info="Switching to ACS board assembly A side", ) if op_code in AcsOpCodes.ACS_ASS_B_SIDE: - command_assembly( + command_mode( object_id=ACS_BOARD_ASS_ID, mode=Modes.NORMAL, submode=DualSideSubmodes.B_SIDE, @@ -47,7 +46,7 @@ def pack_acs_command(tc_queue: TcQueueT, op_code: str): info="Switching to ACS board assembly B side", ) if op_code in AcsOpCodes.ACS_ASS_DUAL_MODE: - command_assembly( + command_mode( object_id=ACS_BOARD_ASS_ID, mode=Modes.NORMAL, submode=DualSideSubmodes.DUAL_SIDE, @@ -55,7 +54,7 @@ def pack_acs_command(tc_queue: TcQueueT, op_code: str): info="Switching to ACS board assembly dual mode", ) if op_code in AcsOpCodes.ACS_ASS_A_ON: - command_assembly( + command_mode( object_id=ACS_BOARD_ASS_ID, mode=Modes.ON, submode=DualSideSubmodes.A_SIDE, @@ -63,7 +62,7 @@ def pack_acs_command(tc_queue: TcQueueT, op_code: str): info="Switching ACS board assembly A side on", ) if op_code in AcsOpCodes.ACS_ASS_B_ON: - command_assembly( + command_mode( object_id=ACS_BOARD_ASS_ID, mode=Modes.ON, submode=DualSideSubmodes.B_SIDE, @@ -71,7 +70,7 @@ def pack_acs_command(tc_queue: TcQueueT, op_code: str): info="Switching ACS board assembly B side on", ) if op_code in AcsOpCodes.ACS_ASS_DUAL_ON: - command_assembly( + command_mode( object_id=ACS_BOARD_ASS_ID, mode=Modes.ON, submode=DualSideSubmodes.B_SIDE, @@ -79,7 +78,7 @@ def pack_acs_command(tc_queue: TcQueueT, op_code: str): info="Switching ACS board assembly dual side on", ) if op_code in AcsOpCodes.ACS_ASS_OFF: - command_assembly( + command_mode( object_id=ACS_BOARD_ASS_ID, mode=Modes.OFF, submode=0, @@ -90,7 +89,7 @@ def pack_acs_command(tc_queue: TcQueueT, op_code: str): def pack_sus_cmds(tc_queue: TcQueueT, op_code: str): if op_code in SusOpCodes.SUS_ASS_NOM_SIDE: - command_assembly( + command_mode( object_id=SUS_BOARD_ASS_ID, mode=Modes.NORMAL, submode=DualSideSubmodes.A_SIDE, @@ -98,7 +97,7 @@ def pack_sus_cmds(tc_queue: TcQueueT, op_code: str): info="Switching to SUS board to nominal side", ) if op_code in SusOpCodes.SUS_ASS_RED_SIDE: - command_assembly( + command_mode( object_id=SUS_BOARD_ASS_ID, mode=Modes.NORMAL, submode=DualSideSubmodes.B_SIDE, @@ -106,7 +105,7 @@ def pack_sus_cmds(tc_queue: TcQueueT, op_code: str): info="Switching to SUS board to redundant side", ) if op_code in SusOpCodes.SUS_ASS_OFF: - command_assembly( + command_mode( object_id=SUS_BOARD_ASS_ID, mode=Modes.OFF, submode=0, @@ -114,7 +113,7 @@ def pack_sus_cmds(tc_queue: TcQueueT, op_code: str): info="Switching SUS board off", ) if op_code in SusOpCodes.SUS_ASS_DUAL_MODE: - command_assembly( + command_mode( object_id=SUS_BOARD_ASS_ID, mode=Modes.NORMAL, submode=DualSideSubmodes.DUAL_SIDE, diff --git a/pus_tc/system/common.py b/pus_tc/system/common.py index 55ae7b3..c712ea3 100644 --- a/pus_tc/system/common.py +++ b/pus_tc/system/common.py @@ -3,7 +3,7 @@ from spacepackets.ecss.tc import PusTelecommand from tmtccmd.tc.pus_200_fsfw_modes import pack_mode_data, Modes, Subservices -def command_assembly( +def command_mode( object_id: bytes, mode: Modes, submode: int, tc_queue: TcQueueT, info: str ): tc_queue.appendleft((QueueCommands.PRINT, info)) diff --git a/pus_tc/system/controllers.py b/pus_tc/system/controllers.py new file mode 100644 index 0000000..30a5b4d --- /dev/null +++ b/pus_tc/system/controllers.py @@ -0,0 +1,44 @@ +from ast import Pass +from tmtccmd.tc.definitions import TcQueueT + + + +from .common import command_mode +import config.object_ids as obj_ids + + +class OpCodes: + THERMAL_CONTROLLER = [obj_ids.THERMAL_CONTROLLER_ID.hex(), "thermal_controller"] + CORE_CONTROLLER = [obj_ids.CORE_CONTROLLER_ID.hex(), "core_controller"] + + +class Info: + THERMAL_CONTROLLER = "Thermal controller" + CORE_CONTROLLER = "ACS controller" + + +def pack_controller_commands(tc_queue: TcQueueT, op_code: str): + mode = int(input("Specify mode: (OFF = 0; ON = 1; NORMAL = 2) [2] ") or "2") + print(mode) + if mode < 0 or mode > 2: + print("Invalid Mode, defaulting to OFF") + mode = 0 + submode = int(input("Specify submode [0]: ") or "0") + command_mode( + object_id=get_object_from_op_code(op_code), + mode=mode, + submode=submode, + tc_queue=tc_queue, + info=op_code + " to " + str(mode) + "," + str(submode), + ) + +def get_object_from_op_code(op_code: str): + try: + return bytes.fromhex(op_code) + except: + pass + + if op_code in OpCodes.THERMAL_CONTROLLER: + return obj_ids.THERMAL_CONTROLLER_ID + if op_code in OpCodes.CORE_CONTROLLER: + return obj_ids.CORE_CONTROLLER_ID diff --git a/pus_tc/system/tcs.py b/pus_tc/system/tcs.py index 5b98ddc..47ab31d 100644 --- a/pus_tc/system/tcs.py +++ b/pus_tc/system/tcs.py @@ -1,7 +1,7 @@ from tmtccmd.tc.definitions import TcQueueT, QueueCommands from tmtccmd.tc.pus_200_fsfw_modes import Modes -from .common import command_assembly +from .common import command_mode from config.object_ids import TCS_BOARD_ASS_ID @@ -17,7 +17,7 @@ class Info: def pack_tcs_sys_commands(tc_queue: TcQueueT, op_code: str): if op_code in OpCodes.TCS_BOARD_ASS_NORMAL: - command_assembly( + command_mode( object_id=TCS_BOARD_ASS_ID, mode=Modes.NORMAL, submode=0, @@ -25,7 +25,7 @@ def pack_tcs_sys_commands(tc_queue: TcQueueT, op_code: str): info=Info.TCS_BOARD_ASS_NORMAL, ) if op_code in OpCodes.TCS_BOARD_ASS_OFF: - command_assembly( + command_mode( object_id=TCS_BOARD_ASS_ID, mode=Modes.OFF, submode=0, diff --git a/pus_tc/tc_packer_hook.py b/pus_tc/tc_packer_hook.py index bcf9f2b..90340f4 100644 --- a/pus_tc/tc_packer_hook.py +++ b/pus_tc/tc_packer_hook.py @@ -40,6 +40,7 @@ from pus_tc.system.acs import pack_acs_command, pack_sus_cmds from pus_tc.devs.plpcdu import pack_pl_pcdu_commands from pus_tc.devs.str_img_helper import pack_str_img_helper_command from pus_tc.system.tcs import pack_tcs_sys_commands +from pus_tc.system.controllers import pack_controller_commands from config.definitions import CustomServiceList from config.object_ids import ( P60_DOCK_HANDLER, @@ -234,6 +235,8 @@ def pack_service_queue_user( return pack_rw_ass_cmds( tc_queue=service_queue, object_id=RW_ASSEMBLY, op_code=op_code ) + if service == CustomServiceList.CONTROLLERS.value: + return pack_controller_commands(tc_queue=service_queue, op_code=op_code) LOGGER.warning("Invalid Service !") diff --git a/pus_tm/factory_hook.py b/pus_tm/factory_hook.py index 6fdca91..afac7c0 100644 --- a/pus_tm/factory_hook.py +++ b/pus_tm/factory_hook.py @@ -33,6 +33,7 @@ def ccsds_tm_handler(apid: int, raw_tm_packet: bytes, _user_args: any) -> None: pus_factory_hook(raw_tm_packet=raw_tm_packet) + def pus_factory_hook(raw_tm_packet: bytes): if len(raw_tm_packet) < 8: LOGGER.warning("Detected packet shorter than 8 bytes!") diff --git a/pus_tm/hk_handling.py b/pus_tm/hk_handling.py index 399ec5c..2197f8d 100644 --- a/pus_tm/hk_handling.py +++ b/pus_tm/hk_handling.py @@ -3,6 +3,8 @@ import struct import os import datetime + + from tmtccmd.config.definitions import HkReplyUnpacked from tmtccmd.tm.pus_3_fsfw_hk import ( Service3Base, @@ -20,8 +22,14 @@ import config.object_ids as obj_ids from pus_tm.devs.reaction_wheels import handle_rw_hk_data from pus_tm.defs import FsfwTmTcPrinter, log_to_both +from pus_tm.tm_tcp_server import TmTcpServer + + + LOGGER = get_console_logger() +TM_TCP_SERVER = TmTcpServer.getInstance() + def handle_hk_packet( raw_tm: bytes, @@ -34,6 +42,9 @@ def handle_hk_packet( named_obj_id = tm_packet.object_id if tm_packet.subservice == 25 or tm_packet.subservice == 26: hk_data = tm_packet.tm_data[8:] + TM_TCP_SERVER.report_raw_hk_data(object_id=named_obj_id, + set_id=tm_packet.set_id, + hk_data=hk_data) printer.generic_hk_tm_print( content_type=HkContentType.HK, object_id=named_obj_id, @@ -49,7 +60,6 @@ def handle_hk_packet( if tm_packet.subservice == 10 or tm_packet.subservice == 12: LOGGER.warning("HK definitions printout not implemented yet") - def handle_regular_hk_print( printer: FsfwTmTcPrinter, object_id: ObjectId, @@ -97,12 +107,13 @@ def handle_regular_hk_print( handle_p60_hk_data(printer=printer, set_id=set_id, hk_data=hk_data) if objb == obj_ids.PL_PCDU_ID: log_to_both(printer, "Received PL PCDU HK data") + if objb == obj_ids.THERMAL_CONTROLLER_ID: + handle_thermal_controller_hk_data( object_id=object_id, printer=printer, set_id=set_id, hk_data=hk_data) else: LOGGER.info("Service 3 TM: Parsing for this SID has not been implemented.") return HkReplyUnpacked() - -def handle_syrlinks_rx_registers_dataset(printer: FsfwTmTcPrinter, hk_data: bytes): +def handle_syrlinks_rx_registers_dataset( printer: FsfwTmTcPrinter, hk_data: bytes): reply = HkReplyUnpacked() header_list = [ "RX Status", @@ -137,7 +148,6 @@ def handle_syrlinks_rx_registers_dataset(printer: FsfwTmTcPrinter, hk_data: byte log_to_both(printer, str(content_list)) printer.print_validity_buffer(validity_buffer=validity_buffer, num_vars=8) - def handle_syrlinks_tx_registers_dataset( printer: FsfwTmTcPrinter, hk_data: bytes, @@ -153,7 +163,6 @@ def handle_syrlinks_tx_registers_dataset( log_to_both(printer, str(content_list)) printer.print_validity_buffer(validity_buffer=validity_buffer, num_vars=3) - def handle_self_test_data(printer: FsfwTmTcPrinter, hk_data: bytes): header_list = [ "Init Err", @@ -258,7 +267,7 @@ def handle_self_test_data(printer: FsfwTmTcPrinter, hk_data: bytes): init_coil_z_temperature, err, raw_mag_x, - init_raw_mag_y, + raw_mag_y, raw_mag_z, cal_mag_x, cal_mag_y, @@ -288,6 +297,34 @@ def handle_self_test_data(printer: FsfwTmTcPrinter, hk_data: bytes): log_to_both(printer, str(content_list)) printer.print_validity_buffer(validity_buffer=validity_buffer, num_vars=num_of_vars) +def handle_thermal_controller_hk_data(object_id: ObjectId, printer: FsfwTmTcPrinter, set_id: int, hk_data: bytes): + if set_id == 0: + LOGGER.info("Received Sensor Temperature data") + + # get all the floats + tm_data = struct.unpack("!ffffffffffffffff", hk_data[:16 * 4]) + parsed_data = {} + + # put them into an list with their names + parsed_data = [] + parsed_data.append({"SENSOR_PLOC_HEATSPREADER": tm_data[0]}) + parsed_data.append({"SENSOR_PLOC_MISSIONBOARD": tm_data[1]}) + parsed_data.append({"SENSOR_4K_CAMERA": tm_data[2]}) + parsed_data.append({"SENSOR_DAC_HEATSPREADER": tm_data[3]}) + parsed_data.append({"SENSOR_STARTRACKER": tm_data[4]}) + parsed_data.append({"SENSOR_RW1": tm_data[5]}) + parsed_data.append({"SENSOR_DRO": tm_data[6]}) + parsed_data.append({"SENSOR_SCEX": tm_data[7]}) + parsed_data.append({"SENSOR_X8": tm_data[8]}) + parsed_data.append({"SENSOR_HPA": tm_data[9]}) + parsed_data.append({"SENSOR_TX_MODUL": tm_data[10]}) + parsed_data.append({"SENSOR_MPA": tm_data[11]}) + parsed_data.append({"SENSOR_ACU": tm_data[12]}) + parsed_data.append({"SENSOR_PLPCDU_HEATSPREADER": tm_data[13]}) + parsed_data.append({"SENSOR_TCS_BOARD": tm_data[14]}) + parsed_data.append({"SENSOR_MAGNETTORQUER": tm_data[15]}) + + TM_TCP_SERVER.report_parsed_hk_data(object_id, set_id, parsed_data) def handle_gps_data(printer: FsfwTmTcPrinter, hk_data: bytes): LOGGER.info(f"Received GPS data, HK data length {len(hk_data)}") @@ -342,7 +379,6 @@ def handle_gps_data(printer: FsfwTmTcPrinter, hk_data: bytes): log_to_both(printer, str(content_list)) printer.print_validity_buffer(validity_buffer=validity_buffer, num_vars=10) - def handle_bpx_hk_data(printer: FsfwTmTcPrinter, set_id: int, hk_data: bytes): if set_id == BpxSetIds.GET_HK_SET: fmt_str = "!HHHHhhhhIB" @@ -402,13 +438,12 @@ def handle_bpx_hk_data(printer: FsfwTmTcPrinter, set_id: int, hk_data: bytes): log_to_both(printer, str(content_list)) printer.print_validity_buffer(validity_buffer=validity_buffer, num_vars=10) - def handle_core_hk_data(printer: FsfwTmTcPrinter, hk_data: bytes): fmt_str = "!fffH" inc_len = struct.calcsize(fmt_str) (temperature, ps_voltage, pl_voltage, tx_agc_value) = struct.unpack( - fmt_str, hk_data[0 : 0 + inc_len] + fmt_str, hk_data[0: 0 + inc_len] ) printout = ( f"Chip Temperature [°C] {temperature} | PS Voltage [mV] {ps_voltage} | " @@ -417,7 +452,6 @@ def handle_core_hk_data(printer: FsfwTmTcPrinter, hk_data: bytes): log_to_both(printer, printout) printer.print_validity_buffer(validity_buffer=hk_data[inc_len:], num_vars=4) - P60_INDEX_LIST = [ "ACU VCC", "PDU1 VCC", @@ -462,7 +496,6 @@ PDU2_CHANNELS_NAMES = [ PDU_CHANNEL_NAMES = [PDU1_CHANNELS_NAMES, PDU2_CHANNELS_NAMES] - class WdtInfo: def __init__(self): self.wdt_reboots_list = [] @@ -474,7 +507,7 @@ class WdtInfo: for idx in range(len(self.wdt_reboots_list)): log_to_both( printer, - f"{WDT_LIST[idx].ljust(5)} | " + f"{TmHandler.WDT_LIST[idx].ljust(5)} | " f"{self.wdt_reboots_list[idx]:010} | {self.time_pings_left_list[idx]:010}", ) @@ -484,13 +517,13 @@ class WdtInfo: self.time_pings_left_list = [] for idx in range(5): self.wdt_reboots_list.append( - struct.unpack("!I", wdt_data[priv_idx : priv_idx + 4])[0] + struct.unpack("!I", wdt_data[priv_idx: priv_idx + 4])[0] ) priv_idx += 4 current_idx += 4 for idx in range(3): self.time_pings_left_list.append( - struct.unpack("!I", wdt_data[priv_idx : priv_idx + 4])[0] + struct.unpack("!I", wdt_data[priv_idx: priv_idx + 4])[0] ) priv_idx += 4 current_idx += 4 @@ -500,7 +533,6 @@ class WdtInfo: priv_idx += 1 return current_idx - def handle_pdu_data( printer: FsfwTmTcPrinter, pdu_idx: int, set_id: int, hk_data: bytes ): @@ -518,7 +550,7 @@ def handle_pdu_data( boot_cause, uptime, reset_cause, - ) = struct.unpack(fmt_str, hk_data[current_idx : current_idx + inc_len]) + ) = struct.unpack(fmt_str, hk_data[current_idx: current_idx + inc_len]) log_to_both(printer, f"VCC {vcc} mV | VBAT {vbat} mV") log_to_both( printer, f"Converter Enables [{conv_enb_0},{conv_enb_1},{conv_enb_2}]" @@ -530,21 +562,21 @@ def handle_pdu_data( current_idx += inc_len latchup_list = [] log_to_both(printer, "Latchups") - for idx in range(len(PDU1_CHANNELS_NAMES)): + for idx in range(len(TmHandler.PDU1_CHANNELS_NAMES)): latchup_list.append( - struct.unpack("!H", hk_data[current_idx : current_idx + 2])[0] + struct.unpack("!H", hk_data[current_idx: current_idx + 2])[0] ) content_line = ( - f"{PDU_CHANNEL_NAMES[priv_idx][idx].ljust(24)} | {latchup_list[idx]}" + f"{TmHandler.PDU_CHANNEL_NAMES[priv_idx][idx].ljust(24)} | {latchup_list[idx]}" ) log_to_both(printer, content_line) current_idx += 2 device_types = [] - for idx in range(len(PDU1_CHANNELS_NAMES)): + for idx in range(len(TmHandler.PDU1_CHANNELS_NAMES)): device_types.append(hk_data[current_idx]) current_idx += 1 device_statuses = [] - for idx in range(len(PDU1_CHANNELS_NAMES)): + for idx in range(len(TmHandler.PDU1_CHANNELS_NAMES)): device_statuses.append(hk_data[current_idx]) current_idx += 1 wdt = WdtInfo() @@ -553,35 +585,35 @@ def handle_pdu_data( if set_id == SetIds.PDU_1_CORE or set_id == SetIds.PDU_2_CORE: log_to_both(printer, f"Received PDU HK from PDU {pdu_idx}") current_list = [] - for idx in range(len(PDU1_CHANNELS_NAMES)): + for idx in range(len(TmHandler.PDU1_CHANNELS_NAMES)): current_list.append( - struct.unpack("!h", hk_data[current_idx : current_idx + 2])[0] + struct.unpack("!h", hk_data[current_idx: current_idx + 2])[0] ) current_idx += 2 voltage_list = [] - for idx in range(len(PDU1_CHANNELS_NAMES)): + for idx in range(len(TmHandler.PDU1_CHANNELS_NAMES)): voltage_list.append( - struct.unpack("!H", hk_data[current_idx : current_idx + 2])[0] + struct.unpack("!H", hk_data[current_idx: current_idx + 2])[0] ) current_idx += 2 output_enb_list = [] - for idx in range(len(PDU1_CHANNELS_NAMES)): + for idx in range(len(TmHandler.PDU1_CHANNELS_NAMES)): output_enb_list.append(hk_data[current_idx]) current_idx += 1 header_str = f"{'Name'.ljust(24)} | OutEnb | U [mV] | I [mA]" print(header_str) printer.file_logger.info(header_str) - for idx in range(len(PDU1_CHANNELS_NAMES)): + for idx in range(len(TmHandler.PDU1_CHANNELS_NAMES)): out_enb = f"{output_enb_list[idx]}".ljust(6) content_line = ( - f"{PDU_CHANNEL_NAMES[priv_idx][idx].ljust(24)} | {out_enb} | " + f"{TmHandler.PDU_CHANNEL_NAMES[priv_idx][idx].ljust(24)} | {out_enb} | " f"{voltage_list[idx]:05} | {current_list[idx]:04}" ) log_to_both(printer, content_line) fmt_str = "!IBh" inc_len = struct.calcsize(fmt_str) (boot_count, batt_mode, temperature) = struct.unpack( - fmt_str, hk_data[current_idx : current_idx + inc_len] + fmt_str, hk_data[current_idx: current_idx + inc_len] ) info = ( f"Boot Count {boot_count} | Battery Mode {batt_mode} | " @@ -589,7 +621,6 @@ def handle_pdu_data( ) log_to_both(printer, info) - def handle_p60_hk_data(printer: FsfwTmTcPrinter, set_id: int, hk_data: bytes): if set_id == SetIds.P60_CORE: log_to_both(printer, "Received P60 Core HK. Voltages in mV, currents in mA") @@ -597,13 +628,13 @@ def handle_p60_hk_data(printer: FsfwTmTcPrinter, set_id: int, hk_data: bytes): current_list = [] for idx in range(13): current_list.append( - struct.unpack("!h", hk_data[current_idx : current_idx + 2])[0] + struct.unpack("!h", hk_data[current_idx: current_idx + 2])[0] ) current_idx += 2 voltage_list = [] for idx in range(13): voltage_list.append( - struct.unpack("!H", hk_data[current_idx : current_idx + 2])[0] + struct.unpack("!H", hk_data[current_idx: current_idx + 2])[0] ) current_idx += 2 out_enb_list = [] @@ -616,7 +647,7 @@ def handle_p60_hk_data(printer: FsfwTmTcPrinter, set_id: int, hk_data: bytes): for idx in range(13): out_enb = f"{out_enb_list[idx]}".ljust(6) content_line = ( - f"{P60_INDEX_LIST[idx].ljust(24)} | {out_enb} | " + f"{TmHandler.P60_INDEX_LIST[idx].ljust(24)} | {out_enb} | " f"{voltage_list[idx]:05} | {current_list[idx]:04}" ) log_to_both(printer, content_line) @@ -629,7 +660,7 @@ def handle_p60_hk_data(printer: FsfwTmTcPrinter, set_id: int, hk_data: bytes): batt_voltage, temp_0, temp_1, - ) = struct.unpack(fmt_str, hk_data[current_idx : current_idx + inc_len]) + ) = struct.unpack(fmt_str, hk_data[current_idx: current_idx + inc_len]) current_idx += inc_len batt_info = ( f"Batt: Mode {batt_mode} | Boot Count {boot_count} | " @@ -646,9 +677,9 @@ def handle_p60_hk_data(printer: FsfwTmTcPrinter, set_id: int, hk_data: bytes): log_to_both(printer, "P60 Dock Latchups") for idx in range(0, 13): latchup_list.append( - struct.unpack("!H", hk_data[current_idx : current_idx + 2])[0] + struct.unpack("!H", hk_data[current_idx: current_idx + 2])[0] ) - content_line = f"{P60_INDEX_LIST[idx].ljust(24)} | {latchup_list[idx]}" + content_line = f"{TmHandler.P60_INDEX_LIST[idx].ljust(24)} | {latchup_list[idx]}" log_to_both(printer, content_line) current_idx += 2 fmt_str = "!IIHBBHHhhB" @@ -664,7 +695,7 @@ def handle_p60_hk_data(printer: FsfwTmTcPrinter, set_id: int, hk_data: bytes): batt_temp_0, batt_temp_1, dearm_status, - ) = struct.unpack(fmt_str, hk_data[current_idx : current_idx + inc_len]) + ) = struct.unpack(fmt_str, hk_data[current_idx: current_idx + inc_len]) current_idx += inc_len wdt = WdtInfo() current_idx = wdt.parse(wdt_data=hk_data[current_idx:], current_idx=current_idx) @@ -675,7 +706,7 @@ def handle_p60_hk_data(printer: FsfwTmTcPrinter, set_id: int, hk_data: bytes): batt_discharge_current, ant6_depl, ar6_depl, - ) = struct.unpack(fmt_str, hk_data[current_idx : current_idx + inc_len]) + ) = struct.unpack(fmt_str, hk_data[current_idx: current_idx + inc_len]) current_idx += inc_len device_types = [] device_statuses = [] diff --git a/pus_tm/tm_tcp_server.py b/pus_tm/tm_tcp_server.py new file mode 100644 index 0000000..4bf0138 --- /dev/null +++ b/pus_tm/tm_tcp_server.py @@ -0,0 +1,102 @@ +import socket +from typing import Optional +import json +import base64 + +from tmtccmd.logging import get_console_logger +from tmtccmd.utility.obj_id import ObjectId +from dle_encoder import DleEncoder + +# TODO add to configuration parameters +SERVER_HOST = "" +SERVER_PORT = 7305 + +LOGGER = get_console_logger() + + +class TmTcpServer: + + _Instance = None + + def __init__( + self): + + self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + self.server_socket.bind((SERVER_HOST, SERVER_PORT)) + + # for now, only accept one connection + self.server_socket.listen(0) + + self.server_socket.setblocking(False) + + self.client_connection: Optional[socket.socket] = None + + self.dle_encoder = DleEncoder() + + def __del__(self): + try: + self.close() + except: + LOGGER.warning("Could not close sockets!") + + def close(self): + self.server_socket.close() + if self.client_connection != None: + self.client_connection.close() + + def getInstance(): + if TmTcpServer._Instance == None: + TmTcpServer._Instance = TmTcpServer() + return TmTcpServer._Instance + + def _send_dictionary_over_socket(self, dictionary): + # keep listeners current + if self.client_connection == None: + # no running connection, see if a client wants to connect + try: + (self.client_connection, _) = self.server_socket.accept() + self.client_connection.setblocking(False) + except: + # no client waiting + return + + data_json_bytes = json.dumps(dictionary).encode() + + # dle encode the bytes + # adding a newline because someone might want to look at it in a console + data_json_bytes = self.dle_encoder.encode(data_json_bytes + b'\n') + + try: + sent_length = self.client_connection.send(data_json_bytes) + except: + self.client_connection = None + return + if sent_length == 0: + self.client_connection.close() + self.client_connection = None + + def report_raw_hk_data(self, object_id: ObjectId, + set_id: int, + hk_data: bytes): + + data_dict = {} + data_dict["type"] = "TM" + data_dict["tmType"] = "Raw HK" + data_dict["objectId"] = object_id.as_string + data_dict["setId"] = set_id + data_dict["rawData"] = base64.b64encode(hk_data).decode() + + self._send_dictionary_over_socket(data_dict) + + def report_parsed_hk_data(self, object_id: ObjectId, + set_id: int, + data_dictionary): + data_dict = {} + data_dict["type"] = "TM" + data_dict["tmType"] = "Parsed HK" + data_dict["objectId"] = object_id.as_string + data_dict["setId"] = set_id + data_dict["content"] = data_dictionary + + self._send_dictionary_over_socket(data_dict) \ No newline at end of file diff --git a/tmtccmd b/tmtccmd index e81e6db..862fdf2 160000 --- a/tmtccmd +++ b/tmtccmd @@ -1 +1 @@ -Subproject commit e81e6dbd594c1cdf51cd355a724cbd267d9dee38 +Subproject commit 862fdf23bc4a90ced47ee1c811de4237e3508536 diff --git a/tmtcloop.py b/tmtcloop.py index c48f436..52d1848 100755 --- a/tmtcloop.py +++ b/tmtcloop.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 """EIVE TMTC Commander""" +from distutils.log import debug import sys import traceback @@ -11,6 +12,7 @@ try: create_default_args_parser, add_default_tmtccmd_args, parse_default_input_arguments, + handle_unspecified_args, ) from tmtccmd.ccsds.handler import CcsdsTmHandler, ApidHandler from tmtccmd.logging import get_console_logger @@ -62,7 +64,7 @@ def main(): tmtc_backend.set_mode(CoreModeList.CONTINUOUS_MODE) get_console_logger().info("Disabling console logger for continuous operation") - get_console_logger().disabled = True + get_console_logger().setLevel("ERROR") tmtccmd.init_and_start_daemons(tmtc_backend=tmtc_backend) tmtccmd.performOperation(tmtc_backend=tmtc_backend) @@ -71,11 +73,12 @@ def main(): sys.argv = sys.argv[:1] while True: - args = parse_default_input_arguments(arg_parser, hook_obj) - setup_args = SetupArgs( - hook_obj=hook_obj, use_gui=False, apid=PUS_APID, cli_args=args - ) - tmtccmd.setup(setup_args=setup_args) + args.service = None + args.op_code = None + handle_unspecified_args(args, hook_obj.get_service_op_code_dictionary()) + + tmtc_backend.set_service(args.service) + tmtc_backend.set_opcode(args.op_code) tmtc_backend.set_mode(CoreModeList.CONTINUOUS_MODE) tmtccmd.performOperation(tmtc_backend=tmtc_backend)