Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
04f5a76962 | |||
5ed3cec20b | |||
c3c58b95ad | |||
5b309e4013 | |||
a39e94279b | |||
b9f58e0612 | |||
d9c202c68e | |||
28c367c6fb | |||
15adb9bf2e | |||
b4e4228040 | |||
26ebe9ab67 | |||
a680bf28f0 | |||
17486fdca7 | |||
c633893df4 | |||
bf16fa14ad |
20
CHANGELOG.md
20
CHANGELOG.md
@ -8,7 +8,23 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|||||||
The [milestone](https://egit.irs.uni-stuttgart.de/eive/eive-obsw/milestones)
|
The [milestone](https://egit.irs.uni-stuttgart.de/eive/eive-obsw/milestones)
|
||||||
list yields a list of all related PRs for each release.
|
list yields a list of all related PRs for each release.
|
||||||
|
|
||||||
# [v2.9.0] 2023-01-01
|
# [unreleased]
|
||||||
|
|
||||||
|
# [v2.10.0] 2023-02-03
|
||||||
|
|
||||||
|
tmtccmd v4.0.0rc0
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
|
||||||
|
- Updated ACS SS commands for OBSW ACS SS update.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/eive/eive-tmtc/pulls/130
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
|
||||||
|
- Fixed parsing of processed GPS data
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/eive/eive-tmtc/pulls/129
|
||||||
|
|
||||||
|
# [v2.9.0] 2023-02-01
|
||||||
|
|
||||||
## Fixed
|
## Fixed
|
||||||
|
|
||||||
@ -21,7 +37,7 @@ list yields a list of all related PRs for each release.
|
|||||||
- Add time dump command.
|
- Add time dump command.
|
||||||
- Time event handling.
|
- Time event handling.
|
||||||
|
|
||||||
# [v2.8.0] 2023-01-01
|
# [v2.8.0] 2023-02-01
|
||||||
|
|
||||||
- Move all device modules inside `pus_tc` and `pus_tm` to `tmtc` module and respective
|
- Move all device modules inside `pus_tc` and `pus_tm` to `tmtc` module and respective
|
||||||
subsystem submodules.
|
subsystem submodules.
|
||||||
|
@ -3,10 +3,10 @@ from pathlib import Path
|
|||||||
|
|
||||||
SW_NAME = "eive-tmtc"
|
SW_NAME = "eive-tmtc"
|
||||||
VERSION_MAJOR = 2
|
VERSION_MAJOR = 2
|
||||||
VERSION_MINOR = 9
|
VERSION_MINOR = 10
|
||||||
VERSION_REVISION = 0
|
VERSION_REVISION = 0
|
||||||
|
|
||||||
__version__ = "2.9.0"
|
__version__ = "2.10.0"
|
||||||
|
|
||||||
EIVE_TMTC_ROOT = Path(__file__).parent
|
EIVE_TMTC_ROOT = Path(__file__).parent
|
||||||
PACKAGE_ROOT = EIVE_TMTC_ROOT.parent
|
PACKAGE_ROOT = EIVE_TMTC_ROOT.parent
|
||||||
|
@ -84,7 +84,8 @@ Event ID (dec); Event ID (hex); Name; Severity; Description; File Path
|
|||||||
10800;0x2a30;STORE_ERROR;LOW;;fsfw/src/fsfw/cfdp/handler/defs.h
|
10800;0x2a30;STORE_ERROR;LOW;;fsfw/src/fsfw/cfdp/handler/defs.h
|
||||||
10801;0x2a31;MSG_QUEUE_ERROR;LOW;;fsfw/src/fsfw/cfdp/handler/defs.h
|
10801;0x2a31;MSG_QUEUE_ERROR;LOW;;fsfw/src/fsfw/cfdp/handler/defs.h
|
||||||
10802;0x2a32;SERIALIZATION_ERROR;LOW;;fsfw/src/fsfw/cfdp/handler/defs.h
|
10802;0x2a32;SERIALIZATION_ERROR;LOW;;fsfw/src/fsfw/cfdp/handler/defs.h
|
||||||
11200;0x2bc0;SAFE_RATE_VIOLATION;MEDIUM;;mission/controller/AcsController.h
|
11200;0x2bc0;SAFE_RATE_VIOLATION;MEDIUM;;mission/acsDefs.h
|
||||||
|
11201;0x2bc1;SAFE_RATE_RECOVERY;MEDIUM;;mission/acsDefs.h
|
||||||
11300;0x2c24;SWITCH_CMD_SENT;INFO;Indicates that a FSFW object requested setting a switch P1: 1 if on was requested, 0 for off | P2: Switch Index;mission/devices/devicedefinitions/powerDefinitions.h
|
11300;0x2c24;SWITCH_CMD_SENT;INFO;Indicates that a FSFW object requested setting a switch P1: 1 if on was requested, 0 for off | P2: Switch Index;mission/devices/devicedefinitions/powerDefinitions.h
|
||||||
11301;0x2c25;SWITCH_HAS_CHANGED;INFO;Indicated that a switch state has changed P1: New switch state, 1 for on, 0 for off | P2: Switch Index;mission/devices/devicedefinitions/powerDefinitions.h
|
11301;0x2c25;SWITCH_HAS_CHANGED;INFO;Indicated that a switch state has changed P1: New switch state, 1 for on, 0 for off | P2: Switch Index;mission/devices/devicedefinitions/powerDefinitions.h
|
||||||
11302;0x2c26;SWITCHING_Q7S_DENIED;MEDIUM;;mission/devices/devicedefinitions/powerDefinitions.h
|
11302;0x2c26;SWITCHING_Q7S_DENIED;MEDIUM;;mission/devices/devicedefinitions/powerDefinitions.h
|
||||||
|
|
@ -19,7 +19,7 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
|
|
||||||
def handle_event_packet(raw_tm: bytes, printer: FsfwTmTcPrinter):
|
def handle_event_packet(raw_tm: bytes, printer: FsfwTmTcPrinter):
|
||||||
pw = PrintWrapper(printer)
|
pw = PrintWrapper(printer)
|
||||||
tm = Service5Tm.unpack(raw_telemetry=raw_tm, time_reader=CdsShortTimestamp.empty())
|
tm = Service5Tm.unpack(data=raw_tm, time_reader=CdsShortTimestamp.empty())
|
||||||
event_dict = get_event_dict()
|
event_dict = get_event_dict()
|
||||||
event_def = tm.event_definition
|
event_def = tm.event_definition
|
||||||
info = event_dict.get(event_def.event_id)
|
info = event_dict.get(event_def.event_id)
|
||||||
@ -35,10 +35,10 @@ def handle_event_packet(raw_tm: bytes, printer: FsfwTmTcPrinter):
|
|||||||
else:
|
else:
|
||||||
obj_name = obj_id_obj.name
|
obj_name = obj_id_obj.name
|
||||||
generic_event_string = f"Object {obj_name} generated Event {info.name} (ID: {event_def.event_id:#04x}) at {tm.time_provider.as_date_time()}"
|
generic_event_string = f"Object {obj_name} generated Event {info.name} (ID: {event_def.event_id:#04x}) at {tm.time_provider.as_date_time()}"
|
||||||
|
_LOGGER.info(generic_event_string)
|
||||||
pw.printer.file_logger.info(
|
pw.printer.file_logger.info(
|
||||||
f"{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}: {generic_event_string}"
|
f"{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}: {generic_event_string}"
|
||||||
)
|
)
|
||||||
pw.ilog(_LOGGER, generic_event_string)
|
|
||||||
specific_handler = True
|
specific_handler = True
|
||||||
if info.name == "MODE_TRANSITION_FAILED":
|
if info.name == "MODE_TRANSITION_FAILED":
|
||||||
reason = generic_retval_printout(event_def.param1)
|
reason = generic_retval_printout(event_def.param1)
|
||||||
@ -56,16 +56,13 @@ def handle_event_packet(raw_tm: bytes, printer: FsfwTmTcPrinter):
|
|||||||
if info.name == "MODE_INFO":
|
if info.name == "MODE_INFO":
|
||||||
mode_name = "Unknown"
|
mode_name = "Unknown"
|
||||||
if obj_name == "ACS_SUBSYSTEM":
|
if obj_name == "ACS_SUBSYSTEM":
|
||||||
if event_def.param1 == Mode.OFF:
|
acs_mode = AcsMode(event_def.param1)
|
||||||
mode_name = "Off"
|
pw.dlog(f"ACS Mode: {acs_mode!r}")
|
||||||
elif event_def.param1 == AcsMode.IDLE:
|
elif obj_name == "ACS_CONTROLLER_ID":
|
||||||
mode_name = "Idle"
|
mode_name = Mode(event_def.param1)
|
||||||
elif event_def.param1 == AcsMode.DETUMBLE:
|
submode = AcsMode(event_def.param2)
|
||||||
mode_name = "Detumble"
|
pw.dlog(f"Mode: {mode_name!r}")
|
||||||
elif event_def.param1 == AcsMode.SAFE:
|
pw.dlog(f"ACS Mode: {submode!r}")
|
||||||
mode_name = "Safe"
|
|
||||||
elif event_def.param1 == AcsMode.TARGET_PT:
|
|
||||||
mode_name = "Target Pointing"
|
|
||||||
else:
|
else:
|
||||||
if event_def.param1 == Mode.OFF:
|
if event_def.param1 == Mode.OFF:
|
||||||
mode_name = "Off"
|
mode_name = "Off"
|
||||||
@ -75,8 +72,8 @@ def handle_event_packet(raw_tm: bytes, printer: FsfwTmTcPrinter):
|
|||||||
mode_name = "Normal"
|
mode_name = "Normal"
|
||||||
elif event_def.param1 == Mode.RAW:
|
elif event_def.param1 == Mode.RAW:
|
||||||
mode_name = "Raw"
|
mode_name = "Raw"
|
||||||
pw.dlog(f"Mode Number {event_def.param1}, Mode Name {mode_name}")
|
pw.dlog(f"Mode Number {event_def.param1}, Mode Name {mode_name}")
|
||||||
pw.dlog(f"Submode: {event_def.param2}")
|
pw.dlog(f"Submode: {event_def.param2}")
|
||||||
elif info.name == "CLOCK_SET":
|
elif info.name == "CLOCK_SET":
|
||||||
old_time = event_def.param1
|
old_time = event_def.param1
|
||||||
new_time = event_def.param2
|
new_time = event_def.param2
|
||||||
|
@ -53,7 +53,7 @@ def pus_factory_hook(
|
|||||||
handle_action_reply(raw_tm=packet, printer=printer, obj_id_dict=obj_id_dict)
|
handle_action_reply(raw_tm=packet, printer=printer, obj_id_dict=obj_id_dict)
|
||||||
elif service == 17:
|
elif service == 17:
|
||||||
tm_packet = Service17Tm.unpack(
|
tm_packet = Service17Tm.unpack(
|
||||||
raw_telemetry=packet, time_reader=CdsShortTimestamp.empty()
|
data=packet, time_reader=CdsShortTimestamp.empty()
|
||||||
)
|
)
|
||||||
if tm_packet.subservice == 2:
|
if tm_packet.subservice == 2:
|
||||||
verif_wrapper.dlog("Received Ping Reply TM[17,2]")
|
verif_wrapper.dlog("Received Ping Reply TM[17,2]")
|
||||||
|
@ -21,6 +21,7 @@ from tmtccmd.tc.pus_3_fsfw_hk import (
|
|||||||
make_sid,
|
make_sid,
|
||||||
enable_periodic_hk_command_with_interval,
|
enable_periodic_hk_command_with_interval,
|
||||||
disable_periodic_hk_command,
|
disable_periodic_hk_command,
|
||||||
|
create_request_one_diag_command,
|
||||||
)
|
)
|
||||||
from tmtccmd.util.tmtc_printer import FsfwTmTcPrinter
|
from tmtccmd.util.tmtc_printer import FsfwTmTcPrinter
|
||||||
|
|
||||||
@ -286,7 +287,9 @@ def pack_acs_ctrl_command(p: ServiceProviderParams):
|
|||||||
elif op_code in OpCodes.REQUEST_PROC_GYR_HK:
|
elif op_code in OpCodes.REQUEST_PROC_GYR_HK:
|
||||||
q.add_log_cmd(Info.REQUEST_PROC_GYR_HK)
|
q.add_log_cmd(Info.REQUEST_PROC_GYR_HK)
|
||||||
q.add_pus_tc(
|
q.add_pus_tc(
|
||||||
generate_one_hk_command(make_sid(ACS_CONTROLLER, SetId.GYR_PROC_SET))
|
create_request_one_diag_command(
|
||||||
|
make_sid(ACS_CONTROLLER, SetId.GYR_PROC_SET)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
elif op_code in OpCodes.ENABLE_PROC_GYR_HK:
|
elif op_code in OpCodes.ENABLE_PROC_GYR_HK:
|
||||||
q.add_log_cmd(Info.ENABLE_PROC_GYR_HK)
|
q.add_log_cmd(Info.ENABLE_PROC_GYR_HK)
|
||||||
@ -619,7 +622,7 @@ def handle_gps_data_processed(pw: PrintWrapper, hk_data: bytes):
|
|||||||
fmt_vec = "!ddd"
|
fmt_vec = "!ddd"
|
||||||
inc_len_scalar = struct.calcsize(fmt_scalar)
|
inc_len_scalar = struct.calcsize(fmt_scalar)
|
||||||
inc_len_vec = struct.calcsize(fmt_vec)
|
inc_len_vec = struct.calcsize(fmt_vec)
|
||||||
if len(hk_data) < 2 * inc_len_scalar + inc_len_vec:
|
if len(hk_data) < 2 * inc_len_scalar + 2 * inc_len_vec:
|
||||||
pw.dlog("Received HK set too small")
|
pw.dlog("Received HK set too small")
|
||||||
return
|
return
|
||||||
current_idx = 0
|
current_idx = 0
|
||||||
@ -637,14 +640,22 @@ def handle_gps_data_processed(pw: PrintWrapper, hk_data: bytes):
|
|||||||
)
|
)
|
||||||
]
|
]
|
||||||
current_idx += inc_len_scalar
|
current_idx += inc_len_scalar
|
||||||
|
pos = [
|
||||||
|
f"{val:8.3f}"
|
||||||
|
for val in struct.unpack(
|
||||||
|
fmt_vec, hk_data[current_idx : current_idx + inc_len_vec]
|
||||||
|
)
|
||||||
|
]
|
||||||
velo = [
|
velo = [
|
||||||
f"{val:8.3f}"
|
f"{val:8.3f}"
|
||||||
for val in struct.unpack(
|
for val in struct.unpack(
|
||||||
fmt_vec, hk_data[current_idx : current_idx + inc_len_vec]
|
fmt_vec, hk_data[current_idx : current_idx + inc_len_vec]
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
current_idx += inc_len_vec
|
||||||
pw.dlog(f"GPS Latitude: {lat} [rad]")
|
pw.dlog(f"GPS Latitude: {lat} [rad]")
|
||||||
pw.dlog(f"GPS Longitude: {long} [rad]")
|
pw.dlog(f"GPS Longitude: {long} [rad]")
|
||||||
|
pw.dlog(f"GPS Position: {pos} [m]")
|
||||||
pw.dlog(f"GPS Velocity: {velo} [m/s]")
|
pw.dlog(f"GPS Velocity: {velo} [m/s]")
|
||||||
pw.printer.print_validity_buffer(hk_data[current_idx:], num_vars=3)
|
pw.printer.print_validity_buffer(hk_data[current_idx:], num_vars=3)
|
||||||
|
|
||||||
@ -672,6 +683,7 @@ def handle_mekf_data(pw: PrintWrapper, hk_data: bytes):
|
|||||||
fmt_vec, hk_data[current_idx : current_idx + inc_len_vec]
|
fmt_vec, hk_data[current_idx : current_idx + inc_len_vec]
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
current_idx += inc_len_vec
|
||||||
pw.dlog(f"MEKF Quaternion: {quat}")
|
pw.dlog(f"MEKF Quaternion: {quat}")
|
||||||
pw.dlog(f"MEKF Rotational Rate: {rate}")
|
pw.dlog(f"MEKF Rotational Rate: {rate}")
|
||||||
pw.printer.print_validity_buffer(hk_data[current_idx:], num_vars=2)
|
pw.printer.print_validity_buffer(hk_data[current_idx:], num_vars=2)
|
||||||
@ -707,6 +719,7 @@ def handle_ctrl_val_data(pw: PrintWrapper, hk_data: bytes):
|
|||||||
fmt_scalar, hk_data[current_idx : current_idx + inc_len_scalar]
|
fmt_scalar, hk_data[current_idx : current_idx + inc_len_scalar]
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
current_idx += inc_len_scalar
|
||||||
pw.dlog(f"Control Values Target Quaternion: {tgt_quat}")
|
pw.dlog(f"Control Values Target Quaternion: {tgt_quat}")
|
||||||
pw.dlog(f"Control Values Error Quaternion: {err_quat}")
|
pw.dlog(f"Control Values Error Quaternion: {err_quat}")
|
||||||
pw.dlog(f"Control Values Error Angle: {err_ang} [rad]")
|
pw.dlog(f"Control Values Error Angle: {err_ang} [rad]")
|
||||||
@ -745,6 +758,7 @@ def handle_act_cmd_data(pw: PrintWrapper, hk_data: bytes):
|
|||||||
fmt_vec3_int16, hk_data[current_idx : current_idx + inc_len_vec3_int16]
|
fmt_vec3_int16, hk_data[current_idx : current_idx + inc_len_vec3_int16]
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
current_idx += inc_len_vec3_int16
|
||||||
pw.dlog(f"Actuator Commands RW Target Torque: {rw_tgt_torque}")
|
pw.dlog(f"Actuator Commands RW Target Torque: {rw_tgt_torque}")
|
||||||
pw.dlog(f"Actuator Commands RW Target Speed: {rw_tgt_speed}")
|
pw.dlog(f"Actuator Commands RW Target Speed: {rw_tgt_speed}")
|
||||||
pw.dlog(f"Actuator Commands MTQ Target Dipole: {mtq_tgt_dipole}")
|
pw.dlog(f"Actuator Commands MTQ Target Dipole: {mtq_tgt_dipole}")
|
||||||
|
@ -20,16 +20,22 @@ class OpCode(str, enum.Enum):
|
|||||||
SAFE = "safe"
|
SAFE = "safe"
|
||||||
DETUMBLE = "detumble"
|
DETUMBLE = "detumble"
|
||||||
IDLE = "idle"
|
IDLE = "idle"
|
||||||
TARGET_PT = "target"
|
PTG_TARGET = "ptg_target"
|
||||||
|
PTG_TARGET_NADIR = "ptg_nadir"
|
||||||
|
PTG_TARGET_GS = "ptg_target_gs"
|
||||||
|
PTG_TARGET_INERTIAL = "ptg_inertial"
|
||||||
REPORT_ALL_MODES = "all_modes"
|
REPORT_ALL_MODES = "all_modes"
|
||||||
|
|
||||||
|
|
||||||
class AcsMode(enum.IntEnum):
|
class AcsMode(enum.IntEnum):
|
||||||
OFF = 0
|
OFF = 0
|
||||||
SAFE = 1 << 24
|
SAFE = 2
|
||||||
DETUMBLE = 2 << 24
|
DETUMBLE = 3
|
||||||
IDLE = 3 << 24
|
IDLE = 4
|
||||||
TARGET_PT = 4 << 24
|
PTG_TARGET_NADIR = 5
|
||||||
|
PTG_TARGET = 6
|
||||||
|
PTG_TARGET_GS = 7
|
||||||
|
PTG_TARGET_INERTIAL = 8
|
||||||
|
|
||||||
|
|
||||||
class Info(str, enum.Enum):
|
class Info(str, enum.Enum):
|
||||||
@ -37,15 +43,22 @@ class Info(str, enum.Enum):
|
|||||||
SAFE = "Safe Mode Command"
|
SAFE = "Safe Mode Command"
|
||||||
DETUMBLE = "Detumble Mode Command"
|
DETUMBLE = "Detumble Mode Command"
|
||||||
IDLE = "Idle Mode Command"
|
IDLE = "Idle Mode Command"
|
||||||
TARGET_PT = "Target Pointing Mode Command"
|
PTG_TARGET_NADIR = "Target Pointing Nadir"
|
||||||
|
PTG_TARGET = "Target Pointing"
|
||||||
|
PTG_TARGET_GS = "Target Pointing Ground Station"
|
||||||
|
PTG_TARGET_INERTIAL = "Target Pointing Inertial"
|
||||||
REPORT_ALL_MODES = "Report All Modes Recursively"
|
REPORT_ALL_MODES = "Report All Modes Recursively"
|
||||||
|
|
||||||
|
|
||||||
HANDLER_LIST: Dict[str, Tuple[int, str]] = {
|
HANDLER_LIST: Dict[str, Tuple[int, str]] = {
|
||||||
OpCode.OFF: (AcsMode.OFF, Info.OFF),
|
OpCode.OFF: (AcsMode.OFF, Info.OFF),
|
||||||
OpCode.IDLE: (AcsMode.IDLE, Info.IDLE),
|
|
||||||
OpCode.SAFE: (AcsMode.SAFE, Info.SAFE),
|
OpCode.SAFE: (AcsMode.SAFE, Info.SAFE),
|
||||||
OpCode.DETUMBLE: (AcsMode.DETUMBLE, Info.DETUMBLE),
|
OpCode.DETUMBLE: (AcsMode.DETUMBLE, Info.DETUMBLE),
|
||||||
|
OpCode.IDLE: (AcsMode.IDLE, Info.IDLE),
|
||||||
|
OpCode.PTG_TARGET: (AcsMode.PTG_TARGET, Info.PTG_TARGET),
|
||||||
|
OpCode.PTG_TARGET_GS: (AcsMode.PTG_TARGET_GS, Info.PTG_TARGET_GS),
|
||||||
|
OpCode.PTG_TARGET_NADIR: (AcsMode.PTG_TARGET_NADIR, Info.PTG_TARGET_NADIR),
|
||||||
|
OpCode.PTG_TARGET_INERTIAL: (AcsMode.PTG_TARGET_INERTIAL, Info.PTG_TARGET_INERTIAL),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -78,8 +91,7 @@ def build_acs_subsystem_cmd(p: ServiceProviderParams):
|
|||||||
@tmtc_definitions_provider
|
@tmtc_definitions_provider
|
||||||
def add_acs_subsystem_cmds(defs: TmtcDefinitionWrapper):
|
def add_acs_subsystem_cmds(defs: TmtcDefinitionWrapper):
|
||||||
oce = OpCodeEntry()
|
oce = OpCodeEntry()
|
||||||
oce.add(OpCode.OFF, Info.OFF)
|
for op_code, (_, info) in HANDLER_LIST.items():
|
||||||
oce.add(OpCode.SAFE, Info.SAFE)
|
oce.add(op_code, info)
|
||||||
oce.add(OpCode.IDLE, Info.IDLE)
|
|
||||||
oce.add(OpCode.REPORT_ALL_MODES, Info.REPORT_ALL_MODES)
|
oce.add(OpCode.REPORT_ALL_MODES, Info.REPORT_ALL_MODES)
|
||||||
defs.add_service(CustomServiceList.ACS_SS, "ACS Subsystem", oce)
|
defs.add_service(CustomServiceList.ACS_SS, "ACS Subsystem", oce)
|
||||||
|
@ -27,8 +27,8 @@ classifiers =
|
|||||||
|
|
||||||
[options]
|
[options]
|
||||||
install_requires =
|
install_requires =
|
||||||
# tmtccmd @ git+https://github.com/robamu-org/tmtccmd@v4.0.0a3
|
tmtccmd @ git+https://github.com/robamu-org/tmtccmd@v4.0.0rc0
|
||||||
tmtccmd @ git+https://github.com/robamu-org/tmtccmd@d6938b2adf0c5cbf3fe8621292b805ed2a66071e#egg=tmtccmd
|
# tmtccmd @ git+https://github.com/robamu-org/tmtccmd@<gitRev>#egg=tmtccmd
|
||||||
packages = find:
|
packages = find:
|
||||||
python_requires = >=3.10
|
python_requires = >=3.10
|
||||||
include_package_data = True
|
include_package_data = True
|
||||||
|
Reference in New Issue
Block a user