Compare commits

..

No commits in common. "master" and "power_handler" have entirely different histories.

23 changed files with 862 additions and 3963 deletions

1
.gitignore vendored
View File

@ -2,5 +2,4 @@
/.idea/*
!/.idea/runConfigurations
output.log

View File

@ -1,6 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Cross Remote Debug" type="com.jetbrains.cidr.remote.gdbserver.type" factoryName="com.jetbrains.cidr.remote.gdbserver.factory" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="eurosim-obsw" TARGET_NAME="Cross" CONFIG_NAME="Cross" version="1" RUN_PATH="$PROJECT_DIR$/target/armv7-unknown-linux-gnueabihf/debug/eurosim-obsw">
<custom-gdb-server version="1" gdb-connect="192.168.1.116:1234" executable="" warmup-ms="0" download-type="ALWAYS" sshConfigName="koesterl@192.168.1.116:22 password" uploadFile="/tmp/CLion/debug/eurosim-obsw" defaultGdbServerArgs=":1234 /tmp/CLion/debug/eurosim-obsw">
<custom-gdb-server version="1" gdb-connect="obc.local:1234" executable="" warmup-ms="0" download-type="ALWAYS" sshConfigName="koesterl@obc.local:22 password" uploadFile="/tmp/CLion/debug/eurosim-obsw" defaultGdbServerArgs=":1234 /tmp/CLion/debug/eurosim-obsw">
<debugger kind="GDB" isBundled="true" />
</custom-gdb-server>
<method v="2">

65
Cargo.lock generated
View File

@ -288,7 +288,6 @@ dependencies = [
name = "eurosim-obsw"
version = "0.1.0"
dependencies = [
"byteorder",
"chrono",
"embedded-can",
"fern",
@ -297,7 +296,6 @@ dependencies = [
"num",
"num-derive",
"num-traits",
"num_enum",
"satrs-core",
"satrs-mib",
"serde",
@ -316,12 +314,6 @@ dependencies = [
"log",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
version = "0.13.1"
@ -376,16 +368,6 @@ dependencies = [
"cxx-build",
]
[[package]]
name = "indexmap"
version = "1.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
dependencies = [
"autocfg",
"hashbrown 0.12.3",
]
[[package]]
name = "itertools"
version = "0.10.5"
@ -518,15 +500,6 @@ version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
[[package]]
name = "nom8"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8"
dependencies = [
"memchr",
]
[[package]]
name = "num"
version = "0.4.0"
@ -639,7 +612,6 @@ version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2be1598bf1c313dcdd12092e3f1920f463462525a21b7b4e11b4168353d0123e"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn",
@ -676,16 +648,6 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "proc-macro-crate"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66618389e4ec1c7afe67d51a9bf34ff9236480f8d51e7489b7d5ab0303c13f34"
dependencies = [
"once_cell",
"toml_edit",
]
[[package]]
name = "proc-macro2"
version = "1.0.47"
@ -734,7 +696,6 @@ checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
[[package]]
name = "satrs-core"
version = "0.1.0-alpha.0"
source = "git+https://egit.irs.uni-stuttgart.de/rust/sat-rs.git?rev=c265e4c271#c265e4c2714b793c3853607c172d444467344aec"
dependencies = [
"bus",
"crossbeam-channel",
@ -742,9 +703,8 @@ dependencies = [
"downcast-rs",
"dyn-clone",
"embed-doc-image",
"hashbrown 0.13.1",
"hashbrown",
"num-traits",
"num_enum",
"paste",
"serde",
"spacepackets",
@ -753,7 +713,6 @@ dependencies = [
[[package]]
name = "satrs-mib"
version = "0.1.0"
source = "git+https://egit.irs.uni-stuttgart.de/rust/sat-rs.git?rev=c265e4c271#c265e4c2714b793c3853607c172d444467344aec"
dependencies = [
"csv",
"satrs-core",
@ -765,7 +724,6 @@ dependencies = [
[[package]]
name = "satrs-mib-codegen"
version = "0.1.0"
source = "git+https://egit.irs.uni-stuttgart.de/rust/sat-rs.git?rev=c265e4c271#c265e4c2714b793c3853607c172d444467344aec"
dependencies = [
"proc-macro2",
"quote",
@ -854,9 +812,9 @@ dependencies = [
[[package]]
name = "spacepackets"
version = "0.5.4"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9313bf066de3ae704ea83584fc65b62434249efe57ae2dcde3e2cffe4ba62648"
checksum = "81541fd89a5bc02845a849895d6ed1721235b3eac26fc77010f0a05f53bc4e8a"
dependencies = [
"chrono",
"crc",
@ -926,23 +884,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "toml_datetime"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5"
[[package]]
name = "toml_edit"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b"
dependencies = [
"indexmap",
"nom8",
"toml_datetime",
]
[[package]]
name = "unicode-ident"
version = "1.0.5"

View File

@ -1,12 +1,12 @@
[package]
name = "eurosim-obsw"
version = "0.1.0"
edition = "2023"
edition = "2021"
authors = ["Linus Köster <linus@koester-im-web.de>", "Robin Müller <muellerr@irs.uni-stuttgart.de>"]
description = "EuroSim OBSW Implementation"
homepage = "https://egit.irs.uni-stuttgart.de/rust/eurosim-obsw"
repository = "https://egit.irs.uni-stuttgart.de/rust/eurosim-obsw"
license = "Apache-2.0"
# license = "Apache-2.0"
categories = ["aerospace", "hardware-support", "embedded"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -26,8 +26,6 @@ strum_macros = "0.24"
num = "0.4"
num-derive = "0.3"
num-traits = "0.2"
byteorder = "1.4"
num_enum = "0.5"
[dependencies.socketcan]
git = "https://github.com/socketcan-rs/socketcan-rs.git"
@ -39,12 +37,10 @@ optional = true
#path = "../satrs-launchpad/spacepackets"
[dependencies.satrs-core]
git = "https://egit.irs.uni-stuttgart.de/rust/sat-rs.git"
rev = "c265e4c271"
path = "../satrs-launchpad/satrs-core"
[dependencies.satrs-mib]
git = "https://egit.irs.uni-stuttgart.de/rust/sat-rs.git"
rev = "c265e4c271"
path = "../satrs-launchpad/satrs-mib"
[features]
default = ["can"]

View File

@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

2
NOTICE
View File

@ -1,2 +0,0 @@
This software contains code developed as part of a Bachelors Thesis done for Airbus Netherlands
in cooperation with the Institute of Space Systems at the University of Stuttgart.

View File

@ -7,9 +7,6 @@ import sys
import time
from typing import Optional
import datetime
import json
import pprint
import struct
import tmtccmd
from spacepackets.ecss import PusTelemetry, PusTelecommand, PusVerificator
@ -18,7 +15,7 @@ from spacepackets.ecss.pus_1_verification import UnpackParams, Service1Tm
from spacepackets.ccsds.time import CdsShortTimestamp
from tmtccmd import CcsdsTmtcBackend, TcHandlerBase, ProcedureParamsWrapper
from tmtccmd.tc.pus_3_fsfw_hk import generate_one_hk_command, make_sid, create_enable_periodic_hk_command, create_disable_periodic_hk_command
from tmtccmd.tc.pus_3_fsfw_hk import generate_one_hk_command, make_sid
from tmtccmd.tc.pus_11_tc_sched import create_time_tagged_cmd
from tmtccmd.core.base import BackendRequest
from tmtccmd.pus import VerificationWrapper
@ -57,7 +54,7 @@ from tmtccmd.util.tmtc_printer import FsfwTmTcPrinter
_LOGGER = logging.getLogger(__name__)
EXAMPLE_PUS_APID = 0x50
EXAMPLE_PUS_APID = 0x02
class SatRsConfigHook(HookBase):
@ -97,8 +94,6 @@ class SatRsConfigHook(HookBase):
)
srv_3 = OpCodeEntry()
srv_3.add(HkOpCodes.GENERATE_ONE_SHOT, "Generate AOCS one shot HK")
srv_3.add(HkOpCodes.ENABLE_PERIODIC, "Enable Periodic AOCS HK")
srv_3.add(HkOpCodes.DISABLE_PERIODIC, "Disable Periodic AOCS HK")
defs.add_service(
name=CoreServiceList.SERVICE_3,
info="PUS Service 3 Housekeeping",
@ -115,21 +110,11 @@ class SatRsConfigHook(HookBase):
srv_11 = OpCodeEntry()
srv_11.add("0", "Scheduled TC Test")
srv_11.add("1", "Scheduled Camera Request TC")
defs.add_service(
name=CoreServiceList.SERVICE_11,
info="PUS Service 11 TC Scheduling",
op_code_entry=srv_11,
)
srv_200 = OpCodeEntry()
srv_200.add("0", "AOCS Mode Idle")
srv_200.add("1", "AOCS Mode On")
defs.add_service(
name = CoreServiceList.SERVICE_200,
info="PUS Custom Service 200 Mode",
op_code_entry=srv_200,
)
return defs
def perform_mode_operation(self, tmtc_backend: CcsdsTmtcBackend, mode: int):
@ -166,7 +151,6 @@ class PusHandler(SpecificApidHandlerBase):
service = tm_packet.service
dedicated_handler = False
if service == 1:
_LOGGER.info(packet.hex(sep=","))
tm_packet = Service1Tm.unpack(
data=packet, params=UnpackParams(CdsShortTimestamp.empty(), 1, 2)
)
@ -184,28 +168,17 @@ class PusHandler(SpecificApidHandlerBase):
self.verif_wrapper.log_to_file(tm_packet, res)
dedicated_handler = True
if service == 3:
# _LOGGER.info("No handling for HK packets implemented")
# _LOGGER.info(f"Raw packet: 0x[{packet.hex(sep=',')}]")
_LOGGER.info("No handling for HK packets implemented")
_LOGGER.info(f"Raw packet: 0x[{packet.hex(sep=',')}]")
pus_tm = PusTelemetry.unpack(packet, time_reader=CdsShortTimestamp.empty())
if pus_tm.subservice == 25:
if len(pus_tm.source_data) < 8:
raise ValueError("No addressable ID in HK packet")
#json_str = str(pus_tm.source_data[8:].decode('utf8'))
#json_object = json.loads(json_str)
#pprint.pprint(json_object)
print(pus_tm.tm_data.hex())
i = 8
print(struct.unpack('d', pus_tm.tm_data[8:16]))
while i < len(pus_tm.tm_data):
print(pus_tm.tm_data[i:i+8].hex())
print(struct.unpack('d', pus_tm.tm_data[i:i+8]))
i += 8
json_str = pus_tm.source_data[8:]
dedicated_handler = True
if service == 5:
tm_packet = Service5Tm.unpack(packet, time_reader=CdsShortTimestamp.empty())
if service == 17:
_LOGGER.info(packet.hex(sep=","))
tm_packet = Service17Tm.unpack(
packet, time_reader=CdsShortTimestamp.empty()
)
@ -245,16 +218,10 @@ def read_addressable_id(data: bytes) -> tuple[int, int]:
return (target_id, set_id)
class CustomServiceList(enum.StrEnum):
ACS = "acs"
class RequestTargetId(enum.IntEnum):
ACS = 1
PLD = 2
class RequestuniqueId(enum.IntEnum):
MGM_VOLTAGE_1 = 1
class AcsHkIds(enum.IntEnum):
MGM_SET = 1
@ -262,19 +229,12 @@ class AcsHkIds(enum.IntEnum):
class HkOpCodes:
GENERATE_ONE_SHOT = ["0", "oneshot"]
ENABLE_PERIODIC = ["1", "enable periodic"]
DISABLE_PERIODIC = ["2", "disable periodic"]
def make_target_id(target_id: int) -> bytes:
byte_string = bytearray(struct.pack("!I", target_id))
return byte_string
def make_mode_submode(mode: int, submode: int) -> bytes:
byte_string = bytearray(struct.pack("!I", mode))
byte_string.extend(struct.pack("!I", submode))
return byte_string
class TcHandler(TcHandlerBase):
def __init__(
@ -300,7 +260,6 @@ class TcHandler(TcHandlerBase):
pus_tc_wrapper = entry_helper.to_pus_tc_entry()
raw_tc = pus_tc_wrapper.pus_tc.pack()
_LOGGER.info(f"Sending {pus_tc_wrapper.pus_tc}")
_LOGGER.info(f"raw data: {pus_tc_wrapper.pus_tc.app_data}")
send_params.com_if.send(raw_tc)
elif entry_helper.entry_type == TcQueueEntryType.LOG:
log_entry = entry_helper.to_log_entry()
@ -321,29 +280,13 @@ class TcHandler(TcHandlerBase):
def_proc = helper.to_def_procedure()
service = def_proc.service
op_code = def_proc.op_code
if service == CoreServiceList.SERVICE_200:
q.add_log_cmd("Sending PUS Mode Request telecommand")
if op_code == "0":
tc = PusTelecommand(service=200, subservice=1, app_data=make_mode_submode(0,0), apid=0x50)
return q.add_pus_tc(tc)
if op_code == "1":
tc = PusTelecommand(service=200, subservice=1, app_data=make_mode_submode(1,0), apid=0x50)
return q.add_pus_tc(tc)
if (
service == CoreServiceList.SERVICE_17
or service == CoreServiceList.SERVICE_17_ALT
):
q.add_log_cmd("Sending PUS ping telecommand")
tc = PusTelecommand(service=17, subservice=1)
_LOGGER.info(tc.pack().hex(sep=","))
return q.add_pus_tc(PusTelecommand(service=17, subservice=1))
if service == CustomServiceList.ACS:
if op_code == "set_mode":
q.add_log_cmd()
q.add_pus_tc()
if service == CoreServiceList.SERVICE_11:
if op_code == "0":
q.add_log_cmd("Sending PUS scheduled TC telecommand")
crt_time = CdsShortTimestamp.from_now()
time_stamp = crt_time + datetime.timedelta(seconds=10)
@ -355,43 +298,19 @@ class TcHandler(TcHandlerBase):
apid=EXAMPLE_PUS_APID,
)
)
if op_code == "1":
q.add_log_cmd("Sending PUS scheduled TC telecommand")
crt_time = CdsShortTimestamp.from_now()
time_stamp = crt_time + datetime.timedelta(seconds=10)
time_stamp = time_stamp.pack()
return q.add_pus_tc(
create_time_tagged_cmd(
time_stamp,
PusTelecommand(service=8, subservice=1, app_data=make_target_id(RequestTargetId.PLD)),
apid=EXAMPLE_PUS_APID,
)
)
if service == CoreServiceList.SERVICE_8:
q.add_log_cmd("Sending PUS action request telecommand")
return q.add_pus_tc(
PusTelecommand(service=8, subservice=1, app_data=make_target_id(RequestTargetId.PLD), apid=0x030)
PusTelecommand(service=8, subservice=1, app_data=make_target_id(RequestTargetId.PLD))
)
if service == CoreServiceList.SERVICE_3:
if op_code in HkOpCodes.GENERATE_ONE_SHOT:
q.add_log_cmd("Sending HK one shot request")
tc = generate_one_hk_command(make_addressable_id(RequestuniqueId.MGM_VOLTAGE_1, AcsHkIds.MGM_SET))
q.add_log_cmd(tc)
q.add_pus_tc(
generate_one_hk_command(
make_addressable_id(RequestTargetId.ACS, AcsHkIds.MGM_SET)
)
)
if op_code in HkOpCodes.ENABLE_PERIODIC:
q.add_log_cmd("Sending periodic HK request")
tc = create_enable_periodic_hk_command(False, make_addressable_id(RequestTargetId.ACS, AcsHkIds.MGM_SET))
q.add_log_cmd(tc)
q.add_pus_tc(tc)
if op_code in HkOpCodes.DISABLE_PERIODIC:
q.add_log_cmd("Sending periodic HK request")
tc = create_disable_periodic_hk_command(False, make_addressable_id(RequestTargetId.ACS, AcsHkIds.MGM_SET))
q.add_log_cmd(tc)
q.add_pus_tc(tc)
pass

View File

@ -1,7 +1,6 @@
{
"com_if": "udp",
"tcpip_udp_ip_addr": "192.168.1.116",
"tcpip_udp_ip_addr_pc": "192.168.56.1",
"tcpip_udp_ip_addr": "169.254.7.6",
"tcpip_udp_port": 7301,
"tcpip_udp_recv_max_size": 1500
}

View File

@ -1,976 +1 @@
use crate::aocs::AOCSSensorMode::{Idle, SendingData};
use crate::can_ids::{DeviceId, MessageId, MessageModel};
use crate::helpers::{ModeHelper, VerifHelper};
use crate::hk::{AocsDataMap, AocsDataType, CSS_SUN_VECTOR_1, CSS_SUN_VECTOR_2, CSS_SUN_VECTOR_3, CSS_VOLTAGE_4, CSS_VOLTAGE_5, CSS_VOLTAGE_6, GPS_ALTITUDE, GPS_LATITUDE, GPS_LONGITUDE, MGM_FIELD_1, MGM_FIELD_2, MGM_FIELD_3, STR_QUATERNION_1, STR_QUATERNION_2, STR_QUATERNION_3, STR_QUATERNION_4};
use crate::power_handler::{DeviceState, PowerSwitcher};
use crate::requests::{Request, RequestWithToken};
use byteorder::{ByteOrder, LittleEndian};
use num_derive::ToPrimitive;
use satrs_core::mode::{ModeAndSubmode, ModeRequest};
use satrs_core::power::{PowerSwitcherCommandSender, SwitchId};
use satrs_core::seq_count::SeqCountProviderSyncClonable;
use std::sync::mpsc::{Receiver, Sender};
use std::sync::{Arc, Mutex};
use log::debug;
#[derive(ToPrimitive, PartialEq, Copy, Clone)]
pub enum AOCSSensorMode {
Idle = 0,
SendingData = 1,
}
pub trait AocsSensorHandler {
type Error;
fn get_package_id(&mut self) -> Result<MessageId, Self::Error>;
fn send_message(&mut self, id: MessageId, buf: &[u8]) -> Result<(), Self::Error>;
fn enable_sensor_data_generation(&mut self) -> Result<(), Self::Error> {
let id = self.get_package_id()?;
self.send_message(id, &[1])
}
fn disable_sensor_data_generation(&mut self) -> Result<(), Self::Error> {
let id = self.get_package_id()?;
self.send_message(id, &[0])
}
fn request_sensor_data_oneshot(&mut self) -> Result<(), Self::Error> {
let id = self.get_package_id()?;
self.send_message(id, &[2])
}
}
pub struct CSSHandler {
power_switcher: PowerSwitcher,
device_id: DeviceId,
switch_id: SwitchId,
device_state: DeviceState,
mode: AOCSSensorMode,
aocs_data: Arc<Mutex<AocsDataMap>>,
can_tx: Sender<MessageModel>,
can_rx: Receiver<MessageModel>,
request_rx: Receiver<RequestWithToken>,
verif_helper: VerifHelper,
mode_helper: ModeHelper,
}
impl AocsSensorHandler for CSSHandler {
type Error = ();
fn get_package_id(&mut self) -> Result<MessageId, Self::Error> {
Ok(MessageId::AOCSDataRequestSunSensor1)
}
fn send_message(&mut self, id: MessageId, buf: &[u8]) -> Result<(), Self::Error> {
self.can_tx
.send(MessageModel::new(id, buf).unwrap())
.unwrap();
return Ok(());
}
}
impl CSSHandler {
pub fn new(
power_switcher: PowerSwitcher,
device_id: DeviceId,
device_state: DeviceState,
aocs_data: Arc<Mutex<AocsDataMap>>,
can_tx: Sender<MessageModel>,
can_rx: Receiver<MessageModel>,
request_rx: Receiver<RequestWithToken>,
verif_helper: VerifHelper,
mode_helper: ModeHelper,
) -> Self {
let switch_id = device_id as u16;
Self {
power_switcher,
device_id,
switch_id,
device_state,
mode: Idle,
aocs_data,
can_tx,
can_rx,
request_rx,
verif_helper,
mode_helper,
}
}
pub fn periodic_op(&mut self) {
self.handle_requests();
self.read_can();
}
fn handle_requests(&mut self) {
if let Ok(req) = self.request_rx.try_recv() {
let (req, start_token) = self
.verif_helper
.start_and_unwrap(req)
.expect("error sending start of execution");
match req {
Request::HkRequest(_) => {
if let Some(token) = start_token {
self.verif_helper
.completion_failure(token)
.expect("error sending completion failure");
}
}
Request::ModeRequest(req) => match req {
ModeRequest::SetMode(mode_submode) => {
if let Some(aocs_mode) = mode_submode_to_aocs_mode(mode_submode) {
self.update_mode(aocs_mode);
}
if let Some(token) = start_token {
self.verif_helper
.completion(token)
.expect("error sending completion success");
}
}
ModeRequest::ReadMode => {
self.mode_helper
.make_and_send_mode_reply(aocs_mode_to_mode_submode(self.mode))
.expect("error sending mode reply");
if let Some(token) = start_token {
self.verif_helper
.completion(token)
.expect("error sending completion success");
}
}
ModeRequest::AnnounceMode => {
if let Some(token) = start_token {
self.verif_helper
.completion_failure(token)
.expect("error sending completion failure");
}
}
ModeRequest::AnnounceModeRecursive => {
self.mode_helper
.make_and_send_mode_reply(aocs_mode_to_mode_submode(self.mode))
.expect("error sending mode reply");
if let Some(token) = start_token {
self.verif_helper
.completion(token)
.expect("error sending completion failure");
}
}
},
Request::ActionRequest(_) => {
if let Some(token) = start_token {
self.verif_helper
.completion_failure(token)
.expect("error sending completion failure");
}
}
}
}
}
fn update_mode(&mut self, mode: AOCSSensorMode) {
if mode != self.mode {
match mode {
Idle => { self.set_mode_idle() }
SendingData => { self.set_mode_reading() }
}
}
}
fn set_mode_reading(&mut self) {
if self.mode == SendingData {
return;
}
// TODO: currently unrecoverable, should probably be changed
self.power_switcher
.send_switch_on_cmd(self.switch_id)
.expect("error sending switch on cmd");
self.enable_sensor_data_generation()
.expect("error enabling sensor data generation");
self.mode = SendingData;
}
fn set_mode_idle(&mut self) {
if self.mode == Idle {
return;
}
self.disable_sensor_data_generation()
.expect("error disabling sensor data generation");
self.power_switcher
.send_switch_off_cmd(self.switch_id)
.expect("error sending switch off cmd");
self.mode = Idle;
}
fn read_can(&mut self) {
if let Ok(package) = self.can_rx.try_recv() {
let mut map = self.aocs_data.lock().expect("error locking data map");
let float_data = self.decode_sensor_data(package.data());
match package.message_id() {
MessageId::AOCSDataSunSensor1 => {
map.update_value(CSS_SUN_VECTOR_1, AocsDataType::FloatValue(float_data))
.expect("error updating value");
}
MessageId::AOCSDataSunSensor2 => {
map.update_value(CSS_SUN_VECTOR_2, AocsDataType::FloatValue(float_data))
.expect("error updating value");
}
MessageId::AOCSDataSunSensor3 => {
map.update_value(CSS_SUN_VECTOR_3, AocsDataType::FloatValue(float_data))
.expect("error updating value");
}
MessageId::AOCSDataSunSensor4 => {
map.update_value(CSS_VOLTAGE_4, AocsDataType::FloatValue(float_data))
.expect("error updating value");
}
MessageId::AOCSDataSunSensor5 => {
map.update_value(CSS_VOLTAGE_5, AocsDataType::FloatValue(float_data))
.expect("error updating value");
}
MessageId::AOCSDataSunSensor6 => {
map.update_value(CSS_VOLTAGE_6, AocsDataType::FloatValue(float_data))
.expect("error updating value");
}
_ => {}
}
drop(map);
}
}
fn decode_sensor_data(&self, buf: &[u8]) -> f64 {
LittleEndian::read_f64(&buf)
}
}
pub struct MGMHandler {
power_switcher: PowerSwitcher,
device_id: DeviceId,
switch_id: SwitchId,
device_state: DeviceState,
mode: AOCSSensorMode,
aocs_data: Arc<Mutex<AocsDataMap>>,
can_tx: Sender<MessageModel>,
can_rx: Receiver<MessageModel>,
request_rx: Receiver<RequestWithToken>,
verif_helper: VerifHelper,
mode_helper: ModeHelper,
}
impl AocsSensorHandler for MGMHandler {
type Error = ();
fn get_package_id(&mut self) -> Result<MessageId, Self::Error> {
Ok(MessageId::AOCSDataRequestMGM1)
}
fn send_message(&mut self, id: MessageId, buf: &[u8]) -> Result<(), Self::Error> {
self.can_tx
.send(MessageModel::new(id, buf).unwrap())
.unwrap();
return Ok(());
}
}
impl MGMHandler {
pub fn new(
power_switcher: PowerSwitcher,
device_id: DeviceId,
device_state: DeviceState,
aocs_data: Arc<Mutex<AocsDataMap>>,
can_tx: Sender<MessageModel>,
can_rx: Receiver<MessageModel>,
request_rx: Receiver<RequestWithToken>,
verif_helper: VerifHelper,
mode_helper: ModeHelper,
) -> Self {
let switch_id = device_id as u16;
Self {
power_switcher,
device_id,
switch_id,
device_state,
mode: Idle,
aocs_data,
can_tx,
can_rx,
request_rx,
verif_helper,
mode_helper,
}
}
pub fn periodic_op(&mut self) {
self.handle_requests();
self.read_can();
}
fn handle_requests(&mut self) {
if let Ok(req) = self.request_rx.try_recv() {
debug!("request received");
let (req, start_token) = self
.verif_helper
.start_and_unwrap(req)
.expect("error sending start of execution");
match req {
Request::HkRequest(_) => {
if let Some(token) = start_token {
self.verif_helper
.completion_failure(token)
.expect("error sending completion failure");
}
}
Request::ModeRequest(req) => match req {
ModeRequest::SetMode(mode_submode) => {
if let Some(aocs_mode) = mode_submode_to_aocs_mode(mode_submode) {
self.update_mode(aocs_mode);
}
if let Some(token) = start_token {
self.verif_helper
.completion(token)
.expect("error sending completion success");
}
}
ModeRequest::ReadMode => {
self.mode_helper
.make_and_send_mode_reply(aocs_mode_to_mode_submode(self.mode))
.expect("error sending mode reply");
if let Some(token) = start_token {
self.verif_helper
.completion(token)
.expect("error sending completion success");
}
}
ModeRequest::AnnounceMode => {
if let Some(token) = start_token {
self.verif_helper
.completion_failure(token)
.expect("error sending completion failure");
}
}
ModeRequest::AnnounceModeRecursive => {
self.mode_helper
.make_and_send_mode_reply(aocs_mode_to_mode_submode(self.mode))
.expect("error sending mode reply");
if let Some(token) = start_token {
self.verif_helper
.completion(token)
.expect("error sending completion failure");
}
}
},
Request::ActionRequest(_) => {
if let Some(token) = start_token {
self.verif_helper
.completion_failure(token)
.expect("error sending completion failure");
}
}
}
}
}
fn update_mode(&mut self, mode: AOCSSensorMode) {
if mode != self.mode {
match mode {
Idle => { self.set_mode_idle() }
SendingData => { self.set_mode_reading() }
}
}
}
fn set_mode_reading(&mut self) {
if self.mode == SendingData {
return;
}
// TODO: currently unrecoverable, should probably be changed
self.power_switcher
.send_switch_on_cmd(self.switch_id)
.expect("error sending switch on cmd");
self.enable_sensor_data_generation()
.expect("error enabling sensor data generation");
self.mode = SendingData;
}
fn set_mode_idle(&mut self) {
if self.mode == Idle {
return;
}
self.disable_sensor_data_generation()
.expect("error disabling sensor data generation");
self.power_switcher
.send_switch_off_cmd(self.switch_id)
.expect("error sending switch off cmd");
self.mode = Idle;
}
fn read_can(&mut self) {
if let Ok(package) = self.can_rx.try_recv() {
let mut map = self.aocs_data.lock().expect("error locking data map");
let float_data = self.decode_sensor_data(package.data());
match package.message_id() {
MessageId::AOCSDataMGM1 => {
map.update_value(MGM_FIELD_1, AocsDataType::FloatValue(float_data))
.expect("error updating value");
}
MessageId::AOCSDataMGM2 => {
map.update_value(MGM_FIELD_2, AocsDataType::FloatValue(float_data))
.expect("error updating value");
}
MessageId::AOCSDataMGM3 => {
map.update_value(MGM_FIELD_3, AocsDataType::FloatValue(float_data))
.expect("error updating value");
}
_ => {}
}
drop(map);
}
}
fn decode_sensor_data(&self, buf: &[u8]) -> f64 {
LittleEndian::read_f64(&buf)
}
}
pub struct STRHandler {
power_switcher: PowerSwitcher,
device_id: DeviceId,
switch_id: SwitchId,
device_state: DeviceState,
mode: AOCSSensorMode,
aocs_data: Arc<Mutex<AocsDataMap>>,
can_tx: Sender<MessageModel>,
can_rx: Receiver<MessageModel>,
request_rx: Receiver<RequestWithToken>,
verif_helper: VerifHelper,
mode_helper: ModeHelper,
}
impl AocsSensorHandler for STRHandler {
type Error = ();
fn get_package_id(&mut self) -> Result<MessageId, Self::Error> {
Ok(MessageId::AOCSDataRequestStarTracker)
}
fn send_message(&mut self, id: MessageId, buf: &[u8]) -> Result<(), Self::Error> {
self.can_tx
.send(MessageModel::new(id, buf).unwrap())
.unwrap();
return Ok(());
}
}
impl STRHandler {
pub fn new(
power_switcher: PowerSwitcher,
device_id: DeviceId,
device_state: DeviceState,
aocs_data: Arc<Mutex<AocsDataMap>>,
can_tx: Sender<MessageModel>,
can_rx: Receiver<MessageModel>,
request_rx: Receiver<RequestWithToken>,
verif_helper: VerifHelper,
mode_helper: ModeHelper,
) -> Self {
let switch_id = device_id as u16;
Self {
power_switcher,
device_id,
switch_id,
device_state,
mode: Idle,
aocs_data,
can_tx,
can_rx,
request_rx,
verif_helper,
mode_helper,
}
}
pub fn periodic_op(&mut self) {
self.handle_requests();
self.read_can();
}
fn handle_requests(&mut self) {
if let Ok(req) = self.request_rx.try_recv() {
let (req, start_token) = self
.verif_helper
.start_and_unwrap(req)
.expect("error sending start of execution");
match req {
Request::HkRequest(_) => {
if let Some(token) = start_token {
self.verif_helper
.completion_failure(token)
.expect("error sending completion failure");
}
}
Request::ModeRequest(req) => match req {
ModeRequest::SetMode(mode_submode) => {
if let Some(aocs_mode) = mode_submode_to_aocs_mode(mode_submode) {
self.update_mode(aocs_mode);
}
if let Some(token) = start_token {
self.verif_helper
.completion(token)
.expect("error sending completion success");
}
}
ModeRequest::ReadMode => {
self.mode_helper
.make_and_send_mode_reply(aocs_mode_to_mode_submode(self.mode))
.expect("error sending mode reply");
if let Some(token) = start_token {
self.verif_helper
.completion(token)
.expect("error sending completion success");
}
}
ModeRequest::AnnounceMode => {
if let Some(token) = start_token {
self.verif_helper
.completion_failure(token)
.expect("error sending completion failure");
}
}
ModeRequest::AnnounceModeRecursive => {
self.mode_helper
.make_and_send_mode_reply(aocs_mode_to_mode_submode(self.mode))
.expect("error sending mode reply");
if let Some(token) = start_token {
self.verif_helper
.completion(token)
.expect("error sending completion failure");
}
}
},
Request::ActionRequest(_) => {
if let Some(token) = start_token {
self.verif_helper
.completion_failure(token)
.expect("error sending completion failure");
}
}
}
}
}
fn update_mode(&mut self, mode: AOCSSensorMode) {
if mode != self.mode {
match mode {
Idle => { self.set_mode_idle() }
SendingData => { self.set_mode_reading() }
}
}
}
fn set_mode_reading(&mut self) {
if self.mode == SendingData {
return;
}
// TODO: currently unrecoverable, should probably be changed
self.power_switcher
.send_switch_on_cmd(self.switch_id)
.expect("error sending switch on cmd");
self.enable_sensor_data_generation()
.expect("error enabling sensor data generation");
self.mode = SendingData;
}
fn set_mode_idle(&mut self) {
if self.mode == Idle {
return;
}
self.disable_sensor_data_generation()
.expect("error disabling sensor data generation");
self.power_switcher
.send_switch_off_cmd(self.switch_id)
.expect("error sending switch off cmd");
self.mode = Idle;
}
fn read_can(&mut self) {
if let Ok(package) = self.can_rx.try_recv() {
let mut map = self.aocs_data.lock().expect("error locking data map");
let float_data = self.decode_sensor_data(package.data());
match package.message_id() {
MessageId::AOCSDataStarTracker1 => {
map.update_value(STR_QUATERNION_1, AocsDataType::FloatValue(float_data))
.expect("error updating value");
}
MessageId::AOCSDataStarTracker2 => {
map.update_value(STR_QUATERNION_2, AocsDataType::FloatValue(float_data))
.expect("error updating value");
}
MessageId::AOCSDataStarTracker3 => {
map.update_value(STR_QUATERNION_3, AocsDataType::FloatValue(float_data))
.expect("error updating value");
}
MessageId::AOCSDataStarTracker4 => {
map.update_value(STR_QUATERNION_4, AocsDataType::FloatValue(float_data))
.expect("error updating value");
}
_ => {}
}
drop(map);
}
}
fn decode_sensor_data(&self, buf: &[u8]) -> f64 {
LittleEndian::read_f64(&buf)
}
}
pub struct GPSHandler {
power_switcher: PowerSwitcher,
device_id: DeviceId,
switch_id: SwitchId,
device_state: DeviceState,
mode: AOCSSensorMode,
aocs_data: Arc<Mutex<AocsDataMap>>,
can_tx: Sender<MessageModel>,
can_rx: Receiver<MessageModel>,
request_rx: Receiver<RequestWithToken>,
verif_helper: VerifHelper,
mode_helper: ModeHelper,
}
impl AocsSensorHandler for GPSHandler {
type Error = ();
fn get_package_id(&mut self) -> Result<MessageId, Self::Error> {
Ok(MessageId::AOCSDataRequestGPS)
}
fn send_message(&mut self, id: MessageId, buf: &[u8]) -> Result<(), Self::Error> {
self.can_tx
.send(MessageModel::new(id, buf).unwrap())
.unwrap();
return Ok(());
}
}
impl GPSHandler {
pub fn new(
power_switcher: PowerSwitcher,
device_id: DeviceId,
device_state: DeviceState,
aocs_data: Arc<Mutex<AocsDataMap>>,
can_tx: Sender<MessageModel>,
can_rx: Receiver<MessageModel>,
request_rx: Receiver<RequestWithToken>,
verif_helper: VerifHelper,
mode_helper: ModeHelper,
) -> Self {
let switch_id = device_id as u16;
Self {
power_switcher,
device_id,
switch_id,
device_state,
mode: Idle,
aocs_data,
can_tx,
can_rx,
request_rx,
verif_helper,
mode_helper,
}
}
pub fn periodic_op(&mut self) {
self.handle_requests();
self.read_can();
}
fn handle_requests(&mut self) {
if let Ok(req) = self.request_rx.try_recv() {
let (req, start_token) = self
.verif_helper
.start_and_unwrap(req)
.expect("error sending start of execution");
match req {
Request::HkRequest(_) => {
if let Some(token) = start_token {
self.verif_helper
.completion_failure(token)
.expect("error sending completion failure");
}
}
Request::ModeRequest(req) => match req {
ModeRequest::SetMode(mode_submode) => {
if let Some(aocs_mode) = mode_submode_to_aocs_mode(mode_submode) {
self.update_mode(aocs_mode);
}
if let Some(token) = start_token {
self.verif_helper
.completion(token)
.expect("error sending completion success");
}
}
ModeRequest::ReadMode => {
self.mode_helper
.make_and_send_mode_reply(aocs_mode_to_mode_submode(self.mode))
.expect("error sending mode reply");
if let Some(token) = start_token {
self.verif_helper
.completion(token)
.expect("error sending completion success");
}
}
ModeRequest::AnnounceMode => {
if let Some(token) = start_token {
self.verif_helper
.completion_failure(token)
.expect("error sending completion failure");
}
}
ModeRequest::AnnounceModeRecursive => {
self.mode_helper
.make_and_send_mode_reply(aocs_mode_to_mode_submode(self.mode))
.expect("error sending mode reply");
if let Some(token) = start_token {
self.verif_helper
.completion(token)
.expect("error sending completion failure");
}
}
},
Request::ActionRequest(_) => {
if let Some(token) = start_token {
self.verif_helper
.completion_failure(token)
.expect("error sending completion failure");
}
}
}
}
}
fn update_mode(&mut self, mode: AOCSSensorMode) {
if mode != self.mode {
match mode {
Idle => { self.set_mode_idle() }
SendingData => { self.set_mode_reading() }
}
}
}
fn set_mode_reading(&mut self) {
if self.mode == SendingData {
return;
}
// TODO: currently unrecoverable, should probably be changed
self.power_switcher
.send_switch_on_cmd(self.switch_id)
.expect("error sending switch on cmd");
self.enable_sensor_data_generation()
.expect("error enabling sensor data generation");
self.mode = SendingData;
}
fn set_mode_idle(&mut self) {
if self.mode == Idle {
return;
}
self.disable_sensor_data_generation()
.expect("error disabling sensor data generation");
self.power_switcher
.send_switch_off_cmd(self.switch_id)
.expect("error sending switch off cmd");
self.mode = Idle;
}
fn read_can(&mut self) {
if let Ok(package) = self.can_rx.try_recv() {
let mut map = self.aocs_data.lock().expect("error locking data map");
let float_data = self.decode_sensor_data(package.data());
match package.message_id() {
MessageId::AOCSDataGPSLatitude => {
map.update_value(GPS_LATITUDE, AocsDataType::FloatValue(float_data))
.expect("error updating value");
}
MessageId::AOCSDataGPSLongitude => {
map.update_value(GPS_LONGITUDE, AocsDataType::FloatValue(float_data))
.expect("error updating value");
}
MessageId::AOCSDataGPSAltitude => {
map.update_value(GPS_ALTITUDE, AocsDataType::FloatValue(float_data))
.expect("error updating value");
}
_ => {}
}
drop(map);
}
}
fn decode_sensor_data(&self, buf: &[u8]) -> f64 {
LittleEndian::read_f64(&buf)
}
}
pub struct AocsController {
request_rx: Receiver<RequestWithToken>,
mgm_request_tx: Sender<RequestWithToken>,
css_request_tx: Sender<RequestWithToken>,
str_request_tx: Sender<RequestWithToken>,
gps_request_tx: Sender<RequestWithToken>,
seq_count_provider: SeqCountProviderSyncClonable,
verif_helper: VerifHelper,
mode_helper: ModeHelper,
mode: AOCSSensorMode,
}
impl AocsController {
pub fn new(
request_rx: Receiver<RequestWithToken>,
mgm_request_tx: Sender<RequestWithToken>,
css_request_tx: Sender<RequestWithToken>,
str_request_tx: Sender<RequestWithToken>,
gps_request_tx: Sender<RequestWithToken>,
seq_count_provider: SeqCountProviderSyncClonable,
verif_helper: VerifHelper,
mode_helper: ModeHelper,
) -> Self {
Self {
request_rx,
mgm_request_tx,
css_request_tx,
str_request_tx,
gps_request_tx,
seq_count_provider,
verif_helper,
mode_helper,
mode: Idle,
}
}
pub fn periodic_op(&mut self) {
self.handle_requests();
}
fn handle_requests(&mut self) {
if let Ok(req) = self.request_rx.try_recv() {
let (req, start_token) = self
.verif_helper
.start_and_unwrap(req)
.expect("error sending start of execution");
match req {
Request::HkRequest(_) => {
if let Some(token) = start_token {
self.verif_helper
.completion_failure(token)
.expect("error sending completion failure");
}
}
Request::ModeRequest(req) => match req {
ModeRequest::SetMode(mode_submode) => {
if let Some(aocs_mode) = mode_submode_to_aocs_mode(mode_submode) {
self.mode = aocs_mode;
}
self.mgm_request_tx
.send(RequestWithToken(Request::ModeRequest(req), None))
.expect("error sending to mgm");
self.css_request_tx
.send(RequestWithToken(Request::ModeRequest(req), None))
.expect("error sending to css");
self.str_request_tx
.send(RequestWithToken(Request::ModeRequest(req), None))
.expect("error sending to str");
self.gps_request_tx
.send(RequestWithToken(Request::ModeRequest(req), None))
.expect("error sending to str");
if let Some(token) = start_token {
self.verif_helper
.completion(token)
.expect("error sending completion success");
}
}
ModeRequest::ReadMode => {
self.mode_helper
.make_and_send_mode_reply(aocs_mode_to_mode_submode(self.mode))
.expect("error sending mode reply");
if let Some(token) = start_token {
self.verif_helper
.completion(token)
.expect("error sending completion success");
}
}
ModeRequest::AnnounceMode => {
if let Some(token) = start_token {
self.verif_helper
.completion_failure(token)
.expect("error sending completion failure");
}
}
ModeRequest::AnnounceModeRecursive => {
self.mode_helper
.make_and_send_mode_reply(aocs_mode_to_mode_submode(self.mode))
.expect("error sending mode reply");
self.mgm_request_tx
.send(RequestWithToken(Request::ModeRequest(req), None))
.expect("error sending mode request to mgm handler");
self.css_request_tx
.send(RequestWithToken(Request::ModeRequest(req), None))
.expect("error sending mode request to css handler");
self.str_request_tx
.send(RequestWithToken(Request::ModeRequest(req), None))
.expect("error sending mode request to str handler");
self.gps_request_tx
.send(RequestWithToken(Request::ModeRequest(req), None))
.expect("error sending mode request to str handler");
if let Some(token) = start_token {
self.verif_helper
.completion(token)
.expect("error sending completion failure");
}
}
},
Request::ActionRequest(_) => {
if let Some(token) = start_token {
self.verif_helper
.completion_failure(token)
.expect("error sending completion failure");
}
}
}
}
}
}
fn aocs_mode_to_mode_submode(sensor_mode: AOCSSensorMode) -> ModeAndSubmode {
match sensor_mode {
Idle => ModeAndSubmode::new(0, 0),
SendingData => ModeAndSubmode::new(1, 0),
}
}
fn mode_submode_to_aocs_mode(mode_submode: ModeAndSubmode) -> Option<AOCSSensorMode> {
match mode_submode.mode() {
0 => Some(Idle),
1 => Some(SendingData),
_ => None,
}
}
pub fn core_aocs_loop() {}

View File

@ -1,21 +1,31 @@
#![allow(dead_code)]
#![allow(unused_variables)]
#![allow(unused_imports)]
use crate::pcdu::DeviceState;
use crate::can_ids::{
can_id_to_message_id, message_id_to_can_id, DeviceId, MessageId, MessageModel,
SenderReceiverApid, SenderReceiverThread, ThreadId,
can_id_to_package_id, package_id_to_can_id, value_to_package_id, DeviceId, PackageId,
PackageModel, SenderReceiverThread, ThreadId,
};
use embedded_can::{self, Frame};
use log::{debug, warn};
use log::{debug, error, info, trace, warn};
use serde::{Deserialize, Serialize};
use serde_json;
use socketcan::{errors, frame, socket, CanFrame, Socket};
use std::collections::HashMap;
use std::ffi::c_void;
use std::io;
use std::sync::mpsc::{Receiver, Sender};
use std::mem::size_of;
use std::sync::mpsc::Sender;
pub struct CanRxHandler {
interface: &'static str,
socket: socket::CanSocket,
//frame_id_to_sender_id: HashMap<embedded_can::Id, u32>, // double hash map: frame id -> receiver id -> sender handle
can_senders: HashMap<u16, Sender<MessageModel>>,
can_senders: HashMap<ThreadId, Sender<PackageModel>>,
//dismissed_ids: Vec<embedded_can::Id>,
message_map: HashMap<MessageId, SenderReceiverApid>,
package_map: HashMap<PackageId, SenderReceiverThread>,
//packet_id_to_sender_id: HashMap<PackageId, ThreadId>,
}
@ -23,8 +33,8 @@ impl CanRxHandler {
pub fn new_socket(
interface: &'static str,
//frame_id_to_sender_id: HashMap<embedded_can::Id, u32>,
can_senders: HashMap<u16, Sender<MessageModel>>,
message_map: HashMap<MessageId, SenderReceiverApid>,
can_senders: HashMap<ThreadId, Sender<PackageModel>>,
package_map: HashMap<PackageId, SenderReceiverThread>,
) -> Result<CanRxHandler, ()> {
let socket = socket::CanSocket::open(&interface);
if let Ok(socket) = socket {
@ -32,18 +42,28 @@ impl CanRxHandler {
interface,
socket,
can_senders,
message_map,
package_map,
})
} else {
Err(())
}
}
pub fn process_incoming(&mut self) {
if let Some(frame) = self.rx_socket() {
self.forward_frame(frame);
/*
pub fn new_socket_with_filter(
interface: &'static str,
can_id_to_sender_id: HashMap<embedded_can::Id, u32>,
can_senders: HashMap<u32, Sender<Vec<u8>>>,
can_filters: &[socket::CanFilter],
) -> Result<CanRxHandler, ()> {
let can_wrapper = Self::new_socket(interface, can_id_to_sender_id, can_senders)?;
let filter_result = can_wrapper.socket.set_filters(can_filters);
if let Err(e) = filter_result {
warn!("Can Bus set filter error: {}", e);
}
Ok(can_wrapper)
}
*/
pub fn read_frame(&self) -> io::Result<frame::CanFrame> {
let frame = self.socket.read_frame();
@ -55,97 +75,51 @@ impl CanRxHandler {
pub fn rx_socket(&self) -> Option<CanFrame> {
let frame = self.socket.read_frame().ok()?;
debug!("Can Frame read: {:?}.", frame);
info!("Can Frame read: {:?}.", frame);
return Some(frame);
/*
if let Ok(frame) = frame {
println!("Frame received: {:?}", frame);
return Some(frame);
}
None
*/
}
pub fn forward_frame(&self, frame: CanFrame) {
let frame_id = can_id_to_message_id(frame.id());
debug!("Frame forwarding with id: {:?}", frame_id);
let frame_id = can_id_to_package_id(frame.id());
info!("Frame forwarding with id: {:?}", frame_id);
if let Some(frame_id) = frame_id {
if self.message_map.contains_key(&frame_id) {
let value = self.message_map.get(&frame_id).unwrap();
if self.package_map.contains_key(&frame_id) {
let value = self.package_map.get(&frame_id).unwrap();
if value.get_sender() != DeviceId::OBC {
let message_sender = self.can_senders.get(&value.get_apid()).unwrap();
let message_sender = self.can_senders.get(&value.get_thread()).unwrap();
let data = frame.data();
let message =
MessageModel::new(frame_id, data).expect("Error generating message.");
PackageModel::new(frame_id, data).expect("Error generating message.");
message_sender.send(message).expect(&*format!(
"Failure sending can bus frame to thread{:?}, frame id {:?}",
value.get_apid(),
value.get_thread(),
frame_id
));
}
}
}
}
/*
pub fn set_filter(&self, filters: &[socket::CanFilter]) -> io::Result<()> {
info!("Setting filter with filter {:?}", filters);
let result = self.socket.set_filters(filters);
if let Err(e) = result {
warn!("Can bus socket filter set error: {}", e);
}
Ok(())
}
*/
}
pub struct CanTxHandler {
interface: &'static str,
socket: socket::CanSocket,
message_map: HashMap<MessageId, SenderReceiverApid>,
message_receiver: Receiver<MessageModel>,
}
impl CanTxHandler {
pub fn new_socket(
interface: &'static str,
message_map: HashMap<MessageId, SenderReceiverApid>,
message_receiver: Receiver<MessageModel>,
) -> Result<CanTxHandler, ()> {
let socket = socket::CanSocket::open(&interface);
if let Ok(socket) = socket {
socket.filter_drop_all().unwrap(); // tx nodes cannot receive data
Ok(CanTxHandler {
interface,
socket,
message_map,
message_receiver,
})
} else {
Err(())
}
}
pub fn process_incoming(&mut self) {
if let Ok(message) = self.message_receiver.recv() {
self.tx_socket(message.message_id(), message.data());
}
}
pub fn tx_socket(&self, message_id: MessageId, data: &[u8]) {
if self.message_map.contains_key(&message_id) {
let value = self.message_map.get(&message_id).unwrap();
if value.get_sender() == DeviceId::OBC {
if data.len() <= 8 {
let frame_id = message_id_to_can_id(&message_id);
let frame = CanFrame::new(frame_id, data);
if let Some(frame) = frame {
self.socket
.write_frame(&frame)
.expect("Error writing frame.");
}
} else {
warn!(
"Message dismissed, data length ({:?}) exceeds 8 bytes",
data.len()
);
}
} else {
warn!(
"Message dismissed, wrong sender id: {:?}",
value.get_sender()
);
}
} else {
warn!("Message dismissed, wrong package id: {:?}", message_id);
}
}
}
/*pub struct CanTxHandler {
interface: &'static str,
socket: socket::CanSocket,
thread_id: ThreadId,
@ -239,8 +213,6 @@ impl CanTxHandler {
*/
}
*/
pub fn open_socket(interface: &str) -> Result<socket::CanSocket, errors::CanSocketOpenError> {
let socket = socket::CanSocket::open(&interface);
return socket;

View File

@ -2,7 +2,6 @@ use embedded_can::{Id, StandardId};
use log::warn;
use std::collections::HashMap;
use crate::tmtc::{CSS_APID, GPS_APID, MGM_APID, MGT_APID, PLD_APID, PWR_APID, RWL_APID, STR_APID};
pub use num_derive::{FromPrimitive, ToPrimitive};
pub use num_traits::{FromPrimitive, ToPrimitive};
pub use strum::IntoEnumIterator; // 0.17.1
@ -17,7 +16,7 @@ pub enum ThreadId {
}
#[derive(Debug, EnumIter, Eq, Hash, PartialEq, Copy, Clone, FromPrimitive)]
pub enum MessageId {
pub enum PackageId {
PCDUStatusRequest = 10,
DevicePowerOnRequest = 11,
DevicePowerOffRequest = 12,
@ -47,7 +46,6 @@ pub enum MessageId {
AOCSDataRequestSunSensor5 = 49,
AOCSDataRequestSunSensor6 = 50,
AOCSDataRequestStarTracker = 51,
AOCSDataRequestGPS = 55,
AOCSDataMGM1 = 61,
AOCSDataMGM2 = 62,
AOCSDataMGM3 = 63,
@ -58,13 +56,7 @@ pub enum MessageId {
AOCSDataSunSensor4 = 68,
AOCSDataSunSensor5 = 69,
AOCSDataSunSensor6 = 70,
AOCSDataStarTracker1 = 71,
AOCSDataStarTracker2 = 72,
AOCSDataStarTracker3 = 73,
AOCSDataStarTracker4 = 74,
AOCSDataGPSLatitude = 81,
AOCSDataGPSLongitude = 82,
AOCSDataGPSAltitude = 83,
AOCSDataStarTracker = 71,
CameraImageRequest = 101,
CameraImageRequestConfirmation = 102,
CameraImageExecutionStart = 103,
@ -96,7 +88,6 @@ pub enum DeviceId {
RWL4 = 21,
Camera = 22,
All = 23,
GPS = 24,
}
impl TryFrom<u16> for DeviceId {
@ -104,56 +95,55 @@ impl TryFrom<u16> for DeviceId {
fn try_from(v: u16) -> Result<Self, Self::Error> {
match v {
x if x == DeviceId::OBC as u16 => Ok(DeviceId::OBC),
x if x == DeviceId::PCDU as u16 => Ok(DeviceId::PCDU),
x if x == DeviceId::MGM1 as u16 => Ok(DeviceId::MGM1),
x if x == DeviceId::MGM2 as u16 => Ok(DeviceId::MGM2),
x if x == DeviceId::MGM3 as u16 => Ok(DeviceId::MGM3),
x if x == DeviceId::MGM4 as u16 => Ok(DeviceId::MGM4),
x if x == DeviceId::SunSensor1 as u16 => Ok(DeviceId::SunSensor1),
x if x == DeviceId::SunSensor2 as u16 => Ok(DeviceId::SunSensor2),
x if x == DeviceId::SunSensor3 as u16 => Ok(DeviceId::SunSensor3),
x if x == DeviceId::SunSensor4 as u16 => Ok(DeviceId::SunSensor4),
x if x == DeviceId::SunSensor5 as u16 => Ok(DeviceId::SunSensor5),
x if x == DeviceId::SunSensor6 as u16 => Ok(DeviceId::SunSensor6),
x if x == DeviceId::StarTracker as u16 => Ok(DeviceId::StarTracker),
x if x == DeviceId::MGT1 as u16 => Ok(DeviceId::MGT1),
x if x == DeviceId::MGT2 as u16 => Ok(DeviceId::MGT2),
x if x == DeviceId::MGT3 as u16 => Ok(DeviceId::MGT3),
x if x == DeviceId::MGT4 as u16 => Ok(DeviceId::MGT4),
x if x == DeviceId::RWL1 as u16 => Ok(DeviceId::RWL1),
x if x == DeviceId::RWL2 as u16 => Ok(DeviceId::RWL2),
x if x == DeviceId::RWL3 as u16 => Ok(DeviceId::RWL3),
x if x == DeviceId::RWL4 as u16 => Ok(DeviceId::RWL4),
x if x == DeviceId::Camera as u16 => Ok(DeviceId::Camera),
x if x == DeviceId::All as u16 => Ok(DeviceId::All),
x if x == DeviceId::GPS as u16 => Ok(DeviceId::GPS),
x if x==DeviceId::OBC as u16 => Ok(DeviceId::OBC),
x if x==DeviceId::PCDU as u16 => Ok(DeviceId::PCDU),
x if x==DeviceId::MGM1 as u16 => Ok(DeviceId::MGM1),
x if x==DeviceId::MGM2 as u16 => Ok(DeviceId::MGM2),
x if x==DeviceId::MGM3 as u16 => Ok(DeviceId::MGM3),
x if x==DeviceId::MGM4 as u16 => Ok(DeviceId::MGM4),
x if x==DeviceId::SunSensor1 as u16 => Ok(DeviceId::SunSensor1),
x if x==DeviceId::SunSensor2 as u16 => Ok(DeviceId::SunSensor2),
x if x==DeviceId::SunSensor3 as u16 => Ok(DeviceId::SunSensor3),
x if x==DeviceId::SunSensor4 as u16 => Ok(DeviceId::SunSensor4),
x if x==DeviceId::SunSensor5 as u16 => Ok(DeviceId::SunSensor5),
x if x==DeviceId::SunSensor6 as u16 => Ok(DeviceId::SunSensor6),
x if x==DeviceId::StarTracker as u16 => Ok(DeviceId::StarTracker),
x if x==DeviceId::MGT1 as u16 => Ok(DeviceId::MGT1),
x if x==DeviceId::MGT2 as u16 => Ok(DeviceId::MGT2),
x if x==DeviceId::MGT3 as u16 => Ok(DeviceId::MGT3),
x if x==DeviceId::MGT4 as u16 => Ok(DeviceId::MGT4),
x if x==DeviceId::RWL1 as u16 => Ok(DeviceId::RWL1),
x if x==DeviceId::RWL2 as u16 => Ok(DeviceId::RWL2),
x if x==DeviceId::RWL3 as u16 => Ok(DeviceId::RWL3),
x if x==DeviceId::RWL4 as u16 => Ok(DeviceId::RWL4),
x if x==DeviceId::Camera as u16 => Ok(DeviceId::Camera),
x if x==DeviceId::All as u16 => Ok(DeviceId::All),
_ => Err(()),
}
}
}
#[derive(Debug)]
pub struct MessageModel {
message_id: MessageId,
pub struct PackageModel {
package_id: PackageId,
data: Vec<u8>,
}
impl MessageModel {
pub fn new(message_id: MessageId, data: &[u8]) -> Result<MessageModel, ()> {
impl PackageModel {
pub fn new(package_id: PackageId, data: &[u8]) -> Result<PackageModel, ()> {
if data.len() > 8 {
warn!("Data exceeds maximum length.");
return Err(());
}
let vec = Vec::from(data);
return Ok(MessageModel {
message_id,
return Ok(PackageModel {
package_id,
data: vec,
});
}
pub fn message_id(&self) -> MessageId {
self.message_id
pub fn package_id(&self) -> PackageId {
self.package_id
}
pub fn data(&self) -> &Vec<u8> {
@ -161,7 +151,6 @@ impl MessageModel {
}
}
// TODO delete!!
#[derive(Debug, Copy, Clone)]
pub struct SenderReceiverThread {
sender: DeviceId,
@ -189,8 +178,8 @@ impl SenderReceiverThread {
}
}
pub fn load_message_id_to_threads() -> HashMap<MessageId, SenderReceiverThread> {
let mut message_map: HashMap<MessageId, SenderReceiverThread> = HashMap::new();
pub fn load_package_ids() -> HashMap<PackageId, SenderReceiverThread> {
let mut package_map: HashMap<PackageId, SenderReceiverThread> = HashMap::new();
let properties = vec![
SenderReceiverThread::new(DeviceId::OBC, DeviceId::PCDU, ThreadId::PowerThread),
@ -222,7 +211,6 @@ pub fn load_message_id_to_threads() -> HashMap<MessageId, SenderReceiverThread>
SenderReceiverThread::new(DeviceId::OBC, DeviceId::SunSensor5, ThreadId::AOCSThread),
SenderReceiverThread::new(DeviceId::OBC, DeviceId::SunSensor6, ThreadId::AOCSThread),
SenderReceiverThread::new(DeviceId::OBC, DeviceId::StarTracker, ThreadId::AOCSThread),
SenderReceiverThread::new(DeviceId::OBC, DeviceId::GPS, ThreadId::AOCSThread),
SenderReceiverThread::new(DeviceId::MGM1, DeviceId::OBC, ThreadId::AOCSThread),
SenderReceiverThread::new(DeviceId::MGM2, DeviceId::OBC, ThreadId::AOCSThread),
SenderReceiverThread::new(DeviceId::MGM3, DeviceId::OBC, ThreadId::AOCSThread),
@ -234,12 +222,6 @@ pub fn load_message_id_to_threads() -> HashMap<MessageId, SenderReceiverThread>
SenderReceiverThread::new(DeviceId::SunSensor5, DeviceId::OBC, ThreadId::AOCSThread),
SenderReceiverThread::new(DeviceId::SunSensor6, DeviceId::OBC, ThreadId::AOCSThread),
SenderReceiverThread::new(DeviceId::StarTracker, DeviceId::OBC, ThreadId::AOCSThread),
SenderReceiverThread::new(DeviceId::StarTracker, DeviceId::OBC, ThreadId::AOCSThread),
SenderReceiverThread::new(DeviceId::StarTracker, DeviceId::OBC, ThreadId::AOCSThread),
SenderReceiverThread::new(DeviceId::StarTracker, DeviceId::OBC, ThreadId::AOCSThread),
SenderReceiverThread::new(DeviceId::GPS, DeviceId::OBC, ThreadId::AOCSThread),
SenderReceiverThread::new(DeviceId::GPS, DeviceId::OBC, ThreadId::AOCSThread),
SenderReceiverThread::new(DeviceId::GPS, DeviceId::OBC, ThreadId::AOCSThread),
SenderReceiverThread::new(DeviceId::OBC, DeviceId::Camera, ThreadId::PLDThread),
SenderReceiverThread::new(DeviceId::Camera, DeviceId::OBC, ThreadId::PLDThread),
SenderReceiverThread::new(DeviceId::Camera, DeviceId::OBC, ThreadId::PLDThread),
@ -247,107 +229,13 @@ pub fn load_message_id_to_threads() -> HashMap<MessageId, SenderReceiverThread>
];
let mut i = 0;
for id in MessageId::iter() {
for id in PackageId::iter() {
let value = properties.get(i).unwrap();
message_map.insert(id, *value);
package_map.insert(id, *value);
i += 1;
}
return message_map;
}
#[derive(Debug, Copy, Clone)]
pub struct SenderReceiverApid {
sender: DeviceId,
receiver: DeviceId,
apid: u16,
}
impl SenderReceiverApid {
pub fn new(sender: DeviceId, receiver: DeviceId, apid: u16) -> Self {
Self {
sender,
receiver,
apid,
}
}
pub fn get_sender(&self) -> DeviceId {
self.sender
}
pub fn get_receiver(&self) -> DeviceId {
self.receiver
}
pub fn get_apid(&self) -> u16 {
self.apid
}
}
pub fn load_message_id_to_apids() -> HashMap<MessageId, SenderReceiverApid> {
let mut message_map: HashMap<MessageId, SenderReceiverApid> = HashMap::new();
let properties = vec![
SenderReceiverApid::new(DeviceId::OBC, DeviceId::PCDU, PWR_APID),
SenderReceiverApid::new(DeviceId::OBC, DeviceId::PCDU, PWR_APID),
SenderReceiverApid::new(DeviceId::OBC, DeviceId::PCDU, PWR_APID),
SenderReceiverApid::new(DeviceId::OBC, DeviceId::PCDU, PWR_APID),
SenderReceiverApid::new(DeviceId::PCDU, DeviceId::OBC, PWR_APID),
SenderReceiverApid::new(DeviceId::PCDU, DeviceId::OBC, PWR_APID),
SenderReceiverApid::new(DeviceId::PCDU, DeviceId::OBC, PWR_APID),
SenderReceiverApid::new(DeviceId::PCDU, DeviceId::OBC, PWR_APID),
SenderReceiverApid::new(DeviceId::PCDU, DeviceId::OBC, PWR_APID),
SenderReceiverApid::new(DeviceId::PCDU, DeviceId::OBC, PWR_APID),
SenderReceiverApid::new(DeviceId::OBC, DeviceId::MGT1, MGT_APID),
SenderReceiverApid::new(DeviceId::OBC, DeviceId::MGT2, MGT_APID),
SenderReceiverApid::new(DeviceId::OBC, DeviceId::MGT3, MGT_APID),
SenderReceiverApid::new(DeviceId::OBC, DeviceId::MGT4, MGT_APID),
SenderReceiverApid::new(DeviceId::OBC, DeviceId::RWL1, RWL_APID),
SenderReceiverApid::new(DeviceId::OBC, DeviceId::RWL2, RWL_APID),
SenderReceiverApid::new(DeviceId::OBC, DeviceId::RWL3, RWL_APID),
SenderReceiverApid::new(DeviceId::OBC, DeviceId::RWL4, RWL_APID),
SenderReceiverApid::new(DeviceId::OBC, DeviceId::MGM1, MGM_APID),
SenderReceiverApid::new(DeviceId::OBC, DeviceId::MGM2, MGM_APID),
SenderReceiverApid::new(DeviceId::OBC, DeviceId::MGM3, MGM_APID),
SenderReceiverApid::new(DeviceId::OBC, DeviceId::MGM4, MGM_APID),
SenderReceiverApid::new(DeviceId::OBC, DeviceId::SunSensor1, CSS_APID),
SenderReceiverApid::new(DeviceId::OBC, DeviceId::SunSensor2, CSS_APID),
SenderReceiverApid::new(DeviceId::OBC, DeviceId::SunSensor3, CSS_APID),
SenderReceiverApid::new(DeviceId::OBC, DeviceId::SunSensor4, CSS_APID),
SenderReceiverApid::new(DeviceId::OBC, DeviceId::SunSensor5, CSS_APID),
SenderReceiverApid::new(DeviceId::OBC, DeviceId::SunSensor6, CSS_APID),
SenderReceiverApid::new(DeviceId::OBC, DeviceId::StarTracker, STR_APID),
SenderReceiverApid::new(DeviceId::OBC, DeviceId::GPS, GPS_APID),
SenderReceiverApid::new(DeviceId::MGM1, DeviceId::OBC, MGM_APID),
SenderReceiverApid::new(DeviceId::MGM2, DeviceId::OBC, MGM_APID),
SenderReceiverApid::new(DeviceId::MGM3, DeviceId::OBC, MGM_APID),
SenderReceiverApid::new(DeviceId::MGM4, DeviceId::OBC, MGM_APID),
SenderReceiverApid::new(DeviceId::SunSensor1, DeviceId::OBC, CSS_APID),
SenderReceiverApid::new(DeviceId::SunSensor2, DeviceId::OBC, CSS_APID),
SenderReceiverApid::new(DeviceId::SunSensor3, DeviceId::OBC, CSS_APID),
SenderReceiverApid::new(DeviceId::SunSensor4, DeviceId::OBC, CSS_APID),
SenderReceiverApid::new(DeviceId::SunSensor5, DeviceId::OBC, CSS_APID),
SenderReceiverApid::new(DeviceId::SunSensor6, DeviceId::OBC, CSS_APID),
SenderReceiverApid::new(DeviceId::StarTracker, DeviceId::OBC, STR_APID),
SenderReceiverApid::new(DeviceId::StarTracker, DeviceId::OBC, STR_APID),
SenderReceiverApid::new(DeviceId::StarTracker, DeviceId::OBC, STR_APID),
SenderReceiverApid::new(DeviceId::StarTracker, DeviceId::OBC, STR_APID),
SenderReceiverApid::new(DeviceId::GPS, DeviceId::OBC, GPS_APID),
SenderReceiverApid::new(DeviceId::GPS, DeviceId::OBC, GPS_APID),
SenderReceiverApid::new(DeviceId::GPS, DeviceId::OBC, GPS_APID),
SenderReceiverApid::new(DeviceId::OBC, DeviceId::Camera, PLD_APID),
SenderReceiverApid::new(DeviceId::Camera, DeviceId::OBC, PLD_APID),
SenderReceiverApid::new(DeviceId::Camera, DeviceId::OBC, PLD_APID),
SenderReceiverApid::new(DeviceId::Camera, DeviceId::OBC, PLD_APID),
];
let mut i = 0;
for id in MessageId::iter() {
let value = properties.get(i).unwrap();
message_map.insert(id, *value);
i += 1;
}
return message_map;
return package_map;
}
/*
@ -384,10 +272,10 @@ pub fn load_device_ids() {
*/
//TODO: change ids from u32 to embeddedcan ids
pub fn message_id_to_value(packageid: &MessageId) -> u32 {
pub fn package_id_to_value(packageid: &PackageId) -> u32 {
*packageid as u32
}
pub fn message_id_to_can_id(packageid: &MessageId) -> Id {
pub fn package_id_to_can_id(packageid: &PackageId) -> Id {
let x = *packageid as u16;
Id::Standard(StandardId::new(x).unwrap())
}
@ -396,12 +284,12 @@ pub fn device_id_to_value(deviceid: &DeviceId) -> u32 {
*deviceid as u32
}
pub fn value_to_message_id(value: u32) -> Option<MessageId> {
pub fn value_to_package_id(value: u32) -> Option<PackageId> {
let element = FromPrimitive::from_u32(value);
return element;
}
pub fn can_id_to_message_id(value: Id) -> Option<MessageId> {
pub fn can_id_to_package_id(value: Id) -> Option<PackageId> {
let buf = match value {
Id::Standard(id) => id.as_raw() as u32,
Id::Extended(id) => id.as_raw(),

View File

@ -1,8 +1,4 @@
use crate::tmtc::{
MpscStoreAndSendError, PusTcSource, AOCS_APID, AOCS_HK_APID, CSS_APID, MGM_APID, MGT_APID,
PLD_APID, PUS_APID, PWR_APID, RWL_APID, STR_APID,
};
use log::warn;
use crate::tmtc::{MpscStoreAndSendError, PusTcSource, PUS_APID};
use satrs_core::spacepackets::{CcsdsPacket, SpHeader};
use satrs_core::tmtc::{CcsdsPacketHandler, ReceivesCcsdsTc};
@ -14,18 +10,7 @@ impl CcsdsPacketHandler for CcsdsReceiver {
type Error = MpscStoreAndSendError;
fn valid_apids(&self) -> &'static [u16] {
&[
PUS_APID,
PLD_APID,
PWR_APID,
AOCS_APID,
AOCS_HK_APID,
MGM_APID,
CSS_APID,
STR_APID,
MGT_APID,
RWL_APID,
]
&[PUS_APID]
}
fn handle_known_apid(
@ -35,9 +20,8 @@ impl CcsdsPacketHandler for CcsdsReceiver {
) -> Result<(), Self::Error> {
if sp_header.apid() == PUS_APID {
return self.tc_source.pass_ccsds(sp_header, tc_raw);
} else {
return self.tc_source.pass_ccsds(sp_header, tc_raw);
}
Ok(())
}
fn handle_unknown_apid(
@ -45,7 +29,7 @@ impl CcsdsPacketHandler for CcsdsReceiver {
sp_header: &SpHeader,
_tc_raw: &[u8],
) -> Result<(), Self::Error> {
warn!("Unknown APID 0x{:x?} detected", sp_header.apid());
println!("Unknown APID 0x{:x?} detected", sp_header.apid());
Ok(())
}
}

View File

@ -1,158 +0,0 @@
use crate::requests::{Request, RequestWithToken};
use crate::tmtc::TmStore;
use eurosim_obsw::tmtc_err;
use satrs_core::mode::ModeAndSubmode;
use satrs_core::pool::StoreAddr;
use satrs_core::pus::mode::Subservice::TmModeReply;
use satrs_core::pus::verification::{
FailParams, TcStateStarted, VerificationReporterWithSender, VerificationToken,
};
use satrs_core::pus::MpscPusInStoreSendError;
use satrs_core::seq_count::{SeqCountProviderSyncClonable, SequenceCountProviderCore};
use satrs_core::spacepackets::time::cds::TimeProvider;
use satrs_core::spacepackets::time::TimeWriter;
use satrs_core::spacepackets::tm::{PusTm, PusTmSecondaryHeader};
use satrs_core::spacepackets::SpHeader;
use std::sync::mpsc::Sender;
use log::info;
#[derive(Clone)]
pub struct VerifHelper {
verif_reporter: VerificationReporterWithSender<MpscPusInStoreSendError>,
time_stamp_buf: [u8; 7],
}
impl VerifHelper {
pub fn new(verif_reporter: VerificationReporterWithSender<MpscPusInStoreSendError>) -> Self {
Self {
verif_reporter,
time_stamp_buf: [0; 7],
}
}
pub fn start_and_unwrap(
&mut self,
request_with_token: RequestWithToken,
) -> Result<(Request, Option<VerificationToken<TcStateStarted>>), ()> {
match request_with_token.1 {
None => Ok((request_with_token.0, None)),
Some(token) => {
self.update_time_stamp();
if let Ok(start_token) = self //implement this for verification
.verif_reporter
.start_success(token, Some(&self.time_stamp_buf))
{
return Ok((request_with_token.0, Some(start_token)));
} else {
return Err(());
}
}
}
}
pub fn start_failure(&mut self, request_with_token: RequestWithToken) -> Result<(), ()> {
if let Some(token) = request_with_token.1 {
self.update_time_stamp();
if let Ok(()) = self.verif_reporter.start_failure(
token,
FailParams::new(
Some(&mut self.time_stamp_buf),
&tmtc_err::INVALID_PUS_SUBSERVICE,
None,
),
) {
return Ok(());
} else {
return Err(());
}
}
Ok(())
}
pub fn completion(&mut self, start_token: VerificationToken<TcStateStarted>) -> Result<(), ()> {
self.update_time_stamp();
if let Ok(()) = self
.verif_reporter
.completion_success(start_token, Some(&self.time_stamp_buf))
{
return Ok(());
} else {
return Err(());
}
}
pub fn completion_failure(
&mut self,
start_token: VerificationToken<TcStateStarted>,
) -> Result<(), ()> {
self.update_time_stamp();
if let Ok(()) = self.verif_reporter.completion_failure(
start_token,
FailParams::new(
Some(&mut self.time_stamp_buf),
&tmtc_err::INVALID_PUS_SUBSERVICE,
None,
),
) {
return Ok(());
} else {
return Err(());
}
}
fn update_time_stamp(&mut self) {
let cds_stamp = TimeProvider::from_now_with_u16_days().unwrap();
cds_stamp.write_to_bytes(&mut self.time_stamp_buf).unwrap();
}
}
pub struct ModeHelper {
apid: u16,
seq_count_provider: SeqCountProviderSyncClonable,
tm_store: TmStore,
tm_funnel_tx: Sender<StoreAddr>,
buf: [u8; 6],
time_stamp_buf: [u8; 7],
}
impl ModeHelper {
pub fn new(
apid: u16,
seq_count_provider: SeqCountProviderSyncClonable,
tm_store: TmStore,
tm_funnel_tx: Sender<StoreAddr>,
) -> Self {
Self {
apid,
seq_count_provider,
tm_store,
tm_funnel_tx,
buf: [0; 6],
time_stamp_buf: [0; 7],
}
}
fn update_time_stamp(&mut self) {
let cds_stamp = TimeProvider::from_now_with_u16_days().unwrap();
cds_stamp.write_to_bytes(&mut self.time_stamp_buf).unwrap();
}
pub fn make_and_send_mode_reply(
&mut self,
mode_submode: ModeAndSubmode,
) -> Result<(), std::sync::mpsc::SendError<StoreAddr>> {
info!("mode reply generated from apid {}", self.apid);
self.update_time_stamp();
let mut sp_header =
SpHeader::tm_unseg(self.apid, self.seq_count_provider.get_and_increment(), 0).unwrap();
self.buf[0..4].copy_from_slice(&mode_submode.mode().to_be_bytes());
self.buf[4..6].copy_from_slice(&mode_submode.submode().to_be_bytes());
let len = 6;
let data = self.buf[0..len].to_vec();
let tm_sec_header =
PusTmSecondaryHeader::new_simple(200, TmModeReply as u8, &self.time_stamp_buf);
let tm = PusTm::new(&mut sp_header, tm_sec_header, Some(&self.buf[0..len]), true);
let addr = self.tm_store.add_pus_tm(&tm);
self.tm_funnel_tx.send(addr)
}
}

425
src/hk.rs
View File

@ -1,421 +1,16 @@
use std::collections::HashMap;
use crate::hk::AocsDataType::FloatValue;
use crate::requests::Request;
use crate::requests::RequestWithToken;
use crate::tmtc::{TmStore, AOCS_HK_APID};
use byteorder::{BigEndian, ByteOrder, LittleEndian};
use chrono::Duration;
use eurosim_obsw::hk_err;
use log::debug;
use satrs_core::hk::{HkRequest, UniqueId};
use satrs_core::pool::StoreAddr;
use satrs_core::pus::hk::Subservice;
use satrs_core::pus::verification::{FailParams, VerificationReporterWithSender};
use satrs_core::pus::MpscPusInStoreSendError;
use satrs_core::seq_count::{SeqCountProviderSyncClonable, SequenceCountProviderCore};
use satrs_core::spacepackets::time::cds::{TimeProvider};
use satrs_core::spacepackets::time::{CcsdsTimeProvider, TimeWriter};
use satrs_core::spacepackets::tm::{PusTm, PusTmSecondaryHeader};
use satrs_core::spacepackets::SpHeader;
use std::sync::mpsc::{Receiver, Sender};
use std::sync::{Arc, Mutex};
use strum_macros::EnumIter;
use satrs_core::tmtc::AddressableId;
pub type CollectionIntervalFactor = u32;
pub const MGM_FIELD_1: UniqueId = 1;
pub const MGM_FIELD_2: UniqueId = 2;
pub const MGM_FIELD_3: UniqueId = 3;
pub const CSS_SUN_VECTOR_1: UniqueId = 4;
pub const CSS_SUN_VECTOR_2: UniqueId = 5;
pub const CSS_SUN_VECTOR_3: UniqueId = 6;
pub const CSS_VOLTAGE_4: UniqueId = 7;
pub const CSS_VOLTAGE_5: UniqueId = 8;
pub const CSS_VOLTAGE_6: UniqueId = 9;
pub const STR_QUATERNION_1: UniqueId = 10;
pub const STR_QUATERNION_2: UniqueId = 11;
pub const STR_QUATERNION_3: UniqueId = 12;
pub const STR_QUATERNION_4: UniqueId = 13;
pub const GPS_LATITUDE: UniqueId = 14;
pub const GPS_LONGITUDE: UniqueId = 15;
pub const GPS_ALTITUDE: UniqueId = 16;
pub const AOCS_HK_NUM_OF_ELEMENTS: usize = 16 * 8;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum AcsHkIds {
TestMgmSet = 1,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum AocsHkIds {
TestAocsSet = 1,
TestMgmSet = 2,
}
#[derive(Clone, Debug)]
pub struct AocsDataMap {
map: HashMap<UniqueId, AocsDataType>,
}
impl AocsDataMap {
pub fn new() -> Self {
let mut data_map = HashMap::new();
data_map.insert(MGM_FIELD_1, FloatValue(0.0));
data_map.insert(MGM_FIELD_2, FloatValue(0.0));
data_map.insert(MGM_FIELD_3, FloatValue(0.0));
data_map.insert(CSS_SUN_VECTOR_1, FloatValue(0.0));
data_map.insert(CSS_SUN_VECTOR_2, FloatValue(0.0));
data_map.insert(CSS_SUN_VECTOR_3, FloatValue(0.0));
data_map.insert(CSS_VOLTAGE_4, FloatValue(0.0));
data_map.insert(CSS_VOLTAGE_5, FloatValue(0.0));
data_map.insert(CSS_VOLTAGE_6, FloatValue(0.0));
data_map.insert(STR_QUATERNION_1, FloatValue(0.0));
data_map.insert(STR_QUATERNION_2, FloatValue(0.0));
data_map.insert(STR_QUATERNION_3, FloatValue(0.0));
data_map.insert(STR_QUATERNION_4, FloatValue(0.0));
data_map.insert(GPS_LATITUDE, FloatValue(0.0));
data_map.insert(GPS_LONGITUDE, FloatValue(0.0));
data_map.insert(GPS_ALTITUDE, FloatValue(0.0));
Self { map: data_map }
}
pub fn update_value(&mut self, id: UniqueId, val: AocsDataType) -> Result<(), ()> {
if self.map.contains_key(&id) {
self.map.insert(id, val);
return Ok(());
}
Err(())
}
pub fn get_value(&self, id: UniqueId) -> Option<&AocsDataType> {
self.map.get(&id)
}
pub fn all_values_as_bytes(&self) -> [u8; AOCS_HK_NUM_OF_ELEMENTS] {
let mut buf: [u8; AOCS_HK_NUM_OF_ELEMENTS] = [0; AOCS_HK_NUM_OF_ELEMENTS];
let mut i = 0;
let map = self.map.clone();
let mut map_as_vec = map.keys().collect::<Vec<&UniqueId>>();
map_as_vec.sort();
for element in map_as_vec {
match map.get(element).unwrap() {
FloatValue(val) => {
let val_as_byte = BigEndian::write_f64(&mut (buf[i..i + 8]), *val);
}
}
i += 8;
}
debug!("{:?}", buf);
buf
}
}
#[derive(Debug, EnumIter, PartialEq, Copy, Clone)]
pub enum AocsDataType {
FloatValue(f64),
}
pub struct AocsHousekeeper {
data_map: Arc<Mutex<AocsDataMap>>,
id_list: Vec<UniqueId>,
request_rx: Receiver<RequestWithToken>,
seq_count_provider: SeqCountProviderSyncClonable,
aocs_tm_store: TmStore,
aocs_tm_funnel_tx: Sender<StoreAddr>,
verif_reporter: VerificationReporterWithSender<MpscPusInStoreSendError>,
periodic_hk_ids: Option<Vec<UniqueId>>,
periodic_on: bool,
prev_time_step: TimeProvider,
collection_interval: Duration,
}
impl AocsHousekeeper {
pub fn new(
sensor_data_pool: Arc<Mutex<AocsDataMap>>,
request_rx: Receiver<RequestWithToken>,
seq_count_provider: SeqCountProviderSyncClonable,
aocs_tm_store: TmStore,
aocs_tm_funnel_tx: Sender<StoreAddr>,
verif_reporter: VerificationReporterWithSender<MpscPusInStoreSendError>,
) -> AocsHousekeeper {
let id_list = vec![
MGM_FIELD_1,
MGM_FIELD_2,
MGM_FIELD_3,
CSS_SUN_VECTOR_1,
CSS_SUN_VECTOR_2,
CSS_SUN_VECTOR_3,
CSS_VOLTAGE_4,
CSS_VOLTAGE_5,
CSS_VOLTAGE_6,
STR_QUATERNION_1,
STR_QUATERNION_2,
STR_QUATERNION_3,
STR_QUATERNION_4,
GPS_LATITUDE,
GPS_LONGITUDE,
GPS_ALTITUDE,
];
AocsHousekeeper {
data_map: sensor_data_pool,
id_list,
request_rx,
seq_count_provider,
aocs_tm_store,
aocs_tm_funnel_tx,
verif_reporter,
periodic_hk_ids: None,
periodic_on: false,
prev_time_step: TimeProvider::from_now_with_u16_days().unwrap(),
collection_interval: Duration::seconds(0),
}
}
pub fn new_with_collection_interval(
sensor_data_pool: Arc<Mutex<AocsDataMap>>,
request_rx: Receiver<RequestWithToken>,
seq_count_provider: SeqCountProviderSyncClonable,
aocs_tm_store: TmStore,
aocs_tm_funnel_tx: Sender<StoreAddr>,
verif_reporter: VerificationReporterWithSender<MpscPusInStoreSendError>,
collection_interval: Duration,
) -> AocsHousekeeper {
let id_list = vec![
MGM_FIELD_1,
MGM_FIELD_2,
MGM_FIELD_3,
CSS_SUN_VECTOR_1,
CSS_SUN_VECTOR_2,
CSS_SUN_VECTOR_3,
CSS_VOLTAGE_4,
CSS_VOLTAGE_5,
CSS_VOLTAGE_6,
STR_QUATERNION_1,
STR_QUATERNION_2,
STR_QUATERNION_3,
STR_QUATERNION_4,
GPS_LATITUDE,
GPS_LONGITUDE,
GPS_ALTITUDE,
];
AocsHousekeeper {
data_map: sensor_data_pool,
id_list,
request_rx,
seq_count_provider,
aocs_tm_store,
aocs_tm_funnel_tx,
verif_reporter,
periodic_hk_ids: None,
periodic_on: false,
prev_time_step: TimeProvider::from_now_with_u16_days().unwrap(),
collection_interval,
}
}
pub fn periodic_op(&mut self) {
self.handle_hk_request();
self.periodic_hk();
}
// housekeeper has methods for both sending individual variables as tm as well as entire aocs data set
// individual values results in way too much traffic, therefore is not used
// the functions for it are kept here since the logic could be easily adapted to send different sets (something which is currently not implemented)
// for now, ..._individual functions are rather unnecessary
pub fn handle_hk_request(&mut self) {
let mut time_stamp_buf: [u8; 7] = [0; 7];
if let Ok(request_with_token) = self.request_rx.try_recv() {
if let Request::HkRequest(hk_req) = request_with_token.0 {
let cds_stamp = TimeProvider::from_now_with_u16_days().unwrap();
cds_stamp.write_to_bytes(&mut time_stamp_buf).unwrap();
let start_token = self //implement this for verification
.verif_reporter
.start_success(request_with_token.1.unwrap(), Some(&time_stamp_buf))
.expect("Error sending start success");
if let Ok(()) = match hk_req {
HkRequest::OneShot(id) => self.one_shot(),
HkRequest::Enable(id) => self.enable_periodic(),
HkRequest::Disable(id) => self.disable_periodic(),
HkRequest::ModifyCollectionInterval(_id, _collection_interval) => Ok(()),
} {
let cds_stamp = TimeProvider::from_now_with_u16_days().unwrap();
cds_stamp.write_to_bytes(&mut time_stamp_buf).unwrap();
self.verif_reporter
.completion_success(start_token, Some(&time_stamp_buf))
.expect("Error sending completion success");
} else {
let cds_stamp = TimeProvider::from_now_with_u16_days().unwrap();
cds_stamp.write_to_bytes(&mut time_stamp_buf).unwrap();
self.verif_reporter
.completion_failure(
start_token,
FailParams::new(
Some(&time_stamp_buf),
&hk_err::UNKNOWN_TARGET_ID,
None,
),
)
.expect("Error sending completion success");
}
}
}
}
pub fn check_period(&mut self) -> bool {
let current_time = TimeProvider::from_now_with_u16_days().unwrap();
let prev_time = self.prev_time_step.clone();
let delta = current_time.date_time().unwrap() - prev_time.date_time().unwrap();
delta > self.collection_interval
}
pub fn periodic_hk(&mut self) {
if self.periodic_on && self.check_period() {
self.prev_time_step = TimeProvider::from_now_with_u16_days().unwrap();
let map = self.data_map.lock().unwrap();
let mut data_as_bytes = map.all_values_as_bytes();
debug!("{:?}", &map);
drop(map);
self.send_hk_packet(1, &mut data_as_bytes);
}
}
pub fn periodic_hk_individual(&mut self) {
//let json_string = self.aocs_data_to_str();
let data = self.data_map.lock().unwrap();
let data_copy = data.clone();
drop(data);
let mut buf: [u8; 8] = [0; 8];
if let Some(ids) = &self.periodic_hk_ids {
for id in ids.clone() {
if let Some(FloatValue(field)) = data_copy.get_value(id) {
let data_str = LittleEndian::write_f64(&mut buf, *field);
let _ = &self.send_hk_packet(id, &buf);
}
}
}
}
pub fn one_shot(&mut self) -> Result<(), ()> {
let map = self.data_map.lock().unwrap();
let data_as_bytes = map.all_values_as_bytes();
drop(map);
// currently gives 1 as id, meaning one is the spid, if multiple spids in this housekeeper, this needs to change!
self.send_hk_packet(1, &data_as_bytes);
Ok(())
}
pub fn one_shot_hk_individual(&mut self, id: UniqueId) -> Result<(), ()> {
let data = self.data_map.lock().unwrap();
let data_copy = data.clone();
drop(data);
let mut buf: [u8; 8] = [0; 8];
if let Some(FloatValue(field)) = data_copy.get_value(id) {
let data_str = LittleEndian::write_f64(&mut buf, *field);
self.send_hk_packet(id, &buf);
return Ok(());
}
Err(())
}
pub fn enable_periodic(&mut self) -> Result<(), ()> {
self.periodic_on = true;
Ok(())
}
pub fn enable_periodic_individual(&mut self, id: UniqueId) -> Result<(), ()> {
if !self.id_list.contains(&id) {
return Err(());
}
let periodic_hk_ids = self.periodic_hk_ids.clone();
match periodic_hk_ids {
None => self.periodic_hk_ids = Some(vec![id]),
Some(mut ids) => {
ids.push(id);
self.periodic_hk_ids = Some(ids);
}
}
Ok(())
}
pub fn disable_periodic(&mut self) -> Result<(), ()> {
self.periodic_on = false;
Ok(())
}
pub fn disable_periodic_individual(&mut self, id: UniqueId) -> Result<(), ()> {
if !self.id_list.contains(&id) {
return Err(());
}
let periodic_hk_ids = self.periodic_hk_ids.clone();
match periodic_hk_ids {
None => return Err(()),
Some(mut ids) => {
if !ids.contains(&id) {
return Err(());
}
// .unwrap is allowed, since existence check is performed
let index = ids.iter().position(|x| *x == id).unwrap();
ids.remove(index);
if ids.len() < 1 {
self.periodic_hk_ids = None;
} else {
self.periodic_hk_ids = Some(ids);
}
}
}
Ok(())
}
/*
pub fn aocs_data_to_str(&mut self) -> String {
let pool = self.data_map.lock().unwrap();
serde_json::to_string(pool.deref()).unwrap()
}
*/
pub fn send_hk_packet_from_str(&mut self, id: UniqueId, data: &str) {
let mut time_stamp_buf: [u8; 7] = [0; 7];
let mut huge_buf: [u8; 8192] = [0; 8192];
let mut sp_header =
SpHeader::tm_unseg(0x02, self.seq_count_provider.get_and_increment(), 0).unwrap();
let cds_stamp = TimeProvider::from_now_with_u16_days().unwrap();
cds_stamp.write_to_bytes(&mut time_stamp_buf).unwrap();
huge_buf[0..4].copy_from_slice(&id.to_be_bytes());
let mut len = 4;
huge_buf[8..data.len() + 8].copy_from_slice(data.as_bytes());
len += data.len();
let tm_sec_header =
PusTmSecondaryHeader::new_simple(3, Subservice::TmHkPacket as u8, &time_stamp_buf);
let hk_tm = PusTm::new(&mut sp_header, tm_sec_header, Some(&huge_buf[0..len]), true);
let addr = self.aocs_tm_store.add_pus_tm(&hk_tm);
self.aocs_tm_funnel_tx.send(addr).expect("sending failed");
}
pub fn send_hk_packet(&mut self, id: UniqueId, data: &[u8]) {
let mut time_stamp_buf: [u8; 7] = [0; 7];
let mut huge_buf: [u8; 8192] = [0; 8192];
let mut sp_header =
SpHeader::tm_unseg(AOCS_HK_APID, self.seq_count_provider.get_and_increment(), 0)
.unwrap();
let cds_stamp = TimeProvider::from_now_with_u16_days().unwrap();
cds_stamp.write_to_bytes(&mut time_stamp_buf).unwrap();
huge_buf[0..4].copy_from_slice(&id.to_be_bytes());
let mut len = 8;
huge_buf[len..data.len() + 8].copy_from_slice(data);
len += data.len();
let data = huge_buf[0..len].to_vec();
let tm_sec_header =
PusTmSecondaryHeader::new_simple(3, Subservice::TmHkPacket as u8, &time_stamp_buf);
sp_header.data_len = len as u16;
let hk_tm = PusTm::new(&mut sp_header, tm_sec_header, Some(&huge_buf[0..len]), true);
let addr = self.aocs_tm_store.add_pus_tm(&hk_tm);
self.aocs_tm_funnel_tx.send(addr).expect("sending failed");
}
pub enum HkRequest {
OneShot(AddressableId),
Enable(AddressableId),
Disable(AddressableId),
ModifyCollectionInterval(AddressableId, CollectionIntervalFactor),
}

View File

@ -1,20 +1,8 @@
use num_enum::{IntoPrimitive, TryFromPrimitive};
use satrs_core::events::{EventU32TypedSev, SeverityInfo};
use std::net::Ipv4Addr;
use satrs_mib::res_code::{ResultU16, ResultU16Info};
use satrs_mib::resultcode;
#[derive(Copy, Clone, PartialEq, Eq, Debug, TryFromPrimitive, IntoPrimitive)]
#[repr(u8)]
pub enum CustomPusServiceId {
Mode = 200,
Health = 201,
}
pub const TEST_EVENT: EventU32TypedSev<SeverityInfo> =
EventU32TypedSev::<SeverityInfo>::const_new(0, 0);
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum RequestTargetId {
AcsSubsystem = 1,
@ -37,14 +25,8 @@ pub mod tmtc_err {
pub const INVALID_PUS_SERVICE: ResultU16 = ResultU16::const_new(GroupId::Tmtc as u8, 0);
#[resultcode]
pub const INVALID_PUS_SUBSERVICE: ResultU16 = ResultU16::const_new(GroupId::Tmtc as u8, 1);
#[resultcode]
pub const PUS_SERVICE_NOT_IMPLEMENTED: ResultU16 = ResultU16::const_new(GroupId::Tmtc as u8, 2);
#[resultcode(
info = "Not enough data inside the TC application data field. Optionally includes: \
8 bytes of failure data containing 2 failure parameters, \
P1 (u32 big endian): Expected data length, P2: Found data length"
)]
#[resultcode(info = "Not enough data inside the TC application data field")]
pub const NOT_ENOUGH_APP_DATA: ResultU16 = ResultU16::const_new(GroupId::Tmtc as u8, 2);
pub const TMTC_RESULTS: &[ResultU16Info] = &[

View File

@ -1,64 +1,90 @@
#![allow(dead_code)]
#![allow(unused_variables)]
// remove this, just here for now since application isn't fully developed
mod action;
mod aocs;
mod cam;
#[cfg(feature = "can")]
mod can;
mod can_ids;
mod ccsds;
mod helpers;
mod pld_handler;
mod hk;
mod logger;
mod messages;
mod pld_handler;
mod power_handler;
mod pus;
mod requests;
mod tmtc;
mod pcdu;
use crate::requests::RequestWithToken;
use crate::tmtc::{core_tmtc_task, OtherArgs, PusTcSource, TcArgs, TcStore, TmArgs, TmFunnel, TmStore, AOCS_APID, AOCS_HK_APID, CSS_APID, MGM_APID, MGT_APID, PLD_APID, PUS_APID, PWR_APID, RWL_APID, STR_APID, GPS_APID};
use crate::requests::{Request, RequestWithToken};
use crate::tmtc::{
core_tmtc_task, OtherArgs, PusTcSource, TcArgs, TcStore, TmArgs, TmFunnel, TmStore, PUS_APID,
};
use eurosim_obsw::{RequestTargetId, OBSW_SERVER_ADDR, SERVER_PORT};
use satrs_core::event_man::{
EventManagerWithMpscQueue, MpscEventReceiver, MpscEventU32SendProvider, SendEventProvider,
};
use satrs_core::events::EventU32;
use satrs_core::pool::{LocalPool, PoolCfg};
use satrs_core::pool::{LocalPool, PoolCfg, StoreAddr};
use satrs_core::pus::event_man::{
DefaultPusMgmtBackendProvider, EventReporter, EventRequestWithToken, PusEventDispatcher,
DefaultPusMgmtBackendProvider, EventReporter, EventRequestWithToken,
PusEventDispatcher,
};
use satrs_core::pus::verification::{
MpscVerifSender, VerificationReporterCfg, VerificationReporterWithSender,
};
use satrs_core::seq_count::SeqCountProviderSyncClonable;
use satrs_core::pus::{EcssTmErrorWithSend, EcssTmSenderCore};
use satrs_core::seq_count::{
SeqCountProviderSyncClonable,
};
use satrs_core::{
spacepackets::time::cds::TimeProvider,
spacepackets::time::TimeWriter,
spacepackets::tm::{PusTm},
};
use strum::IntoEnumIterator;
use crate::can_ids::{
load_message_id_to_apids, load_message_id_to_threads, DeviceId, MessageModel,
};
use chrono::Duration;
use log::info;
use satrs_core::power::{SwitchId, SwitchState};
use crate::can_ids::{can_id_to_package_id, DeviceId, load_package_ids, PackageId, PackageModel, ThreadId};
use embedded_can::{Id, StandardId};
use log::{info, warn};
use std::collections::HashMap;
use std::net::{IpAddr, SocketAddr};
use std::sync::mpsc::channel;
use std::sync::{mpsc, Arc, Mutex, RwLock};
use std::sync::mpsc::{channel};
use std::sync::{mpsc, Arc, RwLock, Mutex};
use std::thread;
use satrs_core::power::{SwitchId, SwitchState};
//use libc::time64_t;
use crate::aocs::{AocsController, MGMHandler, STRHandler, GPSHandler, CSSHandler};
#[cfg(feature = "can")]
use crate::can::CanTxHandler;
use crate::helpers::{ModeHelper, VerifHelper};
use crate::hk::{AocsDataMap, AocsHousekeeper};
use crate::pld_handler::core_pld_task;
use crate::power_handler::{core_power_task, DeviceState, PowerSwitcher};
use crate::action::ActionRequest;
use crate::cam::CameraRequest;
use crate::pld_handler::{CameraHandler, core_pld_task};
use crate::pcdu::{core_power_task, PowerSwitcher};
#[derive(Clone)]
struct EventTmSender {
store_helper: TmStore,
sender: mpsc::Sender<StoreAddr>,
}
impl EventTmSender {
fn new(store_helper: TmStore, sender: mpsc::Sender<StoreAddr>) -> Self {
Self {
store_helper,
sender,
}
}
}
impl EcssTmSenderCore for EventTmSender {
type Error = mpsc::SendError<StoreAddr>;
fn send_tm(&mut self, tm: PusTm) -> Result<(), EcssTmErrorWithSend<Self::Error>> {
let addr = self.store_helper.add_pus_tm(&tm);
self.sender
.send(addr)
.map_err(EcssTmErrorWithSend::SendError)
}
}
fn main() {
println!("Running SESPSat OBSW");
logger::setup_logger().unwrap();
info!("Running DemoSat OBSW!");
let tm_pool = LocalPool::new(PoolCfg::new(vec![
(30, 32),
@ -84,25 +110,17 @@ fn main() {
};
let seq_count_provider = SeqCountProviderSyncClonable::default();
let msg_count_provider = SeqCountProviderSyncClonable::default();
let aocs_hk_seq_count_provider = SeqCountProviderSyncClonable::default();
let aocs_ctrl_seq_count_provider = SeqCountProviderSyncClonable::default();
let mgm_seq_count_provider = SeqCountProviderSyncClonable::default();
let css_seq_count_provider = SeqCountProviderSyncClonable::default();
let str_seq_count_provider = SeqCountProviderSyncClonable::default();
let gps_seq_count_provider = SeqCountProviderSyncClonable::default();
let verif_seq_count_provider = seq_count_provider.clone();
let tmtc_seq_count_provider = seq_count_provider.clone();
let aocs_seq_count_provider = seq_count_provider.clone();
let sock_addr = SocketAddr::new(IpAddr::V4(OBSW_SERVER_ADDR), SERVER_PORT);
let (tc_source_tx, tc_source_rx) = channel();
let (tm_funnel_tx, tm_funnel_rx) = channel();
let (tm_server_tx, tm_server_rx) = channel();
let verif_sender = MpscVerifSender::new(1, "name", tm_store.pool.clone(), tm_funnel_tx.clone());
let verif_sender = MpscVerifSender::new(tm_store.pool.clone(), tm_funnel_tx.clone());
let verif_cfg = VerificationReporterCfg::new(
PUS_APID,
Box::new(verif_seq_count_provider.clone()),
Box::new(msg_count_provider),
#[allow(clippy::box_default)]
Box::new(seq_count_provider.clone()),
1,
2,
8,
@ -118,28 +136,20 @@ fn main() {
let mut event_man = EventManagerWithMpscQueue::new(Box::new(event_recv));
let event_reporter = EventReporter::new(PUS_APID, 128).unwrap();
let pus_tm_backend = DefaultPusMgmtBackendProvider::<EventU32>::default();
let pus_event_dispatcher = PusEventDispatcher::new(event_reporter, Box::new(pus_tm_backend));
let mut pus_event_dispatcher =
PusEventDispatcher::new(event_reporter, Box::new(pus_tm_backend));
let (pus_event_man_tx, pus_event_man_rx) = channel();
let pus_event_man_send_provider = MpscEventU32SendProvider::new(1, pus_event_man_tx);
let reporter_event_handler = verif_reporter.clone();
let reporter_aocs = verif_reporter.clone();
let mut reporter_event_handler = verif_reporter.clone();
let mut reporter_aocs = verif_reporter.clone();
let mut reporter_pld = verif_reporter.clone();
event_man.subscribe_all(pus_event_man_send_provider.id());
// possibly deprecated, as the apid should replace the target id
let mut request_map = HashMap::new();
let (aocs_thread_tx, aocs_thread_rx) = channel::<RequestWithToken>();
let (acs_thread_tx, acs_thread_rx) = channel::<RequestWithToken>();
let (pld_thread_tx, pld_thread_rx) = channel::<RequestWithToken>();
let (pwr_thread_tx, pwr_thread_rx) = channel::<RequestWithToken>();
let (aocs_hk_tx, aocs_hk_rx) = channel::<RequestWithToken>();
let (mgm_tx, mgm_rx) = channel::<RequestWithToken>();
let (css_tx, css_rx) = channel::<RequestWithToken>();
let (str_tx, str_rx) = channel::<RequestWithToken>();
let (gps_tx, gps_rx) = channel::<RequestWithToken>();
let (mgt_tx, mgt_rx) = channel::<RequestWithToken>();
let (rwl_tx, rwl_rx) = channel::<RequestWithToken>();
request_map.insert(RequestTargetId::AcsSubsystem as u32, aocs_thread_tx.clone());
request_map.insert(RequestTargetId::PldSubsystem as u32, pld_thread_tx.clone());
request_map.insert(RequestTargetId::AcsSubsystem as u32, acs_thread_tx);
request_map.insert(RequestTargetId::PldSubsystem as u32, pld_thread_tx);
//add here receivers for tmtc task to send requests to
//request_map.insert(RequestTargetId::CanTask as u32, can_thread_tx);
@ -148,27 +158,13 @@ fn main() {
tc_source: tc_source_tx,
};
let mut apid_map = HashMap::new();
apid_map.insert(PLD_APID, pld_thread_tx.clone());
apid_map.insert(PWR_APID, pwr_thread_tx.clone());
apid_map.insert(AOCS_APID, aocs_thread_tx.clone());
apid_map.insert(AOCS_HK_APID, aocs_hk_tx.clone());
apid_map.insert(MGM_APID, mgm_tx.clone());
apid_map.insert(CSS_APID, css_tx.clone());
apid_map.insert(STR_APID, str_tx.clone());
apid_map.insert(GPS_APID, gps_tx.clone());
apid_map.insert(MGT_APID, mgt_tx.clone());
apid_map.insert(RWL_APID, rwl_tx.clone());
// Create clones here to allow moving the values
let core_args = OtherArgs {
sock_addr,
verif_reporter: verif_reporter.clone(),
verif_reporter,
event_sender,
event_request_tx,
request_map,
apid_map,
seq_count_provider: verif_seq_count_provider,
};
let tc_args = TcArgs {
tc_source,
@ -180,28 +176,20 @@ fn main() {
tm_server_rx,
};
let (mgm_can_tx, mgm_can_rx) = mpsc::channel::<MessageModel>();
let (mgt_can_tx, mgt_can_rx) = mpsc::channel::<MessageModel>();
let (css_can_tx, css_can_rx) = mpsc::channel::<MessageModel>();
let (rwl_can_tx, rwl_can_rx) = mpsc::channel::<MessageModel>();
let (str_can_tx, str_can_rx) = mpsc::channel::<MessageModel>();
let (gps_can_tx, gps_can_rx) = mpsc::channel::<MessageModel>();
let (power_can_tx, power_can_rx) = mpsc::channel::<MessageModel>();
let (pld_can_tx, pld_can_rx) = mpsc::channel::<MessageModel>();
let (aocs_can_tx, aocs_can_rx) = mpsc::channel::<PackageModel>();
let (power_can_tx, power_can_rx) = mpsc::channel::<PackageModel>();
let (pld_can_tx, pld_can_rx) = mpsc::channel::<PackageModel>();
// make tx thread id hashmap
let mut can_senders = HashMap::new();
can_senders.insert(PWR_APID, power_can_tx);
can_senders.insert(PLD_APID, pld_can_tx);
can_senders.insert(MGM_APID, mgm_can_tx);
can_senders.insert(MGT_APID, mgt_can_tx);
can_senders.insert(RWL_APID, rwl_can_tx);
can_senders.insert(CSS_APID, css_can_tx);
can_senders.insert(STR_APID, str_can_tx);
can_senders.insert(GPS_APID, gps_can_tx);
can_senders.insert(ThreadId::AOCSThread, aocs_can_tx);
can_senders.insert(ThreadId::PowerThread, power_can_tx);
can_senders.insert(ThreadId::PLDThread, pld_can_tx);
// get package id hashmap
let message_ids_rx = load_message_id_to_apids();
let package_ids_rx = load_package_ids();
let socket0 = can::CanRxHandler::new_socket("can0", can_senders, package_ids_rx).unwrap();
info!("Starting TMTC task");
let builder0 = thread::Builder::new().name("TMTCThread".into());
@ -209,34 +197,19 @@ fn main() {
core_tmtc_task(core_args, tc_args, tm_args);
});
let (can_tx_sender, can_tx_receiver) = channel();
#[cfg(feature = "can")]
let mut can_rx_socket =
can::CanRxHandler::new_socket("can0", can_senders.clone(), message_ids_rx.clone()).unwrap();
#[cfg(feature = "can")]
info!("Starting CAN Socket listening task");
let builder1 = thread::Builder::new().name("CanRxHandler".into());
let jh1 = builder1.spawn(move || loop {
#[cfg(feature = "can")]
can_rx_socket.process_incoming();
});
#[cfg(feature = "can")]
let mut can_tx_socket =
CanTxHandler::new_socket("can0", message_ids_rx.clone(), can_tx_receiver).unwrap();
#[cfg(feature = "can")]
info!("Starting CAN Socket writing task");
let builder_can_tx = thread::Builder::new().name("TxHandler".into());
let jh_can_tx = builder_can_tx.spawn(move || loop {
#[cfg(feature = "can")]
can_tx_socket.process_incoming();
let frame = socket0.rx_socket();
if let Some(frame) = frame {
let forward = socket0.forward_frame(frame);
}
});
let (pcdu_tx, pcdu_rx) = mpsc::channel::<(SwitchId, SwitchState)>();
let pcdu_can_tx_sender = can_tx_sender.clone();
let pcdu_can_tx =
can::CanTxHandler::new_socket("can0", ThreadId::PowerThread, load_package_ids()).unwrap();
let mut device_state_map = HashMap::new();
for id in DeviceId::iter() {
@ -244,41 +217,126 @@ fn main() {
}
let clonable_device_state_map = Arc::new(Mutex::new(device_state_map));
let power_switcher = PowerSwitcher::new(pcdu_tx, clonable_device_state_map.clone());
let mut power_switcher = PowerSwitcher::new(pcdu_tx, clonable_device_state_map.clone());
info!("Starting Power Handling task");
info!("Starting power task");
let builder2 = thread::Builder::new().name("PowerThread".into());
let jh2 = builder2.spawn(move || {
core_power_task(
pcdu_rx,
pcdu_can_tx_sender,
power_can_rx,
clonable_device_state_map.clone(),
);
core_power_task(pcdu_rx, pcdu_can_tx, power_can_rx, clonable_device_state_map.clone());
});
let package_map_pld_tx = load_message_id_to_threads();
let package_map_aocs_tx = load_package_ids();
let aocs_tm_funnel_tx = tm_funnel_tx.clone();
let mut aocs_tm_store = tm_store.clone();
/*
// AOCS Thread
let socket1 =
can::CanTxHandler::new_socket("can0", ThreadId::AOCSThread, package_map_aocs_tx).unwrap();
info!("Starting AOCS receiving thread");
let builder2 = thread::Builder::new().name("AOCSThread".into());
let jh2 = builder2.spawn(move || {
let mut time_stamp_buf: [u8; 7] = [0; 7];
let mut huge_buf: [u8; 8192] = [0; 8192];
let data: [u8; 3] = [1, 2, 3];
let current_mgm_data = MgmData::default();
//let current_mgt_data = MgtData::default();
//let current_
loop {
// device handling
//info!("Sending {:?}", PackageId::AOCSControlMGT1);
//socket1.tx_socket(PackageId::AOCSControlMGT1, &data);
//info!("Waiting for {:?}", PackageId::AOCSDataMGM1);
let msg = aocs_can_rx.try_recv();
//current_mgm_data.x = new_data
match aocs_can_rx.try_recv() {
Ok(package) => match package.package_id() {
_ => warn!("Incorrect Id"),
},
Err(_) => {}
}
// telecommand handling
match acs_thread_rx.try_recv() {
Ok(request_with_token) => {
match request_with_token.0 {
Request::HkRequest(hk_req) => {
match hk_req {
HkRequest::OneShot(id) => {
assert_eq!(id.target_id, RequestTargetId::AcsSubsystem as u32);
if id.unique_id == 0 {
let mut sp_header = SpHeader::tm_unseg(
0x02,
aocs_seq_count_provider.get_and_increment(),
0,
)
.unwrap();
let cds_stamp =
TimeProvider::from_now_with_u16_days().unwrap();
cds_stamp.write_to_bytes(&mut time_stamp_buf);
let mut len = id.write_to_be_bytes(&mut huge_buf).unwrap();
let json_string = "asdf";
huge_buf[8..json_string.len() + 8]
.copy_from_slice(json_string.as_bytes());
len += json_string.len();
let tm_sec_header = PusTmSecondaryHeader::new_simple(
3,
Subservice::TmHkPacket as u8,
&time_stamp_buf,
);
let hk_tm = PusTm::new(
&mut sp_header,
tm_sec_header,
Some(&huge_buf[0..len]),
true,
);
let addr = aocs_tm_store.add_pus_tm(&hk_tm);
aocs_tm_funnel_tx.send(addr).expect("sending failed");
/* let start_token = self //implement this for verification
.verif_reporter
.start_success(token, &self.time_stamp)
.expect("Error sending start success");
self.tm_tx
.send(addr)
.expect("Sending TM to TM funnel failed");
self.verif_reporter
.completion_success(start_token, &self.time_stamp)
.expect("Error sending completion success");
*/
}
}
HkRequest::Enable(_) => {}
HkRequest::Disable(_) => {}
HkRequest::ModifyCollectionInterval(_, _) => {}
}
}
_ => {}
}
}
Err(_) => {}
}
}
});
*/
let package_map_pld_tx = load_package_ids();
let pld_tm_funnel_tx = tm_funnel_tx.clone();
let pld_tm_store = tm_store.clone();
let mut pld_tm_store = tm_store.clone();
let pld_can_tx_sender = can_tx_sender.clone();
let power_switcher_pld = power_switcher.clone();
let PLDCanSocket =
can::CanTxHandler::new_socket("can0", ThreadId::PLDThread, package_map_pld_tx).unwrap();
//let mut pcdu_tx_clone = pcdu_tx.clone();
info!("Starting Payload Handling task");
println!("Starting Payload Handling task");
let builder3 = thread::Builder::new().name("PLDThread".into());
let jh3 = builder3.spawn(move || {
core_pld_task(
power_switcher_pld.clone(),
pld_thread_rx,
pld_can_rx,
pld_can_tx_sender,
&mut reporter_pld,
);
core_pld_task(power_switcher.clone(), pld_thread_rx, pld_can_rx, &mut reporter_pld);
});
info!("Starting TM funnel task");
println!("Starting TM funnel task");
let builder4 = thread::Builder::new().name("TMFunnelThread".into());
let jh4 = builder4.spawn(move || {
let tm_funnel = TmFunnel {
@ -295,189 +353,15 @@ fn main() {
}
});
let package_map_aocs_tx = load_message_id_to_threads();
let aocs_tm_funnel_tx = tm_funnel_tx.clone();
let aocs_tm_store = tm_store.clone();
let aocs_data_not_threadsafe = AocsDataMap::new();
/*
aocs_data_not_threadsafe
.update_value(1, AocsDataType::float_value(1.0))
.unwrap();
aocs_data_not_threadsafe
.update_value(2, AocsDataType::float_value(2.0))
.unwrap();
aocs_data_not_threadsafe
.update_value(3, AocsDataType::float_value(3.0))
.unwrap();
aocs_data_not_threadsafe
.update_value(4, AocsDataType::float_value(4.0))
.unwrap();
aocs_data_not_threadsafe
.update_value(5, AocsDataType::float_value(5.0))
.unwrap();
aocs_data_not_threadsafe
.update_value(6, AocsDataType::float_value(6.0))
.unwrap();
aocs_data_not_threadsafe
.update_value(7, AocsDataType::float_value(7.0))
.unwrap();
aocs_data_not_threadsafe
.update_value(8, AocsDataType::float_value(8.0))
.unwrap();
aocs_data_not_threadsafe
.update_value(9, AocsDataType::float_value(9.0))
.unwrap();
aocs_data_not_threadsafe
.update_value(10, AocsDataType::float_value(10.0))
.unwrap();
aocs_data_not_threadsafe
.update_value(11, AocsDataType::float_value(11.0))
.unwrap();
aocs_data_not_threadsafe
.update_value(12, AocsDataType::float_value(12.0))
.unwrap();
aocs_data_not_threadsafe
.update_value(13, AocsDataType::float_value(13.0))
.unwrap();
*/
let aocs_data = Arc::new(Mutex::new(aocs_data_not_threadsafe));
info!("Starting AOCS task");
let builder5 = thread::Builder::new().name("AOCSThread".into());
let jh5 = builder5.spawn(move || {
let mut aocs_housekeeper = AocsHousekeeper::new_with_collection_interval(
aocs_data.clone(),
aocs_hk_rx,
aocs_hk_seq_count_provider,
aocs_tm_store.clone(),
aocs_tm_funnel_tx.clone(),
reporter_aocs.clone(),
Duration::seconds(1),
);
let aocs_verif_helper = VerifHelper::new(verif_reporter.clone());
let aocs_controller_mode_helper = ModeHelper::new(
AOCS_APID,
aocs_ctrl_seq_count_provider.clone(),
aocs_tm_store.clone(),
aocs_tm_funnel_tx.clone(),
);
let mut aocs_controller = AocsController::new(
aocs_thread_rx,
mgm_tx.clone(),
css_tx.clone(),
str_tx.clone(),
gps_tx.clone(),
aocs_ctrl_seq_count_provider.clone(),
aocs_verif_helper.clone(),
aocs_controller_mode_helper,
);
let mgm_mode_helper = ModeHelper::new(
MGM_APID,
mgm_seq_count_provider,
aocs_tm_store.clone(),
aocs_tm_funnel_tx.clone(),
);
let mut mgm_handler = MGMHandler::new(
power_switcher.clone(),
DeviceId::MGM1,
DeviceState::Off,
aocs_data.clone(),
can_tx_sender.clone(),
mgm_can_rx,
mgm_rx,
aocs_verif_helper.clone(),
mgm_mode_helper,
);
let str_mode_helper = ModeHelper::new(
STR_APID,
str_seq_count_provider,
aocs_tm_store.clone(),
aocs_tm_funnel_tx.clone(),
);
let mut str_handler = STRHandler::new(
power_switcher.clone(),
DeviceId::StarTracker,
DeviceState::Off,
aocs_data.clone(),
can_tx_sender.clone(),
str_can_rx,
str_rx,
aocs_verif_helper.clone(),
str_mode_helper,
);
let css_mode_helper = ModeHelper::new(
CSS_APID,
css_seq_count_provider,
aocs_tm_store.clone(),
aocs_tm_funnel_tx.clone(),
);
let mut css_handler = CSSHandler::new(
power_switcher.clone(),
DeviceId::SunSensor1,
DeviceState::Off,
aocs_data.clone(),
can_tx_sender.clone(),
css_can_rx,
css_rx,
aocs_verif_helper.clone(),
css_mode_helper,
);
let gps_mode_helper = ModeHelper::new(
GPS_APID,
gps_seq_count_provider,
aocs_tm_store.clone(),
aocs_tm_funnel_tx.clone(),
);
let mut gps_handler = GPSHandler::new(
power_switcher.clone(),
DeviceId::GPS,
DeviceState::Off,
aocs_data.clone(),
can_tx_sender.clone(),
gps_can_rx,
gps_rx,
aocs_verif_helper.clone(),
gps_mode_helper,
);
loop {
aocs_housekeeper.periodic_op();
aocs_controller.periodic_op();
mgm_handler.periodic_op();
str_handler.periodic_op();
css_handler.periodic_op();
gps_handler.periodic_op();
}
});
jh0.unwrap()
.join()
.expect("Joining UDP TMTC server thread failed");
jh1.unwrap()
.join()
.expect("Joining CAN Bus Listening thread failed");
jh_can_tx
.unwrap()
.join()
.expect("Joining CAN Bus Writing thread failed");
jh2.unwrap().join().expect("Joining power thread failed");
jh3.unwrap().join().expect("Joining PLD thread failed");
jh4.unwrap()
.join()
.expect("Joining TM funnel thread failed");
jh5.unwrap().join().expect("Joining AOCS thread failed");
jh4.unwrap().join().expect("Joining TM funnel thread failed");
}
#[derive(Default)]
struct MgmData {

View File

@ -1,13 +0,0 @@
use crate::requests::RequestWithToken;
use std::sync::mpsc::Sender;
pub struct InternalMessage {
response_sender: Option<Sender<ResponseDataTypes>>,
message_data: MessageDataTypes,
}
pub enum MessageDataTypes {
RequestWithToken(RequestWithToken),
}
pub enum ResponseDataTypes {}

View File

@ -1,10 +1,13 @@
use crate::can_ids::{DeviceId, MessageId, MessageModel};
use satrs_core::power::{PowerSwitchInfo, PowerSwitcherCommandSender, SwitchId, SwitchState};
use std::collections::HashMap;
use std::convert::TryFrom;
use std::sync::mpsc::{Receiver, Sender};
use satrs_core::power::{PowerSwitcherCommandSender, PowerSwitchInfo, PowerSwitchProvider, SwitchId, SwitchState};
use crate::can::{CanTxHandler};
use crate::can_ids::{DeviceId, PackageId, PackageModel};
use std::convert::TryFrom;
use std::sync::{Arc, Mutex};
use std::time::Duration;
use std::vec;
use log::info;
pub use strum::IntoEnumIterator; // 0.17.1
pub use strum_macros::EnumIter; // 0.17.1
@ -23,22 +26,16 @@ pub struct PowerSwitcher {
device_state_map: Arc<Mutex<HashMap<DeviceId, SwitchState>>>,
}
pub struct PCDUHandler {
pub struct PCDU {
switch_rx: Receiver<(SwitchId, SwitchState)>,
can_tx: Sender<MessageModel>,
can_rx: Receiver<MessageModel>,
can_tx: CanTxHandler,
can_rx: Receiver<PackageModel>,
device_state_map: Arc<Mutex<HashMap<DeviceId, SwitchState>>>,
}
impl PowerSwitcher {
pub fn new(
switch_tx: Sender<(SwitchId, SwitchState)>,
device_state_map: Arc<Mutex<HashMap<DeviceId, SwitchState>>>,
) -> PowerSwitcher {
PowerSwitcher {
switch_tx,
device_state_map,
}
pub fn new(switch_tx: Sender<(SwitchId, SwitchState)>, device_state_map: Arc<Mutex<HashMap<DeviceId, SwitchState>>>) -> PowerSwitcher {
PowerSwitcher{switch_tx, device_state_map}
}
}
@ -47,16 +44,16 @@ impl PowerSwitcherCommandSender for PowerSwitcher {
fn send_switch_on_cmd(&mut self, switch_id: SwitchId) -> Result<(), Self::Error> {
return match self.switch_tx.send((switch_id, SwitchState::On)) {
Ok(_) => Ok(()),
Err(_) => Err(()),
};
Ok(_) => {Ok(())}
Err(_) => {Err(())}
}
}
fn send_switch_off_cmd(&mut self, switch_id: SwitchId) -> Result<(), Self::Error> {
return match self.switch_tx.send((switch_id, SwitchState::Off)) {
Ok(_) => Ok(()),
Err(_) => Err(()),
};
Ok(_) => {Ok(())}
Err(_) => {Err(())}
}
}
}
@ -70,10 +67,11 @@ impl PowerSwitchInfo for PowerSwitcher {
Ok(*state)
} else {
Err(())
};
}
} else {
Err(())
}
}
fn switch_delay_ms(&self) -> u32 {
@ -81,91 +79,86 @@ impl PowerSwitchInfo for PowerSwitcher {
}
}
impl PCDUHandler {
pub fn new(
switch_rx: Receiver<(SwitchId, SwitchState)>,
can_tx: Sender<MessageModel>,
can_rx: Receiver<MessageModel>,
device_state_map: Arc<Mutex<HashMap<DeviceId, SwitchState>>>,
) -> PCDUHandler {
PCDUHandler {
switch_rx,
can_tx,
can_rx,
device_state_map,
}
impl PowerSwitchProvider for PowerSwitcher {
type Error = ();
}
impl PCDU {
pub fn new(switch_rx: Receiver<(SwitchId, SwitchState)>, can_tx: CanTxHandler, can_rx: Receiver<PackageModel>, device_state_map: Arc<Mutex<HashMap<DeviceId, SwitchState>>>) -> PCDU{
PCDU{switch_rx, can_tx, can_rx, device_state_map}
}
pub fn send_power_on(&mut self, switch_id: SwitchId) -> Result<(), ()> {
return if let Ok(dev_id) = DeviceId::try_from(switch_id) {
let dev_id_bytes = dev_id as u8;
let buf: &[u8] = &dev_id_bytes.to_be_bytes();
self.can_tx
.send(MessageModel::new(MessageId::DevicePowerOnRequest, buf).unwrap())
.unwrap();
self.can_tx.tx_socket(PackageId::DevicePowerOnRequest, buf);
let mut map_lock = self.device_state_map.lock().unwrap();
*map_lock.get_mut(&dev_id).unwrap() = SwitchState::Unknown;
// TODO: potentially change bus logic -> remove acceptance and verification of power off/on, since status is simply called in next step anyway
self.can_rx.recv();
self.can_rx.recv();
Ok(())
} else {
Err(())
};
}
}
pub fn send_power_off(&mut self, switch_id: SwitchId) -> Result<(), ()> {
return if let Ok(dev_id) = DeviceId::try_from(switch_id) {
let dev_id_bytes = dev_id as u8;
let buf: &[u8] = &dev_id_bytes.to_be_bytes();
self.can_tx
.send(MessageModel::new(MessageId::DevicePowerOffRequest, buf).unwrap())
.unwrap();
self.can_tx.tx_socket(PackageId::DevicePowerOffRequest, buf);
let mut map_lock = self.device_state_map.lock().unwrap();
*map_lock.get_mut(&dev_id).unwrap() = SwitchState::Unknown;
self.can_rx.recv();
self.can_rx.recv();
Ok(())
} else {
Err(())
};
}
}
pub fn update_states_helper(&mut self, dev_id: &DeviceId) -> Result<(), ()> {
/*let _switch_id: SwitchId = *dev_id as u16;
let switch_id: SwitchId = *dev_id as u16;
let dev_id_bytes = *dev_id as u8;
let buf: &[u8] = &dev_id_bytes.to_be_bytes();
self.can_tx
.send(PackageModel::new(PackageId::DevicePowerStatusRequest, buf).unwrap())
.unwrap();
self.can_tx.tx_socket(PackageId::DevicePowerStatusRequest, buf);
match self.can_rx.recv_timeout(Duration::from_secs(10)) {
Ok(msg) => {
if msg.package_id() == PackageId::DevicePowerStatusResponse
&& msg.data()[0] == dev_id_bytes
{
debug!("received power status response");
if msg.package_id() == PackageId::DevicePowerStatusResponse && msg.data()[0] == dev_id_bytes{
info!("received power status response");
let mut map_lock = self.device_state_map.lock().unwrap();
let state: SwitchState;
let mut state: SwitchState;
match msg.data()[1] {
0 => state = SwitchState::Off,
1 => state = SwitchState::On,
2 => state = SwitchState::Faulty,
0 => {
state = SwitchState::Off
},
1 => {
state = SwitchState::On
},
2 => {
state = SwitchState::Faulty
},
_ => {
return Err(());
}
}
*map_lock.get_mut(&dev_id).unwrap() = state;
debug!("{:?}", map_lock);
info!("{:?}", map_lock);
Ok(())
} else {
Err(())
}
}
Err(_) => Err(()),
Err(_) => {
Err(())
}
}
*/
Ok(())
}
pub fn update_all_states_helper(&mut self) -> Result<(), ()> {
let map_lock = self.device_state_map.lock().unwrap();
let mut map_lock = self.device_state_map.lock().unwrap();
let mut device_list = vec::Vec::new();
for key in map_lock.keys() {
device_list.push(key.clone());
@ -177,61 +170,56 @@ impl PCDUHandler {
Ok(())
}
pub fn update_switch_states(&mut self, switch_id: SwitchId, mut switch_state: SwitchState) -> Result<(), ()> {
pub fn update_switch_states(&mut self, switch_id: SwitchId) -> Result<(), ()> {
return if let Ok(dev_id) = DeviceId::try_from(switch_id) {
match dev_id {
//DeviceId::All => self.update_all_states_helper(),
DeviceId::All => {Ok(())}
_ => {
let mut map = self.device_state_map.lock().expect("error locking data map");
if let Some(mut val) = map.get_mut(&dev_id) {
val = &mut switch_state;
DeviceId::All => {
self.update_all_states_helper()
}
_ => {
self.update_states_helper(&dev_id)
}
Ok(())
},
}
} else {
Err(())
};
}
}
pub fn handle_power_requests(&mut self) -> Result<u16, ()> {
pub fn handle_power_requests(&mut self) -> Result<u16, ()>{
let mut i = 0;
while let Ok((switch_id, switch_state)) = self.switch_rx.recv() {
match switch_state {
SwitchState::Off => match self.send_power_off(switch_id) {
SwitchState::Off => {
match self.send_power_off(switch_id) {
Ok(_) => {
self.update_switch_states(switch_id, switch_state).expect("error updating switch states");
i = i + 1;
}
Err(_) => {
return Err(());
}
},
SwitchState::On => match self.send_power_on(switch_id) {
}
}
SwitchState::On => {
match self.send_power_on(switch_id) {
Ok(_) => {
self.update_switch_states(switch_id, switch_state).expect("error updating switch states");
i = i + 1;
}
Err(_) => {
return Err(());
}
},
}
}
_ => {}
}
self.update_switch_states(switch_id);
}
return Ok(i);
}
}
pub fn core_power_task(
switch_rx: Receiver<(SwitchId, SwitchState)>,
can_tx: Sender<MessageModel>,
can_rx: Receiver<MessageModel>,
device_state_map: Arc<Mutex<HashMap<DeviceId, SwitchState>>>,
) {
let mut pcdu = PCDUHandler::new(switch_rx, can_tx, can_rx, device_state_map);
loop {
pub fn core_power_task(switch_rx: Receiver<(SwitchId, SwitchState)>, can_tx: CanTxHandler, can_rx: Receiver<PackageModel>, device_state_map: Arc<Mutex<HashMap<DeviceId, SwitchState>>>) {
let mut pcdu = PCDU::new(switch_rx, can_tx, can_rx, device_state_map);
loop{
pcdu.handle_power_requests().unwrap();
}
}

View File

@ -1,18 +1,17 @@
use crate::action::ActionRequest;
use crate::can_ids::{DeviceId, MessageId, MessageModel};
use crate::power_handler::{DeviceState, PowerSwitcher};
use crate::requests::{Request, RequestWithToken};
use eurosim_obsw::{RequestTargetId};
use log::debug;
use satrs_core::power::{PowerSwitchInfo, PowerSwitcherCommandSender, SwitchId};
use satrs_core::pus::verification::{VerificationReporterWithSender};
use satrs_core::pus::MpscPusInStoreSendError;
use std::sync::mpsc;
use std::sync::mpsc::{Receiver, Sender, TryRecvError};
use log::info;
use satrs_core::power::{PowerSwitcherCommandSender, PowerSwitchInfo, SwitchId, SwitchState};
use satrs_core::pus::verification::{StdVerifSenderError, VerificationReporterWithSender};
use satrs_core::spacepackets::time::cds::TimeProvider;
use satrs_core::spacepackets::time::TimeWriter;
use std::sync::mpsc;
use std::sync::mpsc::{Receiver, Sender};
use std::thread::sleep;
use std::time::Duration;
use eurosim_obsw::RequestTargetId;
use crate::action::ActionRequest;
use crate::can::CanTxHandler;
use crate::can_ids::{DeviceId, load_package_ids, PackageId, PackageModel, ThreadId};
use crate::pld_handler::CameraMode::PictureRequest;
use crate::pcdu::{DeviceState, PowerSwitcher};
use crate::requests::{Request, RequestWithToken};
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum CameraMode {
@ -21,7 +20,6 @@ pub enum CameraMode {
Verification,
Start,
End,
Broken,
}
pub struct CameraHandler {
@ -29,40 +27,22 @@ pub struct CameraHandler {
camera_device_id: DeviceId,
camera_switch_id: SwitchId,
device_state: DeviceState,
can_tx: Sender<MessageModel>,
can_rx: Receiver<MessageModel>,
can_tx: CanTxHandler,
can_rx: Receiver<PackageModel>,
mode: CameraMode,
mode_rx: Receiver<CameraMode>,
action_rx: Receiver<RequestWithToken>,
}
impl CameraHandler {
pub fn new(
power_switcher: PowerSwitcher,
camera_device_id: DeviceId,
can_tx: Sender<MessageModel>,
can_rx: Receiver<MessageModel>,
mode_rx: Receiver<CameraMode>,
action_rx: Receiver<RequestWithToken>,
) -> CameraHandler {
pub fn new(power_switcher: PowerSwitcher, camera_device_id: DeviceId, can_tx: CanTxHandler, can_rx: Receiver<PackageModel>, mode_rx: Receiver<CameraMode>) -> CameraHandler {
let camera_switch_id = camera_device_id as u16;
CameraHandler {
power_switcher,
camera_device_id,
camera_switch_id,
device_state: DeviceState::Off,
can_tx,
can_rx,
mode: CameraMode::Idle,
mode_rx,
action_rx,
}
CameraHandler{power_switcher, camera_device_id, camera_switch_id, device_state: DeviceState::Off, can_tx, can_rx, mode: CameraMode::Idle, mode_rx}
}
pub fn set_mode(&mut self, mode: CameraMode) {
if self.mode == CameraMode::Idle {
if self.mode == CameraMode::Idle{
if mode == CameraMode::PictureRequest {
self.mode = CameraMode::PictureRequest;
self.mode = PictureRequest;
}
}
}
@ -71,17 +51,84 @@ impl CameraHandler {
self.mode
}
pub fn handle_mode_requests(&mut self) {
match self.mode_rx.try_recv() {
Ok(mode) => {
self.set_mode(mode);
}
Err(_) => {}
}
}
pub fn periodic_op(&mut self) {
// Camera Device Handler State Machine
/*pub fn handle_action_requests(&mut self) {
match self.action_rx.try_recv() {
match self.mode {
CameraMode::Idle => {}
CameraMode::PictureRequest => {
if self.device_state == DeviceState::Off {
self.power_switcher.send_switch_on_cmd(self.camera_switch_id).expect("sending switch cmd failed");
self.device_state = DeviceState::SwitchingPower;
info!("switching power");
}
if self.device_state == DeviceState::SwitchingPower {
if self.power_switcher.get_is_switch_on(self.camera_switch_id).expect("reading switch state failed") {
self.device_state = DeviceState::On;
info!("device on");
}
}
if self.device_state == DeviceState::On {
self.can_tx.tx_socket(PackageId::CameraImageRequest, &[1]);
info!("sent camera request");
self.mode = CameraMode::Verification;
}
}
CameraMode::Verification => {
if self.device_state == DeviceState::On {
info!("waiting for image request confirmation");
if let Ok(msg) = self.can_rx.recv() {
if msg.package_id() == PackageId::CameraImageRequestConfirmation {
self.mode = CameraMode::Start;
}
}
}
}
CameraMode::Start => {
if self.device_state == DeviceState::On {
info!("waiting for image start confirmation");
if let Ok(msg) = self.can_rx.recv() {
if msg.package_id() == PackageId::CameraImageExecutionStart {
self.mode = CameraMode::End;
}
}
}
}
CameraMode::End => {
if self.device_state == DeviceState::On {
info!("waiting for image end confirmation");
if let Ok(msg) = self.can_rx.recv() {
if msg.package_id() == PackageId::CameraImageExectutionEnd {
self.power_switcher.send_switch_off_cmd(self.camera_switch_id).expect("sending switch command failed");
self.device_state = DeviceState::SwitchingPower;
info!("switching power");
}
}
}
if self.device_state == DeviceState::SwitchingPower {
if !self.power_switcher.get_is_switch_on(self.camera_switch_id).expect("reading switch state failed") {
self.device_state = DeviceState::Off;
info!("device off");
}
}
if self.device_state == DeviceState::Off {
self.mode = CameraMode::Idle;
}
}
}
}
}
pub fn core_pld_task(power_switcher: PowerSwitcher, pld_thread_rx: Receiver<RequestWithToken>, pld_can_rx: Receiver<PackageModel>, reporter_pld: &mut VerificationReporterWithSender<StdVerifSenderError>) {
let (camera_mode_tx, camera_mode_rx) = mpsc::channel();
let camera_can_tx =
CanTxHandler::new_socket("can0", ThreadId::PLDThread, load_package_ids()).unwrap();
let mut camera_handler = CameraHandler::new(power_switcher, DeviceId::Camera, camera_can_tx, pld_can_rx, camera_mode_rx);
let mut time_stamp_buf: [u8; 7] = [0; 7];
loop {
match pld_thread_rx.try_recv() {
Ok(request_with_token) => {
match request_with_token.0 {
Request::ActionRequest(action_id) => {
@ -97,13 +144,11 @@ impl CameraHandler {
.start_success(request_with_token.1, Some(&time_stamp_buf))
.expect("Error sending start success.");
debug!("{:?}", camera_handler.get_mode());
info!("{:?}", camera_handler.get_mode());
while camera_handler.get_mode() != CameraMode::Idle {
camera_handler.periodic_op();
}
let cds_stamp = TimeProvider::from_now_with_u16_days().unwrap();
cds_stamp.write_to_bytes(&mut time_stamp_buf).unwrap();
// send end verification with token
reporter_pld
.completion_success(
@ -123,159 +168,4 @@ impl CameraHandler {
}
}
*/
pub fn take_picture(&mut self) {}
pub fn periodic_op(&mut self) {
// Camera Device Handler State Machine
match self.mode {
CameraMode::Broken => {}
CameraMode::Idle => {}
CameraMode::PictureRequest => {
if self.device_state == DeviceState::Off {
self.power_switcher
.send_switch_on_cmd(self.camera_switch_id)
.expect("sending switch cmd failed");
self.device_state = DeviceState::SwitchingPower;
debug!("switching power");
}
if self.device_state == DeviceState::SwitchingPower {
let allowed_cycles = 10;
for i in 0..allowed_cycles {
if self
.power_switcher
.get_is_switch_on(self.camera_switch_id)
.expect("reading switch state failed")
{
self.device_state = DeviceState::On;
debug!("device on");
}
}
self.mode = CameraMode::Broken;
}
if self.device_state == DeviceState::On {
self.can_tx
.send(MessageModel::new(MessageId::CameraImageRequest, &[1]).unwrap())
.unwrap();
debug!("sent camera request");
self.mode = CameraMode::Verification;
}
}
CameraMode::Verification => {
if self.device_state == DeviceState::On {
debug!("waiting for image request confirmation");
if let Ok(msg) = self.can_rx.recv() {
if msg.message_id() == MessageId::CameraImageRequestConfirmation {
self.mode = CameraMode::Start;
}
}
}
}
CameraMode::Start => {
if self.device_state == DeviceState::On {
debug!("waiting for image start confirmation");
if let Ok(msg) = self.can_rx.recv() {
if msg.message_id() == MessageId::CameraImageExecutionStart {
self.mode = CameraMode::End;
}
}
}
}
CameraMode::End => {
if self.device_state == DeviceState::On {
debug!("waiting for image end confirmation");
if let Ok(msg) = self.can_rx.recv() {
if msg.message_id() == MessageId::CameraImageExectutionEnd {
self.power_switcher
.send_switch_off_cmd(self.camera_switch_id)
.expect("sending switch command failed");
self.device_state = DeviceState::SwitchingPower;
debug!("switching power");
}
}
}
if self.device_state == DeviceState::SwitchingPower {
if !self
.power_switcher
.get_is_switch_on(self.camera_switch_id)
.expect("reading switch state failed")
{
self.device_state = DeviceState::Off;
debug!("device off");
}
}
if self.device_state == DeviceState::Off {
self.mode = CameraMode::Idle;
}
}
}
}
}
pub fn core_pld_task(
power_switcher: PowerSwitcher,
pld_thread_rx: Receiver<RequestWithToken>,
pld_can_rx: Receiver<MessageModel>,
pld_can_tx: Sender<MessageModel>,
reporter_pld: &mut VerificationReporterWithSender<MpscPusInStoreSendError>,
) {
let (_camera_mode_tx, camera_mode_rx) = mpsc::channel();
let (_action_tx, action_rx) = mpsc::channel();
let mut camera_handler = CameraHandler::new(
power_switcher,
DeviceId::Camera,
pld_can_tx,
pld_can_rx,
camera_mode_rx,
action_rx,
);
let mut time_stamp_buf: [u8; 7] = [0; 7];
loop {
match pld_thread_rx.try_recv() {
Ok(request_with_token) => {
match request_with_token.0 {
Request::ActionRequest(action_id) => {
match action_id {
ActionRequest::ImageRequest(target_id) => {
assert_eq!(target_id, RequestTargetId::PldSubsystem);
camera_handler.set_mode(CameraMode::PictureRequest);
let cds_stamp = TimeProvider::from_now_with_u16_days().unwrap();
cds_stamp.write_to_bytes(&mut time_stamp_buf).unwrap();
// send start verification and get token
let start_token = reporter_pld
.start_success(
request_with_token.1.unwrap(),
Some(&time_stamp_buf),
)
.expect("Error sending start success.");
debug!("{:?}", camera_handler.get_mode());
while camera_handler.get_mode() != CameraMode::Idle {
camera_handler.periodic_op();
debug!("{:?}", camera_handler.get_mode());
sleep(Duration::from_millis(1000));
}
let cds_stamp = TimeProvider::from_now_with_u16_days().unwrap();
cds_stamp.write_to_bytes(&mut time_stamp_buf).unwrap();
// send end verification with token
reporter_pld
.completion_success(start_token, Some(&time_stamp_buf))
.expect("Error sending start success.");
}
ActionRequest::OrientationRequest(_) => {}
ActionRequest::PointingRequest(_) => {}
}
}
_ => {}
}
}
Err(_) => {}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,12 @@
use crate::action::ActionRequest;
use satrs_core::hk::HkRequest;
use satrs_core::mode::ModeRequest;
use crate::hk::HkRequest;
use satrs_core::pus::verification::{TcStateAccepted, VerificationToken};
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[non_exhaustive]
pub enum Request {
HkRequest(HkRequest),
ModeRequest(ModeRequest),
ActionRequest(ActionRequest),
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct RequestWithToken(pub Request, pub Option<VerificationToken<TcStateAccepted>>);
pub struct RequestWithToken(pub Request, pub VerificationToken<TcStateAccepted>);

View File

@ -1,446 +0,0 @@
use crate::hk::{CollectionIntervalFactor, HkRequest};
use crate::requests::{Request, RequestWithToken};
use crate::tmtc::{PusTcSource, TmStore};
use eurosim_obsw::{hk_err, tmtc_err};
use satrs_core::events::EventU32;
use satrs_core::pool::StoreAddr;
use satrs_core::pus::event::Subservice;
use satrs_core::pus::event_man::{EventRequest, EventRequestWithToken};
use satrs_core::pus::hk;
use satrs_core::pus::verification::{
FailParams, StdVerifReporterWithSender, TcStateAccepted, VerificationToken,
};
use satrs_core::res_code::ResultU16;
use satrs_core::tmtc::tm_helper::PusTmWithCdsShortHelper;
use satrs_core::tmtc::{AddressableId, PusServiceProvider};
use satrs_core::{
spacepackets::ecss::PusPacket, spacepackets::tc::PusTc, spacepackets::time::cds::TimeProvider,
spacepackets::time::TimeWriter, spacepackets::SpHeader,
};
use std::cell::RefCell;
use crate::action;
use crate::action::ActionRequest;
use eurosim_obsw::RequestTargetId::{AcsSubsystem, PldSubsystem};
use satrs_core::pus::scheduling::PusScheduler;
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::mpsc::Sender;
use log::{debug};
pub struct PusReceiver {
pub tm_helper: PusTmWithCdsShortHelper,
pub tm_tx: Sender<StoreAddr>,
pub tm_store: TmStore,
pub verif_reporter: StdVerifReporterWithSender,
#[allow(dead_code)]
tc_source: PusTcSource,
event_request_tx: Sender<EventRequestWithToken>,
request_map: HashMap<u32, Sender<RequestWithToken>>,
stamper: TimeProvider,
time_stamp: [u8; 7],
scheduler: Rc<RefCell<PusScheduler>>,
}
impl PusReceiver {
pub fn new(
apid: u16,
tm_tx: Sender<StoreAddr>,
tm_store: TmStore,
verif_reporter: StdVerifReporterWithSender,
tc_source: PusTcSource,
event_request_tx: Sender<EventRequestWithToken>,
request_map: HashMap<u32, Sender<RequestWithToken>>,
scheduler: Rc<RefCell<PusScheduler>>,
) -> Self {
Self {
tm_helper: PusTmWithCdsShortHelper::new(apid),
tm_tx,
tm_store,
verif_reporter,
tc_source,
event_request_tx,
request_map,
stamper: TimeProvider::new_with_u16_days(0, 0),
time_stamp: [0; 7],
scheduler,
}
}
}
impl PusServiceProvider for PusReceiver {
type Error = ();
fn handle_pus_tc_packet(
&mut self,
service: u8,
_header: &SpHeader,
pus_tc: &PusTc,
) -> Result<(), Self::Error> {
let init_token = self.verif_reporter.add_tc(pus_tc);
self.update_time_stamp();
let accepted_token = self
.verif_reporter
.acceptance_success(init_token, Some(&self.time_stamp))
.expect("Acceptance success failure");
if service == 17 {
self.handle_test_service(pus_tc, accepted_token);
} else if service == 5 {
self.handle_event_request(pus_tc, accepted_token);
} else if service == 3 {
self.handle_hk_request(pus_tc, accepted_token);
} else if service == 8 {
self.handle_function_request(pus_tc, accepted_token);
} else if service == 11 {
self.handle_scheduled_tc(pus_tc, accepted_token);
} else {
self.update_time_stamp();
self.verif_reporter
.start_failure(
accepted_token,
FailParams::new(Some(&self.time_stamp), &tmtc_err::INVALID_PUS_SERVICE, None),
)
.expect("Start failure verification failed")
}
Ok(())
}
}
impl PusReceiver {
fn handle_test_service(&mut self, pus_tc: &PusTc, token: VerificationToken<TcStateAccepted>) {
if PusPacket::subservice(pus_tc) == 1 {
debug!("Received PUS ping command TC[17,1]");
debug!("Sending ping reply PUS TM[17,2]");
let ping_reply = self.tm_helper.create_pus_tm_timestamp_now(17, 2, None);
let addr = self.tm_store.add_pus_tm(&ping_reply);
let start_token = self
.verif_reporter
.start_success(token, Some(&self.time_stamp))
.expect("Error sending start success");
self.tm_tx
.send(addr)
.expect("Sending TM to TM funnel failed");
self.verif_reporter
.completion_success(start_token, Some(&self.time_stamp))
.expect("Error sending completion success");
} else {
self.update_time_stamp();
self.verif_reporter
.start_failure(
token,
FailParams::new(
Some(&self.time_stamp),
&tmtc_err::INVALID_PUS_SUBSERVICE,
None,
),
)
.expect("Sending start failure TM failed");
}
}
fn update_time_stamp(&mut self) {
self.stamper
.update_from_now()
.expect("Updating timestamp failed");
self.stamper
.write_to_bytes(&mut self.time_stamp)
.expect("Writing timestamp failed");
}
fn handle_hk_request(&mut self, pus_tc: &PusTc, token: VerificationToken<TcStateAccepted>) {
if pus_tc.user_data().is_none() {
self.update_time_stamp();
self.verif_reporter
.start_failure(
token,
FailParams::new(Some(&self.time_stamp), &tmtc_err::NOT_ENOUGH_APP_DATA, None),
)
.expect("Sending start failure TM failed");
return;
}
let user_data = pus_tc.user_data().unwrap();
if user_data.len() < 8 {
let err = if user_data.len() < 4 {
&hk_err::TARGET_ID_MISSING
} else {
&hk_err::UNIQUE_ID_MISSING
};
self.update_time_stamp();
self.verif_reporter
.start_failure(token, FailParams::new(Some(&self.time_stamp), err, None))
.expect("Sending start failure TM failed");
return;
}
let addressable_id = AddressableId::from_raw_be(user_data).unwrap();
if !self.request_map.contains_key(&addressable_id.target_id) {
self.update_time_stamp();
self.verif_reporter
.start_failure(
token,
FailParams::new(Some(&self.time_stamp), &hk_err::UNKNOWN_TARGET_ID, None),
)
.expect("Sending start failure TM failed");
return;
}
let send_request = |request: HkRequest| {
let sender = self.request_map.get(&addressable_id.target_id).unwrap();
sender
.send(RequestWithToken(Request::HkRequest(request), token))
.unwrap_or_else(|_| panic!("Sending HK request {:?} failed", request));
};
if PusPacket::subservice(pus_tc) == hk::Subservice::TcEnableHkGeneration as u8 {
send_request(HkRequest::Enable(addressable_id));
} else if PusPacket::subservice(pus_tc) == hk::Subservice::TcDisableHkGeneration as u8 {
send_request(HkRequest::Disable(addressable_id));
} else if PusPacket::subservice(pus_tc) == hk::Subservice::TcGenerateOneShotHk as u8 {
send_request(HkRequest::OneShot(addressable_id));
} else if PusPacket::subservice(pus_tc)
== hk::Subservice::TcModifyHkCollectionInterval as u8
{
if user_data.len() < 12 {
self.update_time_stamp();
self.verif_reporter
.start_failure(
token,
FailParams::new(
Some(&self.time_stamp),
&hk_err::COLLECTION_INTERVAL_MISSING,
None,
),
)
.expect("Sending start failure TM failed");
return;
}
send_request(HkRequest::ModifyCollectionInterval(
addressable_id,
CollectionIntervalFactor::from_be_bytes(user_data[8..12].try_into().unwrap()),
));
}
}
fn handle_event_request(&mut self, pus_tc: &PusTc, token: VerificationToken<TcStateAccepted>) {
let send_start_failure = |verif_reporter: &mut StdVerifReporterWithSender,
timestamp: &[u8; 7],
failure_code: &ResultU16,
failure_data: Option<&[u8]>| {
verif_reporter
.start_failure(
token,
FailParams::new(Some(timestamp), failure_code, failure_data),
)
.expect("Sending start failure TM failed");
};
let send_start_acceptance = |verif_reporter: &mut StdVerifReporterWithSender,
timestamp: &[u8; 7]| {
verif_reporter
.start_success(token, Some(timestamp))
.expect("Sending start success TM failed")
};
if pus_tc.user_data().is_none() {
self.update_time_stamp();
send_start_failure(
&mut self.verif_reporter,
&self.time_stamp,
&tmtc_err::NOT_ENOUGH_APP_DATA,
None,
);
return;
}
let app_data = pus_tc.user_data().unwrap();
if app_data.len() < 4 {
self.update_time_stamp();
send_start_failure(
&mut self.verif_reporter,
&self.time_stamp,
&tmtc_err::NOT_ENOUGH_APP_DATA,
None,
);
return;
}
let event_id = EventU32::from(u32::from_be_bytes(app_data.try_into().unwrap()));
match PusPacket::subservice(pus_tc).try_into() {
Ok(Subservice::TcEnableEventGeneration) => {
self.update_time_stamp();
let start_token = send_start_acceptance(&mut self.verif_reporter, &self.time_stamp);
self.event_request_tx
.send(EventRequestWithToken {
request: EventRequest::Enable(event_id),
token: start_token,
})
.expect("Sending event request failed");
}
Ok(Subservice::TcDisableEventGeneration) => {
self.update_time_stamp();
let start_token = send_start_acceptance(&mut self.verif_reporter, &self.time_stamp);
self.event_request_tx
.send(EventRequestWithToken {
request: EventRequest::Disable(event_id),
token: start_token,
})
.expect("Sending event request failed");
}
_ => {
self.update_time_stamp();
send_start_failure(
&mut self.verif_reporter,
&self.time_stamp,
&tmtc_err::INVALID_PUS_SUBSERVICE,
None,
);
}
}
}
fn handle_function_request(
&mut self,
pus_tc: &PusTc,
token: VerificationToken<TcStateAccepted>,
) {
if pus_tc.user_data().is_none() {
self.update_time_stamp();
self.verif_reporter
.start_failure(
token,
FailParams::new(Some(&self.time_stamp), &tmtc_err::NOT_ENOUGH_APP_DATA, None),
)
.expect("Sending start failure TM failed");
return;
}
let send_request = |request: ActionRequest| match request {
ActionRequest::ImageRequest(target_id) => {
let id = target_id as u32;
let sender = self.request_map.get(&id).unwrap();
sender
.send(RequestWithToken(Request::ActionRequest(request), token))
.unwrap_or_else(|_| panic!("Sending Action request {:?} failed", request));
}
ActionRequest::OrientationRequest(target_id) => {
let id = target_id as u32;
let sender = self.request_map.get(&id).unwrap();
sender
.send(RequestWithToken(Request::ActionRequest(request), token))
.unwrap_or_else(|_| panic!("Sending Action request {:?} failed", request));
}
_ => {}
};
if PusPacket::subservice(pus_tc) == action::Subservice::ImageRequest as u8 {
send_request(ActionRequest::ImageRequest(PldSubsystem));
} else if PusPacket::subservice(pus_tc) == action::Subservice::OrientationRequest as u8 {
send_request(ActionRequest::OrientationRequest(AcsSubsystem));
}
}
fn handle_scheduled_tc(&mut self, pus_tc: &PusTc, token: VerificationToken<TcStateAccepted>) {
if pus_tc.user_data().is_none() {
self.update_time_stamp();
self.verif_reporter
.start_failure(
token,
FailParams::new(Some(&self.time_stamp), &tmtc_err::NOT_ENOUGH_APP_DATA, None),
)
.expect("Sending start failure TM failed");
return;
}
self.update_time_stamp();
match pus_tc.subservice() {
1 => {
let start_token = self
.verif_reporter
.start_success(token, Some(&self.time_stamp))
.expect("Error sending start success");
let mut scheduler = self.scheduler.borrow_mut();
scheduler.enable();
if scheduler.is_enabled() {
self.verif_reporter
.completion_success(start_token, Some(&self.time_stamp))
.expect("Error sending completion success");
} else {
panic!("Failed to enable scheduler");
}
drop(scheduler);
}
2 => {
let start_token = self
.verif_reporter
.start_success(token, Some(&self.time_stamp))
.expect("Error sending start success");
let mut scheduler = self.scheduler.borrow_mut();
scheduler.disable();
if !scheduler.is_enabled() {
self.verif_reporter
.completion_success(start_token, Some(&self.time_stamp))
.expect("Error sending completion success");
} else {
panic!("Failed to disable scheduler");
}
drop(scheduler);
}
3 => {
let start_token = self
.verif_reporter
.start_success(token, Some(&self.time_stamp))
.expect("Error sending start success");
let mut pool = self
.tc_source
.tc_store
.pool
.write()
.expect("Locking pool failed");
let mut scheduler = self.scheduler.borrow_mut();
scheduler
.reset(pool.as_mut())
.expect("Error resetting TC Pool");
drop(scheduler);
self.verif_reporter
.completion_success(start_token, Some(&self.time_stamp))
.expect("Error sending completion success");
}
4 => {
let start_token = self
.verif_reporter
.start_success(token, Some(&self.time_stamp))
.expect("Error sending start success");
let mut pool = self
.tc_source
.tc_store
.pool
.write()
.expect("Locking pool failed");
let mut scheduler = self.scheduler.borrow_mut();
scheduler
.insert_wrapped_tc::<TimeProvider>(pus_tc, pool.as_mut())
.expect("TODO: panic message");
drop(scheduler);
self.verif_reporter
.completion_success(start_token, Some(&self.time_stamp))
.expect("Error sending completion success");
//let addr = self.tc_source.tc_store.add_pus_tc().unwrap();
//let unix_time = UnixTimestamp::new_only_seconds(self.stamper.unix_seconds());
//let worked = self.scheduler.insert_tc(unix_time, );
}
_ => {
self.verif_reporter
.start_failure(
token,
FailParams::new(
Some(&self.time_stamp),
&tmtc_err::NOT_ENOUGH_APP_DATA,
None,
),
)
.expect("Sending start failure TM failed");
return;
}
}
}
}

View File

@ -1,4 +1,3 @@
use log::info;
use satrs_core::events::EventU32;
use satrs_core::hal::host::udp_server::{ReceiveResult, UdpTcServer};
use satrs_core::params::Params;
@ -13,29 +12,18 @@ use std::thread;
use std::time::Duration;
use crate::ccsds::CcsdsReceiver;
use crate::pus::{PusReceiver, PusTcArgs, PusTmArgs};
use crate::pus::PusReceiver;
use crate::requests::RequestWithToken;
use satrs_core::pool::{SharedPool, StoreAddr, StoreError};
use satrs_core::pus::event_man::EventRequestWithToken;
use satrs_core::pus::scheduling::{PusScheduler, TcInfo};
use satrs_core::pus::scheduling::PusScheduler;
use satrs_core::pus::verification::StdVerifReporterWithSender;
use satrs_core::seq_count::SeqCountProviderSyncClonable;
use satrs_core::spacepackets::{ecss::PusPacket, tc::PusTc, tm::PusTm, SpHeader};
use satrs_core::tmtc::{
CcsdsDistributor, CcsdsError, PusServiceProvider, ReceivesCcsdsTc, ReceivesEcssPusTc,
};
pub const PUS_APID: u16 = 0x02;
pub const PLD_APID: u16 = 0x30;
pub const PWR_APID: u16 = 0x40;
pub const AOCS_APID: u16 = 0x50;
pub const AOCS_HK_APID: u16 = 0x51;
pub const MGM_APID: u16 = 0x52;
pub const CSS_APID: u16 = 0x53;
pub const STR_APID: u16 = 0x54;
pub const MGT_APID: u16 = 0x55;
pub const RWL_APID: u16 = 0x56;
pub const GPS_APID: u16 = 0x57;
pub struct OtherArgs {
pub sock_addr: SocketAddr,
@ -43,8 +31,6 @@ pub struct OtherArgs {
pub event_sender: Sender<(EventU32, Option<Params>)>,
pub event_request_tx: Sender<EventRequestWithToken>,
pub request_map: HashMap<u32, Sender<RequestWithToken>>,
pub apid_map: HashMap<u16, Sender<RequestWithToken>>,
pub seq_count_provider: SeqCountProviderSyncClonable,
}
pub struct TmArgs {
@ -59,7 +45,6 @@ pub struct TcArgs {
}
impl TcArgs {
#[allow(dead_code)]
fn split(self) -> (PusTcSource, Receiver<StoreAddr>) {
(self.tc_source, self.tc_receiver)
}
@ -175,28 +160,22 @@ impl ReceivesCcsdsTc for PusTcSource {
Ok(())
}
}
pub fn core_tmtc_task(args: OtherArgs, mut tc_args: TcArgs, tm_args: TmArgs) {
let scheduler = Rc::new(RefCell::new(
let mut scheduler = Rc::new(RefCell::new(
PusScheduler::new_with_current_init_time(Duration::from_secs(5)).unwrap(),
));
let sched_clone = scheduler.clone();
let pus_tm_args = PusTmArgs {
tm_tx: tm_args.tm_sink_sender,
tm_store: tm_args.tm_store.clone(),
verif_reporter: args.verif_reporter,
seq_count_provider: args.seq_count_provider.clone(),
};
let pus_tc_args = PusTcArgs {
event_request_tx: args.event_request_tx,
request_map: args.request_map,
tc_source: tc_args.tc_source.clone(),
event_sender: args.event_sender,
scheduler: sched_clone,
apid_map: args.apid_map,
};
let mut pus_receiver = PusReceiver::new(PUS_APID, pus_tm_args, pus_tc_args);
let mut sched_clone = scheduler.clone();
let mut pus_receiver = PusReceiver::new(
PUS_APID,
tm_args.tm_sink_sender,
tm_args.tm_store.clone(),
args.verif_reporter,
tc_args.tc_source.clone(),
args.event_request_tx,
args.request_map,
sched_clone,
);
let ccsds_receiver = CcsdsReceiver {
tc_source: tc_args.tc_source.clone(),
@ -213,13 +192,17 @@ pub fn core_tmtc_task(args: OtherArgs, mut tc_args: TcArgs, tm_args: TmArgs) {
tm_store: tm_args.tm_store.pool.clone(),
};
//let (mut tc_source, mut tc_receiver) = tc_args.split();
let mut tc_buf: [u8; 4096] = [0; 4096];
loop {
let tmtc_sched = scheduler.clone();
let mut tmtc_sched = scheduler.clone();
core_tmtc_loop(
&mut udp_tmtc_server,
&mut tc_args,
&mut tc_buf,
//&mut tc_source,
//&mut tc_receiver,
&mut pus_receiver,
tmtc_sched,
);
@ -231,18 +214,16 @@ fn core_tmtc_loop(
udp_tmtc_server: &mut UdpTmtcServer,
tc_args: &mut TcArgs,
tc_buf: &mut [u8],
//tc_source: &mut PusTcSource,
//tc_receiver: &mut Receiver<StoreAddr>,
pus_receiver: &mut PusReceiver,
scheduler: Rc<RefCell<PusScheduler>>,
) {
let releaser = |enabled: bool, info: &TcInfo| -> bool {
if enabled {
tc_args
.tc_source
.tc_source
.send(info.addr())
.expect("sending TC to TC source failed");
let releaser = |enabled: bool, addr: &StoreAddr| -> bool {
match tc_args.tc_source.tc_source.send(*addr) {
Ok(_) => true,
Err(_) => false,
}
true
};
let mut pool = tc_args
@ -254,11 +235,15 @@ fn core_tmtc_loop(
let mut scheduler = scheduler.borrow_mut();
scheduler.update_time_from_now().unwrap();
if let Ok(released_tcs) = scheduler.release_telecommands(releaser, pool.as_mut()) {
match scheduler.release_telecommands(releaser, pool.as_mut()) {
Ok(released_tcs) => {
if released_tcs > 0 {
info!("{released_tcs} TC(s) released from scheduler");
println!("{} Tc(s) released from scheduler", released_tcs);
}
}
Err(_) => {}
}
//.expect("error releasing tc");
drop(pool);
drop(scheduler);
@ -331,9 +316,9 @@ fn core_tm_handling(udp_tmtc_server: &mut UdpTmtcServer, recv_addr: &SocketAddr)
if buf.len() > 9 {
let service = buf[7];
let subservice = buf[8];
info!("Sending PUS TM[{service},{subservice}]")
println!("Sending PUS TM[{service},{subservice}]")
} else {
info!("Sending PUS TM");
println!("Sending PUS TM");
}
udp_tmtc_server
.udp_tc_server