2021-03-25 17:53:05 +01:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
|
|
@file imtq.py
|
|
|
|
@brief Tests for the ISIS IMTQ (Magnettorquer) device handler
|
|
|
|
@author J. Meier
|
|
|
|
@date 25.03.2021
|
|
|
|
"""
|
2023-02-19 13:25:12 +01:00
|
|
|
import logging
|
2022-06-03 18:04:59 +02:00
|
|
|
import struct
|
2022-12-02 16:06:20 +01:00
|
|
|
from typing import List
|
2022-06-03 18:04:59 +02:00
|
|
|
|
2022-11-29 16:53:29 +01:00
|
|
|
from eive_tmtc.config.definitions import CustomServiceList
|
|
|
|
from eive_tmtc.pus_tm.defs import PrintWrapper
|
2021-10-01 10:55:56 +02:00
|
|
|
from spacepackets.ecss.tc import PusTelecommand
|
2022-10-18 17:26:43 +02:00
|
|
|
from tmtccmd.config.tmtc import (
|
|
|
|
tmtc_definitions_provider,
|
|
|
|
OpCodeEntry,
|
|
|
|
TmtcDefinitionWrapper,
|
|
|
|
)
|
2022-08-08 16:32:18 +02:00
|
|
|
from tmtccmd.tc import DefaultPusQueueHelper
|
2022-05-25 15:21:50 +02:00
|
|
|
from tmtccmd.tc.pus_3_fsfw_hk import (
|
|
|
|
make_sid,
|
|
|
|
generate_one_diag_command,
|
|
|
|
generate_one_hk_command,
|
|
|
|
)
|
2023-01-31 12:56:13 +01:00
|
|
|
from tmtccmd.tc.pus_200_fsfw_mode import pack_mode_data, Mode
|
2022-07-08 16:25:46 +02:00
|
|
|
from tmtccmd.util import ObjectIdU32
|
2022-10-20 14:22:19 +02:00
|
|
|
from tmtccmd.util.tmtc_printer import FsfwTmTcPrinter
|
2021-03-25 17:53:05 +01:00
|
|
|
|
|
|
|
|
2023-02-19 13:27:59 +01:00
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
2023-01-16 14:13:06 +01:00
|
|
|
class OpCode:
|
2023-02-19 12:39:25 +01:00
|
|
|
ON = "on"
|
|
|
|
NORMAL = "normal"
|
|
|
|
OFF = "off"
|
|
|
|
SET_DIPOLE = "set_dipole"
|
|
|
|
REQUEST_ENG_HK = "hk_os_eng_hk"
|
|
|
|
REQUEST_MGM_RAW = "hk_os_mgm_raw"
|
|
|
|
POS_X_SELF_TEST = "self_test_pos_x"
|
|
|
|
NEG_X_SELF_TEST = "self_test_neg_x"
|
|
|
|
POS_Y_SELF_TEST = "self_test_pos_y"
|
|
|
|
NEG_Y_SELF_TEST = "self_test_neg_y"
|
|
|
|
POS_Z_SELF_TEST = "self_test_pos_z"
|
|
|
|
NEG_Z_SELF_TEST = "self_test_neg_z"
|
2022-10-18 17:10:33 +02:00
|
|
|
|
|
|
|
|
2023-01-16 14:13:06 +01:00
|
|
|
class ImtqSetId:
|
2023-02-19 03:48:30 +01:00
|
|
|
ENG_HK_NO_TORQUE = 1
|
|
|
|
RAW_MTM_NO_TORQUE = 2
|
|
|
|
ENG_HK_SET_WITH_TORQUE = 3
|
|
|
|
RAW_MTM_WITH_TORQUE = 4
|
|
|
|
STATUS_SET = 5
|
|
|
|
DIPOLES = 6
|
|
|
|
|
|
|
|
CAL_MTM_SET = 9
|
|
|
|
POSITIVE_X_TEST = 10
|
|
|
|
NEGATIVE_X_TEST = 11
|
|
|
|
POSITIVE_Y_TEST = 12
|
|
|
|
NEGATIVE_Y_TEST = 13
|
|
|
|
POSITIVE_Z_TEST = 14
|
|
|
|
NEGATIVE_Z_TEST = 15
|
2023-02-27 15:16:20 +01:00
|
|
|
SELF_TEST_SET = 16
|
2021-03-25 17:53:05 +01:00
|
|
|
|
|
|
|
|
2023-01-16 14:13:06 +01:00
|
|
|
class ImtqActionId:
|
2021-03-25 17:53:05 +01:00
|
|
|
start_actuation_dipole = bytearray([0x0, 0x0, 0x0, 0x02])
|
2021-04-25 17:46:53 +02:00
|
|
|
get_commanded_dipole = bytearray([0x0, 0x0, 0x0, 0x03])
|
2021-06-12 13:49:25 +02:00
|
|
|
perform_positive_x_test = bytearray([0x0, 0x0, 0x0, 0x07])
|
|
|
|
perform_negative_x_test = bytearray([0x0, 0x0, 0x0, 0x08])
|
|
|
|
perform_positive_y_test = bytearray([0x0, 0x0, 0x0, 0x09])
|
|
|
|
perform_negative_y_test = bytearray([0x0, 0x0, 0x0, 0x0A])
|
|
|
|
perform_positive_z_test = bytearray([0x0, 0x0, 0x0, 0x0B])
|
|
|
|
perform_negative_z_test = bytearray([0x0, 0x0, 0x0, 0x0C])
|
2022-07-04 15:22:53 +02:00
|
|
|
# Initiates the reading of the last performed self test. After sending this command the results
|
|
|
|
# can be downlinked via the housekeeping service by using the appropriate set ids listed above.
|
2021-06-12 13:49:25 +02:00
|
|
|
read_self_test_results = bytearray([0x0, 0x0, 0x0, 0x0D])
|
2021-03-25 17:53:05 +01:00
|
|
|
|
|
|
|
|
2022-10-18 17:26:43 +02:00
|
|
|
@tmtc_definitions_provider
|
|
|
|
def add_imtq_cmds(defs: TmtcDefinitionWrapper):
|
|
|
|
oce = OpCodeEntry()
|
2023-01-16 14:13:06 +01:00
|
|
|
oce.add(OpCode.OFF, "Mode Off")
|
|
|
|
oce.add(OpCode.ON, "Mode On")
|
|
|
|
oce.add(OpCode.NORMAL, "Mode Normal")
|
2023-02-19 12:39:25 +01:00
|
|
|
oce.add(OpCode.REQUEST_ENG_HK, "Request Engineering HK One Shot")
|
|
|
|
oce.add(OpCode.REQUEST_MGM_RAW, "Request MGM Raw HK One Shot")
|
|
|
|
oce.add(OpCode.POS_X_SELF_TEST, "IMTQ perform pos X self test")
|
|
|
|
oce.add(OpCode.NEG_X_SELF_TEST, "IMTQ perform neg X self test")
|
|
|
|
oce.add(OpCode.POS_Y_SELF_TEST, "IMTQ perform pos Y self test")
|
|
|
|
oce.add(OpCode.NEG_Y_SELF_TEST, "IMTQ perform neg Y self test")
|
|
|
|
oce.add(OpCode.POS_Z_SELF_TEST, "IMTQ perform pos Z self test")
|
|
|
|
oce.add(OpCode.NEG_Z_SELF_TEST, "IMTQ perform neg Z self test")
|
2023-01-16 14:13:06 +01:00
|
|
|
oce.add(OpCode.SET_DIPOLE, "IMTQ command dipole")
|
2022-10-18 17:26:43 +02:00
|
|
|
oce.add("10", "IMTQ get commanded dipole")
|
|
|
|
oce.add("12", "IMTQ get calibrated MTM measurement one shot")
|
|
|
|
defs.add_service(CustomServiceList.IMTQ.value, "IMQT Device", oce)
|
|
|
|
|
|
|
|
|
2022-08-08 16:32:18 +02:00
|
|
|
def pack_imtq_test_into(object_id: ObjectIdU32, q: DefaultPusQueueHelper, op_code: str):
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_log_cmd(
|
|
|
|
f"Testing ISIS IMTQ handler with object id: {object_id.as_hex_string}"
|
2021-03-25 17:53:05 +01:00
|
|
|
)
|
|
|
|
|
2023-02-19 12:39:25 +01:00
|
|
|
if op_code == OpCode.OFF:
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_log_cmd("IMTQ: Set mode off")
|
2023-01-16 15:05:33 +01:00
|
|
|
command = pack_mode_data(object_id.as_bytes, Mode.OFF, 0)
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_pus_tc(PusTelecommand(service=200, subservice=1, app_data=command))
|
2023-02-19 12:39:25 +01:00
|
|
|
if op_code == OpCode.ON:
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_log_cmd("IMTQ: Set mode on")
|
2023-01-16 15:05:33 +01:00
|
|
|
command = pack_mode_data(object_id.as_bytes, Mode.ON, 0)
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_pus_tc(PusTelecommand(service=200, subservice=1, app_data=command))
|
2023-02-19 12:39:25 +01:00
|
|
|
if op_code == OpCode.NORMAL:
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_log_cmd("IMTQ: Mode Normal")
|
2023-01-16 15:05:33 +01:00
|
|
|
command = pack_mode_data(object_id.as_bytes, Mode.NORMAL, 0)
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_pus_tc(PusTelecommand(service=200, subservice=1, app_data=command))
|
2023-02-19 12:39:25 +01:00
|
|
|
if op_code == OpCode.POS_X_SELF_TEST:
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_log_cmd("IMTQ: Perform positive x self test")
|
2023-01-16 14:13:06 +01:00
|
|
|
command = object_id.as_bytes + ImtqActionId.perform_positive_x_test
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_pus_tc(PusTelecommand(service=8, subservice=128, app_data=command))
|
2021-06-12 13:49:25 +02:00
|
|
|
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_log_cmd("IMTQ: Initiate reading of positive x self test results")
|
2023-01-16 14:13:06 +01:00
|
|
|
command = object_id.as_bytes + ImtqActionId.read_self_test_results
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_pus_tc(PusTelecommand(service=8, subservice=128, app_data=command))
|
2021-06-12 13:49:25 +02:00
|
|
|
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_log_cmd("IMTQ: Request dataset with positive x self test results")
|
2023-01-16 14:13:06 +01:00
|
|
|
sid = make_sid(object_id.as_bytes, ImtqSetId.POSITIVE_X_TEST)
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_pus_tc(generate_one_hk_command(sid))
|
2021-06-12 13:49:25 +02:00
|
|
|
|
2023-02-19 12:39:25 +01:00
|
|
|
if op_code == OpCode.NEG_X_SELF_TEST:
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_log_cmd("IMTQ: Perform negative x self test")
|
2023-01-16 14:13:06 +01:00
|
|
|
command = object_id.as_bytes + ImtqActionId.perform_negative_x_test
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_pus_tc(PusTelecommand(service=8, subservice=128, app_data=command))
|
|
|
|
q.add_log_cmd("IMTQ: Initiate reading of negative x self test results")
|
2023-01-16 14:13:06 +01:00
|
|
|
command = object_id.as_bytes + ImtqActionId.read_self_test_results
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_pus_tc(PusTelecommand(service=8, subservice=128, app_data=command))
|
|
|
|
q.add_log_cmd("IMTQ: Request dataset with negative x self test results")
|
2023-01-16 14:13:06 +01:00
|
|
|
sid = make_sid(object_id.as_bytes, ImtqSetId.NEGATIVE_X_TEST)
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_pus_tc(generate_one_hk_command(sid))
|
2021-06-15 15:23:27 +02:00
|
|
|
|
2023-02-19 12:39:25 +01:00
|
|
|
if op_code == OpCode.POS_Y_SELF_TEST:
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_log_cmd("IMTQ: Perform positive y self test")
|
2023-01-16 14:13:06 +01:00
|
|
|
command = object_id.as_bytes + ImtqActionId.perform_positive_y_test
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_pus_tc(PusTelecommand(service=8, subservice=128, app_data=command))
|
|
|
|
q.add_log_cmd("IMTQ: Initiate reading of positive y self test results")
|
2023-01-16 14:13:06 +01:00
|
|
|
command = object_id.as_bytes + ImtqActionId.read_self_test_results
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_pus_tc(PusTelecommand(service=8, subservice=128, app_data=command))
|
2021-06-15 15:23:27 +02:00
|
|
|
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_log_cmd("IMTQ: Request dataset with positive y self test results")
|
2023-01-16 14:13:06 +01:00
|
|
|
sid = make_sid(object_id.as_bytes, ImtqSetId.POSITIVE_Y_TEST)
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_pus_tc(generate_one_hk_command(sid))
|
2021-06-15 15:23:27 +02:00
|
|
|
|
2023-02-19 12:39:25 +01:00
|
|
|
if op_code == OpCode.NEG_Y_SELF_TEST:
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_log_cmd("IMTQ: Perform negative y self test")
|
2023-01-16 14:13:06 +01:00
|
|
|
command = object_id.as_bytes + ImtqActionId.perform_negative_y_test
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_pus_tc(PusTelecommand(service=8, subservice=128, app_data=command))
|
2021-06-15 15:23:27 +02:00
|
|
|
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_log_cmd("IMTQ: Initiate reading of negative y self test results")
|
2023-01-16 14:13:06 +01:00
|
|
|
command = object_id.as_bytes + ImtqActionId.read_self_test_results
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_pus_tc(PusTelecommand(service=8, subservice=128, app_data=command))
|
2021-06-15 15:23:27 +02:00
|
|
|
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_log_cmd("IMTQ: Request dataset with negative y self test results")
|
2023-01-16 14:13:06 +01:00
|
|
|
sid = make_sid(object_id.as_bytes, ImtqSetId.NEGATIVE_Y_TEST)
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_pus_tc(generate_one_hk_command(sid))
|
2021-06-15 15:23:27 +02:00
|
|
|
|
2023-02-19 12:39:25 +01:00
|
|
|
if op_code == OpCode.POS_Z_SELF_TEST:
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_log_cmd("IMTQ: Perform positive z self test")
|
2023-01-16 14:13:06 +01:00
|
|
|
command = object_id.as_bytes + ImtqActionId.perform_positive_z_test
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_pus_tc(PusTelecommand(service=8, subservice=128, app_data=command))
|
2021-06-15 15:23:27 +02:00
|
|
|
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_log_cmd("IMTQ: Initiate reading of positive z self test results")
|
2023-01-16 14:13:06 +01:00
|
|
|
command = object_id.as_bytes + ImtqActionId.read_self_test_results
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_pus_tc(PusTelecommand(service=8, subservice=128, app_data=command))
|
2021-06-15 15:23:27 +02:00
|
|
|
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_log_cmd("IMTQ: Request dataset with positive z self test results")
|
2023-01-16 14:13:06 +01:00
|
|
|
sid = make_sid(object_id.as_bytes, ImtqSetId.POSITIVE_Y_TEST)
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_pus_tc(generate_one_hk_command(sid))
|
2021-06-15 15:23:27 +02:00
|
|
|
|
2023-02-19 12:39:25 +01:00
|
|
|
if op_code == OpCode.NEG_Z_SELF_TEST:
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_log_cmd("IMTQ: Perform negative z self test")
|
2023-01-16 14:13:06 +01:00
|
|
|
command = object_id.as_bytes + ImtqActionId.perform_negative_z_test
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_pus_tc(PusTelecommand(service=8, subservice=128, app_data=command))
|
|
|
|
q.add_log_cmd("IMTQ: Initiate reading of negative z self test results")
|
2023-01-16 14:13:06 +01:00
|
|
|
command = object_id.as_bytes + ImtqActionId.read_self_test_results
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_pus_tc(PusTelecommand(service=8, subservice=128, app_data=command))
|
|
|
|
q.add_log_cmd("IMTQ: Request dataset with negative z self test results")
|
2023-01-16 14:13:06 +01:00
|
|
|
sid = make_sid(object_id.as_bytes, ImtqSetId.NEGATIVE_Z_TEST)
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_pus_tc(generate_one_hk_command(sid))
|
2021-06-15 15:23:27 +02:00
|
|
|
|
2023-01-16 14:13:06 +01:00
|
|
|
if op_code in OpCode.SET_DIPOLE:
|
2022-10-18 17:07:11 +02:00
|
|
|
x_dipole = int(input("Specify X dipole [range [0, 2000] * 10^-4 * Am^2]: "))
|
|
|
|
y_dipole = int(input("Specify Y dipole [range [0, 2000] * 10^-4 * Am^2]: "))
|
|
|
|
z_dipole = int(input("Specify Z dipole [range [0, 2000] * 10^-4 * Am^2]: "))
|
|
|
|
duration = int(
|
|
|
|
input(
|
|
|
|
f"Specify torque duration [range [0, {pow(2, 16) - 1}, "
|
|
|
|
f"0 for continuous generation until update]: "
|
|
|
|
)
|
|
|
|
)
|
2022-10-18 17:26:43 +02:00
|
|
|
dur_str = "infinite" if duration == 0 else str(duration)
|
|
|
|
q.add_log_cmd(
|
|
|
|
f"IMTQ: Commanding dipole X={x_dipole}, Y={y_dipole}, Z={y_dipole}, duration={dur_str}"
|
|
|
|
)
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_pus_tc(
|
|
|
|
pack_dipole_command(
|
|
|
|
object_id.as_bytes, x_dipole, y_dipole, z_dipole, duration
|
|
|
|
)
|
|
|
|
)
|
2021-06-15 15:23:27 +02:00
|
|
|
|
2022-05-24 18:57:52 +02:00
|
|
|
if op_code == "10":
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_log_cmd("IMTQ: Get commanded dipole")
|
2023-01-16 14:13:06 +01:00
|
|
|
command = object_id.as_bytes + ImtqActionId.get_commanded_dipole
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_pus_tc(PusTelecommand(service=8, subservice=128, app_data=command))
|
2021-06-15 15:23:27 +02:00
|
|
|
|
2023-02-19 12:39:25 +01:00
|
|
|
if op_code == OpCode.REQUEST_ENG_HK:
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_log_cmd("IMTQ: Get engineering hk set")
|
|
|
|
q.add_pus_tc(
|
|
|
|
generate_one_diag_command(
|
2023-02-19 03:48:30 +01:00
|
|
|
sid=make_sid(
|
|
|
|
object_id=object_id.as_bytes, set_id=ImtqSetId.ENG_HK_NO_TORQUE
|
|
|
|
)
|
2022-07-04 15:22:53 +02:00
|
|
|
)
|
2022-05-24 18:57:52 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
if op_code == "12":
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_log_cmd("IMTQ: Get calibrated MTM hk set")
|
|
|
|
q.add_pus_tc(
|
|
|
|
generate_one_diag_command(
|
2023-01-16 14:13:06 +01:00
|
|
|
sid=make_sid(object_id=object_id.as_bytes, set_id=ImtqSetId.CAL_MTM_SET)
|
2022-07-04 15:22:53 +02:00
|
|
|
)
|
2022-05-24 18:57:52 +02:00
|
|
|
)
|
|
|
|
|
2023-02-19 12:39:25 +01:00
|
|
|
if op_code == OpCode.REQUEST_MGM_RAW:
|
2022-07-04 15:22:53 +02:00
|
|
|
q.add_log_cmd("IMTQ: Get raw MTM hk set")
|
|
|
|
q.add_pus_tc(
|
|
|
|
generate_one_diag_command(
|
2023-02-19 03:48:30 +01:00
|
|
|
sid=make_sid(
|
|
|
|
object_id=object_id.as_bytes, set_id=ImtqSetId.RAW_MTM_NO_TORQUE
|
|
|
|
)
|
2022-07-04 15:22:53 +02:00
|
|
|
)
|
2022-05-24 18:57:52 +02:00
|
|
|
)
|
2021-06-12 13:49:25 +02:00
|
|
|
|
2021-03-25 17:53:05 +01:00
|
|
|
|
2022-01-18 14:03:56 +01:00
|
|
|
def pack_dipole_command(
|
2022-07-04 15:22:53 +02:00
|
|
|
object_id: bytes, x_dipole: int, y_dipole: int, z_dipole: int, duration: int
|
2022-05-24 16:59:05 +02:00
|
|
|
) -> PusTelecommand:
|
2022-01-18 14:03:56 +01:00
|
|
|
"""This function packs the command causing the ISIS IMTQ to generate a dipole.
|
2022-10-18 17:07:11 +02:00
|
|
|
:param object_id: The object id of the IMTQ handler.
|
|
|
|
:param x_dipole: The dipole of the x coil in 10^-4*Am^2 (max. 2000)
|
|
|
|
:param y_dipole: The dipole of the y coil in 10^-4*Am^2 (max. 2000)
|
|
|
|
:param z_dipole: The dipole of the z coil in 10^-4*Am^2 (max. 2000)
|
|
|
|
:param duration: The duration in milliseconds the dipole will be generated by the coils.
|
2021-03-25 17:53:05 +01:00
|
|
|
When set to 0, the dipole will be generated until a new dipole actuation
|
|
|
|
command is sent.
|
|
|
|
"""
|
2023-01-16 14:13:06 +01:00
|
|
|
action_id = ImtqActionId.start_actuation_dipole
|
2021-03-25 17:53:05 +01:00
|
|
|
command = object_id + action_id
|
2022-10-18 17:07:11 +02:00
|
|
|
x_dipole = int(round(x_dipole))
|
|
|
|
y_dipole = int(round(y_dipole))
|
|
|
|
z_dipole = int(round(z_dipole))
|
|
|
|
if x_dipole < -2000 or x_dipole > 2000:
|
|
|
|
raise_dipole_error("X dipole", x_dipole)
|
|
|
|
if y_dipole < -2000 or y_dipole > 2000:
|
|
|
|
raise_dipole_error("Y dipole", y_dipole)
|
|
|
|
if z_dipole < -2000 or z_dipole > 2000:
|
|
|
|
raise_dipole_error("Z dipole", z_dipole)
|
|
|
|
duration = int(round(duration))
|
|
|
|
if duration < 0 or duration > pow(2, 16) - 1:
|
|
|
|
raise ValueError(
|
|
|
|
f"Duration in ms of {duration} smaller than 0 or larger than allowed {pow(2, 16) - 1}"
|
|
|
|
)
|
2022-07-04 15:22:53 +02:00
|
|
|
command += struct.pack("!h", x_dipole)
|
|
|
|
command += struct.pack("!h", y_dipole)
|
|
|
|
command += struct.pack("!h", z_dipole)
|
2022-10-18 17:07:11 +02:00
|
|
|
command += struct.pack("!H", duration)
|
2022-07-04 15:22:53 +02:00
|
|
|
command = PusTelecommand(service=8, subservice=128, app_data=command)
|
2021-03-26 13:56:02 +01:00
|
|
|
return command
|
2022-10-18 17:07:11 +02:00
|
|
|
|
|
|
|
|
|
|
|
def raise_dipole_error(dipole_str: str, value: int):
|
|
|
|
raise ValueError(
|
|
|
|
f"{dipole_str} {value} negative or larger than maximum allowed 2000 * 10^-4*Am^2"
|
|
|
|
)
|
2022-10-20 14:22:19 +02:00
|
|
|
|
|
|
|
|
2023-02-19 03:48:30 +01:00
|
|
|
STATUS_HEADERS = [
|
2023-02-19 02:22:18 +01:00
|
|
|
"Status Byte Mode",
|
|
|
|
"Status Byte Error",
|
|
|
|
"Status Byte Config",
|
|
|
|
"Status Byte Uptime [s]",
|
2023-02-19 03:48:30 +01:00
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
ENG_HK_HEADERS = [
|
2022-12-02 16:06:20 +01:00
|
|
|
"Digital Voltage [mV]",
|
|
|
|
"Analog Voltage [mV]",
|
|
|
|
"Digital Current [mA]",
|
|
|
|
"Analog Current [mA]",
|
|
|
|
"Coil Current X [mA]",
|
|
|
|
"Coil Current Y [mA]",
|
|
|
|
"Coil Current Z [mA]",
|
|
|
|
"Coil X Temperature [°C]",
|
|
|
|
"Coil Y Temperature [°C]",
|
|
|
|
"Coil Z Temperature [°C]",
|
|
|
|
"MCU Temperature [°C]",
|
|
|
|
]
|
|
|
|
|
|
|
|
|
2023-02-19 13:25:12 +01:00
|
|
|
def handle_imtq_hk(printer: FsfwTmTcPrinter, hk_data: bytes, set_id: int):
|
2023-02-27 15:24:47 +01:00
|
|
|
if set_id == ImtqSetId.SELF_TEST_SET:
|
2023-02-19 13:25:12 +01:00
|
|
|
return handle_self_test_data(printer, hk_data)
|
|
|
|
elif set_id == ImtqSetId.ENG_HK_NO_TORQUE:
|
2023-02-19 13:27:59 +01:00
|
|
|
_LOGGER.info("Found engineering HK without torque")
|
|
|
|
return handle_eng_set(printer, hk_data)
|
|
|
|
elif set_id == ImtqSetId.ENG_HK_SET_WITH_TORQUE:
|
|
|
|
_LOGGER.info("Found engineering HK during torque")
|
2023-02-19 13:25:12 +01:00
|
|
|
return handle_eng_set(printer, hk_data)
|
|
|
|
elif set_id == ImtqSetId.CAL_MTM_SET:
|
|
|
|
return handle_calibrated_mtm_measurement(printer, hk_data)
|
|
|
|
elif set_id == ImtqSetId.RAW_MTM_NO_TORQUE:
|
2023-02-19 13:27:59 +01:00
|
|
|
_LOGGER.info("Found raw MTM measurement without torque")
|
|
|
|
return handle_raw_mtm_measurement(printer, hk_data)
|
|
|
|
elif set_id == ImtqSetId.RAW_MTM_WITH_TORQUE:
|
|
|
|
_LOGGER.info("Found raw MTM measurement during torque")
|
2023-02-19 13:25:12 +01:00
|
|
|
return handle_raw_mtm_measurement(printer, hk_data)
|
|
|
|
elif set_id == ImtqSetId.STATUS_SET:
|
|
|
|
return handle_status_set(printer, hk_data)
|
|
|
|
else:
|
2023-02-19 13:27:59 +01:00
|
|
|
_LOGGER.warning(
|
|
|
|
f"IMTQ handler HK reply with unknown or unimplemented set id {set_id}"
|
2023-02-19 13:25:12 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2023-02-19 03:48:30 +01:00
|
|
|
def unpack_status_set(hk_data: bytes) -> List:
|
2023-02-19 02:22:18 +01:00
|
|
|
status_mode = hk_data[0]
|
|
|
|
status_error = hk_data[1]
|
|
|
|
status_conf = hk_data[2]
|
|
|
|
status_uptime = struct.unpack("!I", hk_data[3:7])[0]
|
2023-02-19 03:48:30 +01:00
|
|
|
return [status_mode, status_error, status_conf, status_uptime]
|
|
|
|
|
|
|
|
|
|
|
|
def unpack_eng_hk(hk_data: bytes) -> List:
|
|
|
|
digital_voltage = struct.unpack("!H", hk_data[0:2])[0]
|
|
|
|
analog_voltage = struct.unpack("!H", hk_data[2:4])[0]
|
|
|
|
digital_current = struct.unpack("!f", hk_data[4:8])[0]
|
|
|
|
analog_current = struct.unpack("!f", hk_data[8:12])[0]
|
|
|
|
coil_x_current = struct.unpack("!f", hk_data[12:16])[0]
|
|
|
|
coil_y_current = struct.unpack("!f", hk_data[16:20])[0]
|
|
|
|
coil_z_current = struct.unpack("!f", hk_data[20:24])[0]
|
|
|
|
coil_x_temperature = struct.unpack("!h", hk_data[24:26])[0]
|
|
|
|
coil_y_temperature = struct.unpack("!h", hk_data[26:28])[0]
|
|
|
|
coil_z_temperature = struct.unpack("!h", hk_data[28:30])[0]
|
|
|
|
mcu_temperature = struct.unpack("!h", hk_data[30:32])[0]
|
2022-10-20 14:22:19 +02:00
|
|
|
content_list = [
|
|
|
|
digital_voltage,
|
|
|
|
analog_voltage,
|
|
|
|
digital_current,
|
|
|
|
analog_current,
|
|
|
|
coil_x_current,
|
|
|
|
coil_y_current,
|
|
|
|
coil_z_current,
|
|
|
|
coil_x_temperature,
|
|
|
|
coil_y_temperature,
|
|
|
|
coil_z_temperature,
|
|
|
|
mcu_temperature,
|
|
|
|
]
|
2022-12-02 16:06:20 +01:00
|
|
|
return content_list
|
|
|
|
|
|
|
|
|
|
|
|
def handle_eng_set(printer: FsfwTmTcPrinter, hk_data: bytes):
|
|
|
|
pw = PrintWrapper(printer)
|
|
|
|
content_list = unpack_eng_hk(hk_data)
|
2023-02-19 03:48:30 +01:00
|
|
|
validity_buffer = hk_data[32:]
|
2022-12-02 16:06:20 +01:00
|
|
|
|
|
|
|
num_of_vars = len(ENG_HK_HEADERS)
|
2023-02-19 02:22:18 +01:00
|
|
|
for k, v in zip(ENG_HK_HEADERS, content_list):
|
|
|
|
pw.dlog(f"{k.ljust(30)}: {v}")
|
2022-10-20 14:22:19 +02:00
|
|
|
printer.print_validity_buffer(validity_buffer=validity_buffer, num_vars=num_of_vars)
|
|
|
|
|
|
|
|
|
2023-02-19 03:48:30 +01:00
|
|
|
def handle_status_set(printer: FsfwTmTcPrinter, hk_data: bytes):
|
|
|
|
pw = PrintWrapper(printer)
|
|
|
|
content_list = unpack_status_set(hk_data)
|
|
|
|
validity_buffer = hk_data[7:]
|
|
|
|
|
|
|
|
num_of_vars = 4
|
|
|
|
for k, v in zip(STATUS_HEADERS, content_list):
|
|
|
|
pw.dlog(f"{k.ljust(30)}: {v}")
|
|
|
|
printer.print_validity_buffer(validity_buffer=validity_buffer, num_vars=num_of_vars)
|
|
|
|
|
|
|
|
|
2022-10-20 14:22:19 +02:00
|
|
|
def handle_calibrated_mtm_measurement(printer: FsfwTmTcPrinter, hk_data: bytes):
|
|
|
|
pw = PrintWrapper(printer)
|
|
|
|
header_list = [
|
|
|
|
"Calibrated MTM X [nT]",
|
|
|
|
"Calibrated MTM Y [nT]",
|
|
|
|
"Calibrated MTM Z [nT]",
|
|
|
|
"Coil actuation status",
|
|
|
|
]
|
|
|
|
mtm_x = struct.unpack("!I", hk_data[0:4])[0]
|
|
|
|
mtm_y = struct.unpack("!I", hk_data[4:8])[0]
|
|
|
|
mtm_z = struct.unpack("!I", hk_data[8:12])[0]
|
|
|
|
coil_actuation_status = hk_data[12]
|
|
|
|
validity_buffer = hk_data[12:]
|
|
|
|
content_list = [mtm_x, mtm_y, mtm_z, coil_actuation_status]
|
|
|
|
num_of_vars = len(header_list)
|
|
|
|
pw.dlog(str(header_list))
|
|
|
|
pw.dlog(str(content_list))
|
|
|
|
printer.print_validity_buffer(validity_buffer=validity_buffer, num_vars=num_of_vars)
|
|
|
|
|
|
|
|
|
|
|
|
def handle_raw_mtm_measurement(printer: FsfwTmTcPrinter, hk_data: bytes):
|
|
|
|
pw = PrintWrapper(printer)
|
|
|
|
header_list = [
|
|
|
|
"Raw MTM X [nT]",
|
|
|
|
"Raw MTM Y [nT]",
|
|
|
|
"Raw MTM Z [nT]",
|
|
|
|
"Coil actuation status",
|
|
|
|
]
|
|
|
|
mtm_x = struct.unpack("!f", hk_data[0:4])[0]
|
|
|
|
mtm_y = struct.unpack("!f", hk_data[4:8])[0]
|
|
|
|
mtm_z = struct.unpack("!f", hk_data[8:12])[0]
|
|
|
|
coil_actuation_status = hk_data[12]
|
|
|
|
validity_buffer = hk_data[13:]
|
|
|
|
content_list = [mtm_x, mtm_y, mtm_z, coil_actuation_status]
|
|
|
|
num_of_vars = 2
|
|
|
|
pw.dlog(str(header_list))
|
|
|
|
pw.dlog(str(content_list))
|
|
|
|
printer.print_validity_buffer(validity_buffer=validity_buffer, num_vars=num_of_vars)
|
|
|
|
|
|
|
|
|
|
|
|
def handle_self_test_data(printer: FsfwTmTcPrinter, hk_data: bytes):
|
|
|
|
pw = PrintWrapper(printer)
|
|
|
|
header_list = [
|
|
|
|
"Init Err",
|
|
|
|
"Init Raw Mag X [nT]",
|
|
|
|
"Init Raw Mag Y [nT]",
|
|
|
|
"Init Raw Mag Z [nT]",
|
|
|
|
"Init Cal Mag X [nT]",
|
|
|
|
"Init Cal Mag Y [nT]",
|
|
|
|
"Init Cal Mag Z [nT]",
|
|
|
|
"Init Coil X Current [mA]",
|
|
|
|
"Init Coil Y Current [mA]",
|
|
|
|
"Init Coil Z Current [mA]",
|
|
|
|
"Init Coil X Temperature [°C]",
|
|
|
|
"Init Coil Y Temperature [°C]",
|
|
|
|
"Init Coil Z Temperature [°C]",
|
|
|
|
"Err",
|
|
|
|
"Raw Mag X [nT]",
|
|
|
|
"Raw Mag Y [nT]",
|
|
|
|
"Raw Mag Z [nT]",
|
|
|
|
"Cal Mag X [nT]",
|
|
|
|
"Cal Mag Y [nT]",
|
|
|
|
"Cal Mag Z [nT]",
|
|
|
|
"Coil X Current [mA]",
|
|
|
|
"Coil Y Current [mA]",
|
|
|
|
"Coil Z Current [mA]",
|
|
|
|
"Coil X Temperature [°C]",
|
|
|
|
"Coil Y Temperature [°C]",
|
|
|
|
"Coil Z Temperature [°C]",
|
|
|
|
"Fina Err",
|
|
|
|
"Fina Raw Mag X [nT]",
|
|
|
|
"Fina Raw Mag Y [nT]",
|
|
|
|
"Fina Raw Mag Z [nT]",
|
|
|
|
"Fina Cal Mag X [nT]",
|
|
|
|
"Fina Cal Mag Y [nT]",
|
|
|
|
"Fina Cal Mag Z [nT]",
|
|
|
|
"Fina Coil X Current [mA]",
|
|
|
|
"Fina Coil Y Current [mA]",
|
|
|
|
"Fina Coil Z Current [mA]",
|
|
|
|
"Fina Coil X Temperature [°C]",
|
|
|
|
"Fina Coil Y Temperature [°C]",
|
|
|
|
"Fina Coil Z Temperature [°C]",
|
|
|
|
]
|
|
|
|
# INIT step (no coil actuation)
|
|
|
|
init_err = hk_data[0]
|
|
|
|
init_raw_mag_x = struct.unpack("!f", hk_data[1:5])[0]
|
|
|
|
init_raw_mag_y = struct.unpack("!f", hk_data[5:9])[0]
|
|
|
|
init_raw_mag_z = struct.unpack("!f", hk_data[9:13])[0]
|
|
|
|
init_cal_mag_x = struct.unpack("!f", hk_data[13:17])[0]
|
|
|
|
init_cal_mag_y = struct.unpack("!f", hk_data[17:21])[0]
|
|
|
|
init_cal_mag_z = struct.unpack("!f", hk_data[21:25])[0]
|
|
|
|
init_coil_x_current = struct.unpack("!f", hk_data[25:29])[0]
|
|
|
|
init_coil_y_current = struct.unpack("!f", hk_data[29:33])[0]
|
|
|
|
init_coil_z_current = struct.unpack("!f", hk_data[33:37])[0]
|
|
|
|
init_coil_x_temperature = struct.unpack("!H", hk_data[37:39])[0]
|
|
|
|
init_coil_y_temperature = struct.unpack("!H", hk_data[39:41])[0]
|
|
|
|
init_coil_z_temperature = struct.unpack("!H", hk_data[41:43])[0]
|
|
|
|
|
|
|
|
# Actuation step
|
|
|
|
err = hk_data[43]
|
|
|
|
raw_mag_x = struct.unpack("!f", hk_data[44:48])[0]
|
|
|
|
raw_mag_y = struct.unpack("!f", hk_data[48:52])[0]
|
|
|
|
raw_mag_z = struct.unpack("!f", hk_data[52:56])[0]
|
|
|
|
cal_mag_x = struct.unpack("!f", hk_data[56:60])[0]
|
|
|
|
cal_mag_y = struct.unpack("!f", hk_data[60:64])[0]
|
|
|
|
cal_mag_z = struct.unpack("!f", hk_data[64:68])[0]
|
|
|
|
coil_x_current = struct.unpack("!f", hk_data[68:72])[0]
|
|
|
|
coil_y_current = struct.unpack("!f", hk_data[72:76])[0]
|
|
|
|
coil_z_current = struct.unpack("!f", hk_data[76:80])[0]
|
|
|
|
coil_x_temperature = struct.unpack("!H", hk_data[80:82])[0]
|
|
|
|
coil_y_temperature = struct.unpack("!H", hk_data[82:84])[0]
|
|
|
|
coil_z_temperature = struct.unpack("!H", hk_data[84:86])[0]
|
|
|
|
|
|
|
|
# FINA step (no coil actuation)
|
|
|
|
fina_err = hk_data[86]
|
|
|
|
fina_raw_mag_x = struct.unpack("!f", hk_data[87:91])[0]
|
|
|
|
fina_raw_mag_y = struct.unpack("!f", hk_data[91:95])[0]
|
|
|
|
fina_raw_mag_z = struct.unpack("!f", hk_data[95:99])[0]
|
|
|
|
fina_cal_mag_x = struct.unpack("!f", hk_data[99:103])[0]
|
|
|
|
fina_cal_mag_y = struct.unpack("!f", hk_data[103:107])[0]
|
|
|
|
fina_cal_mag_z = struct.unpack("!f", hk_data[107:111])[0]
|
|
|
|
fina_coil_x_current = struct.unpack("!f", hk_data[111:115])[0]
|
|
|
|
fina_coil_y_current = struct.unpack("!f", hk_data[115:119])[0]
|
|
|
|
fina_coil_z_current = struct.unpack("!f", hk_data[119:123])[0]
|
|
|
|
fina_coil_x_temperature = struct.unpack("!H", hk_data[123:125])[0]
|
|
|
|
fina_coil_y_temperature = struct.unpack("!H", hk_data[125:127])[0]
|
|
|
|
fina_coil_z_temperature = struct.unpack("!H", hk_data[127:129])[0]
|
|
|
|
|
|
|
|
validity_buffer = hk_data[129:]
|
|
|
|
content_list = [
|
|
|
|
init_err,
|
|
|
|
init_raw_mag_x,
|
|
|
|
init_raw_mag_y,
|
|
|
|
init_raw_mag_z,
|
|
|
|
init_cal_mag_x,
|
|
|
|
init_cal_mag_y,
|
|
|
|
init_cal_mag_z,
|
|
|
|
init_coil_x_current,
|
|
|
|
init_coil_y_current,
|
|
|
|
init_coil_z_current,
|
|
|
|
init_coil_x_temperature,
|
|
|
|
init_coil_y_temperature,
|
|
|
|
init_coil_z_temperature,
|
|
|
|
err,
|
|
|
|
raw_mag_x,
|
|
|
|
init_raw_mag_y,
|
|
|
|
raw_mag_z,
|
|
|
|
cal_mag_x,
|
|
|
|
cal_mag_y,
|
|
|
|
cal_mag_z,
|
|
|
|
coil_x_current,
|
|
|
|
coil_y_current,
|
|
|
|
coil_z_current,
|
|
|
|
coil_x_temperature,
|
|
|
|
coil_y_temperature,
|
|
|
|
coil_z_temperature,
|
|
|
|
fina_err,
|
|
|
|
fina_raw_mag_x,
|
|
|
|
fina_raw_mag_y,
|
|
|
|
fina_raw_mag_z,
|
|
|
|
fina_cal_mag_x,
|
|
|
|
fina_cal_mag_y,
|
|
|
|
fina_cal_mag_z,
|
|
|
|
fina_coil_x_current,
|
|
|
|
fina_coil_y_current,
|
|
|
|
fina_coil_z_current,
|
|
|
|
fina_coil_x_temperature,
|
|
|
|
fina_coil_y_temperature,
|
|
|
|
fina_coil_z_temperature,
|
|
|
|
]
|
|
|
|
num_of_vars = len(header_list)
|
|
|
|
pw.dlog(str(header_list))
|
|
|
|
pw.dlog(str(content_list))
|
|
|
|
printer.print_validity_buffer(validity_buffer=validity_buffer, num_vars=num_of_vars)
|