Compare commits

..

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

24 changed files with 866 additions and 3415 deletions

1
.gitignore vendored
View File

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

60
Cargo.lock generated
View File

@ -297,7 +297,6 @@ dependencies = [
"num",
"num-derive",
"num-traits",
"num_enum",
"satrs-core",
"satrs-mib",
"serde",
@ -316,12 +315,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 +369,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 +501,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 +613,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 +649,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 +697,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 +704,8 @@ dependencies = [
"downcast-rs",
"dyn-clone",
"embed-doc-image",
"hashbrown 0.13.1",
"hashbrown",
"num-traits",
"num_enum",
"paste",
"serde",
"spacepackets",
@ -753,7 +714,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 +725,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",
@ -926,23 +885,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
@ -27,7 +27,7 @@ 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 +39,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.

43
output.log Normal file
View File

@ -0,0 +1,43 @@
[2023-02-15][09:14:42][main][INFO] Starting TMTC task
[2023-02-15][09:14:42][main][INFO] Starting power task
[2023-02-15][09:14:42][main][INFO] Starting AOCS task
[2023-02-15][09:16:43][main][INFO] Starting TMTC task
[2023-02-15][09:16:43][main][INFO] Starting power task
[2023-02-15][09:16:43][main][INFO] Starting AOCS task
[2023-02-15][11:05:33][main][INFO] Starting TMTC task
[2023-02-15][11:05:33][main][INFO] Starting CAN Socket listening task
[2023-02-15][11:05:33][main][INFO] Starting CAN Socket writing task
[2023-02-15][11:05:33][main][INFO] Starting power task
[2023-02-15][11:05:33][main][INFO] Starting AOCS task
[2023-02-15][11:10:52][main][INFO] Starting TMTC task
[2023-02-15][11:10:52][main][INFO] Starting power task
[2023-02-15][11:10:52][main][INFO] Starting AOCS task
[2023-02-15][11:11:09][main][INFO] Starting TMTC task
[2023-02-15][11:11:09][main][INFO] Starting power task
[2023-02-15][11:11:09][main][INFO] Starting AOCS task
[2023-02-15][11:11:37][main][INFO] Starting TMTC task
[2023-02-15][11:11:37][main][INFO] Starting power task
[2023-02-15][11:11:37][main][INFO] Starting AOCS task
[2023-02-15][14:42:44][main][INFO] Starting TMTC task
[2023-02-15][14:42:44][main][INFO] Starting power task
[2023-02-15][14:42:44][main][INFO] Starting Payload Handling task
[2023-02-15][14:42:44][main][INFO] Starting TM funnel task
[2023-02-15][14:42:44][main][INFO] Starting AOCS task
[2023-02-15][14:43:13][main][INFO] Running DemoSat OBSW
[2023-02-15][14:43:13][main][INFO] Starting TMTC task
[2023-02-15][14:43:13][main][INFO] Starting power task
[2023-02-15][14:43:13][main][INFO] Starting Payload Handling task
[2023-02-15][14:43:13][main][INFO] Starting TM funnel task
[2023-02-15][14:43:13][main][INFO] Starting AOCS task
[2023-02-15][14:48:12][main][INFO] Running DemoSat OBSW!
[2023-02-15][14:48:12][main][INFO] Starting TMTC task
[2023-02-15][14:48:12][main][INFO] Starting power task
[2023-02-15][14:48:12][main][INFO] Starting Payload Handling task
[2023-02-15][14:48:12][main][INFO] Starting TM funnel task
[2023-02-15][14:48:12][main][INFO] Starting AOCS task
[2023-02-16][12:46:02][main][INFO] Running DemoSat OBSW!
[2023-02-16][12:46:02][main][INFO] Starting TMTC task
[2023-02-16][12:46:02][main][INFO] Starting power task
[2023-02-16][12:46:02][main][INFO] Starting Payload Handling task
[2023-02-16][12:46:02][main][INFO] Starting TM funnel task
[2023-02-16][12:46:02][main][INFO] Starting AOCS task

View File

@ -9,7 +9,6 @@ from typing import Optional
import datetime
import json
import pprint
import struct
import tmtccmd
from spacepackets.ecss import PusTelemetry, PusTelecommand, PusVerificator
@ -18,7 +17,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 +56,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 +96,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",
@ -121,15 +118,6 @@ class SatRsConfigHook(HookBase):
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 +154,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)
)
@ -190,22 +177,13 @@ class PusHandler(SpecificApidHandlerBase):
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 = str(pus_tm.source_data[8:].decode('utf8'))
json_object = json.loads(json_str)
pprint.pprint(json_object)
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 +223,13 @@ def read_addressable_id(data: bytes) -> tuple[int, int]:
return (target_id, set_id)
class CustomServiceList(enum.StrEnum):
class CustomServiceList(enum.IntEnum):
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 +237,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 +268,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,22 +288,11 @@ 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":
@ -370,28 +326,16 @@ class TcHandler(TcHandlerBase):
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,7 @@
{
"com_if": "udp",
"tcpip_udp_ip_addr": "192.168.1.116",
"tcpip_udp_ip_addr_pc": "192.168.56.1",
"tcpip_udp_ip_addr_windows": "192.168.1.5",
"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() {}

206
src/aocs_handler.rs Normal file
View File

@ -0,0 +1,206 @@
use std::sync::{Arc, Mutex};
use crate::can_ids::{DeviceId, PackageId, PackageModel};
use crate::hk::HkRequest;
use crate::power_handler::{DeviceState, PowerSwitcher};
use crate::requests::{Request, RequestWithToken};
use satrs_core::power::SwitchId;
use std::sync::mpsc::{Receiver, Sender};
use serde::{Deserialize, Serialize};
use byteorder::{LittleEndian, ByteOrder};
use crate::can_ids::PackageId::AOCSDataRequestMGM1;
pub enum AocsSensorMode {
Idle,
SendingData,
}
pub trait AocsSensorHandler {
type Error;
fn get_package_id(&mut self) -> Result<PackageId, Self::Error>;
fn send_message(&mut self, id: PackageId, 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])
}
}
#[derive(Debug, Copy, Clone, Default, Serialize, Deserialize)]
pub struct MGMData {
axis_1: f64,
axis_2: f64,
axis_3: f64,
}
impl MGMData {
pub fn from_floats(axis_1: f64,
axis_2: f64,
axis_3: f64,
) -> MGMData {
MGMData{axis_1, axis_2, axis_3}
}
pub fn new() -> MGMData { MGMData{axis_1: 0.0, axis_2: 0.0, axis_3: 0.0} }
pub fn update(&mut self,
axis_1: f64,
axis_2: f64,
axis_3: f64
) {
self.axis_1 = axis_1;
self.axis_2 = axis_2;
self.axis_3 = axis_3;
}
pub fn to_array(&self) -> [f64; 3] {
[self.axis_1, self.axis_2, self.axis_3]
}
pub fn to_tuple(&self) -> (f64, f64, f64) {
(self.axis_1, self.axis_2, self.axis_3)
}
}
pub struct MGMHandler {
power_switcher: PowerSwitcher,
device_id: DeviceId,
switch_id: SwitchId,
device_state: DeviceState,
can_tx: Sender<PackageModel>,
can_rx: Receiver<PackageModel>,
mode: AocsSensorMode,
mode_rx: Receiver<AocsSensorMode>,
action_rx: Receiver<RequestWithToken>,
mgm_data: Arc<Mutex<MGMData>>,
sensor_data_enabled: bool,
}
impl AocsSensorHandler for MGMHandler {
type Error = ();
fn get_package_id(&mut self) -> Result<PackageId, Self::Error> {
return match self.device_id {
DeviceId::MGM1 => Ok(PackageId::AOCSDataRequestMGM1),
DeviceId::MGM2 => Ok(PackageId::AOCSDataRequestMGM2),
DeviceId::MGM3 => Ok(PackageId::AOCSDataRequestMGM3),
DeviceId::MGM4 => Ok(PackageId::AOCSDataRequestMGM4),
_ => Err(()),
};
}
fn send_message(&mut self, id: PackageId, buf: &[u8]) -> Result<(), Self::Error> {
self.can_tx.send(PackageModel::new(id, buf).unwrap()).unwrap();
return Ok(());
}
}
impl MGMHandler {
pub fn new(
power_switcher: PowerSwitcher,
device_id: DeviceId,
can_tx: Sender<PackageModel>,
can_rx: Receiver<PackageModel>,
mode_rx: Receiver<AocsSensorMode>,
action_rx: Receiver<RequestWithToken>,
) -> MGMHandler {
let switch_id = device_id as u16;
MGMHandler {
power_switcher,
device_id,
switch_id,
device_state: DeviceState::Off,
can_tx,
can_rx,
mode: AocsSensorMode::Idle,
mode_rx,
action_rx,
mgm_data: Arc::new(Mutex::new(MGMData::new())),
sensor_data_enabled: false,
}
}
pub fn get_data_ref(&mut self) -> Arc<Mutex<MGMData>> {
self.mgm_data.clone()
}
pub fn periodic_op(&mut self) {
self.update_mode();
self.handle_requests();
self.read_sensor_data();
}
pub fn update_mode(&mut self) {
if self.device_state == DeviceState::On {
if let Ok(mode) = self.mode_rx.try_recv() {
self.mode = mode;
}
}
}
pub fn handle_requests(&mut self) {
if self.device_state == DeviceState::On {
if let Ok(request) = self.action_rx.try_recv() {
match request.0 {
Request::HkRequest(hk_req) => {
self.handle_hk_request(hk_req);
}
Request::ActionRequest(_action_request) => {
//self.handle_action_request(action_request);
}
}
}
}
}
pub fn handle_hk_request(&mut self, hk_req: HkRequest) {
match hk_req {
HkRequest::OneShot(_) => {
self.can_tx.send(PackageModel::new(PackageId::AOCSDataRequestMGM1, &[2]).unwrap()).unwrap();
}
HkRequest::Enable(_) => {
if !self.sensor_data_enabled {
self.sensor_data_enabled = true;
self.can_tx.send(PackageModel::new(PackageId::AOCSDataRequestMGM1, &[1]).unwrap()).unwrap();
}
}
HkRequest::Disable(_) => {
if self.sensor_data_enabled {
self.sensor_data_enabled = false;
self.can_tx.send(PackageModel::new(PackageId::AOCSDataRequestMGM1, &[0]).unwrap()).unwrap();
}
}
HkRequest::ModifyCollectionInterval(_, _) => {}
}
}
pub fn read_sensor_data(&mut self) {
if let Ok(package) = self.can_rx.try_recv() {
let float_data = self.decode_sensor_data(package.data());
if let Ok(mut mgm_data) = self.mgm_data.lock() {
match package.package_id() {
PackageId::AOCSDataMGM1 => { mgm_data.axis_1 = float_data }
PackageId::AOCSDataMGM2 => { mgm_data.axis_2 = float_data }
PackageId::AOCSDataMGM3 => { mgm_data.axis_3 = float_data }
_ => {}
}
}
}
}
pub fn decode_sensor_data(&mut self, buf: &[u8]) -> f64 {
LittleEndian::read_f64(&buf)
}
//pub fn handle_action_request(&mut self, action_request: ActionRequest) {}
}

