diff --git a/CHANGELOG.md b/CHANGELOG.md index 91a34f2..029b509 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,33 @@ list yields a list of all related PRs for each release. # [unreleased] +## Added + +- Added handling for new clock events. + +# [v6.2.0] 2024-04-10 + +## Added + +- Added version set for STR. +- Command for relative timeshift. +- Health commands for payload components. + +## Fixed + +- EPS power commands working again. +- GNSS commands working again. + +## Changed + +- Fixed PLOC commanding + +# [v6.1.1] 2024-03-06 + +## Added + +- Added Core Ctrl cmd to update leap seconds. + # [v6.1.0] 2024-02-29 ## Added diff --git a/eive_tmtc/config/custom_mode_op.py b/eive_tmtc/config/custom_mode_op.py index 7981371..6143aaa 100644 --- a/eive_tmtc/config/custom_mode_op.py +++ b/eive_tmtc/config/custom_mode_op.py @@ -3,6 +3,7 @@ @details Template configuration file. Copy this folder to the TMTC commander root and adapt it to your needs. """ + import enum from tmtccmd import CcsdsTmtcBackend diff --git a/eive_tmtc/config/definitions.py b/eive_tmtc/config/definitions.py index e5bf6b8..e1ecece 100644 --- a/eive_tmtc/config/definitions.py +++ b/eive_tmtc/config/definitions.py @@ -15,6 +15,10 @@ TM_DB_PATH = "tm.db" # Separate DB or not? Not sure.. # RAW_TM_PATH = "raw_tm.db" +# TODO: The cleanest way would be to load those from the config file.. +PRINT_RAW_HK_B64_STR = False +PRINT_RAW_EVENTS_B64_STR = False + PUS_APID = 0x65 CFDP_APID = 0x66 PUS_PACKET_ID = PacketId(PacketType.TM, True, PUS_APID) diff --git a/eive_tmtc/config/events.csv b/eive_tmtc/config/events.csv index 200cbdb..3c05a3c 100644 --- a/eive_tmtc/config/events.csv +++ b/eive_tmtc/config/events.csv @@ -75,9 +75,12 @@ Event ID (dec); Event ID (hex); Name; Severity; Description; File Path 7902;0x1ede;BIT_LOCK;INFO;A Bit Lock signal. Was detected. P1: raw BLO state, P2: 0;fsfw/src/fsfw/datalinklayer/DataLinkLayer.h 7903;0x1edf;BIT_LOCK_LOST;INFO;A previously found Bit Lock signal was lost. P1: raw BLO state, P2: 0;fsfw/src/fsfw/datalinklayer/DataLinkLayer.h 7905;0x1ee1;FRAME_PROCESSING_FAILED;LOW;The CCSDS Board could not interpret a TC;fsfw/src/fsfw/datalinklayer/DataLinkLayer.h -8900;0x22c4;CLOCK_SET;INFO;No description;fsfw/src/fsfw/pus/Service9TimeManagement.h -8901;0x22c5;CLOCK_DUMP;INFO;No description;fsfw/src/fsfw/pus/Service9TimeManagement.h -8902;0x22c6;CLOCK_SET_FAILURE;LOW;No description;fsfw/src/fsfw/pus/Service9TimeManagement.h +8900;0x22c4;CLOCK_SET;INFO;Clock has been set. P1: old timeval seconds. P2: new timeval seconds.;fsfw/src/fsfw/pus/Service9TimeManagement.h +8901;0x22c5;CLOCK_DUMP_LEGACY;INFO;Clock dump event. P1: timeval seconds P2: timeval milliseconds.;fsfw/src/fsfw/pus/Service9TimeManagement.h +8902;0x22c6;CLOCK_SET_FAILURE;LOW;Clock could not be set. P1: Returncode.;fsfw/src/fsfw/pus/Service9TimeManagement.h +8903;0x22c7;CLOCK_DUMP;INFO;Clock dump event. P1: timeval seconds P2: timeval microseconds.;fsfw/src/fsfw/pus/Service9TimeManagement.h +8904;0x22c8;CLOCK_DUMP_BEFORE_SETTING_TIME;INFO;No description;fsfw/src/fsfw/pus/Service9TimeManagement.h +8905;0x22c9;CLOCK_DUMP_AFTER_SETTING_TIME;INFO;No description;fsfw/src/fsfw/pus/Service9TimeManagement.h 9100;0x238c;TC_DELETION_FAILED;MEDIUM;Deletion of a TC from the map failed. P1: First 32 bit of request ID, P2. Last 32 bit of Request ID;fsfw/src/fsfw/pus/Service11TelecommandScheduling.h 9700;0x25e4;TEST;INFO;No description;fsfw/src/fsfw/pus/Service17Test.h 10600;0x2968;CHANGE_OF_SETUP_PARAMETER;LOW;No description;fsfw/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h @@ -233,8 +236,9 @@ Event ID (dec); Event ID (hex); Name; Severity; Description; File Path 12902;0x3266;POWER_STATE_MACHINE_TIMEOUT;MEDIUM;No description;mission/system/acs/SusAssembly.h 12903;0x3267;SIDE_SWITCH_TRANSITION_NOT_ALLOWED;LOW;Not implemented, would increase already high complexity. Operator should instead command the assembly off first and then command the assembly on into the desired mode/submode combination;mission/system/acs/SusAssembly.h 13000;0x32c8;CHILDREN_LOST_MODE;MEDIUM;No description;mission/system/tcs/TcsBoardAssembly.h -13100;0x332c;GPS_FIX_CHANGE;INFO;Fix has changed. P1: Old fix. P2: New fix 0: Not seen, 1: No Fix, 2: 2D-Fix, 3: 3D-Fix;mission/acs/archive/GPSDefinitions.h -13101;0x332d;CANT_GET_FIX;LOW;Could not get fix in maximum allowed time. P1: Maximum allowed time to get a fix after the GPS was switched on.;mission/acs/archive/GPSDefinitions.h +13100;0x332c;GPS_FIX_CHANGE;INFO;Fix has changed. P1: New fix. P2: Missed fix changes 0: Not seen, 1: No Fix, 2: 2D-Fix, 3: 3D-Fix;linux/acs/GPSDefinitions.h +13101;0x332d;CANT_GET_FIX;MEDIUM;Could not get fix in maximum allowed time. Trying to reset both GNSS devices. P1: Maximum allowed time to get a fix after the GPS was switched on.;linux/acs/GPSDefinitions.h +13102;0x332e;RESET_FAIL;HIGH;Failed to reset an GNNS Device. P1: Board-Side.;linux/acs/GPSDefinitions.h 13200;0x3390;P60_BOOT_COUNT;INFO;P60 boot count is broadcasted once at SW startup. P1: Boot count;mission/power/P60DockHandler.h 13201;0x3391;BATT_MODE;INFO;Battery mode is broadcasted at startup. P1: Mode;mission/power/P60DockHandler.h 13202;0x3392;BATT_MODE_CHANGED;MEDIUM;Battery mode has changed. P1: Old mode. P2: New mode;mission/power/P60DockHandler.h diff --git a/eive_tmtc/config/object_ids.py b/eive_tmtc/config/object_ids.py index cb81d07..3d1c1c5 100644 --- a/eive_tmtc/config/object_ids.py +++ b/eive_tmtc/config/object_ids.py @@ -3,6 +3,7 @@ @details Template configuration file. Copy this folder to the TMTC commander root and adapt it to your needs. """ + import logging import os.path from typing import Dict diff --git a/eive_tmtc/pus_tc/cmd_definitions.py b/eive_tmtc/pus_tc/cmd_definitions.py index 88ba312..e69de29 100644 --- a/eive_tmtc/pus_tc/cmd_definitions.py +++ b/eive_tmtc/pus_tc/cmd_definitions.py @@ -1,21 +0,0 @@ -from tmtccmd.config import TmtcDefinitionWrapper, OpCodeEntry, CoreServiceList -from tmtccmd.config.tmtc import ( - call_all_definitions_providers, -) -from tmtccmd.config.globals import get_default_tmtc_defs - - -def get_eive_service_op_code_dict() -> TmtcDefinitionWrapper: - """Call all registered TMTC definition providers. They were registered using - the :py:func:`tmtc_definitions_provider` decorator. - """ - def_wrapper = get_default_tmtc_defs() - srv_5 = OpCodeEntry() - srv_5.add("0", "Event Test") - def_wrapper.add_service( - name=CoreServiceList.SERVICE_5.value, - info="PUS Service 5 Event", - op_code_entry=srv_5, - ) - call_all_definitions_providers(def_wrapper) - return def_wrapper diff --git a/eive_tmtc/pus_tc/cmd_demux.py b/eive_tmtc/pus_tc/cmd_demux.py index e45e6ff..7b2d9d5 100644 --- a/eive_tmtc/pus_tc/cmd_demux.py +++ b/eive_tmtc/pus_tc/cmd_demux.py @@ -1,5 +1,6 @@ """Hook function which packs telecommands based on service and operation code string """ + import logging from typing import List, cast @@ -51,6 +52,7 @@ from eive_tmtc.tmtc.com.subsystem import build_com_subsystem_procedure from eive_tmtc.tmtc.com.syrlinks_handler import pack_syrlinks_command from eive_tmtc.tmtc.core import pack_core_commands from eive_tmtc.tmtc.health import build_health_cmds +from eive_tmtc.tmtc.payload.subsystem import create_payload_subsystem_cmd from eive_tmtc.tmtc.payload.ploc_mpsoc import pack_ploc_mpsoc_commands from eive_tmtc.tmtc.payload.ploc_supervisor import pack_ploc_supv_commands from eive_tmtc.tmtc.payload.plpcdu import pack_pl_pcdu_commands @@ -116,9 +118,9 @@ def handle_pus_procedure( def handle_eps_procedure(queue_helper: DefaultPusQueueHelper, cmd_path_list: List[str]): obj_id_man = get_object_ids() - if len(cmd_path_list) == 1: - return pack_power_commands(queue_helper, cmd_path_list[0]) - assert len(cmd_path_list) >= 2 + assert len(cmd_path_list) >= 1 + if cmd_path_list[0] == "power": + return pack_power_commands(queue_helper, cmd_path_list[1]) if cmd_path_list[0] == "pwr_ctrl": return pack_power_ctrl_command(queue_helper, cmd_path_list[1]) if cmd_path_list[0] == "p60_dock": @@ -251,7 +253,8 @@ def handle_payload_procedure( queue_helper: DefaultPusQueueHelper, cmd_path_list: List[str] ): obj_id_man = get_object_ids() - assert len(cmd_path_list) >= 2 + if cmd_path_list[0] == "subsystem": + return create_payload_subsystem_cmd(queue_helper, cmd_path_list[1]) if cmd_path_list[0] == "ploc_mpsoc": return pack_ploc_mpsoc_commands(queue_helper, cmd_path_list[1]) if cmd_path_list[0] == "ploc_supv": @@ -263,7 +266,6 @@ def handle_payload_procedure( object_id=object_id, q=queue_helper, cmd_str=cmd_path_list[1] ) if cmd_path_list[0] == "pl_pcdu": - assert len(cmd_path_list) >= 3 return pack_pl_pcdu_commands(q=queue_helper, cmd_str=cmd_path_list[1]) if cmd_path_list[0] == "scex": return pack_scex_cmds( diff --git a/eive_tmtc/pus_tm/event_handler.py b/eive_tmtc/pus_tm/event_handler.py index 496c28b..2d5e674 100644 --- a/eive_tmtc/pus_tm/event_handler.py +++ b/eive_tmtc/pus_tm/event_handler.py @@ -1,7 +1,9 @@ import logging import datetime import sys +import base64 +from eive_tmtc.config.definitions import PRINT_RAW_EVENTS_B64_STR from eive_tmtc.config.events import get_event_dict from eive_tmtc.config.object_ids import get_object_ids from eive_tmtc.pus_tm.defs import PrintWrapper @@ -21,6 +23,8 @@ _LOGGER = logging.getLogger(__name__) def handle_event_packet( # noqa C901: Complexity okay here raw_tm: bytes, pw: PrintWrapper ): # noqa C901: Complexity okay here + if PRINT_RAW_EVENTS_B64_STR: + print(f"PUS Event TM Base64: {base64.b64encode(raw_tm)}") tm = Service5Tm.unpack(data=raw_tm, time_reader=CdsShortTimestamp.empty()) event_dict = get_event_dict() event_def = tm.event_definition @@ -36,6 +40,7 @@ def handle_event_packet( # noqa C901: Complexity okay here obj_name = event_def.reporter_id.hex(sep=",") else: obj_name = obj_id_obj.name + assert tm.time_provider is not None generic_event_string = ( f"Object {obj_name} generated Event {info.name} (ID: {event_def.event_id:#04x})" f" at {tm.time_provider.as_date_time()}" @@ -122,12 +127,22 @@ def handle_event_packet( # noqa C901: Complexity okay here new_time_dt = datetime.datetime.fromtimestamp(new_time, datetime.timezone.utc) pw.dlog(f"Old time (UTC): {old_time_dt}") pw.dlog(f"New time (UTC): {new_time_dt}") - if info.name == "CLOCK_DUMP": + if info.name == "CLOCK_DUMP_LEGACY": specific_handler = True # param 1 is timeval seconds, param 2 is timeval subsecond milliseconds time = event_def.param1 + event_def.param2 / 1000.0 time_dt = datetime.datetime.fromtimestamp(time, datetime.timezone.utc) pw.dlog(f"Current time: {time_dt}") + if ( + info.name == "CLOCK_DUMP" + or info.name == "CLOCK_DUMP_BEFORE_SETTING_TIME" + or info.name == "CLOCK_DUMP_AFTER_SETTING_TIME" + ): + specific_handler = True + # param 1 is timeval seconds, param 2 is timeval subsecond microseconds + time = event_def.param1 + event_def.param2 / 1000000.0 + time_dt = datetime.datetime.fromtimestamp(time, datetime.timezone.utc) + pw.dlog(f"Clock dump event {info.name}. Current time: {time_dt}") if info.name == "ACTIVE_SD_INFO": sd_0_state = (event_def.param2 >> 16) & 0xFFFF sd_1_state = event_def.param2 & 0xFFFF diff --git a/eive_tmtc/pus_tm/hk_handler.py b/eive_tmtc/pus_tm/hk_handler.py index 56c53af..8274cf0 100644 --- a/eive_tmtc/pus_tm/hk_handler.py +++ b/eive_tmtc/pus_tm/hk_handler.py @@ -1,10 +1,12 @@ """HK Handling for EIVE OBSW""" + import dataclasses import logging import base64 # noqa import sqlite3 from typing import List, cast from uuid import UUID +from eive_tmtc.config.definitions import PRINT_RAW_HK_B64_STR from eive_tmtc.pus_tm.hk import HkTmInfo from eive_tmtc.tmtc.acs.acs_ctrl import handle_acs_ctrl_hk_data @@ -73,7 +75,8 @@ def handle_hk_packet( if tm_packet.subservice == 25 or tm_packet.subservice == 26: hk_data = tm_packet.tm_data[8:] if named_obj_id.as_bytes in hk_filter.object_ids: - # print(f"PUS TM Base64: {base64.b64encode(raw_tm)}") + if PRINT_RAW_HK_B64_STR: + print(f"PUS TM Base64: {base64.b64encode(raw_tm)}") handle_regular_hk_print( printer=printer, packet_uuid=packet_uuid, diff --git a/eive_tmtc/pus_tm/pus_handler.py b/eive_tmtc/pus_tm/pus_handler.py index f3e62d1..7767b7f 100644 --- a/eive_tmtc/pus_tm/pus_handler.py +++ b/eive_tmtc/pus_tm/pus_handler.py @@ -1,5 +1,6 @@ """Core EIVE TM handler module """ + import logging import sqlite3 import uuid diff --git a/eive_tmtc/tmtc/acs/acs_ctrl.py b/eive_tmtc/tmtc/acs/acs_ctrl.py index 9f72faa..a2ab713 100644 --- a/eive_tmtc/tmtc/acs/acs_ctrl.py +++ b/eive_tmtc/tmtc/acs/acs_ctrl.py @@ -7,12 +7,7 @@ import struct from socket import AF_INET from typing import Tuple -from tmtccmd.config.tmtc import ( - CmdTreeNode, - OpCodeEntry, - TmtcDefinitionWrapper, - tmtc_definitions_provider, -) +from tmtccmd.config.tmtc import CmdTreeNode from tmtccmd.fsfw.tmtc_printer import FsfwTmTcPrinter from tmtccmd.pus.s8_fsfw_action import create_action_cmd from tmtccmd.pus.s20_fsfw_param import create_load_param_cmd @@ -37,7 +32,6 @@ from tmtccmd.pus.tc.s3_fsfw_hk import ( ) from tmtccmd.tmtc.queue import DefaultPusQueueHelper -from eive_tmtc.config.definitions import CustomServiceList from eive_tmtc.config.object_ids import ACS_CONTROLLER from eive_tmtc.pus_tm.defs import PrintWrapper from eive_tmtc.tmtc.acs.defs import AcsMode, SafeSubmode diff --git a/eive_tmtc/tmtc/acs/star_tracker.py b/eive_tmtc/tmtc/acs/star_tracker.py index a92230f..c9cd815 100644 --- a/eive_tmtc/tmtc/acs/star_tracker.py +++ b/eive_tmtc/tmtc/acs/star_tracker.py @@ -140,9 +140,15 @@ class OpCode: SELECT_TARGET_FIRMWARE_BACKUP = "fw_backup" SELECT_TARGET_FIRMWARE_MAIN_PERSISTENT = "fw_main_persistent" SELECT_TARGET_FIRMWARE_BACKUP_PERSISTENT = "fw_backup_persistent" + REQUEST_VERSION = "request_version" class Info: + ON_BOOTLOADER = "Switch to Mode On, Submode Bootloder" + ON_FIRMWARE = "Switch to Mode On, Submode Firmware" + NORMAL = "Switch to Mode Normal" + OFF = "Switch to Mode Off" + PING = "Send Ping" ONE_SHOOT_HK = "One shoot HK Set" ENABLE_HK = "Enable Periodic HK" DISABLE_HK = "Disable Periodic HK" @@ -163,6 +169,7 @@ class Info: SELECT_TARGET_FIRMWARE_BACKUP_PERSISTENT = ( "Select backup firmware slot persistently" ) + REQUEST_VERSION = "Request the active Firmware Version" class SetId(enum.IntEnum): @@ -316,10 +323,6 @@ def pack_star_tracker_commands( # noqa C901 q.add_log_cmd("Star tracker: Temperature request") data = obyt + struct.pack("!I", StarTrackerActionId.REQ_TEMPERATURE) q.add_pus_tc(PusTelecommand(service=8, subservice=128, app_data=data)) - if cmd_str == "8": - q.add_log_cmd("Star tracker: Request version") - data = obyt + struct.pack("!I", StarTrackerActionId.REQ_VERSION) - q.add_pus_tc(PusTelecommand(service=8, subservice=128, app_data=data)) if cmd_str == "9": q.add_log_cmd("Star tracker: Request interface") data = obyt + struct.pack("!I", StarTrackerActionId.REQ_INTERFACE) @@ -730,6 +733,13 @@ def pack_star_tracker_commands( # noqa C901 if cmd_str == OpCode.SELECT_TARGET_FIRMWARE_BACKUP_PERSISTENT: q.add_log_cmd(Info.SELECT_TARGET_FIRMWARE_BACKUP) q.add_pus_tc(create_update_firmware_target_cmd(True, FirmwareTarget.BACKUP)) + if cmd_str == OpCode.REQUEST_VERSION: + q.add_log_cmd(Info.REQUEST_VERSION) + q.add_pus_tc( + create_action_cmd( + object_id=STAR_TRACKER_ID, action_id=StarTrackerActionId.REQ_VERSION + ) + ) def create_update_firmware_target_cmd( @@ -880,6 +890,8 @@ def handle_str_hk_data(set_id: int, hk_data: bytes, pw: PrintWrapper): handle_contrast_set(hk_data, pw) elif set_id == SetId.BLOB_STATS: handle_blob_stats_set(hk_data, pw) + elif set_id == SetId.VERSION: + handle_version_set(hk_data, pw) else: _LOGGER.warning(f"HK parsing for Star Tracker set ID {set_id} unimplemented") @@ -902,6 +914,25 @@ def unpack_time_hk(hk_data: bytes, current_idx: int, pw: PrintWrapper) -> int: return current_idx +def handle_version_set(hk_data: bytes, pw: PrintWrapper): + pw.dlog("Received Version Set") + if len(hk_data) != 16: + _LOGGER.warning( + f"Version dataset HK with length {len(hk_data)} of unexpected size" + ) + current_idx = unpack_time_hk(hk_data, 0, pw) + program = struct.unpack("!B", hk_data[current_idx : current_idx + 1])[0] + pw.dlog(f"Program: {program}") + current_idx += 1 + major = struct.unpack("!B", hk_data[current_idx : current_idx + 1])[0] + pw.dlog(f"Major: {major}") + current_idx += 1 + minor = struct.unpack("!B", hk_data[current_idx : current_idx + 1])[0] + pw.dlog(f"Minor: {minor}") + current_idx += 1 + pw.dlog(FsfwTmTcPrinter.get_validity_buffer(hk_data[current_idx:], num_vars=5)) + + def handle_temperature_set(hk_data: bytes, pw: PrintWrapper): pw.dlog("Received temperature set") if len(hk_data) < 24: @@ -1208,7 +1239,7 @@ def handle_blob_stats_set(hk_data: bytes, pw: PrintWrapper): i, noise_list[i], threshold_list[i], lvalid_list[i], oflow_list[i] ) ) - pw.dlog(FsfwTmTcPrinter.get_validity_buffer(hk_data[current_idx:], num_vars=4)) + pw.dlog(FsfwTmTcPrinter.get_validity_buffer(hk_data[current_idx:], num_vars=6)) def handle_star_tracker_action_replies( @@ -1251,60 +1282,15 @@ def handle_read_secondary_tm_set(pw: PrintWrapper, custom_data: bytes): def create_str_node() -> CmdTreeNode: + # Zip the two classes together into a dictionary + op_code_strs = [ + getattr(OpCode, key) for key in dir(OpCode) if not key.startswith("__") + ] + info_strs = [getattr(Info, key) for key in dir(OpCode) if not key.startswith("__")] + combined_dict = dict(zip(op_code_strs, info_strs)) node = CmdTreeNode( "str", "Star Tracker Device", hide_children_which_are_leaves=True ) - node.add_child(CmdTreeNode(OpCode.ON_BOOTLOADER, "Mode On, Submode Bootloader")) - node.add_child(CmdTreeNode(OpCode.ON_FIRMWARE, "Mode On, Submode Firmware")) - node.add_child(CmdTreeNode(OpCode.NORMAL, "Mode Normal")) - node.add_child(CmdTreeNode(OpCode.OFF, "Mode Off")) - node.add_child(CmdTreeNode(OpCode.PING, "Star Tracker: Ping")) - node.add_child(CmdTreeNode(OpCode.TAKE_IMAGE, "Take Image")) - node.add_child(CmdTreeNode(OpCode.UPLOAD_IMAGE, Info.UPLOAD_IMAGE)) - node.add_child(CmdTreeNode(OpCode.DOWNLOAD_IMAGE, Info.DOWNLOAD_IMAGE)) - node.add_child(CmdTreeNode(OpCode.ONE_SHOOT_HK, Info.ONE_SHOOT_HK)) - node.add_child(CmdTreeNode(OpCode.ENABLE_HK, Info.ENABLE_HK)) - node.add_child(CmdTreeNode(OpCode.DISABLE_HK, Info.DISABLE_HK)) - node.add_child( - CmdTreeNode(OpCode.SET_IMG_PROCESSOR_MODE, Info.SET_IMG_PROCESSOR_MODE) - ) - node.add_child( - CmdTreeNode( - OpCode.ADD_SECONDARY_TM_TO_NORMAL_MODE, - Info.ADD_SECONDARY_TM_TO_NORMAL_MODE, - ) - ) - node.add_child( - CmdTreeNode(OpCode.READ_SECONDARY_TM_SET, Info.READ_SECONDARY_TM_SET) - ) - node.add_child( - CmdTreeNode(OpCode.RESET_SECONDARY_TM_SET, Info.RESET_SECONDARY_TM_SET) - ) - node.add_child(CmdTreeNode(OpCode.FW_UPDATE_MAIN, Info.FW_UPDATE_MAIN)) - node.add_child(CmdTreeNode(OpCode.FW_UPDATE_BACKUP, Info.FW_UPDATE_BACKUP)) - node.add_child( - CmdTreeNode( - OpCode.SELECT_TARGET_FIRMWARE_MAIN, Info.SELECT_TARGET_FIRMWARE_MAIN - ) - ) - node.add_child( - CmdTreeNode( - OpCode.SELECT_TARGET_FIRMWARE_BACKUP, Info.SELECT_TARGET_FIRMWARE_BACKUP - ) - ) - node.add_child( - CmdTreeNode( - OpCode.SELECT_TARGET_FIRMWARE_MAIN_PERSISTENT, - Info.SELECT_TARGET_FIRMWARE_MAIN_PERSISTENT, - ) - ) - node.add_child( - CmdTreeNode( - OpCode.SELECT_TARGET_FIRMWARE_BACKUP_PERSISTENT, - Info.SELECT_TARGET_FIRMWARE_BACKUP_PERSISTENT, - ) - ) - node.add_child( - CmdTreeNode(OpCode.SET_TIME_FROM_SYS_TIME, Info.SET_TIME_FROM_SYS_TIME) - ) + for op_code, info in combined_dict.items(): + node.add_child(CmdTreeNode(op_code, info)) return node diff --git a/eive_tmtc/tmtc/core.py b/eive_tmtc/tmtc/core.py index a1db863..f80d6ab 100644 --- a/eive_tmtc/tmtc/core.py +++ b/eive_tmtc/tmtc/core.py @@ -6,7 +6,7 @@ from pathlib import Path from typing import Tuple from spacepackets.ecss import PusTelecommand -from tmtccmd.config import CmdTreeNode, TmtcDefinitionWrapper +from tmtccmd.config import CmdTreeNode from tmtccmd.tmtc import DefaultPusQueueHelper from tmtccmd.pus.s8_fsfw_action import create_action_cmd @@ -15,14 +15,12 @@ from tmtccmd.pus.s20_fsfw_param import ( create_scalar_u8_parameter, create_load_param_cmd, ) -from tmtccmd.config.tmtc import OpCodeEntry, tmtc_definitions_provider from tmtccmd.fsfw.tmtc_printer import FsfwTmTcPrinter from tmtccmd.pus.s11_tc_sched import ( create_enable_tc_sched_cmd, create_disable_tc_sched_cmd, ) -from eive_tmtc.config.definitions import CustomServiceList from eive_tmtc.config.object_ids import CORE_CONTROLLER_ID from eive_tmtc.pus_tm.defs import PrintWrapper @@ -71,6 +69,7 @@ class ActionId(enum.IntEnum): RM_HELPER = 54 MKDIR_HELPER = 55 ENABLE_SCHEDULER = 56 + UPDATE_LEAP_SECONRS = 60 class ParamId(enum.IntEnum): @@ -122,6 +121,7 @@ class OpCode: AUTO_SWITCH_DISABLE = "auto_switch_disable" ENABLE_SCHEDULER = "enable_scheduler" DISABLE_SCHEDULER = "disable_scheduler" + UPDATE_LEAP_SECONDS = "leap_seconds_update" class Info: @@ -165,6 +165,7 @@ class Info: AUTO_SWITCH_DISABLE = "Disable Auto-Switch Feature" ENABLE_SCHEDULER = "Enable scheduler" DISABLE_SCHEDULER = "Disable scheduler" + UPDATE_LEAP_SECONDS = "Updates the Leap Seconds" class Chip(enum.IntEnum): @@ -197,90 +198,6 @@ def create_core_node() -> CmdTreeNode: return node -@tmtc_definitions_provider -def add_core_controller_definitions(defs: TmtcDefinitionWrapper): - oce = OpCodeEntry() - oce.add(keys=OpCode.ANNOUNCE_VERSION, info=Info.ANNOUNCE_VERSION) - oce.add(keys=OpCode.ANNOUNCE_CURRENT_IMAGE, info=Info.ANNOUNCE_CURRENT_IMAGE) - oce.add(keys=OpCode.ANNOUNCE_BOOT_COUNTS, info=Info.ANNOUNCE_BOOT_COUNTS) - oce.add(keys=OpCode.REBOOT_XSC, info=Info.REBOOT_XSC) - oce.add(keys=OpCode.REBOOT_XSC, info=Info.REBOOT_XSC) - oce.add(keys=OpCode.REBOOT_FULL, info=Info.REBOOT_FULL) - oce.add(keys=OpCode.XSC_REBOOT_SELF, info="Reboot Self") - oce.add(keys=OpCode.XSC_REBOOT_0_0, info="Reboot 0 0") - oce.add(keys=OpCode.XSC_REBOOT_0_1, info="Reboot 0 1") - oce.add(keys=OpCode.XSC_REBOOT_1_0, info="Reboot 1 0") - oce.add(keys=OpCode.XSC_REBOOT_1_1, info="Reboot 1 1") - oce.add(keys=OpCode.SET_PREF_SD, info=Info.SET_PREF_SD) - oce.add( - keys=OpCode.READ_REBOOT_MECHANISM_INFO, info=Info.READ_REBOOT_MECHANISM_INFO - ) - oce.add(keys=OpCode.OBSW_UPDATE_FROM_TMP, info=Info.OBSW_UPDATE_FROM_TMP) - oce.add(keys=OpCode.OBSW_UPDATE_FROM_SD_0, info=Info.OBSW_UPDATE_FROM_SD_0) - oce.add(keys=OpCode.OBSW_UPDATE_FROM_SD_1, info=Info.OBSW_UPDATE_FROM_SD_1) - oce.add(keys=OpCode.AUTO_SWITCH_ENABLE, info=Info.AUTO_SWITCH_ENABLE) - oce.add(keys=OpCode.AUTO_SWITCH_DISABLE, info=Info.AUTO_SWITCH_DISABLE) - oce.add(keys=OpCode.SYSTEMCTL_CMD_EXECUTOR, info=Info.SYSTEMCTL_CMD_EXECUTOR) - oce.add( - keys=OpCode.EXECUTE_SHELL_CMD_BLOCKING, info=Info.EXECUTE_SHELL_CMD_BLOCKING - ) - oce.add( - keys=OpCode.EXECUTE_SHELL_CMD_NON_BLOCKING, - info=Info.EXECUTE_SHELL_CMD_NON_BLOCKING, - ) - oce.add( - keys=OpCode.GET_HK, - info="Request housekeeping set", - ) - oce.add( - keys=OpCode.ENABLE_REBOOT_FILE_HANDLING, - info="Enable reboot file handling", - ) - oce.add( - keys=OpCode.DISABLE_REBOOT_FILE_HANDLING, - info="Disable reboot file handling", - ) - oce.add( - keys=OpCode.RESET_ALL_REBOOT_COUNTERS, - info="Reset all reboot counters", - ) - oce.add( - keys=OpCode.RWD_RESET_REBOOT_COUNTER_00, - info="Reset reboot counter 0 0", - ) - oce.add( - keys=OpCode.RWD_RESET_REBOOT_COUNTER_01, - info="Reset reboot counter 0 1", - ) - oce.add( - keys=OpCode.RWD_RESET_REBOOT_COUNTER_10, - info="Reset reboot counter 1 0", - ) - oce.add( - keys=OpCode.RWD_RESET_REBOOT_COUNTER_11, - info="Reset reboot counter 1 1", - ) - oce.add( - keys=OpCode.RWD_SET_MAX_REBOOT_CNT, - info="Reset max reboot count for reboot watchdog", - ) - oce.add(keys=OpCode.OBSW_UPDATE_FROM_SD_0, info=Info.OBSW_UPDATE_FROM_SD_0) - oce.add(keys=OpCode.OBSW_UPDATE_FROM_SD_1, info=Info.OBSW_UPDATE_FROM_SD_1) - oce.add(keys=OpCode.OBSW_UPDATE_FROM_TMP, info=Info.OBSW_UPDATE_FROM_TMP) - oce.add(keys=OpCode.SWITCH_TO_SD_0, info=Info.SWITCH_TO_SD_0) - oce.add(keys=OpCode.SWITCH_TO_SD_1, info=Info.SWITCH_TO_SD_1) - oce.add(keys=OpCode.SWITCH_TO_BOTH_SD_CARDS, info=Info.SWITCH_TO_BOTH_SD_CARDS) - oce.add(keys=OpCode.LIST_DIR_INTO_FILE, info=Info.LIST_DIR_INTO_FILE) - oce.add(keys=OpCode.LIST_DIR_DUMP_DIRECTLY, info=Info.LIST_DIR_DUMP_DIRECTLY) - oce.add(keys=OpCode.MV_HELPER, info=Info.MV_HELPER) - oce.add(keys=OpCode.CP_HELPER, info=Info.CP_HELPER) - oce.add(keys=OpCode.RM_HELPER, info=Info.RM_HELPER) - oce.add(keys=OpCode.MKDIR_HELPER, info=Info.MKDIR_HELPER) - oce.add(keys=OpCode.ENABLE_SCHEDULER, info=Info.ENABLE_SCHEDULER) - oce.add(keys=OpCode.DISABLE_SCHEDULER, info=Info.DISABLE_SCHEDULER) - defs.add_service(CustomServiceList.CORE.value, "Core Controller", oce) - - def pack_core_commands( # noqa C901 q: DefaultPusQueueHelper, cmd_str: str ): # noqa: C901 , complexity okay here @@ -557,6 +474,16 @@ def pack_core_commands( # noqa C901 elif cmd_str == OpCode.DISABLE_SCHEDULER: q.add_log_cmd(Info.DISABLE_SCHEDULER) q.add_pus_tc(create_disable_tc_sched_cmd()) + elif cmd_str == OpCode.UPDATE_LEAP_SECONDS: + q.add_log_cmd(Info.UPDATE_LEAP_SECONDS) + leap_seconds = int(input("Specify new Leap Seconds Value: ")).to_bytes( + length=2, signed=False, byteorder="big" + ) + q.add_pus_tc( + create_action_cmd( + CORE_CONTROLLER_ID, ActionId.UPDATE_LEAP_SECONRS, leap_seconds + ) + ) else: _LOGGER.warning( f"Unknown operation code {cmd_str} for core controller commands" diff --git a/eive_tmtc/tmtc/obj_prompt.py b/eive_tmtc/tmtc/obj_prompt.py index c472a01..0764a92 100644 --- a/eive_tmtc/tmtc/obj_prompt.py +++ b/eive_tmtc/tmtc/obj_prompt.py @@ -6,6 +6,8 @@ from eive_tmtc.config.object_ids import ( GYRO_1_L3G_HANDLER_ID, GYRO_2_ADIS_HANDLER_ID, ACS_BOARD_ASS_ID, + PLOC_MPSOC_ID, + PLOC_SUPV_ID, RW_ASSEMBLY, SUS_BOARD_ASS_ID, MGM_0_LIS3_HANDLER_ID, @@ -28,6 +30,7 @@ SUBSYSTEM_DICT = { 0: "acs", 1: "tcs", 2: "com", + 3: "payload", } ACS_OBJ_DICT = { @@ -59,6 +62,11 @@ TCS_OBJ_DICT = { 5: ("TMP1075 IF BOARD", TMP1075_HANDLER_IF_BRD_ID), } +PAYLOAD_OBJ_DICT = { + 0: ("Payload MPSoC", PLOC_MPSOC_ID), + 1: ("Payload Supervisor", PLOC_SUPV_ID), +} + def get_obj_if_from_dict(lut: dict) -> bytes: for k, v in lut.items(): @@ -81,6 +89,8 @@ def prompt_object() -> bytes: return get_obj_if_from_dict(ACS_OBJ_DICT) elif subsystem == "tcs": return get_obj_if_from_dict(TCS_OBJ_DICT) + elif subsystem == "payload": + return get_obj_if_from_dict(PAYLOAD_OBJ_DICT) else: print(f"No object for subsystem {subsystem}") return bytes() diff --git a/eive_tmtc/tmtc/payload/subsystem.py b/eive_tmtc/tmtc/payload/subsystem.py index 529865e..7ebd77a 100644 --- a/eive_tmtc/tmtc/payload/subsystem.py +++ b/eive_tmtc/tmtc/payload/subsystem.py @@ -21,20 +21,27 @@ class ModeId(enum.IntEnum): class OpCode(str, enum.Enum): OFF = "off" REPORT_ALL_MODES = "report_modes" + MPSOC_STREAM = "mode_mpsoc_stream" + CAM_STREAM = "mode_cam_stream" + EARTH_OBSV = "mode_eart_obsv" class Info(str, enum.Enum): OFF = "Off Command" REPORT_ALL_MODES = "Report all modes" + MPSOC_STREAM = "MPSoC Stream Mode" + CAM_STREAM = "Camera Stream Mode" + EARTH_OBSV = "Earth Observation Mode" HANDLER_LIST: Dict[str, Tuple[int, str]] = { OpCode.OFF: (ModeId.OFF, Info.OFF), + OpCode.MPSOC_STREAM: (ModeId.MPSOC_STREAM, Info.MPSOC_STREAM), } -def build_acs_subsystem_cmd(q: DefaultPusQueueHelper, cmd_str: str): - info_prefix = "ACS Subsystem" +def create_payload_subsystem_cmd(q: DefaultPusQueueHelper, cmd_str: str): + info_prefix = "Payload Subsystem" if cmd_str == OpCode.REPORT_ALL_MODES: q.add_log_cmd(f"{info_prefix}: {Info.REPORT_ALL_MODES}") q.add_pus_tc( @@ -45,19 +52,28 @@ def build_acs_subsystem_cmd(q: DefaultPusQueueHelper, cmd_str: str): ) ) mode_info_tup = HANDLER_LIST.get(cmd_str) + assert mode_info_tup is not None if mode_info_tup is None: return pack_mode_cmd_with_info( object_id=PL_SUBSYSTEM_ID, info=f"{info_prefix}: {mode_info_tup[1]}", - submode=0, mode=mode_info_tup[0], + submode=0, q=q, ) def create_payload_subsystem_node() -> CmdTreeNode: payload_node = CmdTreeNode("payload", "Payload Subsystem") - payload_node.add_child(CmdTreeNode(OpCode.OFF, Info.OFF)) - payload_node.add_child(CmdTreeNode(OpCode.REPORT_ALL_MODES, Info.REPORT_ALL_MODES)) + subsystem_node = CmdTreeNode("subsystem", "Subsystem Commands") + subsystem_node.add_child(CmdTreeNode(OpCode.OFF, Info.OFF)) + subsystem_node.add_child(CmdTreeNode(OpCode.MPSOC_STREAM, Info.MPSOC_STREAM)) + subsystem_node.add_child(CmdTreeNode(OpCode.EARTH_OBSV, Info.EARTH_OBSV)) + subsystem_node.add_child(CmdTreeNode(OpCode.CAM_STREAM, Info.CAM_STREAM)) + + subsystem_node.add_child( + CmdTreeNode(OpCode.REPORT_ALL_MODES, Info.REPORT_ALL_MODES) + ) + payload_node.add_child(subsystem_node) return payload_node diff --git a/eive_tmtc/tmtc/tcs/heater.py b/eive_tmtc/tmtc/tcs/heater.py index 99fe3eb..356b751 100644 --- a/eive_tmtc/tmtc/tcs/heater.py +++ b/eive_tmtc/tmtc/tcs/heater.py @@ -59,7 +59,7 @@ CTN = CmdTreeNode def create_heater_node() -> CmdTreeNode: - node = CmdTreeNode("heater", "Heater Device", hide_children_which_are_leaves=True) + node = CmdTreeNode("heaters", "Heater Device", hide_children_which_are_leaves=True) node.add_child(CTN(OpCode.HEATER_CMD, Info.HEATER_CMD)) node.add_child(CTN(OpCode.HEATER_HEALTHY_CMD, Info.HEATER_HEALTHY_CMD)) node.add_child(CTN(OpCode.HEATER_EXT_CTRL, Info.HEATER_EXT_CTRL)) diff --git a/eive_tmtc/tmtc/time.py b/eive_tmtc/tmtc/time.py index 1e7fdc7..97413c5 100644 --- a/eive_tmtc/tmtc/time.py +++ b/eive_tmtc/tmtc/time.py @@ -1,6 +1,7 @@ import enum +import struct import logging -from datetime import datetime +import datetime from spacepackets.ecss import PusTelecommand, PusService @@ -8,28 +9,34 @@ from tmtccmd.tmtc import DefaultPusQueueHelper from tmtccmd.config import CmdTreeNode +_LOGGER = logging.getLogger(__name__) + + class Subservice(enum.IntEnum): SET_TIME = 128 DUMP_TIME = 129 + RELATIVE_TIMESHIFT = 130 class CmdStr: SET_CURRENT_TIME = "set_curr_time" + RELATIVE_TIMESHIFT = "relative_timeshift" DUMP_TIME = "dump_time" class Info: SET_CURRENT_TIME = "Setting current time in ASCII format" + RELATIVE_TIMESHIFT = "Shift time with a relative offset" DUMP_TIME = "Dump system time as event" def pack_time_management_cmd(q: DefaultPusQueueHelper, cmd_str: str): if cmd_str == CmdStr.SET_CURRENT_TIME: - current_time = datetime.utcnow().isoformat() + "Z" + "\0" - current_time_ascii = current_time.encode("ascii") - logging.getLogger(__name__).info( - f"Current time in ASCII format: {current_time_ascii}" + current_time = ( + datetime.datetime.now(datetime.timezone.utc).isoformat() + "Z" + "\0" ) + current_time_ascii = current_time.encode("ascii") + _LOGGER.info(f"Current time in ASCII format: {current_time_ascii}") q.add_log_cmd(Info.SET_CURRENT_TIME) q.add_pus_tc( PusTelecommand( @@ -38,6 +45,17 @@ def pack_time_management_cmd(q: DefaultPusQueueHelper, cmd_str: str): app_data=current_time_ascii, ) ) + elif cmd_str == CmdStr.RELATIVE_TIMESHIFT: + nanos = int(input("Specify relative timeshift in nanoseconds: ")) + nanos_packed = struct.pack("!q", nanos) + q.add_log_cmd(Info.RELATIVE_TIMESHIFT) + q.add_pus_tc( + PusTelecommand( + service=PusService.S9_TIME_MGMT, + subservice=Subservice.RELATIVE_TIMESHIFT, + app_data=nanos_packed, + ) + ) elif cmd_str == CmdStr.DUMP_TIME: q.add_log_cmd(Info.DUMP_TIME) q.add_pus_tc( @@ -51,4 +69,5 @@ def create_time_node() -> CmdTreeNode: time_node = CmdTreeNode("time", "Time Management") time_node.add_child(CmdTreeNode(CmdStr.SET_CURRENT_TIME, "Set current time")) time_node.add_child(CmdTreeNode(CmdStr.DUMP_TIME, "Dumpy current time")) + time_node.add_child(CmdTreeNode(CmdStr.RELATIVE_TIMESHIFT, Info.RELATIVE_TIMESHIFT)) return time_node diff --git a/pyproject.toml b/pyproject.toml index e4f2a5e..b5f75e8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta" name = "eive-tmtc" description = "TMTC Commander EIVE" readme = "README.md" -version = "6.1.0" +version = "6.2.0" requires-python = ">=3.10" license = {text = "Apache-2.0"} authors = [ diff --git a/scripts/raw-analysis.py b/scripts/raw-analysis.py new file mode 100755 index 0000000..acad4d4 --- /dev/null +++ b/scripts/raw-analysis.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 +from base64 import b64decode +from spacepackets.ccsds.time import CdsShortTimestamp +from spacepackets.ecss.tm import PusTelemetry +from spacepackets.ecss.pus_1_verification import Service1Tm, UnpackParams + +bruh = "CGX6cQAdIAEIOzcAAEBedwUTOzkYZe5WAAEAAAAAAAAAAF4z" +data = b64decode(bruh) +tm = PusTelemetry.unpack(data, CdsShortTimestamp.empty()) +srv1_tm = Service1Tm.from_tm( + tm, UnpackParams(time_reader=CdsShortTimestamp.empty(), bytes_err_code=2) +) +print(f"service {tm.service} subservice {tm.subservice}") +print(f"error code: {srv1_tm.error_code}")