View File

@ -1,6 +1,6 @@
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, DeviceId, PackageId,
PackageModel, SenderReceiverThread, ThreadId,
};
use embedded_can::{self, Frame};
use log::{debug, warn};
@ -13,9 +13,9 @@ 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 +23,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,7 +32,7 @@ impl CanRxHandler {
interface,
socket,
can_senders,
message_map,
package_map,
})
} else {
Err(())
@ -60,19 +60,19 @@ impl CanRxHandler {
}
pub fn forward_frame(&self, frame: CanFrame) {
let frame_id = can_id_to_message_id(frame.id());
let frame_id = can_id_to_package_id(frame.id());
debug!("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
));
}
@ -84,15 +84,15 @@ impl CanRxHandler {
pub struct CanTxHandler {
interface: &'static str,
socket: socket::CanSocket,
message_map: HashMap<MessageId, SenderReceiverApid>,
message_receiver: Receiver<MessageModel>,
package_map: HashMap<PackageId, SenderReceiverThread>,
message_receiver: Receiver<PackageModel>,
}
impl CanTxHandler {
pub fn new_socket(
interface: &'static str,
message_map: HashMap<MessageId, SenderReceiverApid>,
message_receiver: Receiver<MessageModel>,
package_map: HashMap<PackageId, SenderReceiverThread>,
message_receiver: Receiver<PackageModel>,
) -> Result<CanTxHandler, ()> {
let socket = socket::CanSocket::open(&interface);
@ -101,7 +101,7 @@ impl CanTxHandler {
Ok(CanTxHandler {
interface,
socket,
message_map,
package_map,
message_receiver,
})
} else {
@ -110,17 +110,17 @@ impl CanTxHandler {
}
pub fn process_incoming(&mut self) {
if let Ok(message) = self.message_receiver.recv() {
self.tx_socket(message.message_id(), message.data());
if let Ok(package) = self.message_receiver.recv() {
self.tx_socket(package.package_id(), package.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();
pub fn tx_socket(&self, package_id: PackageId, data: &[u8]) {
if self.package_map.contains_key(&package_id) {
let value = self.package_map.get(&package_id).unwrap();
if value.get_sender() == DeviceId::OBC {
if data.len() <= 8 {
let frame_id = message_id_to_can_id(&message_id);
let frame_id = package_id_to_can_id(&package_id);
let frame = CanFrame::new(frame_id, data);
if let Some(frame) = frame {
self.socket
@ -140,7 +140,7 @@ impl CanTxHandler {
);
}
} else {
warn!("Message dismissed, wrong package id: {:?}", message_id);
warn!("Message dismissed, wrong package id: {:?}", package_id);
}
}
}

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 {
@ -127,33 +118,32 @@ impl TryFrom<u16> for DeviceId {
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),
_ => 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,5 @@
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 +11,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 +21,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(

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)
}
}

392
src/hk.rs
View File

@ -1,243 +1,128 @@
use std::collections::HashMap;
use crate::hk::AocsDataType::FloatValue;
use crate::aocs_handler::{MGMData};
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 crate::tmtc::TmStore;
use eurosim_obsw::{hk_err};
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::pus::verification::{
FailParams, StdVerifSenderError, VerificationReporterWithSender,
};
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::time::cds::TimeProvider;
use satrs_core::spacepackets::time::TimeWriter;
use satrs_core::spacepackets::tm::{PusTm, PusTmSecondaryHeader};
use satrs_core::spacepackets::SpHeader;
use satrs_core::tmtc::AddressableId;
use serde::{Deserialize, Serialize};
use std::ops::{Deref};
use std::sync::mpsc::{Receiver, Sender};
use std::sync::{Arc, Mutex};
use strum_macros::EnumIter;
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 AocsHkIds {
TestAocsSet = 1,
TestMgmSet = 2,
}
#[derive(Clone, Debug)]
pub struct AocsDataMap {
map: HashMap<UniqueId, AocsDataType>,
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum HkRequest {
OneShot(AddressableId),
Enable(AddressableId),
Disable(AddressableId),
ModifyCollectionInterval(AddressableId, CollectionIntervalFactor),
}
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(Serialize, Deserialize)]
pub struct AocsSensorData {
mgm_data: MGMData, // Voltage for 3 axis
css_data: [f64; 18], // Voltage for 18 sun sensors
str_data: [f64; 4], // Quaternion for position of satellite
}
#[derive(Debug, EnumIter, PartialEq, Copy, Clone)]
pub enum AocsDataType {
FloatValue(f64),
impl AocsSensorData {
pub fn new() -> AocsSensorData {
let mgm_data = MGMData::default();
let css_data = [0.0; 18];
let str_data = [0.0; 4];
AocsSensorData {
mgm_data,
css_data,
str_data,
}
}
pub fn update_mgm_data(&mut self, mgm_data: &Arc<Mutex<MGMData>>) {
let data = mgm_data.lock().unwrap();
self.mgm_data = *data;
}
pub fn write_css_data(&mut self, css_data: [f64; 18]) {
self.css_data = css_data;
}
pub fn write_str_data(&mut self, str_data: [f64; 4]) {
self.str_data = str_data;
}
pub fn get_mgm_data(&mut self) -> MGMData {
self.mgm_data
}
pub fn read_css_data(&mut self) -> [f64; 18] {
self.css_data
}
pub fn read_str_data(&mut self) -> [f64; 4] {
self.str_data
}
}
pub struct AocsHousekeeper {
data_map: Arc<Mutex<AocsDataMap>>,
id_list: Vec<UniqueId>,
request_rx: Receiver<RequestWithToken>,
sensor_data_pool: Arc<Mutex<AocsSensorData>>,
action_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,
verif_reporter: VerificationReporterWithSender<StdVerifSenderError>,
}
impl AocsHousekeeper {
pub fn new(
sensor_data_pool: Arc<Mutex<AocsDataMap>>,
request_rx: Receiver<RequestWithToken>,
sensor_data_pool: Arc<Mutex<AocsSensorData>>,
action_rx: Receiver<RequestWithToken>,
seq_count_provider: SeqCountProviderSyncClonable,
aocs_tm_store: TmStore,
aocs_tm_funnel_tx: Sender<StoreAddr>,
verif_reporter: VerificationReporterWithSender<MpscPusInStoreSendError>,
verif_reporter: VerificationReporterWithSender<StdVerifSenderError>,
) -> 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,
sensor_data_pool,
action_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 Ok(request_with_token) = self.action_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))
.start_success(request_with_token.1, 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::OneShot(id) => self.one_shot_hk(id),
HkRequest::Enable(id) => self.enable_hk(id),
HkRequest::Disable(id) => self.disable_hk(id),
HkRequest::ModifyCollectionInterval(_id, _collection_interval) => Ok(()),
} {
let cds_stamp = TimeProvider::from_now_with_u16_days().unwrap();
@ -263,122 +148,26 @@ impl AocsHousekeeper {
}
}
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);
pub fn one_shot_hk(&mut self, id: AddressableId) -> Result<(), ()> {
let json_string = self.aocs_data_to_str();
self.send_hk_packet(id, &json_string);
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;
pub fn enable_hk(&mut self, _id: AddressableId) -> Result<(), ()> {
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);
}
}
pub fn disable_hk(&mut self, _id: AddressableId) -> Result<(), ()> {
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();
let pool = self.sensor_data_pool.lock().unwrap();
serde_json::to_string(pool.deref()).unwrap()
}
*/
pub fn send_hk_packet_from_str(&mut self, id: UniqueId, data: &str) {
pub fn send_hk_packet(&mut self, id: AddressableId, data: &str) {
let mut time_stamp_buf: [u8; 7] = [0; 7];
let mut huge_buf: [u8; 8192] = [0; 8192];
@ -386,8 +175,7 @@ impl AocsHousekeeper {
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;
let mut len = id.write_to_be_bytes(&mut huge_buf).unwrap();
huge_buf[8..data.len() + 8].copy_from_slice(data.as_bytes());
len += data.len();
let tm_sec_header =
@ -396,26 +184,4 @@ impl AocsHousekeeper {
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");
}
}

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

@ -4,43 +4,45 @@
mod action;
mod aocs;
mod aocs_handler;
mod cam;
#[cfg(feature = "can")]
mod can;
mod can_ids;
mod ccsds;
mod helpers;
mod hk;
mod logger;
mod messages;
mod pld_handler;
mod power_handler;
mod pus;
mod requests;
mod tmtc;
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::{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,
};
use satrs_core::pus::verification::{
MpscVerifSender, VerificationReporterCfg, VerificationReporterWithSender,
};
use satrs_core::pus::{EcssTmErrorWithSend, EcssTmSenderCore};
use satrs_core::seq_count::SeqCountProviderSyncClonable;
use satrs_core::{spacepackets::tm::PusTm};
use strum::IntoEnumIterator;
use crate::can_ids::{
load_message_id_to_apids, load_message_id_to_threads, DeviceId, MessageModel,
load_package_ids, DeviceId, PackageModel, ThreadId,
};
use chrono::Duration;
use log::info;
use log::{info};
use satrs_core::power::{SwitchId, SwitchState};
use std::collections::HashMap;
use std::net::{IpAddr, SocketAddr};
@ -48,13 +50,38 @@ use std::sync::mpsc::channel;
use std::sync::{mpsc, Arc, Mutex, RwLock};
use std::thread;
//use libc::time64_t;
use crate::aocs::{AocsController, MGMHandler, STRHandler, GPSHandler, CSSHandler};
use crate::aocs_handler::{MGMData, MGMHandler};
#[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::hk::{AocsHousekeeper, AocsSensorData};
use crate::pld_handler::{core_pld_task};
use crate::power_handler::{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() {
logger::setup_logger().unwrap();
@ -84,25 +111,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,7 +137,8 @@ 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 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();
@ -126,20 +146,11 @@ fn main() {
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 (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, aocs_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 +159,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 +177,18 @@ 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();
info!("Starting TMTC task");
let builder0 = thread::Builder::new().name("TMTCThread".into());
@ -212,8 +199,7 @@ fn main() {
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();
let mut can_rx_socket = can::CanRxHandler::new_socket("can0", can_senders.clone(), package_ids_rx.clone()).unwrap();
#[cfg(feature = "can")]
info!("Starting CAN Socket listening task");
@ -224,19 +210,19 @@ fn main() {
});
#[cfg(feature = "can")]
let mut can_tx_socket =
CanTxHandler::new_socket("can0", message_ids_rx.clone(), can_tx_receiver).unwrap();
let mut can_tx_socket = CanTxHandler::new_socket("can0", package_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 {
let jh_can_tx = builder_can_tx.spawn( move || loop {
#[cfg(feature = "can")]
can_tx_socket.process_incoming();
});
let (pcdu_tx, pcdu_rx) = mpsc::channel::<(SwitchId, SwitchState)>();
let pcdu_can_tx_sender = can_tx_sender.clone();
let pcdu_can_tx_sender =
can_tx_sender.clone();
let mut device_state_map = HashMap::new();
for id in DeviceId::iter() {
@ -246,7 +232,7 @@ fn main() {
let 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(
@ -257,11 +243,12 @@ fn main() {
);
});
let package_map_pld_tx = load_message_id_to_threads();
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 pld_can_tx_sender = can_tx_sender.clone();
let pld_can_tx_sender =
can_tx_sender.clone();
let power_switcher_pld = power_switcher.clone();
@ -295,169 +282,38 @@ fn main() {
}
});
let package_map_aocs_tx = load_message_id_to_threads();
let package_map_aocs_tx = load_package_ids();
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));
let mgm_shared_data: Arc<Mutex<MGMData>> = Arc::default();
let aocs_sensor_data = Arc::new(Mutex::new(AocsSensorData::new()));
let (aocs_mode_tx, aocs_mode_rx) = channel();
let (mgm_action_tx, mgm_action_rx) = channel();
let power_switcher_aocs = power_switcher.clone();
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 mut mgm_handler = MGMHandler::new(power_switcher_aocs.clone(), DeviceId::MGM1, can_tx_sender.clone(), aocs_can_rx, aocs_mode_rx, mgm_action_rx);
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(
let aocs_sensor_data = Arc::new(Mutex::new(AocsSensorData::new()));
let mut aocs_housekeeper = AocsHousekeeper::new(
aocs_sensor_data.clone(),
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,
aocs_seq_count_provider,
aocs_tm_store,
aocs_tm_funnel_tx,
reporter_aocs,
);
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();
let mut locked_sensor_data = aocs_sensor_data.lock().unwrap();
locked_sensor_data.update_mgm_data(&mgm_handler.get_data_ref());
drop(locked_sensor_data);
aocs_housekeeper.handle_hk_request();
}
});
@ -465,11 +321,11 @@ fn main() {
.join()
.expect("Joining UDP TMTC server thread failed");
jh1.unwrap()
.join()
.expect("Joining CAN Bus Listening thread failed");
jh_can_tx
.unwrap()
jh_can_tx.unwrap()
.join()
.expect("Joining CAN Bus Writing thread failed");
jh2.unwrap().join().expect("Joining power thread failed");

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,18 +1,15 @@
use crate::action::ActionRequest;
use crate::can_ids::{DeviceId, MessageId, MessageModel};
use crate::can_ids::{DeviceId, PackageId, PackageModel};
use crate::power_handler::{DeviceState, PowerSwitcher};
use crate::requests::{Request, RequestWithToken};
use eurosim_obsw::{RequestTargetId};
use log::debug;
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 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;
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum CameraMode {
@ -21,7 +18,6 @@ pub enum CameraMode {
Verification,
Start,
End,
Broken,
}
pub struct CameraHandler {
@ -29,8 +25,8 @@ pub struct CameraHandler {
camera_device_id: DeviceId,
camera_switch_id: SwitchId,
device_state: DeviceState,
can_tx: Sender<MessageModel>,
can_rx: Receiver<MessageModel>,
can_tx: Sender<PackageModel>,
can_rx: Receiver<PackageModel>,
mode: CameraMode,
mode_rx: Receiver<CameraMode>,
action_rx: Receiver<RequestWithToken>,
@ -40,8 +36,8 @@ impl CameraHandler {
pub fn new(
power_switcher: PowerSwitcher,
camera_device_id: DeviceId,
can_tx: Sender<MessageModel>,
can_rx: Receiver<MessageModel>,
can_tx: Sender<PackageModel>,
can_rx: Receiver<PackageModel>,
mode_rx: Receiver<CameraMode>,
action_rx: Receiver<RequestWithToken>,
) -> CameraHandler {
@ -131,7 +127,6 @@ impl CameraHandler {
// Camera Device Handler State Machine
match self.mode {
CameraMode::Broken => {}
CameraMode::Idle => {}
CameraMode::PictureRequest => {
if self.device_state == DeviceState::Off {
@ -142,23 +137,17 @@ impl CameraHandler {
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");
}
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();
self.can_tx.send(PackageModel::new(PackageId::CameraImageRequest, &[1]).unwrap()).unwrap();
debug!("sent camera request");
self.mode = CameraMode::Verification;
}
@ -167,7 +156,7 @@ impl CameraHandler {
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 {
if msg.package_id() == PackageId::CameraImageRequestConfirmation {
self.mode = CameraMode::Start;
}
}
@ -177,7 +166,7 @@ impl CameraHandler {
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 {
if msg.package_id() == PackageId::CameraImageExecutionStart {
self.mode = CameraMode::End;
}
}
@ -187,7 +176,7 @@ impl CameraHandler {
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 {
if msg.package_id() == PackageId::CameraImageExectutionEnd {
self.power_switcher
.send_switch_off_cmd(self.camera_switch_id)
.expect("sending switch command failed");
@ -217,9 +206,9 @@ impl CameraHandler {
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>,
pld_can_rx: Receiver<PackageModel>,
pld_can_tx: Sender<PackageModel>,
reporter_pld: &mut VerificationReporterWithSender<StdVerifSenderError>,
) {
let (_camera_mode_tx, camera_mode_rx) = mpsc::channel();
let (_action_tx, action_rx) = mpsc::channel();
@ -248,17 +237,12 @@ pub fn core_pld_task(
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),
)
.start_success(request_with_token.1, 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();

View File

@ -1,9 +1,13 @@
use crate::can_ids::{DeviceId, MessageId, MessageModel};
use satrs_core::power::{PowerSwitchInfo, PowerSwitcherCommandSender, SwitchId, SwitchState};
use crate::can_ids::{DeviceId, PackageId, PackageModel};
use log::{debug};
use satrs_core::power::{
PowerSwitchInfo, PowerSwitchProvider, PowerSwitcherCommandSender, SwitchId, SwitchState,
};
use std::collections::HashMap;
use std::convert::TryFrom;
use std::sync::mpsc::{Receiver, Sender};
use std::sync::{Arc, Mutex};
use std::time::Duration;
use std::vec;
pub use strum::IntoEnumIterator; // 0.17.1
pub use strum_macros::EnumIter; // 0.17.1
@ -23,10 +27,10 @@ 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: Sender<PackageModel>,
can_rx: Receiver<PackageModel>,
device_state_map: Arc<Mutex<HashMap<DeviceId, SwitchState>>>,
}
@ -81,14 +85,18 @@ impl PowerSwitchInfo for PowerSwitcher {
}
}
impl PCDUHandler {
impl PowerSwitchProvider for PowerSwitcher {
type Error = ();
}
impl PCDU {
pub fn new(
switch_rx: Receiver<(SwitchId, SwitchState)>,
can_tx: Sender<MessageModel>,
can_rx: Receiver<MessageModel>,
can_tx: Sender<PackageModel>,
can_rx: Receiver<PackageModel>,
device_state_map: Arc<Mutex<HashMap<DeviceId, SwitchState>>>,
) -> PCDUHandler {
PCDUHandler {
) -> PCDU {
PCDU {
switch_rx,
can_tx,
can_rx,
@ -100,12 +108,12 @@ impl PCDUHandler {
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.send(PackageModel::new(PackageId::DevicePowerOnRequest, buf).unwrap()).unwrap();
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().unwrap();
self.can_rx.recv().unwrap();
Ok(())
} else {
Err(())
@ -116,11 +124,11 @@ impl PCDUHandler {
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.send(PackageModel::new(PackageId::DevicePowerOffRequest, buf).unwrap()).unwrap();
let mut map_lock = self.device_state_map.lock().unwrap();
*map_lock.get_mut(&dev_id).unwrap() = SwitchState::Unknown;
self.can_rx.recv().unwrap();
self.can_rx.recv().unwrap();
Ok(())
} else {
Err(())
@ -128,12 +136,10 @@ impl PCDUHandler {
}
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.send(PackageModel::new(PackageId::DevicePowerStatusRequest, buf).unwrap()).unwrap();
match self.can_rx.recv_timeout(Duration::from_secs(10)) {
Ok(msg) => {
if msg.package_id() == PackageId::DevicePowerStatusResponse
@ -159,9 +165,6 @@ impl PCDUHandler {
}
Err(_) => Err(()),
}
*/
Ok(())
}
pub fn update_all_states_helper(&mut self) -> Result<(), ()> {
@ -177,18 +180,11 @@ 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;
}
Ok(())
},
DeviceId::All => self.update_all_states_helper(),
_ => self.update_states_helper(&dev_id),
}
} else {
Err(())
@ -201,7 +197,6 @@ impl PCDUHandler {
match switch_state {
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(_) => {
@ -210,7 +205,6 @@ impl PCDUHandler {
},
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(_) => {
@ -219,6 +213,7 @@ impl PCDUHandler {
},
_ => {}
}
self.update_switch_states(switch_id).unwrap();
}
return Ok(i);
}
@ -226,11 +221,11 @@ impl PCDUHandler {
pub fn core_power_task(
switch_rx: Receiver<(SwitchId, SwitchState)>,
can_tx: Sender<MessageModel>,
can_rx: Receiver<MessageModel>,
can_tx: Sender<PackageModel>,
can_rx: Receiver<PackageModel>,
device_state_map: Arc<Mutex<HashMap<DeviceId, SwitchState>>>,
) {
let mut pcdu = PCDUHandler::new(switch_rx, can_tx, can_rx, device_state_map);
let mut pcdu = PCDU::new(switch_rx, can_tx, can_rx, device_state_map);
loop {
pcdu.handle_power_requests().unwrap();
}

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::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(
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 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,6 +192,8 @@ 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();
@ -220,6 +201,8 @@ pub fn core_tmtc_task(args: OtherArgs, mut tc_args: TcArgs, tm_args: TmArgs) {
&mut udp_tmtc_server,
&mut tc_args,
&mut tc_buf,
//&mut tc_source,
//&mut tc_receiver,
&mut pus_receiver,
tmtc_sched,
);
@ -231,6 +214,8 @@ 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>>,
) {
@ -256,7 +241,7 @@ fn core_tmtc_loop(
scheduler.update_time_from_now().unwrap();
if let Ok(released_tcs) = scheduler.release_telecommands(releaser, pool.as_mut()) {
if released_tcs > 0 {
info!("{released_tcs} TC(s) released from scheduler");
println!("{released_tcs} TC(s) released from scheduler");
}
}
drop(pool);
@ -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